Search code examples
xmlnodesparentchildren

How can I get childnode innertext from parent by another childnode


I have searched the web a bit for this and also found a solution to my problem but I believe it might be possible to reduce the amount of coding necessary. I was hoping you might be able to help me.

I have the following XML and I need to get the value from title by the id. (In this case I am interested in the title "somefile2.jpg" which I need to find by the id of "2")

<entry>
    <name></name>
    <title type="text">somefile1.jpg</title>
    <m:properties xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices">
      <d:path></path>
      <d:id>1</d:id>
    </m:properties>
</entry>
<entry>
    <name></name>
    <title type="text">somefile2.jpg</title>
    <m:properties xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices">
      <d:path></path>
      <d:id>2</d:id>
    </m:properties>
</entry>
<entry>
    <name></name>
    <title type="text">somefile3.jpg</title>
    <m:properties xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices">
      <d:path></path>
      <d:id>3</d:id>
    </m:properties>
</entry>

To solve this I run the following code:

XmlDocument xDoc = new XmlDocument();
xDoc.LoadXml(xmlfile);

XmlNamespaceManager nameSpaceManager = new XmlNamespaceManager(xDoc.NameTable);
nameSpaceManager.AddNamespace("b", "http://www.w3.org/2005/Atom");
nameSpaceManager.AddNamespace("m", "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata");
nameSpaceManager.AddNamespace("d", "http://schemas.microsoft.com/ado/2007/08/dataservices");

//Find the correct XML node by child ID and get it's title
XmlNode parentNode = null;
string incomingID = "2";
foreach (XmlNode node in xDoc.SelectNodes(@"//m:properties/d:id", nameSpaceManager))
{
    if (node.InnerText == incomingID)
    {
        parentNode = node.ParentNode.ParentNode;
        break;
    }
}

//Add the nodes to a new XML document so it can be traversed
XmlDocument parent = new XmlDocument();
parent.LoadXml("<root>" + parentNode.InnerXml + "</root>");

XmlNamespaceManager parentNameSpaceManager = new XmlNamespaceManager(parent.NameTable);
parentNameSpaceManager.AddNamespace("b", "http://www.w3.org/2005/Atom");
parentNameSpaceManager.AddNamespace("m", "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata");
parentNameSpaceManager.AddNamespace("d", "http://schemas.microsoft.com/ado/2007/08/dataservices");

string xmlFilename = parent.GetElementsByTagName("title")[0].InnerText;

If possible I would like to change the code so I don't create a whole new XmlDocument just to find the title. Do you think it is possible to get the title by some shorter code? I was thinking something in the line of:

string xmlFilename = xDoc.SelectSingleNode(@"//m:properties[id='" + incomingID + "']", nameSpaceManager).ParentNode.ParentNode.FirstChild["title"].InnerText;

If i run the above code it returns an Exception: Objectreference not set to an instance of an object


Solution

  • Omg.. as usual when you've posted a question you find the answer not long after. This was my solution:

    string xmlFilename = parentNode["title"].InnerText;
    

    This means I can finally remove the dreadful 2nd XmlDocument. :)