【问题标题】:Write xml from list of path/values从路径/值列表中写入 xml
【发布时间】:2016-08-16 20:52:25
【问题描述】:

这是上一个问题的后续问题:Write xml with a path and value。我现在想添加两个额外的东西:1)属性和 2)具有父节点的多个项目。这是我拥有的路径列表:

[
  {'Path': 'Item/Info/Name', 'Value': 'Body HD'},
  {'Path': 'Item/Info/Synopsis', 'Value': 'A great movie'},
  {'Path': 'Item/Locales/Locale[@Country="US"][@Language="ES"]/Name', 'Value': 'El Grecco'},      
  {'Path': 'Item/Genres/Genre', 'Value': 'Action'},
  {'Path': 'Item/Genres/Genre', 'Value': 'Drama'},
  {'Path': 'Item/Purchases/Purchase[@Country="US"]/HDPrice', 'Value': '10.99'},
  {'Path': 'Item/Purchases/Purchase[@Country="US"]/SDPrice', 'Value': '9.99'},
  {'Path': 'Item/Purchases/Purchase[@Country="CA"]/SDPrice', 'Value': '4.99'},
]

它应该生成的xml是:

<Item>
    <Info>
        <Name>Body HD</Name>
        <Synopsis>A great movie</Synopsis>
    </Info>
    <Locales>
        <Locale Country="US" Language="ES">
            <Name>El Grecco</Name>
        </Locale>
    </Locales>
    <Genres>
        <Genre>Action</Genre>
        <Genre>Drama</Genre>
    </Genres>
    <Purchases>
        <Purchase Country="US">
            <HDPrice>10.99</HDPrice>
            <SDPrice>9.99</SDPrice>
        </Purchase>
        <Purchase Country="CA">
            <SDPrice>4.99</SDPrice>
        </Purchase>
    </Purchases>
</Item>

我将如何构建它?

【问题讨论】:

  • 'Item/Locales/Locale[Country="US"]Language=["ES"]/Name'中,为什么Country括号内,而Language
  • @Robᵩ 谢谢我更新了。

标签: python xml xpath lxml


【解决方案1】:

要从 xpath 和值构建 XML 树,我使用 RegEx 和 lxml

import re

from lxml import etree

条目是:

entries = [
    {'Path': 'Item/Info/Name', 'Value': 'Body HD'},
    {'Path': 'Item/Info/Synopsis', 'Value': 'A great movie'},
    {'Path': 'Item/Locales/Locale[@Country="US"][@Language="ES"]/Name', 'Value': 'El Grecco'},
    {'Path': 'Item/Genres/Genre', 'Value': 'Action'},
    {'Path': 'Item/Genres/Genre', 'Value': 'Drama'},
    {'Path': 'Item/Purchases/Purchase[@Country="US"]/HDPrice', 'Value': '10.99'},
    {'Path': 'Item/Purchases/Purchase[@Country="US"]/SDPrice', 'Value': '9.99'},
    {'Path': 'Item/Purchases/Purchase[@Country="CA"]/SDPrice', 'Value': '4.99'},
]

为了解析每个 xpath 步骤,我使用以下 RegEx(非常简单的一个):

TAG_REGEX = r"(?P<tag>\w+)"
CONDITION_REGEX = r"(?P<condition>(?:\[.*?\])*)"
STEP_REGEX = TAG_REGEX + CONDITION_REGEX
ATTR_REGEX = r"@(?P<key>\w+)=\"(?P<value>.*?)\""

search_step = re.compile(STEP_REGEX, flags=re.DOTALL).search
findall_attr = re.compile(ATTR_REGEX, flags=re.DOTALL).findall


def parse_step(step):
    mo = search_step(step)
    if mo:
        tag = mo.group("tag")
        condition = mo.group("condition")
        return tag, dict(findall_attr(condition))
    raise ValueError(xpath)

parse_step 返回一个标签名称和一个属性字典

然后,我用同样的方法构建 XML 树:

root = None
for entry in entries:
    path = entry["Path"]
    parts = path.split("/")
    xpath_list = ["/" + parts[0]] + parts[1:]
    curr = root
    for xpath in xpath_list:
        tag_name, attrs = parse_step(xpath)
        if curr is None:
            root = curr = etree.Element(tag_name, **attrs)
        else:
            nodes = curr.xpath(xpath)
            if nodes:
                curr = nodes[0]
            else:
                curr = etree.SubElement(curr, tag_name, **attrs)
    if curr.text:
        curr = etree.SubElement(curr.getparent(), curr.tag, **curr.attrib)
    curr.text = entry["Value"]

print(etree.tostring(root, pretty_print=True))

结果是:

<Item>
  <Info>
    <Name>Body HD</Name>
    <Synopsis>A great movie</Synopsis>
  </Info>
  <Locales>
    <Locale Country="US" Language="ES">
      <Name>El Grecco</Name>
    </Locale>
  </Locales>
  <Genres>
    <Genre>Action</Genre>
    <Genre>Drama</Genre>
  </Genres>
  <Purchases>
    <Purchase Country="US">
      <HDPrice>10.99</HDPrice>
      <SDPrice>9.99</SDPrice>
    </Purchase>
    <Purchase Country="CA">
      <SDPrice>4.99</SDPrice>
    </Purchase>
  </Purchases>
</Item>

【讨论】:

  • 干得好!!这里唯一缺少的是流派的多个值。似乎每个连续的流派都会覆盖前一个流派。
  • 有限制!在这个实现中,当 xpath 匹配时,我考虑第一个节点 (curr = nodes[0]),我不附加新的子元素。很难猜出该怎么做:追加一个新元素还是使用最后一个?例如,您不得为根 Item 附加元素。
  • 如果文本已经存在,我们可以复制最后一个元素。见编辑。
  • 谢谢,别忘了改进正则表达式...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-12-30
  • 2018-08-08
  • 2015-01-01
  • 1970-01-01
  • 2012-12-10
  • 2013-08-11
  • 1970-01-01
相关资源
最近更新 更多