pyparsing - 解析XML注释
我需要解析一个包含 XML 注释的文件。具体来说,这是一个使用 MS ///
规范的 C# 文件。
从中我需要提取出 foobar
,或者 /// foobar
也可以。(注意 - 如果把 XML 全部放在一行,这样还是不行…)
testStr = """
///<summary>
/// foobar
///</summary>
"""
这是我现在的代码:
import pyparsing as pp
_eol = pp.Literal("\n").suppress()
_cPoundOpenXmlComment = Suppress('///<summary>') + pp.SkipTo(_eol)
_cPoundCloseXmlComment = Suppress('///</summary>') + pp.SkipTo(_eol)
_xmlCommentTxt = ~_cPoundCloseXmlComment + pp.SkipTo(_eol)
xmlComment = _cPoundOpenXmlComment + pp.OneOrMore(_xmlCommentTxt) + _cPoundCloseXmlComment
match = xmlComment.scanString(testStr)
我想要输出:
for item,start,stop in match:
for entry in item:
print(entry)
但是我在处理多行时,语法一直没有成功。
(注意 - 我在 Python 3.2 中测试了上面的示例;它能运行,但(根据我的问题)没有打印出任何值)
谢谢!
3 个回答
1
你可以使用一个xml解析器来处理xml文件。这样提取出相关的注释行应该很简单:
import re
from xml.etree import cElementTree as etree
# extract all /// lines
lines = re.findall(r'^\s*///(.*)', text, re.MULTILINE)
# parse xml
root = etree.fromstring('<root>%s</root>' % ''.join(lines))
print root.findtext('summary')
# -> foobar
3
我觉得你用的 Literal('\n')
是个问题。你不应该用带空格的字符来构建一个 Literal(因为默认情况下,Literal 会跳过空格再尝试匹配)。试试用 LineEnd()
来代替。
编辑 1:仅仅因为你在使用 LineEnd 时出现了无限循环,并不意味着 Literal('\n') 就好一些。试着在你的 _eol
定义后面加上 .setDebug()
,你会发现它根本匹配不到任何东西。
与其试图把你的评论内容定义为“一个或多个不是结束行的行,但要一直到行尾”,不如直接这样做:
xmlComment = _cPoundOpenXmlComment + pp.SkipTo(_cPoundCloseXmlComment) + _cPoundCloseXmlComment
你在使用 LineEnd() 时出现无限循环的原因是,你实际上是在做 OneOrMore(SkipTo(LineEnd())),但从来没有消耗掉 LineEnd(),所以 OneOrMore 就一直在匹配、匹配、再匹配,解析并返回一个空字符串,因为解析的位置正好在行尾。
2
可以试试用 nestedExpr
这个方法:
import pyparsing as pp
text = '''\
///<summary>
/// foobar
///</summary>
blah blah
///<summary> /// bar ///</summary>
///<summary> ///<summary> /// baz ///</summary> ///</summary>
'''
comment=pp.nestedExpr("///<summary>","///</summary>")
for match in comment.searchString(text):
print(match)
# [['///', 'foobar']]
# [['///', 'bar']]
# [[['///', 'baz']]]