简体   繁体   English

如何选择多个具有相似名称的XML子节点

[英]How to select multiple XML child nodes with similar names

Here is my XML file: 这是我的XML文件:

<hashtable>
  <entry>
    <string>krishna.com</string>
    <hashtable>
      <entry>
        <string>status</string>
        <string>available</string>
      </entry>
      <entry>
        <string>classkey</string>
        <string>domcno</string>
      </entry>
    </hashtable>
  </entry>
  <entry>
    <string>krishna.net</string>
    <hashtable>
      <entry>
        <string>status</string>
        <string>regthroughothers</string>
      </entry>
      <entry>
        <string>classkey</string>
        <string>dotnet</string>
      </entry>
    </hashtable>
  </entry>
</hashtable>

I want to find status is available(node: hashtable/entry/hashtable/entry/string) by krishna.com(node: hashtable/entry/string). 我想通过krishna.com(node:hashtable / entry / string)找到可用的状态(节点:hashtable / entry / hashtable / entry / string)。

Here my difficulty is there are so many similar names of nodes like string & entry , so how can I check if status is available of domain krishna.com & krishna.net by checking status (string node) and available (string node). 在这里,我的困难是有太多类似的节点名称,例如stringentry ,所以我如何通过检查status (字符串节点)和available status (字符串节点)来检查krishna.com和krishna.net域的status是否可用。

you can try something like this 你可以尝试这样的事情

XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml("Path to your .xml file");
XmlNodeList nodeList = xmlDoc.SelectNodes("//entry/string");

now you can write your own code to get at the information in your nodeList; 现在,您可以编写自己的代码来获取nodeList中的信息;

Here's an XPath solution for you. 这是为您提供的XPath解决方案。

using System;
using System.Xml.Linq;
using System.Xml.XPath;

static string GetStatus(XDocument doc, string nodeName)
{
    //The first xpath translates to: "Select the <hashtable> element that immediately
    // follows the <string> element with a value of nodeName."
    //The second xpath selects the <string> element that immediately follows another <string>
    // element with a value of 'status'. This selected element is a descendant of the
    // <hashtable> element that was selected first. 
    XElement status = doc.XPathSelectElement("//hashtable[preceding-sibling::string = '" + nodeName + "']")
                         .XPathSelectElement("descendant::string[preceding-sibling::string = 'status']");
    return status.Value;
}

Fairly self explanatory to use this: 使用此方法的原因很合理:

XDocument doc = XDocument.Load("File_path_to_XML.xml");
string status = GetStatus(doc, "krishna.com");
// status == "available"
string status2 = GetStatus(doc, "krishna.net");
// status2 == "regthroughothers"

You may use LINQ to XML to search for nodes fulfilling specified criteria. 您可以使用LINQ to XML来搜索满足指定条件的节点。 This is an example to select the first level "entry" nodes that contain a "status" and "available" child nodes beneath its child "hashtable" node as in the structure of your example: 此示例选择在其子“哈希表”节点下包含“状态”和“可用”子节点的第一级“入口”节点,如示例结构所示:

XDocument doc;
using (FileStream fs = new FileStream("XMLFile1.xml", FileMode.Open))
{
   doc = XDocument.Load(fs);
}
string[] elms = doc.Element("hashtable").Elements("entry").Where(elm => 
            elm.Element("hashtable").Element("entry").Elements("string").First().Value == "status" &&
            elm.Element("hashtable").Element("entry").Elements("string").Skip(1).First().Value == "available")
        .Select(elm => elm.Element("string").Value).ToArray();

If your file structure can be different that the example you provided you'll need to modify the query accordingly 如果您的文件结构与您提供的示例不同,则需要相应地修改查询

You might need something like: 您可能需要类似:

//hashtable/entry/string[1][text() = 'krishna.com']"/../hastable/entry/string[1][text() = 'status']"/../string[2][text() = 'available']

Untested but a few things to note: 未经测试,但需要注意以下几点:

  • // means starting at any node //表示从任何节点开始
  • A/B means element B under element A A/B表示元素A下的元素B
  • A/B[1] means first element B under element A A/B[1]表示元素A下的第一个元素B
  • A[text() = 'foo'] means element A containing foo as a text value A[text() = 'foo']表示元素A,其中包含foo作为文本值
  • .. means parent node ..表示父节点

If this doesn't work, you could always first locate the hashtable for krishna.com and then find the string node containing the value "status" in it in 1st position under an entry node and then ensure that only sibling of that string node is another string node containing "available". 如果这样做不起作用,则始终可以先找到krishna.com的hashtable ,然后在entry节点下的第一个位置中找到包含值“ status”的string节点,然后确保仅该string节点的同级对象另一个包含“可用”的string节点。

Here is what I think: 这是我的想法:

XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load("your_xml_file.xml");
XmlElement root = xmlDoc.DocumentElement;
string query = "child::entry/child::string[following-sibling::*/descendant::string[text()='available']]";
XmlNodeList nodes = root.SelectNodes(query);
foreach (XmlNode node in nodes)
{
    Console.WriteLine(node.InnerText);
}  
//Result
krishna.com

It will display the name of domain which is "available". 它将显示“可用”域的名称。
In the query string, "child::entry" will select root's child which is called "entry". 在查询字符串中,“ child :: entry”将选择root的子级,称为“ entry”。 (not the descendant ones). (不是后代)。 So the path is "/hashtable/entry". 因此路径为“ / hashtable / entry”。
Next, for each "entry" node, it will select the "string" child which contains the domain name. 接下来,对于每个“入口”节点,它将选择包含域名的“字符串”子级。 In this step, it uses an expression to select the "available" ones onle. 在此步骤中,它使用表达式选择“可用”一个。 Now the path becomes to "/hashtable/entry/string". 现在,路径变为“ / hashtable / entry / string”。 In the expression, first it will select all of the following-siblings, and in your xml, only "hashtable" meets the condition. 在表达式中,首先它将选择以下所有兄弟姐妹,并且在您的xml中,仅“ hashtable”满足条件。 At last, to all of the following siblings, we check its descendants, if the descendant's name is "string" and its inner text is "available", then current domain node will be selected. 最后,对于以下所有兄弟姐妹,我们检查其后代,如果后代的名称为“ string”且其内部文本为“ available”,则将选择当前域节点。
Hope it's helpful. 希望对您有所帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM