内存中 XML 树修改与函数式构造(LINQ to XML)

就地修改 XML 树是更改 XML 文档形状的传统方法。 典型的应用程序将文档加载到 DOM 或 LINQ to XML 等数据存储中;使用编程接口插入或删除节点,或更改其内容;然后将 XML 保存到文件或通过网络传输它。

LINQ to XML 支持在很多方案中有用的另一种方法: 功能构造。 函数式构建将修改数据视为转化问题,而非对数据存储进行详细操作。 如果你能有效地将数据从一种形式转化为另一种形式,结果就如同对一个数据存储进行某种方式的操作以改变其形态一样。 功能构造方法的关键在于将查询结果传递给 XDocumentXElement 构造函数。

在许多情况下,可以在操纵数据存储所需时间的一小部分内编写变换代码,生成的代码更可靠且更易于维护。 在这些情况下,尽管转换方法可以采用更高的处理能力,但修改数据是一种更有效的方法。 如果开发人员熟悉功能方法,则在许多情况下生成的代码更易于理解,并且很容易找到修改树的每个部分的代码。

对许多 DOM 程序员来说,就地修改 XML 树的方法更为熟悉,而使用函数式方法编写的代码对尚不了解这种方法的开发人员可能显得陌生。 如果只需要对大型 XML 树进行少量修改,则在许多情况下修改树的方法将花费更少的 CPU 时间。

本文提供了这两种方法的示例。 假设你想要修改以下简单的 XML 文档,使属性成为元素:

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

以下示例中的第一个使用传统的就地修改方法,第二个示例使用功能构造方法。

示例:使用传统的就地方法将属性转换为元素

可以编写一些过程代码以从属性创建元素,然后删除这些属性,如下所示:

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)

此示例生成以下输出:

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

示例:使用功能构造方法将属性转换为元素

相比之下,功能方法包括用于形成新树的代码、从源树中选取和选择元素和属性,并在将元素和属性添加到新树时根据需要对其进行转换。

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)

此示例输出与第一个示例相同的 XML。 但是,请注意,在函数式方法中,您实际上可以看到新 XML 的结果结构。 可以看到 Root 元素的创建过程、从源树中提取 Child1 元素的代码,以及将源树中的属性转化为新树中的元素的代码。

在本例中,函数示例既短也不比第一个示例简单。 但是,如果对 XML 树进行了许多更改,则过程方法将变得相当复杂,有些模糊。 相比之下,使用功能方法时,你仍然只是形成所需的 XML,根据需要嵌入查询和表达式,以拉取所需内容。 函数方法生成更易于维护的代码。

请注意,在这种情况下,功能方法的表现可能不如树操作法。 主要问题是,功能方法会创建更多的生存期较短的对象。 但是,如果使用函数方法能够提高程序员的效率,则折中也是一种有效的方式。

这是一个非常简单的示例,但它有助于显示两种方法之间的哲学差异。 功能方法可提高转换大型 XML 文档的工作效率。