是否有一种在 Java 中创建原始 XML 解析器而不使用 Jackson、JDK 和 Document Builder 实现的好方法?理论上这应该是什么样子?
例如实现基本元素定义语法的解析:
<root>
<first></first>
<second></second>
</root>
实现解析元素树的 pretty-print :每个元素都在单独的 行,嵌套元素缩进 4 个空格,并通过 < 和 > 对 '<' 和 '>' 符号进行基本转义 解析:
<escaped<>></escaped<>>
然后,实现解析内联空元素:
<root>
<empty/>
</root>
最佳答案
我会使用基于已编译正则表达式的分词器构建一个递归下降解析器(虽然不可能使用正则表达式来解析 XML,但使用 XML 的正则表达式并没有什么问题)标记化)。
我将分词器界面设计大致如下(内部使用扫描仪):
class XmlTokenizer {
String getCurrentText();
boolean tryConsumeStartTagStart();
boolean tryConsumeAttributeName();
boolean tryConsumeText();
...
然后解析器可以尝试当前位置有效的标记类型,并使用 getCurrentText() 方法获取相应的文本(例如元素或属性名称)。
例如,内容解析如下所示:
void parseNodeContent(Node node) {
while (true) {
if (tokenizer.tryConsumeText()) {
node.appendText(getCurrentText());
} else if (tryConsumeStartTagStart()) {
node.append(parseElement());
} else if
... // processing instructions, entity references
} else {
// Let the caller deal with all the rest, including errors.
break;
}
}
}
元素解析可能如下所示:
// Precondition: on element start
// Postcondition: on element end
Element parseElement() {
Element result = new Element(tokenizer.getCurrentText());
while (tryConsumeAttributeName()) {
String attributeName = tokenizer.getCurrentText();
... // attribute value parsing
}
if (!tokenizer.tryConsumeStartTagEndSelfClosing()) {
if (!tokenizer.tryConsumeStartTagEnd()) {
throw new RuntimeException("Invalid start tag end");
}
parseContent(result);
if (!tokenizer.tryConsumeEndTag(result.name())) {
throw new RuntimeException("End tag missing for " +result.name());
}
}
return result;
}
我从 Kenton Varla 的 Protocol Buffer 定义解析器中选择了 tryConsumeXxx()
样式,我发现它非常有用。
关于java - 在没有现有解析器实现的情况下用 Java 构建 XML 解析器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46744236/