1

有一些文件是用 Markdown、MediaWiki 语法、克里奥尔语、源代码和纯文本编码的。

这些文件可能包含一个杂散的 XML 元素。当我说流浪时,它们位于不是 XML 的文件中,如下所示:

  • QUnit<reference path=""/>在单元测试中
  • Javadoc 包含 XML 元素

如何以最可靠的方式提取此元素?它不是 XML 文档,但 XML 元素本身格式正确

我一直在玩 sed 来提取元素的内容:

gsed  -n '/<myelement>/,/<\/myelement>/p' < test.txt > output.txt

这只是从文件中删除所有非 XML 并留下我的自定义元素。这不允许我单独处理每一个。然后我可以在结果文件上运行 xmlstarlet ,但这并不能告诉我元素出现在源文档中的什么位置。

做这个的最好方式是什么?如何修改 sed 以一次匹配一个(我可以自己替换)。

将整个文件读入根元素,然后像使用 XML 工具处理半结构化 XML 文件一样处理文件,然后在 XML 解析中处理替换会更好吗?

4

2 回答 2

2

如果gsed(基于正则表达式的)解决方案提取正确的 xml 文本,那么您可以扩展解决方案以包括开始/结束位置,假设<myelement>未嵌套:

$ perl -0777 -ne 'print "start: $-[0], end: $+[0], xml: {{{$&}}}\n" while /<myelement>.*?<\/myelement>/gs' < input > output

输入

some arbitrary text
A well-formed xml:

<myelement>
... xml here
</myelement>

some arbitrary text follows more elements: <myelement>... xml</myelement> the end

输出

start: 40, end: 77, xml: {{{<myelement>
... xml here
</myelement>}}}
start: 122, end: 152, xml: {{{<myelement>... xml</myelement>}}}

这是一个 Python 解决方案,它构建正则表达式以匹配纯文本中的一些 xml 元素,假设每个根元素没有嵌套,并且它不在基于 Python 中的匹配模式的注释或 cdata 中:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import re
import sys
from xml.etree import ElementTree as etree

# build regex that matches xml element
# xml_element = start_tag <anything> end_tag
#             | self_close_tag
xml_element = '(?xs) {start_tag} (?(self_close) |.*? {end_tag})'

# start_tag = '<' name  *attr '>'
# self_close_tag = '<' name *attr '/>'
ws = r'[ \t\r\n]*'  # whitespace
start_tag = '< (?P<name>{name}) {ws} (?:{attr} {ws})* (?P<self_close> / )? >'
end_tag = '</ (?P=name) >'
name = '[a-zA-Z]+'  # note: expand if necessary but the stricter the better
attr = '{name} {ws} = {ws} "[^"]*"'  # match attribute
                                     #  - fragile against missing '"'
                                     #  - no “'” support
assert '{{' not in xml_element
while '{' in xml_element: # unwrap definitions
    xml_element = xml_element.format(**vars())

# extract xml from stdin
all_text = sys.stdin.read()
for m in re.finditer(xml_element, all_text):
    print("start: {span[0]}, end: {span[1]}, xml: {begin}{xml}{end}".format(
            span=m.span(), xml=m.group(), begin="{{{", end="}}}"))
    # assert well-formness of the matched xml text by parsing it
    etree.XML(m.group())

在匹配更多种类的 xml 元素和避免误报之间需要权衡取舍。

一个更健壮的解决方案应该考虑输入的格式,即 QUnit,Javadoc 词法分析器/解析器可以帮助提取 xml 片段,这些片段可以稍后输入 xml 解析器。

谨防:

为什么不能使用正则表达式来解析 HTML/XML:通俗易懂的正式解释

您能否提供一些示例说明为什么使用正则表达式难以解析 XML 和 HTML?

于 2012-12-16T08:21:28.267 回答
1

无需手动提取元素。您可以通过在处理期间将数据包装在根节点中来利用全面的 XML 生态系统。

例如,如果 Java 源文件或 Javascript 文件位于根元素内,那么它在技术上就是 XML。

然后,您可以使用为此目的而设计的工具,例如 XPath 或 SAX。我使用了xmlstarlet。

于 2013-01-01T20:21:29.230 回答