使用 SAX 解析器确定是不是在叶节点
Posted
技术标签:
【中文标题】使用 SAX 解析器确定是不是在叶节点【英文标题】:Determining if at leaf node with SAX parser使用 SAX 解析器确定是否在叶节点 【发布时间】:2019-09-03 15:25:39 【问题描述】:使用org.xml.sax.helpers.DefaultHandler
,你能确定你是否在endElement(String, String, String)
内的叶节点上吗?
或者您是否需要使用 DOM 解析器来确定这一点?
【问题讨论】:
【参考方案1】:让我们从一些基本定义开始:
XML 文档是一个有序的、带标签的树。树的每个节点都是一个 XML 元素,并写有一个开始和结束标记。
(来自here)。最重要的是:这意味着 XML 文件具有非常规则、简单的结构。例如,leaf 节点的定义就是:没有任何子节点的节点。
现在:只要 SAX 解析器遇到节点的 关闭 标记,就会调用 endElement()
方法。假设你的 XML 有有效的内容,这也意味着解析器之前给你一个对应的startElement()
调用!
换句话说:确定是否“结束”叶节点所需的所有信息都可供您使用:
您被告知哪些元素已“启动” 你被告知哪些元素结束举个例子:
<outer>
<inner/>
</outer>
这将导致这样的一系列事件/回调:
事件:开始元素外部 事件:开始元素内部 事件:内部元素结束 事件:结束元素外部因此,“显然”,当您的解析器记住事件历史时,确定inner
或outer
中的哪一个是叶节点是直截了当的!
因此,答案是:不,您不需要 DOM 解析器。最后,无论如何,DOM 都是由相同的信息构成的!如果 DOM 解析器可以推断出对象的“范围”,那么您的 SAX 解析器也可以。
但只是为了记录:您仍然需要仔细实现跟踪“开始”、“打开”和“结束”标签的数据结构,例如正确确定这个:
<outer> <inner> <inner/> </inner> </outer>
表示两个非叶子(outer
和第一个inner
)和一个叶子节点(内部inner
)。
【讨论】:
@tobias_k 感谢您的意见,我希望我的更新答案能反映您的观点。【参考方案2】:从实现的角度来看,您可以只使用一个布尔标志来执行此操作,跟踪元素是否是潜在的叶节点。每当您输入一个元素时,该标志始终为真,但只有第一个实际的叶节点结束元素才会应用叶节点逻辑。
每当应用 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>
【讨论】:
以上是关于使用 SAX 解析器确定是不是在叶节点的主要内容,如果未能解决你的问题,请参考以下文章
在 JAVA 中使用 SAX 解析器从 XML 文件中提取文本节点
如何在 android 中使用 DOM 或 SAX 解析器从 XML 读取子节点