使用SAX解析器确定是否在叶节点处

时间:2019-04-12 20:11:36

标签: java sax domparser

使用org.xml.sax.helpers.DefaultHandler,可以确定您是否在endElement(String, String, String)内的叶节点上吗?

还是您需要使用DOM解析器来确定这一点?

2 个答案:

答案 0 :(得分:10)

让我们从一些基本定义开始:

  

XML文档是带有标签的有序树。树的每个节点都是XML元素,并带有一个开始和结束标记。

(来自here)。最重要的是:这意味着XML文件具有非常规则的简单结构。例如, leaf 节点的定义就是这样:没有任何子节点的节点。

现在:每当SAX解析器遇到节点的 closing 标记时,都将调用endElement()方法。假设您的XML具有有效的内容,那也意味着解析器之前已经给您一个相应的startElement()调用!

换句话说:确定您是否要“结束”叶节点所需的所有信息对您都可用:

  • 有人告诉您哪些元素是“开始的”
  • 系统会告知您哪些元素结束

以这个例子为例:

<outer>
  <inner/>
</outer>

这将导致一系列事件/回调:

  • 事件:外部开始元素
  • 事件:内部开始元素
  • 事件:内部结束元素
  • 事件:外部结束元素

因此,显然,当您的解析器记住事件的历史记录时,确定innerouter中的哪个是叶子节点是很直接的!

因此,答案是:不,您不需要DOM解析器。最后,无论如何,DOM是由完全相同的信息构成的!如果DOM解析器可以推断出对象的“范围”,那么SAX解析器也可以。

但仅作记录:您仍然需要仔细实现跟踪“开始”,“打开”和“结束”标记的数据结构,例如正确确定该标记:

<outer> <inner> <inner/> </inner> </outer>

表示两个非叶子(outer和第一个inner)和一个叶子节点(内部inner)。

答案 1 :(得分:4)

从实现的角度来看,您可以仅使用单个布尔标志来执行此操作,以跟踪元素是否为潜在的叶节点。每当您输入元素时,该标志始终为true,但只有第一个实际的叶子节点结尾元素将应用叶子节点逻辑。

无论何时应用startElement,都可以重复重置此标志。

如果多个叶节点处于同一级别,则将设置连续的isLeafNode标志。

如果我们将XML视为堆栈,则可以查看其背后的逻辑推理。 startElements被压入堆栈。推送后从堆栈中弹出的第一个弹出节点将是叶节点。随后的弹出窗口不会出现叶子,但是如果再次执行推送,则会重置该弹出窗口。

private boolean isLeafNode = false;

public void startElement(String uri, String localName, String qName, Attributes attributes) {
    isLeafNode = true;
}

public void endElement(String uri, String localName, String qName) {
    if(isLeafNode) {
        //do leaf node logic
    }

    isLeafNode = false;
}

因此,对于以下XML,叶节点如下。

<foo>
    <bar>Leaf</bar>
    <baz>
        <bop>Leaf</bop>
        <beep>Leaf</beep>
        <blip>
            <moo>Leaf</moo>
        </blip>
    </baz>
</foo>