最佳的读取、修改和写入XML的方法

20
我的计划是使用C#程序读取一个XML文档,搜索想要更改的特定条目,然后写入修改后的文档。但我卡在了这里,因为使用XmlTextReader读取文件时很难区分元素的开头和结尾。我需要一些建议来指导我正确前进。
这个文档是HTML文件,所以你可以想象它相当复杂。
我想在HTML文档中搜索一个元素ID,例如查找这个并更改src属性;
<img border="0" src="bigpicture.png" width="248" height="36" alt="" id="lookforthis" />
8个回答

35
如果它确实是有效的XML,并且可以轻松地放入内存中,我会选择LINQ to XMLXDocumentXElement等)。这是我使用过的最好的XML API。很容易形成查询,也很容易构造新元素。
您可以在适当的情况下使用XPath,或者使用内置的轴方法(Elements()Descendants()Attributes()等)。如果您能让我们知道您遇到困难的具体部分,我很乐意帮助您了解如何在LINQ to XML中表达它们。
另一方面,如果这是不合法的HTML,您将会遇到更大的困难,因为XML API通常期望使用有效的XML文档。当然,您可以首先使用HTMLTidy,但这可能会产生不良影响。
针对您的具体示例:
XDocument doc = XDocument.Load("file.xml");
foreach (var img in doc.Descendants("img"))
{
    // src will be null if the attribute is missing
    string src = (string) img.Attribute("src");
    img.SetAttributeValue("src", src + "with-changes");
}

1
我完全同意!我有几个老的应用程序需要通过解析等方式来完成,而L2X使得这一切变得更加容易和强大。 - Dillie-O
1
Jon,你可能会发现HtmlAgilityPack非常有用,它可以让你不必担心有效的XML,而是可以使用类似于XDocument的API来处理真实世界中的脏HTML。 - Peter J
1
@Peter:幸运的是我很少需要处理不规范的HTML - 我发现自己更频繁地使用真正的XML。不过我会记住的。 - Jon Skeet

5

您正在处理的文档相对较小吗?如果是,您可以使用XmlDocument对象将它们加载到内存中,修改它们,然后将更改写回。

XmlDocument doc = new XmlDocument();
doc.Load("path_to_input_file");
// Make changes to the document.
using(XmlTextWriter xtw = new XmlTextWriter("path_to_output_file", Encoding.UTF8)) {
  xtw.Formatting = Formatting.Indented; // optional, if you want it to look nice
  doc.WriteContentTo(xtw);
}

根据输入XML的结构不同,这可以使您的解析代码变得更加简单。


3

这是我编写的一个工具,用于修改IAR EWARM项目(ewp)文件并向项目添加链接器定义。从命令行中,您需要使用两个参数运行它,输入和输出文件名(*.ewp)。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Xml;

    namespace ewp_tool
    {
        class Program
        {
            static void Main(string[] args)
            {
                XmlDocument doc = new XmlDocument();
                doc.Load(args[0]);

                XmlNodeList list = doc.SelectNodes("/project/configuration[name='Debug']/settings[name='ILINK']/data/option[name='IlinkConfigDefines']/state");
                foreach(XmlElement x in list) {
                    x.InnerText = "MAIN_APP=1";
                }

                using (XmlTextWriter xtw = new XmlTextWriter(args[1], Encoding.UTF8))
                {
                    //xtw.Formatting = Formatting.Indented; // leave this out, it breaks EWP!
                    doc.WriteContentTo(xtw);
                }
            }
        }
    }

XML的结构如下所示。
    <U+FEFF><?xml version="1.0" encoding="iso-8859-1"?>
    <project>
      <fileVersion>2</fileVersion>
      <configuration>
        <name>Debug</name>
        <toolchain>
          <name>ARM</name>
        </toolchain>
        <debug>1</debug>

         ...

        <settings>
          <name>ILINK</name>
          <archiveVersion>0</archiveVersion>
          <data>

            ...

            <option>
              <name>IlinkConfigDefines</name>
              <state>MAIN_APP=0</state>
            </option>

1
如果您有适合计算机内存的较小文档,可以使用XmlDocument。否则,您可以使用XmlReader来迭代文档。
使用XmlReader,您可以通过以下方式找到元素类型:
while (xml.Read()) {
   switch xml.NodeType {
     case XmlNodeType.Element:
      //Do something
     case XmlNodeType.Text:
      //Do something
     case XmlNodeType.EndElement:  
      //Do something
   }
}

1

我在这种情况下最喜欢用的工具是 HtmlAgilityPack。我使用它将复杂的HTML文档解析为可查询的LINQ集合。对于查询和解析HTML(通常不是有效的XML)非常有用。

针对您的问题,代码看起来会像这样:

var htmlDoc = HtmlAgilityPack.LoadDocument(stringOfHtml);
var images = htmlDoc.DocumentNode.SelectNodes("//img[id=lookforthis]");

if(images != null)
{
  foreach (HtmlNode node in images)  
  {  
      node.Attributes.Append("alt", "added an alt to lookforthis images.");  
  }  
}

htmlDoc.Save('output.html');

1

对于手头的任务 - (阅读现有文档、以规范化的方式编写和修改),我会选择通过XPathDocument流经XslCompiledTransform

在您无法形式化、没有预先存在的文档或通常需要更具适应性的逻辑时,我会像Skeet所说的那样使用LINQ和XDocument。

基本上,如果任务是转换,则使用XSLT,如果任务是操作,则使用LINQ。


0
一个相对简单的方法是创建一个新的XmlDocument,然后使用Load()方法填充它。一旦你有了文档,你可以使用CreateNavigator()来获取一个XPathNavigator对象,你可以用它来查找和修改文档中的元素。最后,你可以使用XmlDocument上的Save()方法将更改后的文档写回。

-1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接