Find all namespace declarations in an XML document - xPath 1.0 vs xPath 2.0

后端 未结 4 2130
渐次进展
渐次进展 2021-02-03 14:34

As part of a Java 6 application, I want to find all namespace declarations in an XML document, including any duplicates.

Edit: Per Martin\'s request, h

4条回答
  •  甜味超标
    2021-02-03 15:31

    To find all namespace declarations, I applied this xPath statement to the XML document using xPath 1.0:

    //namespace::* It finds 4 namespace declarations, which is what I expect (and desire):
    
    /root[1]/@xmlns:att - attribute.com
    /root[1]/@xmlns:ele - element.com 
    /root[1]/@xmlns:txt - textnode.com 
    /root[1]/@xmlns:xml - http://www.w3.org/XML/1998/namespace
    

    You are using a non-compliant (buggy) XPath 1.0 implementation.

    I get different and correct results with all XSLT 1.0 processors I have. This transformation (just evaluating the XPath expression and printing one line for each selected namespace node):

    
        
    
     
         
           
         
     
    
    

    when applied on the provided XML document:

    
        a
        e
        txt:f
    
    

    produces a correct result:

    xml: http://www.w3.org/XML/1998/namespace
    ele: element.com
    att: attribute.com
    txt: textnode.com
    xml: http://www.w3.org/XML/1998/namespace
    ele: element.com
    att: attribute.com
    txt: textnode.com
    xml: http://www.w3.org/XML/1998/namespace
    ele: element.com
    att: attribute.com
    txt: textnode.com
    xml: http://www.w3.org/XML/1998/namespace
    ele: element.com
    att: attribute.com
    txt: textnode.com
    

    with all of these XSLT 1.0 and XSLT 2.0 processors:

    MSXML3, MSXML4, MSXML6, .NET XslCompiledTransform, .NET XslTransform, Altova (XML SPY), Saxon 6.5.4, Saxon 9.1.07, XQSharp.

    Here is a short C# program that confirms the number of nodes selected in .NET is 16:

    namespace TestNamespaces
    {
        using System;
        using System.IO;
        using System.Xml.XPath;
    
        class Test
        {
            static void Main(string[] args)
            {
                string xml =
    @"
        a
        e
        txt:f
    ";
                XPathDocument doc = new XPathDocument(new StringReader(xml));
    
                double count = 
                  (double) doc.CreateNavigator().Evaluate("count(//namespace::*)");
    
                Console.WriteLine(count);
            }
        }
    }
    

    The result is:

    16.

    UPDATE:

    This is an XPath 2.0 expression that finds just the "distinct" namespace nodes and produces a line of name - value pairs for each of them:

    for $i in distinct-values(
                 for $ns in //namespace::*
                   return
                      index-of(
                               (for $x in //namespace::*
                                 return
                                    concat(name($x), ' ', string($x))
    
                                ),
                                concat(name($ns), ' ', string($ns))
                              )
                              [1]
                                                      )
      return
        for $x in (//namespace::*)[$i]
         return
            concat(name($x), ' :', string($x), '
    ')
    

提交回复
热议问题