简体   繁体   English

用路径和值编写xml

[英]Write xml with a path and value

I have a list of paths and values, something like this: 我有一个路径和值的列表,像这样:

[
  {'Path': 'Item/Info/Name', 'Value': 'Body HD'},
  {'Path': 'Item/Genres/Genre', 'Value': 'Action'},
]

And I want to build out the full xml structure, which would be: 我想构建完整的xml结构,即:

<Item>
    <Info>
        <Name>Body HD</Name>
    </Info>
    <Genres>
        <Genre>Action</Genre>
    </Genres>
</Item>

Is there a way to do this with lxml ? 有没有办法用lxml做到这一点? Or how could I build a function to fill in the inferred paths? 或者我该如何构建一个函数来填充推断的路径?

Yes, you can do that with lxml . 是的,您可以使用lxml做到这一点。

I suggest you to use a template XML and fill it. 我建议您使用模板XML并填充它。

Template: 模板:

<Item>
    <Info>
        <Name/>
    </Info>
    <Genres>
        <Genre/>
    </Genres>
</Item>

from lxml import etree

tree = etree.parse("template.xml")

Then, fill it: 然后,填写:

entries = [
    {'Path': 'Item/Info/Name', 'Value': 'Body HD'},
    {'Path': 'Item/Genres/Genre', 'Value': 'Action'}]

for entry in entries:
    xpath = entry["Path"]
    node = tree.xpath(xpath)[0]
    node.text = entry['Value']

Note: instead of "Path", I would prefer "XPath" 注意:我希望使用“ XPath”代替“ Path”

If you dont want template, you can generate the whole tree structure like this: 如果您不想要模板,则可以像这样生成整个树结构:

from lxml import etree

entries = [
    {'Path': 'Item/Info/Name', 'Value': 'Body HD'},
    {'Path': 'Item/Genres/Genre', 'Value': 'Action'}]

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:
        name = xpath.strip("/")
        if curr is None:
            root = curr = etree.Element(name)
        else:
            nodes = curr.xpath(xpath)
            if nodes:
                curr = nodes[0]
            else:
                curr = etree.SubElement(curr, name)
    curr.text = entry["Value"]

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

The result is: 结果是:

<Item>
  <Info>
    <Name>Body HD</Name>
  </Info>
  <Genres>
    <Genre>Action</Genre>
  </Genres>
</Item>

Of course, there are limitations. 当然有局限性。

You could do something like: 您可以执行以下操作:

l = [
  {'Path': 'Item/Info/Name', 'Value': 'Body HD'},
  {'Path': 'Item/Genres/Genre', 'Value': 'Action'},
]


import lxml.etree as et
root_node = l[0]["Path"].split("/", 1)[0]
tree = et.fromstring("<{}></{}>".format(root_node, root_node))


for dct in l:        
    nodes = iter(dct["Path"].split("/")[1:])
    # catch path like Item/Foo where there is only one child.
    nxt_child = child = et.Element(next(nodes))
    for node in nodes:
        # keep adding nodes 
        nxt_child = et.Element(node)
        child.append(nxt_child)
    # set value to last node.
    nxt_child.text = dct["Value"]
    # append it to the tree.
    tree.append(child)


print(et.tostring(tree))

Which would give you: 这会给你:

<Item>
  <Info>
    <Name>Body HD</Name>
  </Info>
  <Genres>
    <Genre>Action</Genre>
  </Genres>
</Item>

You know Item is the root node and the first in every Path, so first create a tree using that node and then just add to the tree as you go. 您知道Item是根节点,并且是每个Path中的第一个节点,因此首先使用该节点创建树,然后随便添加到树中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM