【问题标题】:Strategy for parsing LOTS and LOTS of not-so-well formed SGML / XML documents解析 LOTS 和 LOTS 格式不太好的 SGML/XML 文档的策略
【发布时间】:2011-05-12 23:33:16
【问题描述】:

我有数以千计的 SGML 文档,有些格式正确,有些格式不太好。我需要获取文档中的某些元素,但是每次我去加载并尝试将它们读入 XDocument、XMLDocument 甚至只是 StreamReader 时,我都会收到不同的各种 XMLException 错误。

诸如“'[' 是一个意外的标记。”之类的东西。为什么?因为我有一个像 DOCTYPE 这样的文档

<!DOCTYPE RChapter PUBLIC "-//LSC//DTD R Chapter for Authoring//EN" [] >

我了解到“[]”内部需要有一些有效的东西。同样,我不控制文档的创建,但我必须“破解”它们并获取我想要的数据。另一个例子是有一个“未封闭”的 ELEMENT,例如:

<Caption>Plants, and facilities<hardhyphen><hyphen>Inspection.</Caption>

此 XMLException 是“第 27 行的‘连字符’开始标记与‘标题’的结束标记不匹配。第 27 行,位置 58。”很明显吧?

但是问题是,您如何才能真正获得这些文档中的某些元素,而不会遇到 XMLExceptions。 SAX 解析器是正确的方式吗?我基本上想打开文档,直接找到我想要的元素(不用担心附近的格式是否正确),提取数据,然后继续。我是否应该忘记使用 XMLDocument、XDocument 进行解析,而只进行简单的字符串替换,例如

str.Replace("<hardhypen><hyphen>", "-")

然后尝试将其加载到 XML 解析器之一。有什么策略技巧吗?

【问题讨论】:

标签: xml string linq-to-xml xmldocument sgml


【解决方案1】:

问题是您正在尝试使用 XML 工具解析 SGML。他们不一样。如果您想使用 XML 工具/语言来访问数据,您可能需要在尝试解析之前将 SGML 转换为 XML。

理想情况下,您要么使用支持 SGML 的语言/工具(如 OmniMark),要么使用可以处理“类似 XML”的数据的工具(如第一个答案中的 nokogiri?)。

这可能非常简单,但在某些时候可能会变得棘手。特别是如果您正在谈论多种文档类型(DTD)。 (此外,没有“格式良好”的 SGML 这样的东西。是的,元素/等必须正确嵌套,但 SGML 必须有一个 DTD。)

以下是您需要处理的 SGML 和 XML 之间的一些差异。 (您可能不想走这条路,但无论如何它可能有助于提供信息。):

  1. DOCTYPE 声明

    您示例中的 DOCTYPE 声明是完全有效的 SGML 文档类型。 [](内部子集)不必包含任何内容。如果您在内部子集中确实有声明(通常是实体声明),那么您很可能必须在 XML 中保留一个 doctype 声明。

    XML 解析器的问题是您在声明中没有系统标识符。在 XML 文档类型声明中,如果有公共标识符,则需要系统标识符。在 SGML 文档类型声明中,它不是必需的。

    底线:除非您需要将 XML 解析为 DTD/Schema 或在内部子集中有声明,否则请去掉 doctype 声明。如果 XML 确实必须有效,那么您至少需要添加一个系统标识符。不要忘记添加&lt;?xml ...?&gt; 处理指令。

  2. 没有结束标签的元素

    &lt;hardhyphen&gt;&lt;hyphen&gt; 元素是有效的 SGML。 SGML DTD 允许您指定标记最小化。这意味着您可以指定是否需要结束标记。 (你也可以让开始标签成为可选的,但那太疯狂了。)在 XML 中你必须关闭这些元素(比如 &lt;hardhyphen/&gt;&lt;hardhyphen&gt;&lt;/hardhyphen&gt;

    最好的办法是查看您的 SGML DTD 并查看哪些元素具有可选的结束标记。标签最小化在元素声明中的元素名称之后指定。 '-' 表示该标签是必需的。 'o'(字母 'oh')表示标签是可选的。例如,如果您看到&lt;!ELEMENT hyphen - o (#PCDATA)&gt;,这意味着开始标签是必需的(-),而结束标签是可选的(o)。如果看到&lt;!ELEMENT hyphen - - (#PCDATA)&gt;,则开始和结束标记都是必需的。

    底线:正确关闭所有没有结束标签的元素

  3. 处理说明

    SGML 中的处理指令 (PI) 在像 XML 一样关闭时没有第二个 ?。您需要添加第二个?

    示例 SGML PI:&lt;?asdf jkl&gt;

    示例 XML PI:&lt;?asdf jkl?&gt;

  4. 包含/排除

    您可能不必担心这一点,但在 SGML DTD 中,您可以在元素声明中指定另一个元素在该元素内部的任何位置都允许(或不允许)。如果您的目标 XML 需要解析为 DTD,这可能会很痛苦; XML DTD 不允许包含/排除。

    这是一个包含的样子:

    &lt;!ELEMENT chapter - - (section)+ +(revst|revend)&gt;

    这就是说revstrevend 可以在chapter 内的任何地方使用。如果元素声明有-(revst|revend),则意味着revstrevend不允许chapter 内的任何位置。

希望这会有所帮助。

【讨论】:

    【解决方案2】:

    是的,使用Nokogiri

    在该页面上向下滚动一点,然后将“概要”下的代码复制到一个文件中,例如 xml-parser.rb。然后,如果您在 Mac 上(Mac 上已经安装了 Ruby。),从终端运行 gem install nokogiri,然后使用:ruby xml-parser.rb 运行文件。

    您也可以直接从终端输入irb,然后输入require 'nokogiri',开始实时使用nokogiri api。一定要喜欢交互式 Ruby。 :)

    如果您使用的是 Windows,请试试这个Ruby installer for Windows

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-05-23
      • 2010-09-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多