2017-05-08 58 views
2

我正在使用lxml来修改xml。在下面的代码中,我想删除所有“标题”元素的子元素,并将子元素分配给其父元素。使用lxml从父项中删除xml子代

原本

<heading><whateverchildvalue>TEXTIWANT</whateverchildvalue></heading> 

<heading>TEXTIWANT</heading>) 

我试图用循环对于这一点,但不知何故,当我打电话node.remove(attr_children [0]),它跳出循环和继续下一个“ET.tostring(parsed)”(?)的调用,并且不修改第二个“标题”。要理解这一点,请删除“node.remove(attr_children [0])”,然后重新运行以下代码并比较以前版本的打印内容。我在这里做错了什么,以便它可以做一个适当的循环,并将该子文本分配给xml字符串中所有“标题”元素的“标题”父项?

xml_string=""" 
<note> 
<to>Tove</to> 
<mybigheader> 
    <heading><deleteme>Jani</deleteme></heading> 
    <heading><wantkey>Reminder</wantkey></heading> 
</mybigheader> 
<body>Don't forget me this weekend!</body> 
</note> 
""" 


def modif_xml(xml_string): 

    parsed = ET.fromstring(xml_string) 
    for node in parsed.iter(): 
     print "node is ", node 
     if "heading" in node.tag: 
      attr_children = node.getchildren() 
      for i in attr_children: 
       child_tag = i.tag 
       child_value = i.text 
      node.remove(attr_children[0]) 
      node.text = child_value 

    my_xml = ET.tostring(parsed) 
    root = ET.XML(my_xml) 
    print ET.tostring(root, pretty_print=True) 


modif_xml(xml_string) 

回答

1

考虑XSLT,用于将XML文件中的专用说明性语言。 Python的lxml模块可以运行XSLT 1.0脚本。虽然这可能看起来有些过分,但您可以避免使用任何for循环和if逻辑。另外,XSLT脚本 XML文件,可以像任何XML一样处理:从字符串或文件中解析。

特别下方运行Identity Transform(复制文件原样),然后通过调用apply-templates没有xsl:copy(避免当前节点)重新写标题的孩子的模板:

import lxml.etree as et 

xml_string=""" 
<note> 
<to>Tove</to> 
<mybigheader> 
    <heading><deleteme>Jani</deleteme></heading> 
    <heading><wantkey>Reminder</wantkey></heading> 
</mybigheader> 
<body>Don't forget me this weekend!</body> 
</note> 
"""  
dom = et.fromstring(xml_string) 

xsl_string=''' 
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> 
<xsl:output version="1.0" encoding="UTF-8" indent="yes" method="xml"/> 
<xsl:strip-space elements="*"/> 

    <!-- Identity Transform --> 
    <xsl:template match="@*|node()"> 
    <xsl:copy> 
     <xsl:apply-templates select="@*|node()"/> 
    </xsl:copy> 
    </xsl:template> 

    <xsl:template match="heading/*"> 
    <xsl:apply-templates /> 
    </xsl:template> 

</xsl:transform> 
'''  
xslt = et.fromstring(xsl_string) 

transform = et.XSLT(xslt) 
newdom = transform(dom) 

print(newdom) 

# <?xml version="1.0"?> 
# <note> 
# <to>Tove</to> 
# <mybigheader> 
#  <heading>Jani</heading> 
#  <heading>Reminder</heading> 
# </mybigheader> 
# <body>Don't forget me this weekend!</body> 
# </note>