pyparsing - 解析xml注释

时间:2011-10-19 16:54:37

标签: python grammar xml-comments pyparsing

我需要解析包含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 个答案:

答案 0 :(得分:2)

我认为Literal('\n')是你的问题。您不希望使用空格字符构建Literal(因为默认情况下,Literals会在尝试匹配之前跳过空格)。请尝试使用LineEnd()

编辑1: 仅仅因为你使用LineEnd获得无限循环并不意味着Literal('\ n')更好。尝试在.setDebug()定义的末尾添加_eol,您会发现它永远不会与任何内容匹配。

不要试图将评论的主体定义为“一条或多条不是结束线的行,而是将所有内容都放到行尾”,而不是尝试:

xmlComment = _cPoundOpenXmlComment + pp.SkipTo(_cPoundCloseXmlComment) + _cPoundCloseXmlComment 

(你使用LineEnd()获得无限循环的原因是你基本上在做OneOrMore(SkipTo(LineEnd())),但从不使用LineEnd(),所以OneOrMore只是保持匹配和匹配匹配,解析并返回一个空字符串,因为解析位置是 at 行尾。)

答案 1 :(得分: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']]]

答案 2 :(得分: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