Синтаксический анализатор для файла XML DTD
Я довольно новичок в реализации синтаксического анализатора, и я пытаюсь разобрать файл XML DTD, чтобы создать для него контекстно-свободную грамматику. Я пробовал, когда pyparsing и yacc, но все-таки я мог бы получить какой-то результат. Поэтому я был бы признателен, если бы кто-нибудь дал мне несколько советов или пример кода для написания такого синтаксического анализатора. ниже приведен пример файла DTD:
<!DOCTYPE PcSpecs [
<!ELEMENT PCS (PC*)>
<!ELEMENT PC (MODEL, PRICE, PROCESSOR, RAM, DISK+)>
<!ELEMENT MODEL (#PCDATA)>
<!ELEMENT PRICE (#PCDATA)>
<!ELEMENT PROCESSOR (MANF, MODEL, SPEED)>
<!ELEMENT MANF (#PCDATA)>
<!ELEMENT MODEL (#PCDATA)>
<!ELEMENT SPEED (#PCDATA)>
<!ELEMENT RAM (#PCDATA)>
<!ELEMENT DISK (HARDDISK | CD | DVD)>
<!ELEMENT HARDDISK (MANF, MODEL, SIZE)>
<!ELEMENT SIZE (#PCDATA)>
<!ELEMENT CD (SPEED)>
<!ELEMENT DVD (SPEED)>
]>
Заранее благодарю.
1 ответ:
Вот начало для вас, он будет анализировать данные в структуру данных ParseResults, которую вы можете затем обойти и создать парсер для определенного doctype:
from pyparsing import * LT,GT,EXCLAM,LBRACK,RBRACK,LPAR,RPAR = map(Suppress,"<>![]()") DOCTYPE = Keyword("DOCTYPE").suppress() ELEMENT = Keyword("ELEMENT").suppress() ident = Word(alphas, alphanums+"_") elementRef = Group(ident("name") + Optional(oneOf("* +")("rep"))) elementExpr = infixNotation(elementRef, [ (',', 2, opAssoc.LEFT), ('|', 2, opAssoc.LEFT), ]) PCDATA = Literal(r"\#PCDATA") elementDefn = Group(LT+EXCLAM + ELEMENT + ident("name") + LPAR + (elementExpr | PCDATA("PCDATA"))("contents") + RPAR + GT) doctypeDefn = LT+EXCLAM + DOCTYPE + ident("name") + LBRACK + ZeroOrMore(elementDefn)("elements") + RBRACK + GT
Я начал просто использовать список разделителей для списка элементов в каждом определении элемента, но затем я заметил, что', ' и '|' на самом деле являются операторами, а не просто разделителями,и даже могут быть смешаны,как в "A,B, C|D, E". Поэтому я использовал помощник pyparsing по инфикснотации, чтобы разрешить такие определения.
С вашим входной образец, я могу анализировать и отображать результаты с помощью:
doctype = doctypeDefn.parseString(sample) print doctype.dump() for elem in doctype.elements: print elem.dump()
Дача:
['PcSpecs', ['PCS', ['PC', '*']], ['PC', [['MODEL'], ... - elements: [['PCS', ['PC', '*']], ['PC', [['MODEL'], ... - name: PcSpecs ['PCS', ['PC', '*']] - contents: ['PC', '*'] - name: PC - rep: * - name: PCS ['PC', [['MODEL'], ',', ['PRICE'], ',', ['PROCESSOR'], ',', ['RAM'], ',', ['DISK', '+']]] - contents: [['MODEL'], ',', ['PRICE'], ',', ['PROCESSOR'], ',', ['RAM'], ',', ['DISK', '+']] - name: PC ['MODEL', '\\#PCDATA'] - PCDATA: \#PCDATA - contents: \#PCDATA - name: MODEL ['PRICE', '\\#PCDATA'] - PCDATA: \#PCDATA - contents: \#PCDATA - name: PRICE ['PROCESSOR', [['MANF'], ',', ['MODEL'], ',', ['SPEED']]] - contents: [['MANF'], ',', ['MODEL'], ',', ['SPEED']] - name: PROCESSOR ['MANF', '\\#PCDATA'] - PCDATA: \#PCDATA - contents: \#PCDATA - name: MANF ['MODEL', '\\#PCDATA'] - PCDATA: \#PCDATA - contents: \#PCDATA - name: MODEL ['SPEED', '\\#PCDATA'] - PCDATA: \#PCDATA - contents: \#PCDATA - name: SPEED ['RAM', '\\#PCDATA'] - PCDATA: \#PCDATA - contents: \#PCDATA - name: RAM ['DISK', [['HARDDISK'], '|', ['CD'], '|', ['DVD']]] - contents: [['HARDDISK'], '|', ['CD'], '|', ['DVD']] - name: DISK ['HARDDISK', [['MANF'], ',', ['MODEL'], ',', ['SIZE']]] - contents: [['MANF'], ',', ['MODEL'], ',', ['SIZE']] - name: HARDDISK ['SIZE', '\\#PCDATA'] - PCDATA: \#PCDATA - contents: \#PCDATA - name: SIZE ['CD', ['SPEED']] - contents: ['SPEED'] - name: SPEED - name: CD ['DVD', ['SPEED']] - contents: ['SPEED'] - name: SPEED - name: DVD