我有一个供应商提供的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)现在可以使用该代码。 但是,我仍然没有一种方法可以直接访问要修改的特定属性,而又不需要遍历所有不需要修改的属性。有人有办法做到这一点吗?
答案 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