Java 解析XML文件以获取所有命名空间信息
我希望能够从给定的XML文件中获取所有名称空间信息 例如,如果输入XML文件类似于:Java 解析XML文件以获取所有命名空间信息,java,xml,xslt,xpath,xquery,Java,Xml,Xslt,Xpath,Xquery,我希望能够从给定的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> <d
<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>
重要提示:
<> P>重要的是,我们还考虑在特定命名空间内定义的子节点,但其定义可以在更高的节点上定义。例如,我们仍然希望选取节点ns1:id
,在这里我们需要追溯到父节点ns1:article
,以发现名称空间url是xmlns:ns1=http://predic8.com/material/1/
我是用Java实现的,所以我不介意使用基于Java的解决方案,甚至是基于XSLT的解决方案。我会使用内置的,这是由流式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);
}
File File=new文件(“samples/sample11.xml”);
XMLInputFactory inputFactory=XMLInputFactory.newInstance();
XMLStreamReader=inputFactory.createXMLStreamReader(新文件InputStream(文件));
Set namespace=new HashSet();
while(reader.hasNext()){
int evt=reader.next();
if(evt==XMLStreamConstants.START_元素){
QName QName=reader.getName();
if(qName!=null){
if(qName.getPrefix()!=null&&qName.getPrefix().compareTo(“”)=0)
名称空间.add(String.format(“%s,%s,%s”,
qName.getLocalPart()、qName.getPrefix()、qName.getNamespaceURI());
}
}
}
for(字符串命名空间:命名空间){
System.out.println(名称空间);
}
这可以通过单个XPath 2.0表达式完成:
distinct-values(//*[name()!=local-name()]/
concat(local-name(), ', ', substring-before(name(), ':'), ', ', namespace-uri())
进一步开发了Michael Kay提出的XPath表达式(实际上似乎是一种简化),以处理属于默认名称空间的不固定元素名称:
distinct-values(//*[namespace-uri()]
/concat(local-name(),
', ',
substring-before(name(), ':'),
', ',
namespace-uri(),
'
'
)
)
<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>
在以下文档上计算此XPath表达式时(提供的文档中包含默认名称空间中添加的元素):
另一个轻微的改进是为属性名生成名称空间数据:
distinct-values(//(*|@*)[namespace-uri()]
/concat(if(. intersect ../@*)
then '@'
else (),
local-name(),
', ',
substring-before(name(), ':'),
', ',
namespace-uri(),
'
'
)
)
在以下XML文档上计算此XPath表达式时(上一个(上面)在文章
元素之一上添加了XML:lang
属性):
那么你到底在寻找什么样的信息呢?输出中的第一行有一个本地名称、一个名称空间前缀和一个名称空间名称,但接下来的三行以一个名称空间声明属性结尾,奇怪的是,它缺少结束符。那么属性节点的限定名称呢,您对它们也感兴趣吗?谢谢,我现在编辑了这个问题,因为这是一个错误。我真的是在得到一个三元组的形式(本地名称,前缀,url)。另外,现在我不想担心限定的属性节点。Larry,最好指出一个事实,当前接受的答案既不涉及默认命名空间中的名称,也不涉及命名空间属性名称。而且它过于复杂,难以阅读。将其与XSLT 2.0解决方案进行比较,XSLT 2.0解决方案实际上是对单个XPath表达式的评估——如其他两个答案中所述……Dimitre,我当然同意,虽然我知道问题中没有明确规定,但它似乎是完整解决方案的关键要求。毕竟,我确实提到了“所有”名称空间信息。感谢您指出这一点并提供解决方案,(+1)。我也相应地修改了正确答案,以反映更正确的解决方案。Larry,虽然您的问题可能有趣且具有挑战性,但我们确实希望您尝试自己解决这些问题(并发布代码,即使它不起作用)而不是要求社区为你找到一个完整的解决方案。谢谢,谢谢,亚历克斯,这个很好用。我对您的解决方案进行了编辑,以提供更完整的解决方案(目前,它仍在等待同行审查)。这似乎不包括默认命名空间中的元素名称——或者我错了吗?通过更改谓词,它可以很容易地适配为处理默认命名空间或无命名空间中的元素名称,但是这个问题没有明确说明要求是什么,所以我猜。
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(),
'
'
)
)
<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