使用sax和java从xml文件中删除多个节点

4
我是一个新手,使用Java和SAX解析器进行XML解析。我有一个非常大的XML文件,由于其大小,建议我使用SAX解析器。我已经完成了部分解析任务,并且它按预期工作。现在,还有一个任务需要处理XML:根据用户请求删除/更新一些节点。
我能够通过它们的名称找到所有标记,更改它们的数据属性等。如果我能够使用SAX做这些事情,那么删除也可能是可能的。
示例XML描述了某些情况下的一些功能。用户输入是“case”的名称(“case1”,“case2”)。
<ruleset>
    <rule id="1">
        <condition>
            <case1>somefunctionality</case1>
            <allow>true</allow>
        </condition>
    </rule>
    <rule id="2">
        <condition>
            <case2>somefunctionality</case2>
            <allow>false</allow>
        </condition>
    </rule>
</ruleset>

如果用户想删除这些案例中的一个(例如case1),不仅要删除case1标签,还必须删除完整的rule标签。如果要删除case1,XML将变为:
<ruleset>
    <rule id="2">
        <condition>
            <case2>somefunctionality</case2>
            <allow>false</allow>
        </condition>
    </rule>
</ruleset>

我的问题是,能否使用SAX来实现?我目前无法使用DOM或其他解析器。唯一的其他选择甚至更糟:字符串搜索。如何使用SaxParser实现?

3个回答

6

Try as

    XMLReader xr = new XMLFilterImpl(XMLReaderFactory.createXMLReader()) {
        private boolean skip;

        @Override
        public void startElement(String uri, String localName, String qName, Attributes atts)
                throws SAXException {
            if (qName.equals("rule")) {
                if (atts.getValue("id").equals("1")) {
                    skip = true;
                } else {
                    super.startElement(uri, localName, qName, atts);
                    skip = false;
                }
            } else {
                if (!skip) {
                    super.startElement(uri, localName, qName, atts);
                }
            }
        }

        public void endElement(String uri, String localName, String qName) throws SAXException {
            if (!skip) {
                super.endElement(uri, localName, qName);
            }
        }

        @Override
        public void characters(char[] ch, int start, int length) throws SAXException {
            if (!skip) {
                super.characters(ch, start, length);
            }
        }
    };
    Source src = new SAXSource(xr, new InputSource("test.xml"));
    Result res = new StreamResult(System.out);
    TransformerFactory.newInstance().newTransformer().transform(src, res);

输出

<?xml version="1.0" encoding="UTF-8"?><ruleset>
    <rule id="2">
        <condition>
            <case2>somefunctionality</case2>
            <allow>false</allow>
        </condition>
    </rule>
</ruleset>

这种方法并不总是按预期工作,因为SAX按顺序解析元素 - 这意味着如果您有两个相邻的关闭标签,endElement方法将被调用两次,并且会根据上一次跳过的时间(即上一个startElement)进行跳过。 - Mike

0
你需要构建的是一个SAX事件缓冲区。
当你遇到一个<rule>元素时,你需要保存它(或重新生成它所需的信息)以及在它和你想要删除的“case”之间发生的所有其他事件。
如果你保存的“rule”与需要删除的“rule”相同,只需丢弃信息并继续即可。
如果你保存的“rule”不是需要删除的“rule”,则应重新生成保存的SAX事件并继续。

0

SAX 最常用于读取/解析 XML。但是有一篇关于如何使用 SAX 写文件的文章。而且这个章节似乎可以在线查看 - 请参见:

http://xmlwriter.net/sample_chapters/Professional_XML/31100604.shtml

[这篇文章的日期是1999年,因此它使用了一个旧版本的SAX,但概念仍然适用]

基本思路是创建一个自定义的DocumentHandler/ContentHandler。每当它接收到一个SAX事件时,它将该事件序列化并将其写入流/文件/其他内容。因此,您可以将输入文档作为SAX事件源,并将这些事件转发给XMLOutputter。

最困难的部分是使您能够将XML文档解析为SAX事件流,驱动XMLOutputter并生成输入文件的精确副本。一旦您做到了这一点,就可以进入编辑逻辑,其中您可以读取规则并使用这些规则修改输出文件。

与DOM、JDOM、XSLT等相比,这需要更多的工作,但它可能有助于您的情况,因为您永远不必将整个文档存储在内存中。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接