Modyfikacja drzewa XML w pamięci a konstrukcja funkcjonalna (LINQ to XML)

Modyfikowanie drzewa XML jest tradycyjnym podejściem do zmiany kształtu dokumentu XML. Typowa aplikacja ładuje dokument do magazynu danych, takiego jak DOM lub LINQ to XML; używa interfejsu programowania do wstawiania lub usuwania węzłów lub zmiany ich zawartości; a następnie zapisuje plik XML w pliku lub przesyła go za pośrednictwem sieci.

LINQ to XML umożliwia inne podejście, które jest przydatne w wielu scenariuszach: konstrukcja funkcjonalna. Konstrukcja funkcjonalna traktuje modyfikowanie danych jako problem transformacji, a nie jako szczegółowe manipulowanie magazynem danych. Jeśli możesz przyjąć reprezentację danych i efektywnie przekształcić je z jednego formularza na inny, wynik będzie taki sam, jak w przypadku, gdy jeden magazyn danych został w jakiś sposób zmanipulowany, aby przejąć inny kształt. Kluczem do podejścia do budowy funkcjonalnej jest przekazanie wyników zapytań do XDocument i XElement konstruktorów.

W wielu przypadkach można napisać kod transformacyjny w ułamku czasu, który zajmie manipulowanie magazynem danych, a wynikowy kod jest bardziej niezawodny i łatwiejszy w obsłudze. W takich przypadkach, mimo że podejście transformacyjne może mieć większą moc obliczeniową, jest to bardziej skuteczny sposób modyfikowania danych. Jeśli deweloper jest zaznajomiony z podejściem funkcjonalnym, wynikowy kod w wielu przypadkach jest łatwiejszy do zrozumienia i łatwo jest znaleźć kod, który modyfikuje każdą część drzewa.

Podejście, w którym można zmodyfikować drzewo XML, jest bardziej znane wielu programistom DOM, podczas gdy kod napisany przy użyciu podejścia funkcjonalnego może wyglądać nieznany deweloperowi, który jeszcze nie rozumie tego podejścia. Jeśli musisz wprowadzić tylko niewielką modyfikację dużego drzewa XML, podejście, w którym modyfikujesz drzewo w wielu przypadkach, zajmie mniej czasu procesora CPU.

Ten artykuł zawiera przykłady obu podejść. Załóżmy, że chcesz zmodyfikować następujący prosty dokument XML, aby atrybuty stały się elementami:

<?xml version="1.0" encoding="utf-8" ?>
<Root Data1="123" Data2="456">
  <Child1>Content</Child1>
</Root>

Pierwszy z poniższych przykładów używa tradycyjnego podejścia modyfikacji w miejscu, a drugi używa podejścia do budowy funkcjonalnej.

Przykład: przekształcanie atrybutów w elementy przy użyciu tradycyjnego podejścia w miejscu

Możesz napisać kod proceduralny, aby utworzyć elementy na podstawie atrybutów, a następnie usunąć atrybuty w następujący sposób:

XElement root = XElement.Load("Data.xml");
foreach (XAttribute att in root.Attributes()) {
    root.Add(new XElement(att.Name, (string)att));
}
root.Attributes().Remove();
Console.WriteLine(root);
Dim root As XElement = XElement.Load("Data.xml")
For Each att As XAttribute In root.Attributes()
    root.Add(New XElement(att.Name, att.Value))
Next
root.Attributes().Remove()
Console.WriteLine(root)

Ten przykład generuje następujące wyniki:

<Root>
  <Child1>Content</Child1>
  <Data1>123</Data1>
  <Data2>456</Data2>
</Root>

Przykład: Przekształcanie atrybutów w elementy przy użyciu podejścia do budowy funkcjonalnej

Natomiast podejście funkcjonalne składa się z kodu w celu utworzenia nowego drzewa, wybierania i wybierania elementów i atrybutów z drzewa źródłowego oraz przekształcania ich odpowiednio w miarę dodawania ich do nowego drzewa.

XElement root = XElement.Load("Data.xml");
XElement newTree = new XElement("Root",
    root.Element("Child1"),
    from att in root.Attributes()
    select new XElement(att.Name, (string)att)
);
Console.WriteLine(newTree);
Dim root As XElement = XElement.Load("Data.xml")
Dim newTree As XElement = _
    <Root>
        <%= root.<Child1> %>
        <%= From att In root.Attributes() _
            Select New XElement(att.Name, att.Value) %>
    </Root>
Console.WriteLine(newTree)

W tym przykładzie jest zwracany ten sam kod XML co pierwszy przykład. Zauważ jednak, że w podejściu funkcjonalnym można zobaczyć wynikową strukturę nowego kodu XML. Możesz zobaczyć tworzenie Root elementu, kod, który ściąga Child1 element z drzewa źródłowego, oraz kod, który przekształca atrybuty z drzewa źródłowego na elementy w nowym drzewie.

Przykład funkcjonalny w tym przypadku nie jest krótszy ani prostszy niż w pierwszym przykładzie. Jeśli jednak masz wiele zmian w drzewie XML, podejście proceduralne stanie się dość złożone i nieco zatusze. Natomiast w przypadku korzystania z podejścia funkcjonalnego nadal wystarczy utworzyć żądany kod XML, osadzając zapytania i wyrażenia odpowiednio, aby ściągnąć żądaną zawartość. Podejście funkcjonalne zapewnia kod, który jest łatwiejszy do utrzymania.

Zwróć uwagę, że w tym przypadku podejście funkcjonalne prawdopodobnie nie będzie działać tak dobrze, jak podejście do manipulowania drzewem. Głównym problemem jest to, że podejście funkcjonalne tworzy więcej obiektów krótkotrwałych. Jednak kompromis jest skuteczny, jeśli użycie podejścia funkcjonalnego pozwala na większą produktywność programistów.

Jest to bardzo prosty przykład, ale służy do pokazania różnicy w filozofii między dwoma podejściami. Podejście funkcjonalne daje większe zyski w zakresie produktywności w przypadku przekształcania większych dokumentów XML.