我正在寻找更好的解决方案来执行以下操作。给定XML树,例如
<root>
<x>
<p class="a"> </p>
<p class="b"> </p> <!-- Not yet wrapped, so these two <p> nodes can be wrapped, like below. -->
<p class="b"> </p>
<p class="a"> </p> <!-- Not yet wrapped, so these two <p> nodes can be wrapped. -->
<p class="a"> </p>
</x>
<y>
<p class="a"> </p>
<wrap class="b"> <!-- The <p> nodes are wrapped in a <wrap> and the attribute has moved. -->
<p> </p>
<p> </p>
</wrap>
<p class="a"> </p>
</y>
</root>
我想选择具有相同类属性的所有相邻<p>
节点,并将它们包装在同一类的<wrap>
元素中;但是,如果它们已经被包裹起来,请不要包装它们。
我目前的做法是选择所有可以包装的节点:
candidates = xml.xpath("//*[not(self::wrap)]/p[@class]")
然后挑选任何候选人并将所有有效的兄弟姐妹积累到一个列表中:
if len(candidates) == 0 :
return
candidate = candidates[0] # Pick any one of the candidates.
siblings = get_siblings(candidate) # Gather all of the candidate's matching sibling elements into a list.
构建兄弟列表很简单:给定候选<p>
元素,迭代匹配的所有getprevious()
元素(即也是<p class="b">
元素)直到找到第一个元素兄弟姐妹。然后将所有getnext()
元素收集到一个列表中,生成一组完整的匹配元素。
获得该列表后,我创建一个新的<wrap>
元素,复制class
属性,然后将所有兄弟元素添加到新元素中。完成后,我添加了新元素(所有<p>
兄弟姐妹作为其子代),原来的第一个兄弟姐妹曾经是:
parent = candidate.getparent() # Get parent element of the candidate.
index = parent.index(candidate) # Get the index of the candidate.
wrap = lxml.etree.Element("wrap") # Create a new <wrap> element...
wrap.attrib["class"] = candidate.attrib["class"] # ...and copy the class attribute.
for s in siblings : # Iterate over all sibling elements in the list, and
wrap.append(s) # add the sibling to the new <wrap> element, and
del s.attrib["class"] # remove the class attribute from the sibling (because it's in the <wrap> element.
parent.insert(index, wrap) # Once all siblings are moved, add the new <wrap> element where the siblings used to be.
问题
环顾四周似乎有更好的解决方案,而不是手动实现这样的重写,例如使用XSLT? (我之前从未使用过它,所以我不确定XSLT是否打算解决这些问题。)那么:什么是“正确”的方法呢?是否有更正式的基于XML的工具用于此类重写/转换,或者是一种手动实现,就像上面常用的方法一样?
答案 0 :(得分:0)
import xml.etree.ElementTree as et
from lxml import etree as lxet
e1 = et.Element('e1')
e2 = et.Element('e2')
e3 = et.SubElement(e1, 'e3')
e2.append(e3)
et.dump(e1)
<e1><e3 /></e1>
et.dump(e2)
<e2><e3 /></e2>
lxe1 = lxet.Element('e1')
lxe2 = lxet.Element('e2')
lxe3 = lxet.SubElement(lxe1, 'e3')
lxe2.append(lxe3)
lxet.dump(lxe1)
<e1/>
lxet.dump(lxe2)
<e2>
<e3/>
</e2>