使用 lxml 更改现有的命名空间属性
Changing an existing namespaced attribute with lxml
我有一个现有的 XML 文档,我想将命名空间属性更改为另一个值。
我有这个:
<ac:structured-macro ac:name="center">
<ac:rich-text-body>
<p>
some text
</p>
</ac:rich-text-body>
</ac:structured-macro>
我想把上面的变成这样:
<ac:structured-macro ac:name="new_center">
<ac:rich-text-body>
<p>
some text
</p>
</ac:rich-text-body>
</ac:structured-macro>
这个python代码:
from lxml import etree
pagexml = """<ac:structured-macro ac:name="center"> <ac:rich-text-body> <p> some text </p> </ac:rich-text-body> </ac:structured> -macro>"""
prefix_map = {"ac": "http://www.atlassian.com/schema/confluence/4/ac/",
"ri": "http://www.atlassian.com/schema/confluence/4/ri/"}
parser = etree.XMLParser(recover=True)
root = etree.fromstring(pagexml, parser)
for action, elem in etree.iterwalk(root, events=("end",)):
if elem.tag == "ac:structured-macro":
if elem.get("ac:name") == "center":
elem.set("{ac}name", "new_center")
print(etree.tostring(root, pretty_print=True, encoding=str))
产生这个:
<ac:structured-macro xmlns:ns0="ac" ac:name="center" ns0:name="new_center">
<ac:rich-text-body>
<p>
some text
</p>
</ac:rich-text-body>
</ac:structured-macro>
<ac:structured-macro>
可以存在于 XML 树中的任何位置。我知道我可以用正则表达式来做到这一点,但我更愿意以正确的方式来做,因为我认为那样会更健壮。我希望在某个地方我可以传递 prefix_map
并让它尊重 ac
命名空间。
我不熟悉lxml。这里再提供一个解决方案,仅供参考。
from simplified_scrapy import SimplifiedDoc
html = '''
<ac:structured-macro ac:name="center">
<ac:rich-text-body>
<p>
some text
</p>
</ac:rich-text-body>
</ac:structured-macro>
'''
doc = SimplifiedDoc(html)
structuredMacro = doc.select('ac:structured-macro')
structuredMacro.setAttr('ac:name', 'new_center')
# Or
# structuredMacro.setAttrs({'ac:name': 'new_center'})
print(doc.html)
结果:
<ac:structured-macro ac:name="new_center">
<ac:rich-text-body>
<p>
some text
</p>
</ac:rich-text-body>
</ac:structured-macro>
我有一个现有的 XML 文档,我想将命名空间属性更改为另一个值。
我有这个:
<ac:structured-macro ac:name="center">
<ac:rich-text-body>
<p>
some text
</p>
</ac:rich-text-body>
</ac:structured-macro>
我想把上面的变成这样:
<ac:structured-macro ac:name="new_center">
<ac:rich-text-body>
<p>
some text
</p>
</ac:rich-text-body>
</ac:structured-macro>
这个python代码:
from lxml import etree
pagexml = """<ac:structured-macro ac:name="center"> <ac:rich-text-body> <p> some text </p> </ac:rich-text-body> </ac:structured> -macro>"""
prefix_map = {"ac": "http://www.atlassian.com/schema/confluence/4/ac/",
"ri": "http://www.atlassian.com/schema/confluence/4/ri/"}
parser = etree.XMLParser(recover=True)
root = etree.fromstring(pagexml, parser)
for action, elem in etree.iterwalk(root, events=("end",)):
if elem.tag == "ac:structured-macro":
if elem.get("ac:name") == "center":
elem.set("{ac}name", "new_center")
print(etree.tostring(root, pretty_print=True, encoding=str))
产生这个:
<ac:structured-macro xmlns:ns0="ac" ac:name="center" ns0:name="new_center">
<ac:rich-text-body>
<p>
some text
</p>
</ac:rich-text-body>
</ac:structured-macro>
<ac:structured-macro>
可以存在于 XML 树中的任何位置。我知道我可以用正则表达式来做到这一点,但我更愿意以正确的方式来做,因为我认为那样会更健壮。我希望在某个地方我可以传递 prefix_map
并让它尊重 ac
命名空间。
我不熟悉lxml。这里再提供一个解决方案,仅供参考。
from simplified_scrapy import SimplifiedDoc
html = '''
<ac:structured-macro ac:name="center">
<ac:rich-text-body>
<p>
some text
</p>
</ac:rich-text-body>
</ac:structured-macro>
'''
doc = SimplifiedDoc(html)
structuredMacro = doc.select('ac:structured-macro')
structuredMacro.setAttr('ac:name', 'new_center')
# Or
# structuredMacro.setAttrs({'ac:name': 'new_center'})
print(doc.html)
结果:
<ac:structured-macro ac:name="new_center">
<ac:rich-text-body>
<p>
some text
</p>
</ac:rich-text-body>
</ac:structured-macro>