【问题标题】:Uncommenting fragment of XML with Xml Document in C#在 C# 中使用 Xml 文档取消注释 XML 片段
【发布时间】:2015-02-09 21:58:31
【问题描述】:

在 XML 中取消注释某个节点的正文的最简单方法是什么?元素具有唯一名称,文档结构如下:

一些文件.xml

<?xml version="1.0"?>
<name1>
  <irrelevant1>
    <irrelevant2>
    <!--
      <irrelevant3 />
    -->
    </irrelevant2>
  </irrelevant1>
  <name2>
    <name3>
    <!--
      <name4 field="The" />
      <name4 field="Owls" />
      <name4 field="Are />
      <name4 field="Not" />
      <name4 field="What" />
      <name4 field="They" />
      <name4 field="Seem />
    -->
    </name3>
  </name2>
</name1>

目标应该是这样的,移除了 cmets:

uncommented.xml

<?xml version="1.0"?>
<name1>
  <irrelevant1>
    <irrelevant2>
    <!--
      <irrelevant3 />
    -->
    </irrelevant2>
  </irrelevant1>
  <name2>
    <name3>
      <name4 field="The" />
      <name4 field="Owls" />
      <name4 field="Are />
      <name4 field="Not" />
      <name4 field="What" />
      <name4 field="They" />
      <name4 field="Seem />
    </name3>
  </name2>
</name1>

我的解析方法:

XmlDocument xdoc = new XmlDocument();
xdoc.Load(@"C:\somefile.xml");

XmlNodeList nl = xdoc.GetElementsByTagName("name2");

XmlNode xn = nl[0];
string xn_content = xn.InnerXml;

xn_content = Regex.Replace(xn_content, "<!--|-->", String.Empty);

XmlDocument doc = new XmlDocument();
doc.LoadXml(xn_content);
XmlNode newNode = doc.DocumentElement;

// this import doesn't really help
xdoc.ImportNode(newNode, true);
xn.RemoveAll();
xn.AppendChild(newNode);

xdoc.Save(@"C:\uncommented.xml");

带有 ArgumentException 的结果:

{"要插入的节点来自不同的文档上下文。"}

【问题讨论】:

  • 您愿意使用 Linq to XML (XDocument) 吗?
  • 为什么 irrelevant3 没有被取消注释。 irrelevant2name3 使用的规则是什么。为什么只有name3s 的孩子没有注释?我们如何以编程方式区分它们?
  • 您缺少&lt;name4 field="Are /&gt; 的右引号。应该是&lt;name4 field="Are" /&gt;。也适用于&lt;name4 field="Seem /&gt;
  • @EZI :我使用 xdoc.GetElementsByTagName("name2") 仅处理部分内容,这样我的正则表达式就可以针对所需的片段
  • @sirVir 在 Linq 中,您只需获取后代节点并遍历它们以检查它们是否是 XComment。然后调用 ReplaceWith() 方法,将 XComment.Value 属性传递给它。您的 XComment 现在是 XElement。

标签: c# regex xml parsing dom


【解决方案1】:

您的直接问题是您调用XmlDocument.ImportNode() 但不使用返回的节点。你需要做newNode = xDoc.ImportNode(newNode, true);

但是,更简洁的方法是完全避免 Regex 解析。相反,下降XmlNode 层次结构,选择您希望取消注释的XmlComment 节点,将它们的InnerText 加载到XmlDocumentFragment,然后将其新创建的子节点添加到评论的父节点:

public static class XmlNodeExtensions
{
    public static XmlDocument Document(this XmlNode node)
    {
        for (; node != null; node = node.ParentNode)
        {
            var doc = node as XmlDocument;
            if (doc != null)
                return doc;
        }
        return null;
    }

    public static IEnumerable<XmlNode> AncestorsAndSelf(this XmlNode node)
    {
        for (; node != null; node = node.ParentNode)
            yield return node;
    }

    public static IEnumerable<XmlNode> DescendantsAndSelf(this XmlNode root)
    {
        if (root == null)
            yield break;
        yield return root;
        foreach (var child in root.ChildNodes.Cast<XmlNode>())
            foreach (var subChild in child.DescendantsAndSelf())
                yield return subChild;
    }

    public static void UncommentXmlNodes(IEnumerable<XmlComment> comments)
    {
        foreach (var comment in comments.ToList())
            UncommentXmlNode(comment);
    }

    public static void UncommentXmlNode(XmlComment comment)
    {
        if (comment == null)
            throw new NullReferenceException();
        var doc = comment.Document();
        if (doc == null)
            throw new InvalidOperationException();
        var parent = comment.ParentNode;
        var innerText = comment.InnerText;
        XmlDocumentFragment docFrag = doc.CreateDocumentFragment();
        //Set the contents of the document fragment.
        docFrag.InnerXml = innerText;
        XmlNode insertAfter = comment;
        foreach (var child in docFrag.ChildNodes.OfType<XmlElement>().ToList())
        {
            insertAfter = parent.InsertAfter(child, insertAfter);
        }
        parent.RemoveChild(comment);
    }
}

然后这样称呼它:

        string xml = @"<?xml version=""1.0""?>
        <name1>
          <irrelevant1>
            <irrelevant2>
            <!--
              <irrelevant3 />
            -->
            </irrelevant2>
          </irrelevant1>
          <name2>
            <name3>
            <!--
              <name4 field=""The"" />
              <name4 field=""Owls"" />
              <name4 field=""Are"" />
              <name4 field=""Not"" />
              <name4 field=""What"" />
              <name4 field=""They"" />
              <name4 field=""Seem"" />
            -->
            </name3>
          </name2>
        </name1>
        ";
        var xmlDoc = new XmlDocument();
        xmlDoc.LoadXml(xml);
        Debug.WriteLine(xmlDoc.ToXml());

        XmlNodeExtensions.UncommentXmlNodes(xmlDoc.DocumentElement.DescendantsAndSelf().OfType<XmlComment>().Where(c => c.ParentNode.Name == "name3"));

        Debug.WriteLine(xmlDoc.ToXml());

请注意,您注释的 XML 无效。 &lt;name4 field="Are /&gt; 应该是 &lt;name4 field="Are"/&gt;&lt;name4 field="Seem /&gt; 应该是 &lt;name4 field="Seem"/&gt;。我在测试用例中为你解决了这个问题,因为我认为这是一个错字。

【讨论】:

    猜你喜欢
    • 2012-12-08
    • 1970-01-01
    • 2020-12-30
    • 2020-09-27
    • 2015-09-19
    • 2010-11-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多