我正在尝试学习解析XML文档,我有一个使用命名空间的XML文档,因此,我确信我需要做一些正确解析的事情。
这就是我所拥有的:
DefaultHandler handler = new DefaultHandler() {
boolean bfname = false;
boolean blname = false;
boolean bnname = false;
boolean bsalary = false;
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
System.out.println("Start Element :" + qName);
if (qName.equalsIgnoreCase("FIRSTNAME")) {
bfname = true;
}
if (qName.equalsIgnoreCase("LASTNAME")) {
blname = true;
}
if (qName.equalsIgnoreCase("NICKNAME")) {
bnname = true;
}
if (qName.equalsIgnoreCase("SALARY")) {
bsalary = true;
}
}
public void endElement(String uri, String localName,
String qName) throws SAXException {
System.out.println("End Element :" + qName);
}
public void characters(char ch[], int start, int length) throws SAXException {
if (bfname) {
System.out.println("First Name : " + new String(ch, start, length));
bfname = false;
}
if (blname) {
System.out.println("Last Name : " + new String(ch, start, length));
blname = false;
}
if (bnname) {
System.out.println("Nick Name : " + new String(ch, start, length));
bnname = false;
}
if (bsalary) {
System.out.println("Salary : " + new String(ch, start, length));
bsalary = false;
}
}
};
saxParser.parse(file, handler);
我的问题是,在这个例子中我如何处理namespase?
答案 0 :(得分:6)
要详细说明带有示例代码的Blaise's point,请考虑这个人为的例子:
<?xml version="1.0" encoding="UTF-8"?>
<!-- ns.xml -->
<root xmlns:foo="http://data" xmlns="http://data">
<foo:record>ONE</foo:record>
<bar:record xmlns:bar="http://data">TWO</bar:record>
<record>THREE</record>
<record xmlns="http://metadata">meta 1</record>
<foo:record xmlns:foo="http://metadata">meta 2</foo:record>
</root>
有两种不同类型的记录元素。 http://data
命名空间中的一个; http://metadata
命名空间中的另一个。有三个数据记录和两个元数据记录。
该文件可以归一化为:
<?xml version="1.0" encoding="UTF-8"?>
<ns0:root xmlns:ns0="http://data" xmlns:ns1="http://metadata">
<ns0:record>ONE</ns0:record>
<ns0:record>TWO</ns0:record>
<ns0:record>THREE</ns0:record>
<ns1:record>meta 1</ns1:record>
<ns1:record>meta 2</ns1:record>
</ns0:root>
但代码必须处理一般情况。
以下是打印元数据记录的一些代码:
class MetadataPrinter extends DefaultHandler {
private boolean isMeta = false;
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
isMeta = "http://metadata".equals(uri) && "record".equals(localName);
}
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
if (isMeta) {
System.out.println();
isMeta = false;
}
}
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
if (isMeta) {
System.out.print(new String(ch, start, length));
}
}
}
SAXParserFactory factory = SAXParserFactory.newInstance();
factory.setNamespaceAware(true);
SAXParser parser = factory.newSAXParser();
parser.parse(new File("ns.xml"), new MetadataPrinter());
注意:必须在某些较旧的Java XML API(其中包括SAX和DOM)中显式启用命名空间感知。
答案 1 :(得分:4)
在命名空间限定的XML文档中,节点名称有两个组件:名称空间URI和本地名称(这些作为参数传递给startElement
和endElement
事件)。当您检查是否存在元素时,您应该在这两个参数上进行匹配。目前,您的代码适用于以下两个文档,即使它们的命名空间不同。
<foo xmlns="FOO">
<bar>Hello World</bar>
</foo>
和
<foo xmlns="BAR">
<bar>Hello World</bar>
</foo>
您目前(并且错误地)匹配qName
参数。您正在做的问题是qName
可能会根据用于表示命名空间的前缀而更改。下面的两个文档具有完全相同的命名空间限定。本地名称和名称空间是相同的,但它们的QNames是不同的。
<foo xmlns="FOO">
<bar>Hello World</bar>
</foo>
和
<ns:foo xmlns:ns="FOO">
<ns:bar>Hello World</ns:bar>
<ns:foo>