thisdotnull
thisdotnull

Reputation: 862

Selecting from an XmlNode using XmlNamespaceManager

I have been looking for ages to find a way to select nodes from an XmlNode(NOT AN XmlDocument) which has multiple namespaces.

Almost every post that I have searched has advised me to use an XmlNamespaceManager, however, XmlNamespaceManager needs an XmlNameTable which does not exists for an XmlNode.

I tried doing this with an XmlDocument and it worked since XmlDocument has a property XmlDocument.NameTable but it does not exists for XmlNode.

I tried creating a NameTable manually but it does not work as the same piece of code works when I use an XmlDocument. I guess I need to populate that NameTable with something or somehow bind it to the XmlNode to make this work. Please suggest.

Upvotes: 3

Views: 2648

Answers (2)

Derek Wade
Derek Wade

Reputation: 746

For some reason the XmlNamespaceManager doesn't automatically load the defined namespaces in the document (This seems like a simple expectation). For some reason the namespace declarations are treated as attributes. I was able to automate adding the namespaces using the following code.

private static XmlNamespaceManager AddNamespaces(XmlDocument xmlDoc)
{
    XmlNamespaceManager nsmgr = new XmlNamespaceManager(xmlDoc.NameTable);
    AddNamespaces(xmlDoc.ChildNodes, nsmgr);
    return nsmgr;
}
private static void AddNamespaces(XmlNodeList nodes, XmlNamespaceManager nsmgr) {
    if (nodes == null)
        throw new ArgumentException("XmlNodeList is null");

    if (nsmgr == null)
        throw new ArgumentException("XmlNamespaceManager is null");

    foreach (XmlNode node in nodes)
    {
        if (node.NodeType == XmlNodeType.Element)
        {
            foreach (XmlAttribute attr in node.Attributes)
            {
                if (attr.Name.StartsWith("xmlns:"))
                {
                    String ns = attr.Name.Replace("xmlns:", "");
                    nsmgr.AddNamespace(ns, attr.Value);
                }
            }
            if (node.HasChildNodes)
            {
                nsmgr.PushScope();
                AddNamespaces(node.ChildNodes, nsmgr);
                nsmgr.PopScope();
            }
        }
    }
}

Sample call example:

    XmlDocument ResponseXmlDoc = new System.Xml.XmlDocument();
    ...<Load your XML Document>...
    XmlNamespaceManager nsmgr = AddNamespaces(ResponseXmlDoc);

And use the returned NamespaceManager

XmlNodeList list = ResponseXmlDoc.SelectNodes("//d:response", nsmgr);

Upvotes: 0

CeeRo
CeeRo

Reputation: 1142

Can you use

XPathNavigator nav = XmlNode.CreateNavigator();
XmlNamespaceManager man = new XmlNamespaceManager(nav.NameTable);

Including the rest in case it'll be helpful:

man.AddNamespace("app", "http://www.w3.org/2007/app"); //Gotta add each namespace
XPathNodeIterator nodeIter = nav.Select(xPathSearchString, man);

while (nodeIter.MoveNext())
{
    var value = nodeIter.Current.Value;
}

http://msdn.microsoft.com/en-us/library/system.xml.xmlnode.createnavigator.aspx

Upvotes: 4

Related Questions