Мне нужно разобрать вложенные двоичные булевы выражения в дерево XML. Например, возьмем выражениеPyparsing/Python Binary Boolean Expression to XML Nesting Issue (2.7.10)
expression2 = "((Param1 = 1 AND Param2 = 1) \
OR (Param3 = 1 AND Param4 = 1)) \
AND \
(((Param5 = 0 AND Param6 = 1) \
OR(Param7 = 0 AND Param8 = 1)) \
AND \
((Param9 = 0 AND Param10 = 1) \
OR(Param11 = 0 AND Param12 = 1)))"
, который по существу представляет собой сочетание (Expression) (Operator) (Expression)
терминов.
Мне нужен вывод, чтобы быть комбинацией этих выражений с соответствующими тегами в XML. иначе
<MainBody>
<FirstExpression>
Parameter
</FirstExpression>
<Operator>=</Operator>
<SecondExpression>
1
</SecondExpression>
</MainBody>
, где firstexpression может быть параметром или mainbody (здесь вложенности), оператор всегда =, <,>, И, ИЛИ, и secondexpression является либо целым или mainbody
Всегда будут группы из трех человек, иначе наименьший дискретный объект будет состоять из первого выражения оператора и второго выражения.
Код, который я придумал (это мой первый раз, когда я использовал python), меня там немного.
import pyparsing as pp
import xml.etree.ElementTree as ET
operator = pp.Regex(">=|<=|!=|>|<|=").setName("operator").setResultsName("Operator")
number = pp.Regex(r"[+-]?\d+(:?\.\d*)?(:?[eE][+-]?\d+)?").setResultsName("SecondExpression")
identifier = pp.Word(pp.alphas, pp.alphanums + "_" + ".").setName("FirstExpression").setResultsName("FirstExpression")
comparison_term = identifier | number
condition = pp.Group(comparison_term + operator + comparison_term).setResultsName("MainBody")
expr = pp.operatorPrecedence(condition,[
("NOT", 1, pp.opAssoc.RIGHT,),
("AND", 2, pp.opAssoc.LEFT,),
("OR", 2, pp.opAssoc.LEFT,),
])
expression2 = "((Param1 = 1 AND Param2 = 1) \
OR (Param3 = 1 AND Param4 = 1)) \
AND \
(((Param5 = 0 AND Param6 = 1) \
OR(Param7 = 0 AND Param8 = 1)) \
AND \
((Param9 = 0 AND Param10 = 1) \
OR(Param11 = 0 AND Param12 = 1)))"
out = expr.parseString(expression2)
text = out.asXML()
f = open('rules.xml','w+')
f.write(text)
f.close()
root = ET.parse("rules.xml").getroot()
print ET.tostring(root)
Это выводит XML этой формы:
<ITEM>
<ITEM>
<ITEM>
<MainBody>
<MainBody>
<FirstExpression>Param1</FirstExpression>
<Operator>=</Operator>
<SecondExpression>1</SecondExpression>
</MainBody>
<ITEM>AND</ITEM>
<MainBody>
<FirstExpression>Param2</FirstExpression>
<Operator>=</Operator>
<SecondExpression>1</SecondExpression>
</MainBody>
</MainBody>
<ITEM>OR</ITEM>
<MainBody>
<MainBody>
<FirstExpression>Param3</FirstExpression>
<Operator>=</Operator>
<SecondExpression>1</SecondExpression>
</MainBody>
<ITEM>AND</ITEM>
<MainBody>
<FirstExpression>Param4</FirstExpression>
<Operator>=</Operator>
<SecondExpression>1</SecondExpression>
</MainBody>
</MainBody>
</ITEM>
<ITEM>AND</ITEM>
<ITEM>
<ITEM>
<MainBody>
<MainBody>
<FirstExpression>Param5</FirstExpression>
<Operator>=</Operator>
<SecondExpression>0</SecondExpression>
</MainBody>
<ITEM>AND</ITEM>
<MainBody>
<FirstExpression>Param6</FirstExpression>
<Operator>=</Operator>
<SecondExpression>1</SecondExpression>
</MainBody>
</MainBody>
<ITEM>OR</ITEM>
<MainBody>
<MainBody>
<FirstExpression>Param7</FirstExpression>
<Operator>=</Operator>
<SecondExpression>0</SecondExpression>
</MainBody>
<ITEM>AND</ITEM>
<MainBody>
<FirstExpression>Param8</FirstExpression>
<Operator>=</Operator>
<SecondExpression>1</SecondExpression>
</MainBody>
</MainBody>
</ITEM>
<ITEM>AND</ITEM>
<ITEM>
<MainBody>
<MainBody>
<FirstExpression>Param9</FirstExpression>
<Operator>=</Operator>
<SecondExpression>0</SecondExpression>
</MainBody>
<ITEM>AND</ITEM>
<MainBody>
<FirstExpression>Param10</FirstExpression>
<Operator>=</Operator>
<SecondExpression>1</SecondExpression>
</MainBody>
</MainBody>
<ITEM>OR</ITEM>
<MainBody>
<MainBody>
<FirstExpression>Param11</FirstExpression>
<Operator>=</Operator>
<SecondExpression>0</SecondExpression>
</MainBody>
<ITEM>AND</ITEM>
<MainBody>
<FirstExpression>Param12</FirstExpression>
<Operator>=</Operator>
<SecondExpression>1</SecondExpression>
</MainBody>
</MainBody>
</ITEM>
</ITEM>
</ITEM>
</ITEM>
Очевидно, что это не нужно, я хочу, как только объекты с тегами находятся на самом глубоком уровне. Мне нужно, чтобы он был настолько глубоким, насколько это необходимо для гораздо более крупных правил, чем это - по существу двоичное дерево с коллекциями Mainbody, FirstExpression, Operator и Second Expression.
Мне также нужно поместить целочисленные значения внутри тегов, что еще одна вещь, которую я не знаю, как это сделать.
Я думаю, что pyparsing должен быть в состоянии сделать это с группами как-то, но я не могу понять это.
Может ли кто-нибудь предложить предложение о том, как этого достичь?
Благодаря
EDIT 11/5/15:
здание от того, что Павел написал я прибыл в этот код с (хорошо предназначенной быть) рекурсивной грамматики:
import pyparsing as pp
operator = pp.oneOf(">= <= != > < =")("operator")
integer = pp.Regex(r"[+-]?\d+(:?\.\d*)?(:?[eE][+-]?\d+)?")("integer")
parameter = pp.Word(pp.alphas, pp.alphanums + "_" + "." + "-")("parameter")
comparison_term = parameter | integer
firstExpression = pp.Forward()
secondExpression = pp.Forward()
mainbody = pp.Group(firstExpression + operator + secondExpression)("Mainbody")
firstExpression << pp.Group(parameter | pp.Optional(mainbody))("FirstExpression")
secondExpression << pp.Group(integer | pp.Optional(mainbody))("SecondExpression")
AND_ = pp.Keyword("AND")("operator")
OR_ = pp.Keyword("OR")("operator")
NOT_ = pp.Keyword("NOT")("operator")
expr = pp.operatorPrecedence(mainbody,[
(NOT_, 1, pp.opAssoc.RIGHT,),
(AND_, 2, pp.opAssoc.LEFT,),
(OR_, 2, pp.opAssoc.LEFT,),
])
# undocumented hack to assign a results name to (expr) - RED FLAG
expr.expr.resultsName = "Mainbody"
expression1 = "((Param1 = 1) \
OR (Param2 = 1))"
out = expr.parseString(expression1)[0] # extract item 0 from single-item list
text = out.asXML("Mainbody") # add tag for outermost element
print text
Будет ли бесконечная рекурсия. Изменение | на + в линиях firstExpression и secondExpression исправляет это, но я считаю, что это заставляет парсер никогда не искать группу, которую нужно группировать.
Я включил упрощенное правило, чтобы показать точный результат, который я пытаюсь получить.
Этот код генерирует:
<Mainbody>
<Mainbody>
<FirstExpression>
<parameter>Param1</parameter>
</FirstExpression>
<operator>=</operator>
<SecondExpression>
<integer>1</integer>
</SecondExpression>
</Mainbody>
<operator>OR</operator>
<Mainbody>
<FirstExpression>
<parameter>Param2</parameter>
</FirstExpression>
<operator>=</operator>
<SecondExpression>
<integer>1</integer>
</SecondExpression>
</Mainbody>
</Mainbody>
То, что я пытаюсь получить
<Mainbody>
<FirstExpression>
<Mainbody>
<FirstExpression>
<parameter>Param1</parameter>
</FirstExpression>
<operator>=</operator>
<SecondExpression>
<integer>1</integer>
</SecondExpression>
</Mainbody>
</FirstExpression>
<operator>OR</operator>
<SecondExpression>
<Mainbody>
<FirstExpression>
<parameter>Param2</parameter>
</FirstExpression>
<operator>=</operator>
<SecondExpression>
<integer>1</integer>
</SecondExpression>
</Mainbody>
</SecondExpression>
</Mainbody>
Это выглядит вопрос, что я вижу это анализатор не правильно мечения/признания/группировки основной как FirstExpression или SecondExpression. Я пробовал настраивать грамматику и часто получаю бесконечную рекурсию, поэтому я чувствую, что что-то не так в моем определении грамматики.Мне нужно, чтобы это работало для любого числа двоичных группировок (PARAMETER = INTEGER) с помощью AND/OR.
Любые предложения?
Благодаря
Я очень ценю помощь. Это определенно дало мне дальше, но меня все еще не было. Я попытался реализовать рекурсивную грамматику. Я добавил дополнительную информацию к моему первоначальному вопросу с тем, что я пробовал в дополнение к вашему решению. –