【问题标题】:Change xml value in varous places that have the same tag在具有相同标签的各个地方更改 xml 值
【发布时间】:2017-05-03 11:04:41
【问题描述】:

我有一个 python 脚本,它使用 lxml 来更改特定标签的值。我有以下 xml

                    <gmd:CI_Citation>
                    <gmd:date>
                        <gmd:CI_Date>
                            <gmd:date>
                                <gco:Date>**1900-01-01**</gco:Date>
                            </gmd:date>
                            <gmd:dateType>
                                <gmd:CI_DateTypeCode codeList="http://standards.iso.org/ittf/PubliclyAvailableStandards/ISO_19139_Schemas/resources/Codelist/gmxCodelists.xml#CI_DateTypeCode" codeListValue="publication">Publication</gmd:CI_DateTypeCode>
                            </gmd:dateType>
                        </gmd:CI_Date>
                    </gmd:date>
                    <gmd:date>
                        <gmd:CI_Date>
                            <gmd:date>
                                <gco:Date>**1900-01-01**</gco:Date>
                            </gmd:date>
                            <gmd:dateType>
                                <gmd:CI_DateTypeCode codeList="http://standards.iso.org/ittf/PubliclyAvailableStandards/ISO_19139_Schemas/resources/Codelist/gmxCodelists.xml#CI_DateTypeCode" codeListValue="creation">Creation</gmd:CI_DateTypeCode>
                            </gmd:dateType>
                        </gmd:CI_Date>
                    </gmd:date>
                    <gmd:date>
                        <gmd:CI_Date>
                            <gmd:date>
                                <gco:Date>**1900-01-01**</gco:Date>
                            </gmd:date>
                            <gmd:dateType>
                                <gmd:CI_DateTypeCode codeList="http://standards.iso.org/ittf/PubliclyAvailableStandards/ISO_19139_Schemas/resources/Codelist/gmxCodelists.xml#CI_DateTypeCode" codeListValue="revision">Revision</gmd:CI_DateTypeCode>
                            </gmd:dateType>
                        </gmd:CI_Date>
                    </gmd:date>
                </gmd:CI_Citation>

对于每个不同的日期类型(发布、创建和修订)我想将日期更改为特定日期,但是所有 3 个的标签都是相同的 -

//:gmd_citation/:gmd_CI:Citation/:gmd_date/:gmd_CI_Date/:gmd_date/:gco_Date

我正在使用以下函数来更改值

def updateXMLTag (tag, value):
  xmlValue = root.xpath(tag)
  xmlValue[0].text = str(value)

使用 xpath 获取特定标签的最佳方法是什么,以便可以更改值?

【问题讨论】:

  • XML 输入格式不正确,因为未声明 gmdgco 前缀。
  • xml就是这样。 (虽然我只发布了 xml 文档的一部分)。
  • 我已经多次评论 XML 问题,任何带有命名空间(以冒号分隔的前缀)的 XML,始终包含根标记或定义命名空间 URI 的任何位置(搜索 xmlns=)。请更新示例帖子。
  • @MapMan:您不能将 XML 文档的一部分简单地声称“xml 就是这样”。您发布的不是 XML。 lxml 会窒息它。命名空间和它们的前缀可能看起来像一个小细节,但它们的存在是有原因的,不管你喜欢与否。
  • 我同意你的观点,但不确定发布 400 行 xml 文档是否是个好主意,因此我只发布了相关位。

标签: python xml xpath lxml


【解决方案1】:

这是我使用 xpath 获取特定元素并对其进行编辑的方式:

# Find the best implementation available on the platform

try:
    from cStringIO import StringIO
except:
    from StringIO import StringIO

from lxml import etree

# proper namespaces added to get valid xml
xmlstr = StringIO("""<gmd:CI_Citation xmlns:gmd="http://gmd.example.com" xmlns:gco="http://gco.example.com">
        <gmd:date>
        <gmd:CI_Date>
            <gmd:date>
                <gco:Date>1900-01-01</gco:Date>
            </gmd:date>
            <gmd:dateType>
                <gmd:CI_DateTypeCode codeList="http://standards.iso.org/ittf/PubliclyAvailableStandards/ISO_19139_Schemas/resources/Codelist/gmxCodelists.xml#CI_DateTypeCode" codeListValue="publication">Publication</gmd:CI_DateTypeCode>
            </gmd:dateType>
        </gmd:CI_Date>
    </gmd:date>
    <gmd:date>
        <gmd:CI_Date>
            <gmd:date>
                <gco:Date>1900-01-01</gco:Date>
            </gmd:date>
            <gmd:dateType>
                <gmd:CI_DateTypeCode codeList="http://standards.iso.org/ittf/PubliclyAvailableStandards/ISO_19139_Schemas/resources/Codelist/gmxCodelists.xml#CI_DateTypeCode" codeListValue="creation">Creation</gmd:CI_DateTypeCode>
            </gmd:dateType>
        </gmd:CI_Date>
    </gmd:date>
    <gmd:date>
        <gmd:CI_Date>
            <gmd:date>
                <gco:Date>1900-01-01</gco:Date>
            </gmd:date>
        <gmd:dateType>
            <gmd:CI_DateTypeCode codeList="http://standards.iso.org/ittf/PubliclyAvailableStandards/ISO_19139_Schemas/resources/Codelist/gmxCodelists.xml#CI_DateTypeCode" codeListValue="revision">Revision</gmd:CI_DateTypeCode>
            </gmd:dateType>
        </gmd:CI_Date>
    </gmd:date>
</gmd:CI_Citation>""")

tree = etree.parse(xmlstr)

这里我们使用 xpath 来获取所有 (3) 个目标元素。

targets = tree.xpath('/gmd:CI_Citation/gmd:date/gmd:CI_Date/gmd:dateType/gmd:CI_DateTypeCode', \
           namespaces={'gmd': "http://gmd.example.com", 'gco': "http://gco.example.com"})

这三个元素通过唯一的属性值来区分, 可以通过一个简单的函数hasattr进行检查

def hasattr(elem, att, val):
    try:
        return elem.attrib[att] == val
    except:
        return False

targets[0] codeListValue/文本节点:“publication”/“Publication”

targets[1] codeListValue/文本节点:“creation”/“Creation”

targets[2] codeListValue/文本节点:“revision”/“Revision”

哪一个需要改变?

hasattr(targets[0], 'codeListValue', 'publication')  # True
hasattr(targets[1], 'codeListValue', 'creation')  # True
hasattr(targets[2], 'codeListValue', 'publication')  # False

# Let's change one of them
t1 = targets[1]
t1.text = 'New Creation'  # change text node

# and/or change attribute
t1.attrib['codeListValue'] = 'Latest Creation'

最后,我们将结果保存到文件中

tree.write("output1.xml")

编辑 1

在这里,我们导航到需要更改的已找到目标 [1] 的表亲 1 (gco:Date):

t1 = targets[1]
parent1 = t1.getparent()
date1 = parent1.getprevious()
cousin1 = date1.getchildren()
len(cousin1)     #1
cousin1[0].text  #'1900-01-01'

# change the date
cousin1[0].text = '2017-5-3'
# again, write the result

tree.write("out456.xml")

【讨论】:

  • 感谢您的示例,但它不会更改 gco:Date ,这是需要更改的内容,而不是 codeListvalue 的文本。
  • @MapMan,我已经编辑了我的答案以显示如何更改日期。
猜你喜欢
  • 1970-01-01
  • 2013-06-03
  • 1970-01-01
  • 2014-10-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-25
相关资源
最近更新 更多