按子节点值在其中定位XML节点,并更改另一个值

时间:2012-07-06 16:48:48

标签: c# xml

三部分问题。

是否可以通过其中的子项找到特定的XML节点来检索父级的其他子节点?例如:

<House>
    <Kitchen>
        <Appliance>
            <Name>Refrigerator</Name>
            <Brand>Maytag</Brand>
            <Model>F2039-39</Model>
        </Appliance>
        <Appliance>
            <Name>Toaster</Name>
            <Brand>Black and Decker</Brand>
            <Model>B8d-k30</Model>
        </Appliance>
    </Kitchen>
</House>

为此,我想通过搜索“Refrigerator”或“Toaster”来找到相应的Appliance节点,并从中检索品牌。

这个问题的第二部分是:这是一种愚蠢的方式吗?在Appliance标签中使用属性会使这更容易吗?如果是这样,我将如何找到它?

至于第三部分,一旦我找到了该设备,我将如何改变该特定设备的说法,模型?

4 个答案:

答案 0 :(得分:3)

使用XLinq,您可以非常自然地执行此查询:

// Given:
//   var xdoc = XDocument.Load(...);
//   string applianceName = "Toaster";

// Find the appliance node who has a sub-element <Name> matching the appliance
var app = xdoc.Root
              .Descendants("Appliance")
              .SingleOrDefault(e => (string)e.Element("Name") == applianceName);

// If we've found one and it matches, make a change
if (app != null)
{
    if (((string)app.Element("Model")).StartsWith("B8d-k30"))
    {
        app.Element("Model").Value = "B8d-k30 Mark II";
    }
}

xdoc.Save(@"output.xml"); // save changes back to the document

答案 1 :(得分:3)

如果您使用的是XmlDocument

foreach(XmlNode applianceNode in 
          myDocument.DocumentElement.SelectNodes("Kitchen/Applicance[Name='Refrigerator']")
{
   XmlNode modelNode = applicianceNode.SelectSingleNode("Model").InnerText = SomeOtherValue;
}

如果你将名称标签设为一个属性(applicanceName),那么它就没什么区别了。

foreach(XmlNode applianceNode in 
          myDocument.DocumentElement.SelectNodes("Kitchen/Applicance[@applianceName='Refrigerator']")
{
// ...
}

答案 2 :(得分:0)

    string xml = @"<House>
    <Kitchen>
        <Appliance>
            <Name>Refrigerator</Name>
            <Brand>Maytag</Brand>
            <Model>F2039-39</Model>
        </Appliance>
        <Appliance>
            <Name>Toaster</Name>
            <Brand>Black and Decker</Brand>
            <Model>B8d-k30</Model>
        </Appliance>
    </Kitchen>
</House>";

    XDocument xdoc = XDocument.Parse(xml);

    string newModel = "B8d-k45";

    var matchingElement = (from appliance in xdoc.Descendants("Appliance")
                           where appliance.Element("Name").Value == "Toaster"
                           select appliance).FirstOrDefault();

    if (matchingElement != null)
    {
        matchingElement.Element("Model").Value = newModel;
    }

    Console.WriteLine(xdoc.ToString());

答案 3 :(得分:0)

Necromancing。
是的,它甚至比XPath更简单,并且完全没有Linq工作:
只需使用..来到父节点(第二个想法,使用“ordinalignorecase”时Linq会更容易)

public static void CreateNewHouse()
{
    System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
    doc.XmlResolver = null;
    doc.Load(@"d:\House.xml");

    foreach (System.Xml.XmlNode modelNode in doc.DocumentElement
.SelectNodes("/House/Kitchen/Appliance/Name[text()='Refrigerator']/../Model"))
    {
        modelNode.InnerText = "A New Value";
    }

    doc.Save(@"d:\MyHouse.xml");
}

MyHouse.xml:

<House>
  <Kitchen>
    <Appliance>
      <Name>Refrigerator</Name>
      <Brand>Maytag</Brand>
      <Model>A New Value</Model>
    </Appliance>
    <Appliance>
      <Name>Toaster</Name>
      <Brand>Black and Decker</Brand>
      <Model>B8d-k30</Model>
    </Appliance>
  </Kitchen>
</House>

如果您需要不区分大小写,请将text()替换为:

translate(text(), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')

(仅适用于ASCII /英文版),当然将“冰箱”更改为小写(“冰箱”)

如果XML文档具有默认命名空间,则需要在Select * Node中提供它,例如:

 xnImageTag.SelectSingleNode("./dft:Source", nsmgr);

其中

System.Xml.XmlNamespaceManager nsmgr = GetReportNamespaceManager(doc);

public static System.Xml.XmlNamespaceManager GetReportNamespaceManager(System.Xml.XmlDocument doc)
{
    if (doc == null)
        throw new ArgumentNullException("doc");

    System.Xml.XmlNamespaceManager nsmgr = new System.Xml.XmlNamespaceManager(doc.NameTable);

    // <Report xmlns="http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition" xmlns:rd="http://schemas.microsoft.com/SQLServer/reporting/reportdesigner">

    if (doc.DocumentElement != null)
    {
        string strNamespace = doc.DocumentElement.NamespaceURI;
        System.Console.WriteLine(strNamespace);
        nsmgr.AddNamespace("dft", strNamespace);
        return nsmgr;
    }

    nsmgr.AddNamespace("dft", "http://schemas.microsoft.com/sqlserver/reporting/2005/01/reportdefinition");
    // nsmgr.AddNamespace("dft", "http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition");

    return nsmgr;
} // End Function GetReportNamespaceManager