我正在尝试更新一个xml文档,将一个子元素添加到xpath标识的一组父元素中。在
为此,我通过xpath标识要更改的元素,然后对这些元素运行for循环。我将这段代码称为“xpath for block”
我可以:
我不能:
代码:
from lxml import etree as ET
def _modify_mods_content(mods_content):
"""Massage the MODS content before auto-populating page
Args:
mods_content (str): content of MODS datastream as a string
Returns:
updated_content (str): updated MODS content
"""
nsmap = {'mods': NAMESPACES['mods']}
mods_xml = ET.fromstring(mods_content)
# Create empty given-name element
given_name_tag = ET.QName(NAMESPACES['mods'], 'namePart')
given_name = ET.Element(given_name_tag)
given_name.attrib['type'] = 'given'
# xpath to find every personal name that does not have a child
# given name element
no_given_names_xpath = '//mods:name[@type="personal"][not(mods:namePart[@type="given"])]'
for element in mods_xml.xpath(no_given_names_xpath, namespaces=nsmap):
element.insert(0, given_name)
new_string = ET.tostring(mods_xml)
return new_string
如果我在xpath for block中输入pdb提示符,我可以看到元素正在更新,如果我在树上一直执行“getparent”,我可以看到根mods_xml文档似乎只在该实例中更新了。在
一旦我离开for循环,所有更新都不会持久。在
例如:
原始文件:
^{pr2}$第一次在xpath for块中
<root>
<mods:name type="personal">
<mods:namePart type="given"></mods:namePart>
<mods:namePart type="family">Smith</mods:namePart>
</mods:name>
<mods:name type="personal">
<mods:namePart type="family">Jones</mods:namePart>
</mods:name>
</root>
第二次在xpath for块中:
<root>
<mods:name type="personal">
<mods:namePart type="family">Smith</mods:namePart>
</mods:name>
<mods:name type="personal">
<mods:namePart type="given"></mods:namePart>
<mods:namePart type="family">Jones</mods:namePart>
</mods:name>
</root>
编辑:以下示例最初没有插入元素。这些示例是从一个更长更复杂的文档中简化而来的。我一定错过了最后的更新是在离开块之后被持久化的。在
一旦我离开街区
<root>
<mods:name type="personal">
<mods:namePart type="family">Smith</mods:namePart>
</mods:name>
<mods:name type="personal">
<mods:namePart type="given"></mods:namePart>
<mods:namePart type="family">Jones</mods:namePart>
</mods:name>
</root>
我意识到这可以用XSLT实现。我只想知道有没有更“Python”的方法。在
我实际上(有点)让它工作了,但这是一个可怕的黑客,a)我不想做,b)只有当所有元素都在同一深度(幸运的是,在这种情况下,它们恰好是这样)才有效:
while mods_xml.xpath(no_given_names_xpath, namespaces=nsmap):
elements = mods_xml.xpath(no_given_names_xpath, namespaces=nsmap)
replacement_element = elements[0]
replacement_element.insert(0, given_name)
parent = elements[0].getparent()
parent.replace(elements[0], replacement_element)
new_xml_string = ET.tostring(parent, pretty_print=True)
mods_xml = ET.fromstring(new_xml_string)
欢迎有任何想法或意见!在
一位不在堆栈溢出上的同事给出了有用的答案。在
该问题与this issue here有关。我原以为我创建的给定的\u name元素是一个空白元素,我可以在循环中每次添加到父文档中(就像我在进行字符串连接一样)。在
事实上,lxml将元素视为一个不同的对象,并且只是在文件中移动它(上面的示例被简化了,所以我一定错过了插入的最后一个位置)。在
解决方案是每次使用一个小的私有函数来生成一个新元素。在
更正代码:
相关问题 更多 >
编程相关推荐