我希望能够得到从给定的XML文件中的所有命名空间信息。
因此,举例来说,如果输入XML文件是这样的:
<ns1:create xmlns:ns1="http://predic8.com/wsdl/material/ArticleService/1/">
<ns1:article xmlns:ns1="xmlns:ns1='http://predic8.com/material/1/">
<ns1:id>1</ns1:id>
<description>bar</description>
<name>foo</name>
<ns1:price>
<amount>00.00</amount>
<currency>USD</currency>
</ns1:price>
<ns1:price>
<amount>11.11</amount>
<currency>AUD</currency>
</ns1:price>
</ns1:article>
<ns1:article xmlns:ns1="xmlns:ns1='http://predic8.com/material/1/">
<ns1:id>2</ns1:id>
<description>some name</description>
<name>some description</name>
<ns1:price>
<amount>00.01</amount>
<currency>USD</currency>
</ns1:price>
</ns1:article>
</ns1:create>
我想期望的输出,看起来是这样的(在这种情况下逗号分隔):
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
发现,命名空间网址为xmlns:ns1='http://predic8.com/material/1/
我用Java实现的,所以我不会介意无论是基于Java的解决方案,甚至是基于XSLT的解决方案似乎是适当的。
进一步发展由迈克尔·凯提出的XPath表达式 (实际上似乎简化)也处理属于默认命名空间前缀的元素名称:
distinct-values(//*[namespace-uri()]
/concat(local-name(),
', ',
substring-before(name(), ':'),
', ',
namespace-uri(),
'
'
)
)
当该XPath表达式在以下文件 (所提供的一个,但与处于默认名称空间添加元素)来评价 :
<ns1:create xmlns:ns1="http://predic8.com/wsdl/material/ArticleService/1/">
<ns1:article xmlns:ns1="xmlns:ns1='http://predic8.com/material/1/">
<ns1:id>1</ns1:id>
<description>bar</description>
<name>foo</name>
<ns1:price>
<amount>00.00</amount>
<currency>USD</currency>
</ns1:price>
<ns1:price>
<amount>11.11</amount>
<currency>AUD</currency>
</ns1:price>
</ns1:article>
<ns1:article xmlns:ns1="xmlns:ns1='http://predic8.com/material/1/">
<ns1:id>2</ns1:id>
<description>some name</description>
<name>some description</name>
<ns1:price>
<amount>00.01</amount>
<currency>USD</currency>
</ns1:price>
<quality xmlns="my:q">high</quality>
</ns1:article>
</ns1:create>
在想,正确的结果产生 :
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(),
'
'
)
)
当该XPath表达式上下面的XML文档进行评估 (前一个(以上)与加入xml:lang
属性上的一个article
的元素):
<ns1:create xmlns:ns1="http://predic8.com/wsdl/material/ArticleService/1/">
<ns1:article xml:lang="en-us" xmlns:ns1="xmlns:ns1='http://predic8.com/material/1/">
<ns1:id>1</ns1:id>
<description>bar</description>
<name>foo</name>
<ns1:price>
<amount>00.00</amount>
<currency>USD</currency>
</ns1:price>
<ns1:price>
<amount>11.11</amount>
<currency>AUD</currency>
</ns1:price>
</ns1:article>
<ns1:article xmlns:ns1="xmlns:ns1='http://predic8.com/material/1/">
<ns1:id>2</ns1:id>
<description>some name</description>
<name>some description</name>
<ns1:price>
<amount>00.01</amount>
<currency>USD</currency>
</ns1:price>
<quality xmlns="my:q">high</quality>
</ns1:article>
</ns1:create>
再次正确的结果产生:
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<String> namespaces = new HashSet<String>();
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())