简体   繁体   中英

How to select multiple XML child nodes with similar names

Here is my XML file:

<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).

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).

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;

Here's an XPath solution for you.

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. 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[1] means first element B under element A
  • A[text() = 'foo'] means element A containing foo as a text value
  • .. 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".

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". (not the descendant ones). So the path is "/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". In the expression, first it will select all of the following-siblings, and in your xml, only "hashtable" meets the condition. 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.
Hope it's helpful.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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