有没有办法使用SAX Parser使用Visitor模式?

时间:2012-06-01 13:13:13

标签: java sax saxparser

我很好奇:如果我需要使用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));
    }
}

取自here的例子。

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?

2 个答案:

答案 0 :(得分:1)

您可以在SAX解析器中使用Map<String, ElementHandler>,并允许为元素名称注册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();
    }
}

答案 1 :(得分:0)

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