Select-Xml (needs) Easier XPath Queries with Namespaces

Topics: Developer Forum
Developer
Jun 12, 2007 at 7:39 PM
Edited Jun 12, 2007 at 7:40 PM
Can we take a cue from Easier XPath Queries with Namespaces and, in the absence of a -Namespace argument, use code like:

XPathDocument doc = new XPathDocument( path );
// Use a Navigator to Automagically slurp namespaces!!!!
XPathNavigator nav = doc.CreateNavigator();
// move to document element 
nav.MoveToChild(XPathNodeType.Element);
foreach (XPathNavigator node in nav.Select( xpath , nav ))
{
   yield node; // err, whatever it is, I can't recall at the moment.
}

This would allow you to just use whatever namespace prefixes were used in the document without having to specify them on the command line! (I can see a few people going "eh? what?" and scratching their heads, but trust me, there's a few XML geeks in the back breaking into choruses of "Hallelujah!")
Coordinator
Jun 13, 2007 at 4:51 AM
Hmm I'm real close to pulling the trigger on releasing 1.1.1 but this would be a nice feature to have because it is a drag to have to define prefix/namespace mappings. How confident are you in this code and getting it into Select-Xml?
Developer
Jun 13, 2007 at 12:41 PM
Edited Jun 13, 2007 at 12:42 PM
Heh, I was sure it was too late for that, or I would have given you this when I posted it, here's a patch for what you'd have to do. As you can see, it doesn't really change much. I'm sure it won't break existing functionality, but I tried to compile and install this, and I can't figure out how to get the new pscx snapin to replace the old pscx snapin (and I'm late for an apt, so I gotta run).

77d76
<                     XPathNavigator xpathNavigator = xpathDocument.CreateNavigator();
86,90d84
<                         xpathExpression.SetContext(xmlNamespaceMgr);
<                     }
<                     else
<                     {
<                         xpathExpression.SetContext(xpathNavigator);
92a87
>                     xpathExpression.SetContext(xmlNamespaceMgr);
93a89
>                     XPathNavigator xpathNavigator = xpathDocument.CreateNavigator();


Will change:
 
                while (!xmlReader.EOF)
                {
                    XPathDocument xpathDocument = new XPathDocument(xmlReader);
                    XPathExpression xpathExpression = XPathExpression.Compile(this._xpathExpression);
                    XmlNamespaceManager xmlNamespaceMgr = new XmlNamespaceManager(xmlReader.NameTable);
 
                    if (_xmlNamespaces != null)
                    {
                        foreach (string xmlNamespace in _xmlNamespaces)
                        {
                            string[] tmp = xmlNamespace.Split(new char[] { '=' });
                            xmlNamespaceMgr.AddNamespace(tmp[0].Trim(), tmp[1].Trim());
                        }
                    }
 
                    xpathExpression.SetContext(xmlNamespaceMgr);
 
                    XPathNavigator xpathNavigator = xpathDocument.CreateNavigator();
                    XPathNodeIterator nodes = xpathNavigator.Select(xpathExpression);
 
                    while (nodes.MoveNext())
                    {
                        WriteObject(nodes.Current.Clone());
                    }                    
                }


To:

 
                while (!xmlReader.EOF)
                {
                    XPathDocument xpathDocument = new XPathDocument(xmlReader);
                    XPathExpression xpathExpression = XPathExpression.Compile(this._xpathExpression);
                    XmlNamespaceManager xmlNamespaceMgr = new XmlNamespaceManager(xmlReader.NameTable);
                    XPathNavigator xpathNavigator = xpathDocument.CreateNavigator();
 
                    if (_xmlNamespaces != null)
                    {
                        foreach (string xmlNamespace in _xmlNamespaces)
                        {
                            string[] tmp = xmlNamespace.Split(new char[] { '=' });
                            xmlNamespaceMgr.AddNamespace(tmp[0].Trim(), tmp[1].Trim());
                        }
                        xpathExpression.SetContext(xmlNamespaceMgr);
                    }
                    else
                    {
                        xpathExpression.SetContext(xpathNavigator);
                    }
 
 
                    XPathNodeIterator nodes = xpathNavigator.Select(xpathExpression);
 
                    while (nodes.MoveNext())
                    {
                        WriteObject(nodes.Current.Clone());
                    }                    
                }
 
Coordinator
Jun 16, 2007 at 3:44 AM
OK I have this working unfortunately it is a drag that this approach doesn't work with the default namespace.
Coordinator
Jun 16, 2007 at 3:48 AM
This discussion has been copied to a work item. Click here to go to the work item and continue the discussion.
Coordinator
Jun 20, 2007 at 4:22 AM
Edited Jun 20, 2007 at 4:23 AM
BTW, what do you guys think about this reaction to the IXmlNamespaceResolver automatic namespace/prefix mapping?

http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=1757583&SiteID=1&mode=1
Developer
Jun 20, 2007 at 8:51 AM
Just an idea: we could also provide some shortcut for this kind of queries:

18# $xml = [xml]"<root><n/><n><n xmlns='test'>jadajada</n></n><n/></root>"
19# $xml.SelectNodes('//*[local-name(.) = "n"]') | select OuterXml,NamespaceURI
 
OuterXml                                                                   NamespaceURI
--------                                                                   ------------
<n />
<n><n xmlns="test">jadajada</n></n>
<n xmlns="test">jadajada</n>                                               test
<n />