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
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), '
')