问题
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:
<Item>
<Info>
<Name>Body HD</Name>
</Info>
<Genres>
<Genre>Action</Genre>
</Genres>
</Item>
Is there a way to do this with lxml
? Or how could I build a function to fill in the inferred paths?
回答1:
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.
回答2:
Yes, you can do that with lxml
.
I suggest you to use a template XML and fill it.
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"
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.
来源:https://stackoverflow.com/questions/38983126/write-xml-with-a-path-and-value