我有成千上万的SGML文档,其中一些格式正确,有些文档格式不太好。我需要在文档中获取某些ELEMENTS,但每次我加载并尝试将它们读入XDocument,XMLDocument或甚至只是一个StreamReader时,我会得到不同的各种XMLException错误。
“'['是意想不到的令牌。”为什么?因为我有一个像DOCTYPE一样的文件
<!DOCTYPE RChapter PUBLIC "-//LSC//DTD R Chapter for Authoring//EN" [] >
我已经了解到“[]”需要内部有效的东西。同样,我不控制文档的创建,但我必须“破解”它们并获取我想要的数据。另一个例子是有一个“未闭合的”元素,例如:
<Caption>Plants, and facilities<hardhyphen><hyphen>Inspection.</Caption>
此XMLException是“第27行的'连字符'开始标记与'标题'的结束标记不匹配。第27行,第58位。”很明显,对吧?
但接下来的问题是如何在不遇到XMLExceptions的情况下在这些文档中实际获得某些ELEMENTS。 SAX解析器是正确的方法吗?我基本上想要打开文档,直接找到我想要的元素(不用担心附近可能会或者可能没有形成的内容),拉出数据,继续前进。我应该忘记使用XMLDocument,XDocument进行解析,只需要进行简单的字符串替换,例如
str.Replace("<hardhypen><hyphen>", "-")
然后尝试将其加载到其中一个XML解析器中。有关策略的任何提示吗?
答案 0 :(得分:3)
问题在于您尝试使用XML工具解析SGML。他们不一样。如果要使用XML工具/语言来访问数据,则可能需要在尝试解析之前将SGML转换为XML。
理想情况下,你要么使用支持SGML的语言/工具(如OmniMark),要么使用能够处理“XML like”数据的东西(比如第一个答案中的nokogiri?)。
这可能非常简单,但在某些方面可能会变得棘手。特别是如果你在谈论多个doctypes(DTD)。 (此外,没有“格式良好”的SGML。是的,元素/ etc必须正确嵌套,但SGML 有DTD。)
以下是您需要处理的SGML和XML之间的一些差异。 (你可能不想走这条路,但无论如何它可能对信息有用。):
DOCTYPE声明
示例中的DOCTYPE声明是完全有效的SGML文档类型。 []
(内部子集)不必包含任何内容。如果你确实在内部子集中有声明(通常是实体声明),那么你很可能必须在XML中保留doctype声明。
XML解析器遇到的问题是您在声明中没有系统标识符。在XML doctype声明中,如果存在公共标识符,则需要系统标识符。在SGML doctype声明中,它不是必需的。
底线:除非您需要将XML解析为DTD / Schema或在内部子集中包含声明,否则请删除doctype声明。如果XML必须有效,则至少需要添加系统标识符。不要忘记添加<?xml ...?>
处理说明。
没有结束标记的元素
<hardhyphen>
和<hyphen>
元素是有效的SGML。 SGML DTD允许您指定标记最小化。这意味着您可以指定是否需要结束标记。 (您也可以将开始标记设置为可选,但这是疯狂的谈话。)在XML中,您必须关闭这些元素(例如<hardhyphen/>
或<hardhyphen></hardhyphen>
)
最好的办法是查看您的SGML DTD并查看哪些元素具有可选的结束标记。标签最小化在元素声明中的元素名称后面指定。 ' - '表示标签是必需的。 'o'(字母'oh')表示标签是可选的。例如,如果您看到<!ELEMENT hyphen - o (#PCDATA)>
,则表示需要开始标记(-
),结束标记是可选的(o
)。如果您看到<!ELEMENT hyphen - - (#PCDATA)>
,则需要开始和结束标记。
底线:正确关闭所有没有结束标记的元素
处理说明
SGML中的处理指令(PI)在像XML一样关闭时没有第二个?
。您需要添加第二个?
。
示例SGML PI:<?asdf jkl>
示例XML PI:<?asdf jkl?>
<强>夹杂物/排除强>
您可能不必担心这一点,但在SGML DTD中,您可以在元素声明中指定允许在该元素内部的任何位置使用另一个元素(或不允许)。如果您的目标XML需要解析为DTD,这可能会很痛苦; XML DTD不允许包含/排除。
这就是包含的内容:
<!ELEMENT chapter - - (section)+ +(revst|revend)>
这表示revst
内的任何地方都允许revend
或chapter
。如果元素声明有-(revst|revend)
,则表示revst
内的revend
或chapter
希望这有帮助。
答案 1 :(得分:1)
是的,请使用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。