(正規表現ベースの)ソリューションが正しいxmlテキストを抽出する場合、ネストされていないことgsed
を前提として、ソリューションを拡張して開始/終了位置を含めることができます。<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の一致パターンに基づくコメントやcdataにないことを前提として、プレーンテキストの一部のxml要素に一致する正規表現を構築する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フラグメントを抽出するのに役立ちます。
注意:
正規表現を使用してHTML/XMLを解析できない理由:素人の用語での正式な説明
正規表現を使用してXMLとHTMLを解析するのが難しい理由の例をいくつか挙げてください。