python中的解析字典
我有一个XML,它在解析时提供了具有父子关系的字典python中的解析字典,python,xml,python-3.x,Python,Xml,Python 3.x,我有一个XML,它在解析时提供了具有父子关系的字典 import xml.etree.ElementTree as ET def remove_value(listOfDicts, key): for subVal in listOfDicts: if key in subVal: del subVal[key] def get_children(parent): for child in parent: if "AC
import xml.etree.ElementTree as ET
def remove_value(listOfDicts, key):
for subVal in listOfDicts:
if key in subVal:
del subVal[key]
def get_children(parent):
for child in parent:
if "ACTION" in child.tag:
continue
if 'BOOLOP' in child.attrib:
yield child.attrib['BOOLOP']
else:
yield child.attrib
def get_parent_children_mapping(tree):
return { parent: list(get_children(parent)) for parent in tree.iter() if "ACTION" not in parent.tag }
s = """
<RULE COMMENT="" DEFAULTPRIORITY="50" DESCRIPTION="DefaultShipping" DISABLEFLG="N" DefinedOutsideTree="true" FIRINGPHASE="" NAME="DefaultShipping" PATH="PB.SMB.DefaultShipping" RULECLASSIFICATION="PICK" TRIGGER="1">
<BOOLOP BOOLOP="and" SEQ="0" TYPE="0">
<BOOLOP BOOLOP="or" SEQ="1" TYPE="0">
<FRAGMENT FUNC1="value" FUNC2="propval" NULLACTION="Fragment is false" OP="=" PROP1="DEFAULT_SKU1" PROP2="_sku" SEQ="1" TYPE="1"/>
<FRAGMENT FUNC1="value" FUNC2="propval" NULLACTION="Fragment is false" OP="=" PROP1="DEFAULT_SKU2" PROP2="_sku" SEQ="2" TYPE="1"/>
<FRAGMENT FUNC1="value" FUNC2="propval" NULLACTION="Fragment is false" OP="=" PROP1="DEFAULT_SKU3" PROP2="_sku" SEQ="3" TYPE="1"/>
</BOOLOP>
<FRAGMENT FUNC1="propval" FUNC2="literal" NULLACTION="Fragment is false" OP="=" PROP1="_amEntitled" PROP2="1" SEQ="2" TYPE="1"/>
<BOOLOP BOOLOP="and" SEQ="3" TYPE="0">
<FRAGMENT FUNC1="value" FUNC2="literal" NULLACTION="Fragment is true" OP="!=" PROP1="IsShipingSelected" PROP2="yes" SEQ="1" TYPE="1"/>
<FRAGMENT FUNC1="value" FUNC2="literal" NULLACTION="Fragment is true" OP="!=" PROP1="IsShipingSelected" PROP2="no" SEQ="2" TYPE="1"/>
</BOOLOP>
</BOOLOP>
</RULE>
"""
entries = ['NULLACTION','SEQ','TYPE']
tree = ET.fromstring(s)
for parent, children in get_parent_children_mapping(tree).items():
if children:
for vals in entries:
remove_value(children, vals)
if 'NAME' in parent.attrib:
print("{0} : {1}".format(parent.attrib['NAME'], children))
elif 'BOOLOP' in parent.attrib:
print("{0} : {1}".format(parent.attrib['BOOLOP'], children))
else:
print("{0} : {1}".format(parent.tag, children))
输出描述了父子关系。现在我想进一步操作输出,如下所示:
(FUNC1(PROP1)操作FUNC2(PROP2)和FUNC1(PROP1)操作FUNC2(PROP2))或(FUNC1(PROP1)操作FUNC2(PROP2))
解析器中是否有内置的东西,或者我是否需要编写自己的解析器。感谢您的帮助
注意
在我的输出示例中,FUNC1、FUNC2、PROP1等表示它们的值
感谢@Martijn Pieters对语法树的指导 不,没有内置解析器,也不需要解析器。您需要构建一个,这并不难:
from dataclasses import dataclass, field, fields
from typing import List
@dataclass
class Node:
seq: int
type: int
@classmethod
def tree_from_xml(cls, node):
name = node.tag
for cls in cls.__subclasses__():
if cls.__name__.upper() == name:
return cls.node_from_xml(node)
@classmethod
def node_from_xml(cls, node, **kwargs):
fieldargs = {f.name: node.attrib.get(f.name.upper()) for f in fields(cls)}
fieldargs['seq'] = int(fieldargs['seq'])
fieldargs['type'] = int(fieldargs['type'])
fieldargs.update(kwargs)
return cls(**fieldargs)
@dataclass
class BoolOp(Node):
boolop: str
operands: List[Node] = field(default_factory=list)
def __str__(self):
joined = f' {self.boolop} '.join(map(str, self.operands))
return f'({joined})'
@classmethod
def node_from_xml(cls, node):
operands = (Node.tree_from_xml(child) for child in node)
return super().node_from_xml(node, operands=[op for op in operands if op])
@dataclass
class Fragment(Node):
func1: str
func2: str
nullaction: str
op: str
prop1: str
prop2: str
def __str__(self):
return f'{self.func1}({self.prop1}) {self.op} {self.func2}({self.prop2})'
然后从顶级BOOLOP
XML节点构建这些对象,并打印结果:
rule = Node.tree_from_xml(tree.find('.//BOOLOP'))
print(rule)
请注意,规则
是一个节点
子类,因此您仍然可以直接检查树,或者对该对象调用str()
,以获得字符串转换
演示:
这正是我想要的。我肯定会阅读更多关于语法树的内容。我只有一个问题。这是我的网站的链接。我这样做是因为我需要找到迭代规则标签并获得所有属性集(即规则定义),然后根据项目中附加的属性找到触发的属性。但是感谢您的帮助。从上周开始,我一直在努力实现这一目标。起初,我甚至尝试将xml转换为JSON,但这是一项痛苦的工作。所以我又回到了xml@Duck_dragon正确的;通过将规则结构保持为树,您可以根据需要向这些节点添加功能,或者添加更多节点以覆盖更多XML标记,这一切都取决于您的最终目标。例如,如果您需要将规则与一组特定的值进行匹配,那么添加对每个规则求值的功能是有意义的。如果我写入
findall而不是find,则会出现错误AttributeError:'list'对象没有属性“tag”
。基本上,我需要根据某些标准获得所有规则。我在我的数据库中只有经过编辑的代码question@Duck_dragon基本思想是表达式是层次结构,如果需要对其进行推理,则使用包含节点的节点树结构可以简化工作,特别是当这些节点是具有功能的类时。
rule = Node.tree_from_xml(tree.find('.//BOOLOP'))
print(rule)
>>> rule = Node.tree_from_xml(tree.find('.//BOOLOP'))
>>> print(rule)
((value(DEFAULT_SKU1) = propval(_sku) or value(DEFAULT_SKU2) = propval(_sku) or value(DEFAULT_SKU3) = propval(_sku)) and propval(_amEntitled) = literal(1) and (value(IsShipingSelected) != literal(yes) and value(IsShipingSelected) != literal(no)))