如何使用SAX Parser处理命名空间?

时间:2014-02-16 05:01:00

标签: java xml sax

我正在尝试学习解析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?

2 个答案:

答案 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和本地名称(这些作为参数传递给startElementendElement事件)。当您检查是否存在元素时,您应该在这两个参数上进行匹配。目前,您的代码适用于以下两个文档,即使它们的命名空间不同。

<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>