4

我对此很好奇:如果我需要使用 Sax 解析器来提高效率(这是一个大文件)。通常我使用这样的东西:

public class Example extends DefaultHandler
{
    private Stack stack = new Stack ();

    public void startElement (String uri, String local, String qName, Attributes atts) throws SAXException
    {
        stack.push (qName);
    }

    public void endElement (String uri, String local, String qName) throws SAXException
    {
        if ("line".equals (qName))
            System.out.println ();

        stack.pop ();
    }

    public void characters (char buf [], int offset, int length) throws SAXException
    {
        if (!"line".equals (stack.peek ()))
            return;

        System.out.write (new String (buf, offset, length));
    }
}

取自此处的示例。

Sax 已经是访问者模式的实现,但就我而言,我只需要获取每个元素的内容并根据元素本身的性质对其进行处理。

我的典型 XML 文件类似于:

<?xml version="1.0" encoding="utf-8"?>
<labs xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <auth>
        <uid> </uid>
        <gid> </gid>
        <key> </key>
    </auth>
    <campaign>
        <sms>
            <newsletter>206</newsletter>
            <message>
                <from>Da Definire</from>
                <subject>Da definire</subject>
                <body><![CDATA[Testo Da Definire]]></body>
            </message>
            <delivery method="manual"></delivery>
            <recipients>
                <db>276</db>
                <filter>
                    <test>1538</test>
                </filter>
                <new_recipients>
                    <csv_file>Corso2012_SMS.csv</csv_file>
                </new_recipients>
            </recipients>
        </sms>
    </campaign>
</labs>

当我在 csv_file 节点中时,我需要获取文件名并从该文件上传用户,如果我在filter/test我需要检查过滤器是否存在等等。有没有办法通过 SAX 应用访问者模式?

4

2 回答 2

1

您可以简单地Map<String, ElementHandler>在您的 SAX 解析器中有一个,并允许为元素名称注册 ElementHandlers。假设您只对叶子元素感兴趣:

  • 每次启动一个元素时,您都会查看映射中是否有此元素名称的处理程序,然后清除缓冲区。
  • 每次characters()调用时,您将字符附加到缓冲区(如果有前一个元素开始的处理程序)
  • 每次元素结束时,如果前一个元素开始有处理程序,则使用缓冲区的内容调用处理程序

这是一个例子:

private ElementHandler currentHandler;
private StringBuilder buffer = new StringBuilder();
private Map<String, ElementHandler> handlers = new HashMap<String, ElementHandler>();

public void registerHandler(String qName, ElementHandler handler) {
    handlers.put(qName, handler);
}    

public void startElement (String uri, String local, String qName, Attributes atts) throws SAXException {
    currentHandler = handlers.get(qName);
    buffer.delete(0, buffer.length());
}

public void characters (char buf [], int offset, int length) throws SAXException {
    if (currentHandler != null) {
        buffer.append(buf, offset, length);
    }
}

public void endElement (String uri, String local, String qName) throws SAXException {
    if (currentHandler != null) {
        currentHandler.handle(buffer.toString();
    }
}
于 2012-06-01T14:49:03.247 回答
0

不要忘记StAX。它可能不会使访问者模式变得更容易,但是如果您的文档相对简单并且您已经计划对它们进行流式传输,那么它确实具有比 SAX 更简单的编程模型。您只需遍历解析流中的事件,一次一个,根据您的选择忽略或操作它们。

于 2012-06-02T00:04:36.167 回答