名称值配对的XML条目如何直接访问?

时间:2018-07-08 15:55:13

标签: c# xml

我有一个供应商提供的XML文件,需要对其进行编程修改。这些项目(节点,元素,属性)有多个层次,并且具有多个与名称/值配对的条目。

<root>
  <VendorEntries>
     <VendorEntry Name="Entry1">
        <Attributes>
           <Attribute Name="A" Value="abc"/>
           <Attribute Name="B" Value="xyz"/>
        </Attributes>
     </VendorEntry>
     <VendorEntry Name="Entry2">
        <Attributes>
           <Attribute Name="A" Value="lmn"/>
           <Attribute Name="B" Value="qrs"/>
        </Attributes>
     </VendorEntry>
  </VendorItems>
</root>

遍历以下内容(在VS2015调试器中)时,我看到了每个ChildNode,但是看不到如何获得对Entry1 / A的访问权限,因此可以将其从“ abc”更新为“ efg”。

XmlDocument vendorXML = new XmlDocument();
vendorXML.Load(@"C:\path\file.xml");
XmlNodeList entries= vendorXML.SelectNodes("/root/VendorEntries/VendorEntry");

foreach (XmlNode entry in entries) {  //  /root/VendorEntries/VendorEntry(s) nodes
    XmlAttribute entryName = entry.Attributes["Name"];
    Console.WriteLine($"{entry.Name} {entryName.Value}");  // VendorEntry
    foreach (XmlNode atNodes in entry.ChildNodes) { // /root/VendorEntries/VendorEntry/Attributes(s) nodes
        foreach (XmlNode atNode in atNodes.ChildNodes)  { // /root/VendorEntries/VendorEntry/Attributes/Attribute(s) nodes
            XmlAttribute atName = atNode.Attributes["Name"];
            XmlAttribute atValue = atNode.Attributes["Value"];
            Console.WriteLine($"..{atNode.Name}  {atName.Value} {atValue.Value}"); // ..Attribute Name Value>
            if (entryName.Value.Equals("SOME_ENTRY") &&  atName.Value.Equals("SOME_PARAM"))
            {
                atValue.Value = "NEW PARAM ENTRY";
            }
        }
    }
}
vendorXML.Save(@"C:\path\file.xml");

已修改:(感谢elgonzo)现在可以使用该代码。 但是,我仍然没有一种方法可以直接访问要修改的特定属性,而又不需要遍历所有不需要修改的属性。有人有办法做到这一点吗?

3 个答案:

答案 0 :(得分:1)

使用XDocument,您可以使用Linq to XML来专门选择要修改的内容:

var vendorXml = XDocument.Load(@"c:\path\file.xml");            

vendorXml.Descendants("VendorEntry")
    .Where(a => a.Attribute("Name").Value == "Entry1")
    .Descendants("Attribute")
    .SingleOrDefault(a => a.Attribute("Name").Value == "A")
    .SetAttributeValue("Value", "efg");

或者,按照@Prany的建议,您可以使用XPath选择元素:

vendorXml        
.XPathSelectElement("//VendorEntry[@Name='Entry1']/Attributes/Attribute[@Name='A']")
.SetAttributeValue("Value", "efg");

或者如果出于某些原因您想使用XmlDocument,则可以使用相同的方法:

XmlDocument vendorXml = new XmlDocument();
vendorXml.Load(@"c:\path\file.xml");
var node = (XmlElement)vendorXml.SelectSingleNode("//VendorEntry[@Name='Entry1']/Attributes/Attribute[@Name='A']");
node.SetAttribute("Value", "efg");

答案 1 :(得分:1)

我喜欢使用Xml Linq并将结果放入嵌套字典中:

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

namespace ConsoleApplication1
{
    class Program
    {
        const string FILENAME = @"c:\temp\test.xml";
        static void Main(string[] args)
        {
            XDocument doc = XDocument.Load(FILENAME);

            Dictionary<string, Dictionary<string, XElement>> dict = doc.Descendants("VendorEntry")
                .GroupBy(x => (string)x.Attribute("Name"), y => y.Descendants("Attribute")
                    .GroupBy(a => (string)a.Attribute("Name"), b => b)
                    .ToDictionary(a => a.Key, b => b.FirstOrDefault()))
                .ToDictionary(x => x.Key, y => y.FirstOrDefault());

            Dictionary<string, XElement> entry2 = dict["Entry2"];

            entry2["B"].SetAttributeValue("Value", "xyz");

            doc.Save(FILENAME);
        }
    }
}

答案 2 :(得分:0)

您可以使用XpathSelectElement

XDocument doc = XDocument.Load(path);
string value = doc.XPathSelectElement("//VendorEntries/VendorEntry[1]/Attributes/Attribute[1]").LastAttribute.Value;
//This will select value from Entry1/A