How to find XmlNodes based on a child elements nam

2019-08-10 13:51发布

问题:

Im having trouble getting a XmlNodeList where there is 1 child with a specific name that

<tables>
  <table tableName="Orders">
    <item table="Orders">
      ...
   </item>
    <item table="Orders">
      ...
   </item>
  </table>
  <table tableName="OrderWithParent">
    <item table="OrderWithParent">
      <column columnName="OrderWithParentId"><![CDATA[156]]></column>
      <column columnName="OrderParentId"><![CDATA[1]]></column>
      ...
   </item>
    <item table="OrderWithParent">
      <column columnName="OrderWithParentId"><![CDATA[156]]></column>
      <column columnName="OrderParentId"><![CDATA[1]]></column>
      ...
   </item>
    <item table="OrderWithParent">
      <column columnName="OrderWithParentId"><![CDATA[156]]></column>
      <column columnName="OrderParentId"><![CDATA[2]]></column>
      ...
   </item>
  </table>
</tables>

So thats my basic xml layout...

Ive deserialized the top Orders... and now i wanna find the OrderWithParent's where their column with columnName="OrderParentId" == order.Id

the order nodes where retrieved like this:

var orders = root.SelectNodes("/tables/table[@tableName='Orders']/item[@table='Orders']");

So atm im using an XmlDocument.. im hope to using XDocument aswell.. but i havent been able to find a solution with either of them. Help is much appreciated!

回答1:

Assuming that order.Id means Id property of a predefined variable order which you didn't show, the following XPath should return the target item element :

var xpath = $"//item[@table='OrderWithParent' and column[@columnName='OrderWithParentId'] = {order.Id}]";

For older C# version where string interpolation $ is not supported :

var xpath = String.Format("//item[@table='OrderWithParent' and column[@columnName='OrderWithParentId'] = {0}]", order.Id);

Another assumption is, that order.Id value is always number. Otherwise you'll need to wrap the value with quotes in the XPath i.e in the above snippet, replace {order.Id} with '{order.Id}' or {0} with '{0}'.

If you switch to using XDocument, you can still execute the same XPath expression through XPathSelectElements(), XPathSelectElement(), or XPathEvaluate() methods.



回答2:

I think your searching for the wrong node in your syntax. Try this, see if it helps:

var orders = root.SelectNodes("/tables/table[@tableName='OrderWithParent']/item[@table='OrderWithParent']");

this assumes I'm not misunderstanding the question though.



回答3:

Try this

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            string xml =
                "<?xml version=\"1.0\" encoding=\"utf-8\" ?>" +
                    "<tables>" +
                      "<table tableName=\"Orders\">" +
                        "<item table=\"Orders\">" +
                          "..." +
                        "</item>" +
                        "<item table=\"Orders\">" +
                          "..." +
                        "</item>" +
                      "</table>" +
                      "<table tableName=\"OrderWithParent\">" +
                        "<item table=\"OrderWithParent\">" +
                          "<column columnName=\"OrderWithParentId\"><![CDATA[156]]></column>" +
                          "<column columnName=\"OrderParentId\"><![CDATA[1]]></column>" +
                          "..." +
                        "</item>" +
                        "<item table=\"OrderWithParent\">" +
                          "<column columnName=\"OrderWithParentId\"><![CDATA[156]]></column>" +
                          "<column columnName=\"OrderParentId\"><![CDATA[1]]></column>" +
                          "..." +
                        "</item>" +
                        "<item table=\"OrderWithParent\">" +
                          "<column columnName=\"OrderWithParentId\"><![CDATA[156]]></column>" +
                          "<column columnName=\"OrderParentId\"><![CDATA[2]]></column>" +
                          "..." +
                        "</item>" +
                      "</table>" +
                    "</tables>";

            XDocument doc = XDocument.Parse(xml);

            XElement[] results = doc.Descendants("table").Elements("item")
                .Where(y => ((string)y.Attribute("table") == "OrderWithParent") &&
                    (y.Elements("column").Where(z => 
                       (z.Attribute("columnName") != null) &&
                       (z.Attribute("columnName").Value == "OrderParentId") &&
                       (z.Value  == "1")
                       )).Any()
                    )
                .ToArray();
        }
    }
}