有些文件采用Markdown,MediaWiki语法,Creole,源代码以及纯文本进行编码。
这些文件可能包含一个迷路XML元素。当我说流浪时,它们的文件不是XML,如下所示:
<reference path=""/>
如何以最可靠的方式提取此元素?它不是XML文档,但XML元素本身是格式良好的
我一直在使用sed来提取元素的内容:
gsed -n '/<myelement>/,/<\/myelement>/p' < test.txt > output.txt
这只是从文件中删除所有非XML,并留下我的自定义元素。这不允许我单独处理每一个。然后,我可以在生成的文件上运行xmlstarlet,但这并不能告诉我元素在源文档中的位置。
最好的方法是什么?如何修改sed以一次匹配一个(我可以替换自己)。
将整个文件读入根元素然后将文件处理成是一个带有XML工具的半结构化XML文件,然后在XML解析中处理替换,会不会更好?
答案 0 :(得分: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元素,假设每个根元素不是嵌套的,并且它不在注释或基于的cdata中 Matching patterns in Python:
#!/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片段。
请注意:
Why it's not possible to use regex to parse HTML/XML: a formal explanation in layman's terms
Can you provide some examples of why it is hard to parse XML and HTML with a regex?
答案 1 :(得分:1)
无需手动提取元素。您可以通过在处理期间将数据包装在根节点中来利用全面的XML生态系统。
例如,Java源文件或Javascript文件在技术上是XML,如果它位于根元素内。
然后,您可以使用为此目的设计的工具,例如XPath或SAX。我用过xmlstarlet。