【问题标题】:Change the node names in an XML file using C#使用 C# 更改 XML 文件中的节点名称
【发布时间】:2009-01-24 01:31:14
【问题描述】:

我有一大堆具有以下结构的 XML 文件:

<Stuff1>
  <Content>someContent</name>
  <type>someType</type>
</Stuff1>
<Stuff2>
  <Content>someContent</name>
  <type>someType</type>
</Stuff2>
<Stuff3>
  <Content>someContent</name>
  <type>someType</type>
</Stuff3>
...
...

我需要将每个“内容”节点名称更改为 StuffxContent;基本上将父节点名称添加到内容节点的名称。

我计划使用 XMLDocument 类并想出一个方法,但我想我会问是否有更好的方法来做到这一点。

【问题讨论】:

    标签: c# xml


    【解决方案1】:

    (1.) [XmlElement / XmlNode].Name 属性是只读的。

    (2.) 问题中使用的 XML 结构很粗糙,可以改进。

    (3.) 无论如何,这里是给定问题的代码解决方案:

    String sampleXml =
      "<doc>"+
        "<Stuff1>"+
          "<Content>someContent</Content>"+
          "<type>someType</type>"+
        "</Stuff1>"+
        "<Stuff2>"+
          "<Content>someContent</Content>"+
          "<type>someType</type>"+
        "</Stuff2>"+
        "<Stuff3>"+
          "<Content>someContent</Content>"+
          "<type>someType</type>"+
        "</Stuff3>"+
      "</doc>";
    
    XmlDocument xmlDoc = new XmlDocument();
    xmlDoc.LoadXml(sampleXml);
    
    XmlNodeList stuffNodeList = xmlDoc.SelectNodes("//*[starts-with(name(), 'Stuff')]");
    
    foreach (XmlNode stuffNode in stuffNodeList)
    {
        // get existing 'Content' node
        XmlNode contentNode = stuffNode.SelectSingleNode("Content");
    
        // create new (renamed) Content node
        XmlNode newNode = xmlDoc.CreateElement(contentNode.Name + stuffNode.Name);
    
        // [if needed] copy existing Content children
        //newNode.InnerXml = stuffNode.InnerXml;
    
        // replace existing Content node with newly renamed Content node
        stuffNode.InsertBefore(newNode, contentNode);
        stuffNode.RemoveChild(contentNode);
    }
    
    //xmlDoc.Save
    

    PS:我来这里是为了寻找一种更好的方式来重命名节点/元素;我还在找。

    【讨论】:

    • 遗憾的是,拥有 51 代表的人比拥有 31k 代表的人更了解这一点。为您 +1,即使它是一个比我希望的稍微复杂的解决方案。
    • 它不会影响提问者的示例,但为了完整起见,您的例程不应仅复制 InnerXml,还应复制任何属性:for (int i = contentNode.Attributes.Count - 1; i > = 0; i --) { newNode.Attributes.Prepend((XmlAttribute)contentNode.RemoveAttributeAt(i)); }
    • 我猜如果您尝试更改 documentElement 的名称,这将不起作用。这就是我要找的。​​span>
    • 如果你想重命名文档元素,这样的方法可能对你有用: XmlDocument oldDoc = new XmlDocument(); oldDoc.LoadXml(myOldXmlDoc);字符串 strNewXml= "" + oldDoc.DocumentElement.InnerXml + ""; XmlDocument newDoc= new XmlDocument(); newDoc.LoadXml(strNewXml);
    【解决方案2】:

    我发现重命名节点的最简单方法是:

    xmlNode.InnerXmL = newNode.InnerXml.Replace("OldName>", "NewName>")
    

    不要包含开始 &lt; 以确保结束 &lt;/OldName&gt; 标记也被重命名。

    【讨论】:

    • 可能不适用于空元素标签,例如&lt;OldName /&gt;。但是用相同的名称重命名嵌套元素。以及以旧名称作为后缀的元素,例如 &lt;VeryOldName&gt;..&lt;/VeryOldName&gt;。 :-(
    • 这里甚至没有空间来描述这种方法的所有错误。也许阅读this question
    • 也许是一种“快速而肮脏”的方法,但它只是为我节省了大量的编码时间
    【解决方案3】:

    我用这个方法重命名了节点:

    /// <summary>
    /// Rename Node
    /// </summary>
    /// <param name="parentnode"></param>
    /// <param name="oldname"></param>
    /// <param name="newname"></param>
    private static void RenameNode(XmlNode parentnode, string oldChildName, string newChildName)
    {
        var newnode = parentnode.OwnerDocument.CreateNode(XmlNodeType.Element, newChildName, "");
        var oldNode = parentnode.SelectSingleNode(oldChildName);
    
        foreach (XmlAttribute att in oldNode.Attributes)
            newnode.Attributes.Append(att);
        foreach (XmlNode child in oldNode.ChildNodes)
            newnode.AppendChild(child);
    
        parentnode.ReplaceChild(newnode, oldNode);
    }
    

    【讨论】:

      【解决方案4】:

      也许更好的解决方案是遍历每个节点,并将信息写入新文档。显然,这将取决于您将来如何使用这些数据,但我建议您按照 FlySwat 的建议重新格式化...

      <stuff id="1">
          <content/>
      </stuff>
      

      我还建议使用最近添加的 XDocument 将是创建新文档的最佳方式。

      【讨论】:

        【解决方案5】:

        我会回答更高的问题:你为什么要使用XmlDocument 来尝试这个?

        我认为实现您的目标的最佳方式是一个简单的 XSLT 文件
        匹配“CONTENTSTUFF”节点并输出“CONTENT”节点...

        没有理由购买这么重的枪......

        无论哪种方式,如果您仍然希望使用 C# 风格,
        使用XmlReader + XmlWriter 而不是XmlDocument 用于内存和速度目的。 XmlDocument 将整个 XML 存储在内存中,对于 Traversing once 来说非常繁重...

        如果您多次访问该元素,XmlDocument 是很好的(不是这里的情况)。

        【讨论】:

          【解决方案6】:

          我不是 XML 专家,在我的例子中,我只需要将 HTML 文件中的所有标记名称设置为大写,以便在 XmlDocument 中使用 GetElementsByTagName 进行进一步操作。我需要大写的原因是,对于 XmlDocument,标签名称区分大小写(因为它是 XML),并且我不能保证我的 HTML 文件在标签名称中具有一致的大小写。

          所以我这样解决它:我使用 XDocument 作为中间步骤,您可以在其中重命名元素(即标签名称),然后将其加载到 XmlDocument 中。这是我的 VB.NET 代码(C# 代码非常相似)。

          Dim x As XDocument = XDocument.Load("myFile.html")
          For Each element In x.Descendants()
            element.Name = element.Name.LocalName.ToUpper()
          Next
          Dim x2 As XmlDocument = New XmlDocument()
          x2.LoadXml(x.ToString())
          

          出于我的目的,它运行良好,但我知道在某些情况下,如果您处理的是纯 XML 文件,这可能不是一个解决方案。

          【讨论】:

            【解决方案7】:

            将其作为字符串加载并在整个批次上进行替换..

                String sampleXml =
              "<doc>"+
                "<Stuff1>"+
                  "<Content>someContent</Content>"+
                  "<type>someType</type>"+
                "</Stuff1>"+
                "<Stuff2>"+
                  "<Content>someContent</Content>"+
                  "<type>someType</type>"+
                "</Stuff2>"+
                "<Stuff3>"+
                  "<Content>someContent</Content>"+
                  "<type>someType</type>"+
                "</Stuff3>"+
              "</doc>"; 
            
                sampleXml = sampleXml.Replace("Content","StuffxContent")
            

            【讨论】:

            • 糟糕的解决方案,'x' 显然是初始问题中的占位符,用于指代任何编号的 Stuff 节点是此 Content 节点的父节点。
            【解决方案8】:

            您提供的 XML 表明有人完全忽略了 XML。

            而不是拥有

            <stuff1>
               <content/>
            </stuff1>
            

            你应该有:/

            <stuff id="1">
                <content/>
            </stuff>
            

            现在您将能够使用 Xpath 遍历文档(即,//stuff[id='1']/content/)节点的名称不应该用于建立身份,您可以使用属性。

            按照您的要求,将 XML 加载到 xml 文档中,然后简单地遍历重命名它们的第一级子节点。

            伪代码:

            foreach (XmlNode n in YourDoc.ChildNodes)
            {        
                n.ChildNode[0].Name = n.Name + n.ChildNode[0].Name;
            }
            
            YourDoc.Save();
            

            但是,我强烈建议您实际修复 XML 以便它有用,而不是进一步破坏它。

            【讨论】:

            • 感谢您的回答! XML 的架构与我在问题中显示的架构非常不同(而且更复杂)。我试图为这个问题简化它:)。
            • 我无法理解为什么这被标记为正确,因为正如 DeepBlue 下面所说,Name 属性是只读的。令人着迷的是,它收到了 11 票...
            • 我同意。您曾经使用过来自 Apple 的任何 XML 吗?都是这样,解析起来非常痛苦......
            • @sundeep 您真的应该重新考虑取消将此答案标记为正确。它只是不是
            • 如果你有20k,懂技术,知道答案本质上不好,请投票删除。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2010-11-20
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-01-31
            • 1970-01-01
            相关资源
            最近更新 更多