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

raf*_*uru 6 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);
Run Code Online (Sandbox Code Playgroud)

我的问题是,在这个例子中我如何处理namespase?

McD*_*ell 6

要详细说明Blaise对示例代码的看法,请考虑这个人为的例子:

<?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>
Run Code Online (Sandbox Code Playgroud)

有两种不同类型的记录元素.一个在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>
Run Code Online (Sandbox Code Playgroud)

但代码必须处理一般情况.

以下是一些用于打印元数据记录的代码:

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());
Run Code Online (Sandbox Code Playgroud)

注意:必须在某些较旧的Java XML API(其中包括SAX和DOM)中显式启用名称空间感知.


bdo*_*han 4

在命名空间限定的 XML 文档中,节点名称有两个组成部分:命名空间 URI 和本地名称(这些作为参数传递给 和startElement事件endElement)。当您检查某个元素是否存在时,您应该匹配这两个参数。目前,您的代码适用于下面的两个文档,即使它们的命名空间限定不同。

<foo xmlns="FOO">
    <bar>Hello World</bar>
</foo>
Run Code Online (Sandbox Code Playgroud)

和

<foo xmlns="BAR">
    <bar>Hello World</bar>
</foo>
Run Code Online (Sandbox Code Playgroud)

您当前(并且错误地)匹配了该qName参数。您所做的问题是,qName可能会根据用于表示名称空间的前缀而发生变化。下面的两个文档具有完全相同的命名空间限定。本地名称和命名空间相同,但它们的 QName 不同。

<foo xmlns="FOO">
    <bar>Hello World</bar>
</foo>
Run Code Online (Sandbox Code Playgroud)

和

<ns:foo xmlns:ns="FOO">
    <ns:bar>Hello World</ns:bar>
<ns:foo>
Run Code Online (Sandbox Code Playgroud)