Py学习  »  Python

如何处理在python XML中修改XML的隐式名称空间。埃特雷。元素树

WesR • 4 年前 • 1976 次点击  

编辑:其他人回应说,对于我在这里发布的这个简单问题,xslt是一个更好的解决方案。我暂时删除了我的答案。

我已经读过十几篇StackOverflow文章,试图理解如何导入一个具有名称空间的XML文档,修改它,然后在不更改名称空间的情况下编写它。我发现了一些不清楚或有矛盾信息的东西。终于让它发挥作用了,我想把我学到的东西记录下来,希望它能帮助其他同样困惑的人。我将在这里提出问题,并在回答中给出答案。

问题是:给定 Python docs 如何导航树,而不必在XPath for findall中显式地包含名称空间URI,并在保留名称空间前缀的情况下将其写回。文档中的示例代码没有给出完整的解决方案。

以下是XML数据:

<?xml version="1.0"?>
<actors xmlns:fictional="http://characters.example.com"
        xmlns="http://people.example.com">
    <actor>
        <name>John Cleese</name>
        <fictional:character>Lancelot</fictional:character>
        <fictional:character>Archie Leach</fictional:character>
    </actor>
    <actor>
        <name>Eric Idle</name>
        <fictional:character>Sir Robin</fictional:character>
        <fictional:character>Gunther</fictional:character>
        <fictional:character>Commander Clement</fictional:character>
    </actor>
</actors>

所需的输出只是在演员姓名前加上“先生”,如下所示:

<actors xmlns="http://people.example.com" xmlns:fictional="http://characters.example.com">
    <actor>
        <name>Sir John Cleese</name>
        <fictional:character>Lancelot</fictional:character>
        <fictional:character>Archie Leach</fictional:character>
    </actor>
    <actor>
        <name>Sir Eric Idle</name>
        <fictional:character>Sir Robin</fictional:character>
        <fictional:character>Gunther</fictional:character>
        <fictional:character>Commander Clement</fictional:character>
    </actor>
</actors>
Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/133310
文章 [ 3 ]  |  最新文章 4 年前
Mads Hansen
Reply   •   1 楼
Mads Hansen    5 年前

我将对XML应用XSLT

from lxml import etree

XSL= ‘’’
<xsl:stylesheet version=”1.0" xmlns:xsl=”http://www.w3.org/1999/XSL/Transform" 
   xmlns:people="http://people.example.com">

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

  <xsl:template match=”people:name/text()”>
    <xsl:text>Sir </xsl:text>
    <xsl:value-of select=”.” />
  </xsl:template>

</xsl:stylesheet>
‘’’
# load input
dom = etree.parse(‘/path/to/my.xml’)
# load XSLT
transform = etree.XSLT(etree.fromstring(XSL))
# apply XSLT on loaded dom
str(transform(dom))
zx485
Reply   •   2 楼
zx485    5 年前

您可以简单地使用XSLT-1.0来处理XML:

  1. 创建以下XSLT-1.0文件(此处名为“trans.XSLT”),并注意以下事实: xmlns=... 命名空间定义为 xmlns:std=... 在样式表元素中。这个 身份模板 只需将所有元素从输入复制到输出,另一个模板在每个元素的值之前添加字符串“Sir” <name> 要素

     <?xml version="1.0" encoding="UTF-8"?>
     <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:std="http://people.example.com">
    
         <!-- Identity template -->
         <xsl:template match="node()|@*">
             <xsl:copy>
                 <xsl:apply-templates select="node()|@*" />
             </xsl:copy>
         </xsl:template>
    
         <xsl:template match="std:name">
           <xsl:copy>
             <xsl:value-of select="concat('Sir ',.)"/>
           </xsl:copy>
         </xsl:template>
    
     </xsl:stylesheet>
    
  2. 从Python中调用此模板:

     import lxml.etree as ET
    
     xml_filename = "input.xml"
     xsl_filename = "trans.xslt"
     out_filename = "output.xml"
    
     dom = ET.parse(xml_filename)
     xslt = ET.parse(xsl_filename)
     transform = ET.XSLT(xslt)
     newdom = transform(dom)
     newdom.write(out_filename, encoding='utf-8', xml_declaration=True)
    

    最后一个命令指定输出格式。必须指定XML声明及其编码 关于write命令 (而且不是在可能的情况下) .tostring ).产出如下:

这两个步骤生成以下输出:

<?xml version='1.0' encoding='UTF-8'?>
<actors xmlns:fictional="http://characters.example.com" xmlns="http://people.example.com">
    <actor>
        <name>Sir John Cleese</name>
        <fictional:character>Lancelot</fictional:character>
        <fictional:character>Archie Leach</fictional:character>
    </actor>
    <actor>
        <name>Sir Eric Idle</name>
        <fictional:character>Sir Robin</fictional:character>
        <fictional:character>Gunther</fictional:character>
        <fictional:character>Commander Clement</fictional:character>
    </actor>
</actors>
mzjn
Reply   •   3 楼
mzjn    5 年前

使用lxml解析XML时,原始名称空间前缀将被保留。下面的代码符合您的要求。注意使用 {*} 作为命名空间通配符。

from lxml import etree
 
tree = etree.parse("data1.xml")
 
for name in tree.findall(".//{*}name"):
    name.text = "Sir " + name.text