社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

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

WesR • 4 年前 • 1964 次点击  

编辑:其他人回应说,对于我在这里发布的这个简单问题,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