【问题标题】:Remove multiple nodes from an xml file using sax and java使用 sax 和 java 从 xml 文件中删除多个节点
【发布时间】:2012-11-30 14:40:23
【问题描述】:

我是使用 Java 和 SAX 解析器进行 XML 解析的新手。我有一个非常大的 XML 文件,并且由于它的大小,我被建议使用 SAX 解析器。我已经完成了部分任务的解析,它按预期工作。现在,XML 作业剩下一项任务:根据用户的请求删除/更新一些节点。

我可以通过名称找到所有标签,更改其data 属性等。如果我能够使用 SAX 执行这些操作,也可以删除。

示例 XML 描述了某些情况下的一些功能。用户的输入是“案例”的名称(case1case2)。

<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 完成?

【问题讨论】:

    标签: java xml sax


    【解决方案1】:

    试一试

        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 会按顺序解析元素 - 这意味着如果您有 2 个彼此相邻的关闭标签,则 endElement 方法将被调用两次,并将根据上次跳过的时间跳过调用(最后一个 startElement)
    【解决方案2】:

    您需要构建的是一个 SAX 事件缓冲区。

    当您遇到&lt;rule&gt; 元素时,您需要保存它(或重新生成它所需的信息)以及它与您要删除的“案例”之间发生的所有其他事件。

    如果您保存的“规则”与需要删除的“规则”相同,则丢弃信息并继续。

    如果您保存的“规则”不是需要删除的,您应该重新生成已保存的 sax 事件并继续。

    【讨论】:

      【解决方案3】:

      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 等要多得多,但它可能对您的情况有所帮助,因为您不必将整个文档存储在内存中。

      【讨论】:

        猜你喜欢
        • 2023-03-24
        • 1970-01-01
        • 2014-03-10
        • 2011-09-25
        • 2013-02-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多