使用org.xml.sax.helpers.DefaultHandler
,可以确定您是否在endElement(String, String, String)
内的叶节点上吗?
还是您需要使用DOM解析器来确定这一点?
答案 0 :(得分:10)
让我们从一些基本定义开始:
XML文档是带有标签的有序树。树的每个节点都是XML元素,并带有一个开始和结束标记。
(来自here)。最重要的是:这意味着XML文件具有非常规则的简单结构。例如, leaf 节点的定义就是这样:没有任何子节点的节点。
现在:每当SAX解析器遇到节点的 closing 标记时,都将调用endElement()
方法。假设您的XML具有有效的内容,那也意味着解析器之前已经给您一个相应的startElement()
调用!
换句话说:确定您是否要“结束”叶节点所需的所有信息对您都可用:
以这个例子为例:
<outer>
<inner/>
</outer>
这将导致一系列事件/回调:
因此,显然,当您的解析器记住事件的历史记录时,确定inner
或outer
中的哪个是叶子节点是很直接的!
因此,答案是:不,您不需要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>