Как можно напрямую обращаться к значению парных записей 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) я вижу каждый из ChildNodes, но не вижу, как получить доступ к Entry1 / A, чтобы он мог обновляться с «abc» до «efg» ...

XmlDocument vendorXML = new XmlDocument();
vendorXML.Load(@"C:pathfile.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:pathfile.xml");

Изменено: (Благодаря elgonzo) код работает сейчас. Тем не менее, я до сих пор не вижу способа прямого доступа к конкретному атрибуту для изменения без перебора всех тех, которые не нуждаются в модификации. У кого-то есть способ сделать это?

c#,xml,

0

Ответов: 3


1 принят

С помощью XDocument вы можете использовать Linq для XML, чтобы выбрать именно то, что вы хотите изменить:

var vendorXml = XDocument.Load(@"c:pathfile.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:pathfile.xml");
var node = (XmlElement)vendorXml.SelectSingleNode("//VendorEntry[@Name='Entry1']/Attributes/Attribute[@Name='A']");
node.SetAttribute("Value", "efg");

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:	emp	est.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);
        }
    }
}

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
C #, XML,
Похожие вопросы