pyparsing - разобрать xml комментарий - PullRequest
4 голосов
/ 19 октября 2011

Мне нужно проанализировать файл, содержащий комментарии xml.В частности, это ac # файл, использующий соглашение MS ///.

Из этого мне нужно будет извлечь 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 ]

2 голосов
/ 19 октября 2011

Как насчет использования 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 голосов
/ 19 октября 2011

Я думаю Literal('\n') это ваша проблема. Вы не хотите создавать литерал с пробельными символами (поскольку литералы по умолчанию пропускают пробельные символы перед попыткой сопоставления). Попробуйте использовать LineEnd() вместо.

РЕДАКТИРОВАТЬ 1: Тот факт, что вы получаете бесконечный цикл с LineEnd, не означает, что Literal ('\ n') лучше. Попробуйте добавить .setDebug() в конце определения _eol, и вы увидите, что оно никогда ничего не соответствует.

Вместо того, чтобы пытаться определить тело вашего комментария как «одну или несколько строк, которые не являются закрывающей строкой, но получают все до конца строки», что делать, если вы просто сделаете:

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

(Причина, по которой вы получили бесконечный цикл с LineEnd (), заключалась в том, что вы по существу выполняли OneOrMore (SkipTo (LineEnd ())), но никогда не использовали LineEnd (), поэтому OneOrMore просто продолжал сопоставлять и сопоставлять и сопоставлять , синтаксический анализ и возврат пустой строки, поскольку позиция синтаксического анализа была в конце строки.)

1 голос
/ 20 октября 2011

Вы можете использовать синтаксический анализатор 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
...