LINQ to XML cz. 4, Transformacje i serializacja
Poprzednie odcinki cyklu stanowią solidną podstawę do rozpoczęcia "prawdziwej" pracy z technologią Linq to Xml. Ta "prawdziwa" praca to transformacje i serializacja dokumentów Xmlowych - jedne z najczęstszych zastosowań technologii Linq to Xml. Przy okazji poznamy nowe elementy języka C#, które świetnie uzupełniają Linq to Xml.
Technologia Linq to Xml doskonale nadaje się do prostych transformacji dokumentów Xmlowych. Nie oznacza to, że Linq to Xml zastępuje Xslt. Xslt jest wciąż standardem w tym zakresie. Często jednak zdarza się, że trzeba tylko nieznacznie zmienić dokument Xmlowy. Zwykle w takim przypadku zastosowanie Xslt to "przewaga formy nad treścią" - czas potrzebny na parsowanie, kompilację oraz czas samej kompilacja arkusza jest niewspółmiernie duży w stosunku do pożądanego efektu. Z drugiej strony użycie interfejsu DOM jest zazwyczaj dość uciążliwe. Linq to Xml znakomicie wypełnia tę lukę. Jak? Zobaczmy na przykładach.
(W przykładach będziemy używać tego samego dokumentu co w poprzednich odcinkach cyklu, który wygląda tak:
<?xml version=""1.0""?>
<wycieczka>
<segment>
<wylot kod-lotniska=""SEA"" data=""2008-10-09T15:25Z"">
Seattle-Tacoma International</wylot>
<przylot kod-lotniska=""LHR"" data=""2008-10-10T02:20Z"">
London Heathrow</przylot>
</segment>
<segment>
<wylot kod-lotniska=""LHR"" data=""2008-10-10T05:35Z"">
London Heathrow</wylot>
<przylot kod-lotniska=""WRO"" data=""2008-10-10T10:05Z"">
Wroclaw Strachowice</przylot>
</segment>
</wycieczka>)
Na dobry początek spróbujmy coś prostego - usuńmy z dokumentu węzły tekstowe zawierające nazwy lotnisk. W Linq to Xml można to zrobić za pomocą jednej linijki kodu, która wygląda tak:
xDoc.Elements("wycieczka").Elements("segment").Elements().Nodes().Remove()Krótkie i nawet działa!
Zróbmy coś co wymaga więcej niż jednej linijki kodu - spróbujmy rozdzielić atrybut data na dwa atrybuty - data i godzina zawierające odopowiednio datę (dzień) i godzinę. Można to osiągnąć w następujący sposób:
foreach(var element in
xDoc.Elements("wycieczka").Elements("segment").Elements()) {
element.Add(new XAttribute("godzina",
element.Attribute("data").Value.Substring(11, 5)));
element.Attribute("data").Value =
element.Attribute("data").Value.Substring(0, 10);
}
Rzeczywiście - to już 4 linie. W pierwszej wybieramy wszystkie elementy po których będziemy iterować. Następnie każdemy elementowi dodajemy atrybut "godzina" którego wartość jest wycięta w odpowiedni sposób z istniejącego atrybutu "data". Wartość samego atrybutu "data" obcinamy tak, żeby nie zawierała informacji o godzinie.
Po tej rozgrzewce spróbujmy zrobić coś bardziej skomplikowanego. Mianowicie zbudujmy xhtmlową tabelkę zawierającą szczegóły dotyczące wycieczki. Z Linq to Xml można to zrobić:
var element =
new XElement("table",
new XElement("tr",
new XElement("th",
new XText("Wylot")),
new XElement("th",
new XText("Przylot"))),
from segment in xDoc.Elements("wycieczka").Elements("segment")
select new
XElement("tr", from przelot in segment.Elements()
select new XElement("td",
new XText(string.Format("{0} ({1}) {2}",
(string)przelot,
(string)przelot.Attribute("kod-lotniska"),
(string)przelot.Attribute("data"))))));
Wygląda to troche bardziej skomplikowanie niż poprzednie fragmenty. Co się tu dzieje? Zacznijmy od początku - najpierw tworzymy element o nazwie "table" oraz wiersz nagłówkowy tabeli. Ten kod jest bardzo podobny do kodu z pierwszego artykułu cyklu zawierającego opis "ręcznego" (tj. bezpośrednio w programie) tworzenia dokumentów Xmlowych za pomocą Linq to Xml. To co najbardziej interesujące dzieje się w drugiej części fragmentu kodu gdzie wykorzystujemy następujący konstruktor klasy XElement:
XElement(XName name, params object[] content)
który pozwala na przekazanie tablicy węzłów, które będą dziećmi tworzonego elementu. Konstruktor ten w połączeniu z zapytaniem Linqowym umożliwia stworzenie nowych elementów na podstawie przetwarzanego dokumentu Xmlowego. W naszym przykładzie - dla każdego elementu "segment" w źródłowym dokumencie tworzymy nowy element "tr", w którym z kolei tworzymy (przy wykorzystaniu tej samej techniki) tyle elelementów "td" ile węzeł "segment" ma elementów-dzieci. Stworzony węzeł "td" ma jako dziecko węzeł tekstowy zawierający odpowiednie informacje pobrane z dokumentu źródłowego.

