清理SAX处理程序

时间:2013-03-14 10:09:14

标签: xml-parsing refactoring sax

我已经制作了一个SAX解析器,用于解析具有许多不同标签的XML文件。出于性能原因,我选择了SAX而不是DOM。我很高兴我这样做,因为它工作得很快很好。我目前唯一的问题是主类(扩展DefaultHandler)有点大而且不容易看到。它包含一个巨大的if / elseif块,我在其中检查标记名称,其中一些嵌套if用于读取特定属性。该块位于StartElement方法中。

有什么好的干净方法可以解决这个问题吗?我想有一个读取文件的主类,然后是每个标签的Handler。在这个标记处理程序中,我想读取该标记的属性,对它们执行某些操作,然后返回主处理程序以读取下一个标记,该标记再次被重定向到适当的处理程序。

我的主处理程序还有一些全局Collection变量,它们收集有关我用它解析的所有文档的信息。理想情况下,我可以从Tag Handlers中为这些集合添加一些内容。

如果可能,代码示例将非常有用。我在这个网站上读到了一个关于Handler Stack的东西,但没有代码示例我无法重现它。

提前致谢:)

1 个答案:

答案 0 :(得分:3)

我建议设置一系列SAX过滤器。 SAX过滤器就像任何其他SAX处理程序一样,除了它有另一个SAX处理程序在事件完成时将事件传递给它。它们经常用于对XML流执行一系列转换,但它们也可用于按您希望的方式对事物进行分解。

你没有提到你正在使用的语言,但你提到DefaultHandler所以我会假设Java。首先要做的是编写过滤器代码。在Java中,您可以通过实现XMLFilter(或者更简单地通过子类化XMLFilterImpl)来实现此目的。

import java.util.Collection;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.XMLFilterImpl;

public class TagOneFilter extends XMLFilterImpl {

    private Collection<Object> collectionOfStuff;

    public TagOneFilter(Collection<Object> collectionOfStuff) {
        this.collectionOfStuff = collectionOfStuff;
    }

    @Override
    public void startElement(String uri, String localName, String qName,
            Attributes atts) throws SAXException {
        if ("tagOne".equals(qName)) {
            // Interrogate the parameters and update collectionOfStuff
        }

        // Pass the event to downstream filters.
        if (getContentHandler() != null)
            getContentHandler().startElement(uri, localName, qName, atts);
    }
}

接下来,您的主类,它实例化所有过滤器并将它们链接在一起。

import java.util.ArrayList;
import java.util.Collection;

import org.xml.sax.XMLReader;
import org.xml.sax.helpers.XMLReaderFactory;

public class Driver {

    public static void main(String[] args) throws Exception {
        Collection<Object> collectionOfStuff = new ArrayList<Object>();
        XMLReader parser = XMLReaderFactory.createXMLReader();

        TagOneFilter tagOneFilter = new TagOneFilter(collectionOfStuff);
        tagOneFilter.setParent(parser);

        TagTwoFilter tagTwoFilter = new TagTwoFilter(collectionOfStuff);
        tagTwoFilter.setParent(tagOneFilter);

        // Call parse() on the tail of the filter chain. This will finish
        // tying the filters together before executing the parse at the
        // XMLReader at the beginning.
        tagTwoFilter.parse(args[0]);

        // Now do something interesting with your collectionOfStuff.
    }
}