解析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())