解析XML文件以获取所有命名空间信息

我希望能够从给定的XML文件中获取所有命名空间信息。

例如,如果输入XML文件类似于:

  1 bar foo  00.00 USD   11.11 AUD    2 some name some description  00.01 USD    

我希望输出看起来像这样(在这种情况下以逗号分隔):

 create, ns1, http://predic8.com/wsdl/material/ArticleService/1/ article, ns1, http://predic8.com/material/1/ price, ns1, http://predic8.com/material/1/ id, ns1, http://predic8.com/material/1/ 

重要笔记:

重要的是我们还要考虑在特定命名空间内定义的子节点,但其定义可以在更高节点处定义。 例如,我们仍然想要获取节点ns1:id ,我们需要追溯到父节点ns1:article以发现命名空间url是xmlns:ns1='http://predic8.com/material/1/

我在Java中实现,所以我不介意基于Java的解决方案,甚至基于XSLT的解决方案似乎都是合适的。

进一步开发了Michael Kay提出的XPath表达式 (似乎实际上是一种简化),以处理属于默认命名空间的未加前缀的元素名称:

 distinct-values(//*[namespace-uri()] /concat(local-name(), ', ', substring-before(name(), ':'), ', ', namespace-uri(), '
' ) ) 

在以下文档 (提供的文档但在默认命名空间中添加了一个元素)评估此XPath表达式时

   1 bar foo  00.00 USD   11.11 AUD    2 some name some description  00.01 USD  high   

产生了想要的正确结果

  create, ns1, http://predic8.com/wsdl/material/ArticleService/1/ article, ns1, xmlns:ns1='http://predic8.com/material/1/ id, ns1, xmlns:ns1='http://predic8.com/material/1/ price, ns1, xmlns:ns1='http://predic8.com/material/1/ quality, , my:q 

进一步的轻微改进也是为属性名称生成名称空间数据:

 distinct-values(//(*|@*)[namespace-uri()] /concat(if(. intersect ../@*) then '@' else (), local-name(), ', ', substring-before(name(), ':'), ', ', namespace-uri(), '
' ) ) 

当在以下XML文档 (前一个(上面)上评估此XPath表达式并在其中一个article元素上添加了xml:lang属性时):

   1 bar foo  00.00 USD   11.11 AUD    2 some name some description  00.01 USD  high   

再次产生正确的结果:

  create, ns1, http://predic8.com/wsdl/material/ArticleService/1/ article, ns1, xmlns:ns1='http://predic8.com/material/1/ @lang, xml, http://www.w3.org/XML/1998/namespace id, ns1, xmlns:ns1='http://predic8.com/material/1/ price, ns1, xmlns:ns1='http://predic8.com/material/1/ quality, , my:q 

我将使用内置的XMLStreamReader ,它是流式XML解析器实现的接口(从XMLInputFactory类获取它)。 它的getName方法返回一个QName,它可以为您提供所需的一切。

有点像:

 File file = new File("samples/sample11.xml"); XMLInputFactory inputFactory = XMLInputFactory.newInstance(); XMLStreamReader reader = inputFactory.createXMLStreamReader(new FileInputStream(file)); Set namespaces = new HashSet(); while (reader.hasNext()) { int evt = reader.next(); if (evt == XMLStreamConstants.START_ELEMENT) { QName qName = reader.getName(); if(qName != null){ if(qName.getPrefix() != null && qName.getPrefix().compareTo("")!=0) namespaces.add(String.format("%s, %s, %s", qName.getLocalPart(), qName.getPrefix(), qName.getNamespaceURI())); } } } for(String namespace : namespaces){ System.out.println(namespace); } 

这可以使用单个XPath 2.0表达式完成:

 distinct-values(//*[name()!=local-name()]/ concat(local-name(), ', ', substring-before(name(), ':'), ', ', namespace-uri())