在没有现有解析器实现的情况下在Java中构建XML解析器

时间:2017-10-14 11:53:18

标签: java xml parsing dom

在没有使用Jackson,JDK和Document Builder实现的情况下,是否有一种在Java中创建原始XML解析器的好方法?理论上这应该是什么样的?

例如,实现基本元素定义语法的解析:

<root>
<first></first>
<second></second>
</root>

实现解析元素树的漂亮打印:每个元素在一个单独的上 line,嵌套元素缩进4个空格并基本转义&#39;&lt;&#39;和&#39;&gt;&#39;符号通过&lt;和&gt;什么时候 解析:

<escaped&lt;&gt;></escaped&lt;&gt;>

然后,实现解析内联空元素:

<root>
<empty/>
</root>

3 个答案:

答案 0 :(得分:1)

我使用基于编译正则表达式的标记化器构建递归下降解析器(虽然使用正则表达式解析 XML是不可能的,使用XML的正则表达式没有任何问题标记化)。

我大致如下设计了tokenizer接口(在内部使用Scanner):

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的协议缓冲区定义解析器中选择了tryConsumeXxx()样式,我发现它非常有用。

答案 1 :(得分:0)

第一步很清楚你需要标记化XML。在该步骤之后,您将获得令牌列表 - 例如标记,属性,值等。

下一步取决于实施。如果您提到DOM,则必须处理整个列表。所以'&lt;'打开标签创建,然后名称来,在可能的参数列表'&gt;'之后。然后必须将子注释构建到该特定节点的子树中。请注意,您需要更换像&amp;;进入&amp ;.

对于基本处理应该没问题。其他主题包括命名空间和验证......

答案 2 :(得分:0)

当然,可能有十几种不同的方法可以做到这一点。例如,XML适用于递归下降解析。在任何级别检查,XML文件都具有基本结构

<tag1>something</tag1><tag2>something</tag2>...

其中“something”本身与整个文件的结构相同。 “某事”可能是空的,标签本身可能会折叠成<tag/> - 必须查找这些案例。

解析器查找<tag>something</tag>形式的模式列表,如果“某些东西”以另一个<tag>开头,它会递归调用自己来解析这个新节。当文档的所有部分都被探索到底部时,递归完成。在每个新的递归调用中,我们创建一个类的实例来保存数据,并且构建这些实例的递归树,而不是像DOM模型。

熟练的解析器设计师能够使整个事情更有效率,当然,你必须处理解析命名空间,属性等。但是使用递归解析器实现这样的东西是一个有趣的运动。