假设我们有以下 XML 文件:
from lxml import etree
root = etree.fromstring("""
<a>
<b>
<c>Hello</c>
<d>1234</d>
</b>
<b>
<c>Bonjour</c>
<d>5678</d>
</b>
</a>
""")
Run Code Online (Sandbox Code Playgroud)
怎么可能用类似 SQL 的查询语言更新 XML?
示例(伪代码):
etree.query("""UPDATE a.b SET c.text = 'foo' WHERE d.text = '5678'""")
Run Code Online (Sandbox Code Playgroud)
甚至更复杂的链式查询,例如:
UPDATE a.b SET c.text = (SELECT ... FROM ... WHERE ...) WHERE d.text = '5678'
Run Code Online (Sandbox Code Playgroud)
目标是能够使用类似 SQL 的语法仅用一两行代码来修改复杂的 XML 文档。旁注:作为对比,用人工做这个lxml,find等作品,但要长得多。
考虑XSLT,一种旨在转换 XML 文档的专用语言,它共享 SQL 的一些属性:
Pythonlxml可以运行 XSLT 1.0 脚本,这些脚本只是特殊的 XML 文件。要回答您的第一个查询,请使用<xsl:choose>.
加载文件
from lxml import etree
root = etree.fromstring("""\
<a>
<b>
<c>Hello</c>
<d>1234</d>
</b>
<b>
<c>Bonjour</c>
<d>5678</d>
</b>
</a>""")
xsl = etree.fromstring("""\
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- INITIALIZE PARAMETERS -->
<xsl:param name="c_val"/>
<xsl:param name="d_val"/>
<!-- IDENTITY TRANSFORM -->
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<!-- CONDITIONALLY UPDATE <c> -->
<xsl:template match="c">
<xsl:copy>
<xsl:choose>
<xsl:when test="following-sibling::d = $d_val">
<xsl:value-of select="$c_val"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="text()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>""")
Run Code Online (Sandbox Code Playgroud)
运行转换
# INITIALIZE TRANSFORMER
transformer = etree.XSLT(xsl)
# TRANSFORM WITH PARAMETERS
result = transformer(
root,
c_val=etree.XSLT.strparam("foo"),
d_val=etree.XSLT.strparam("5678")
)
# OUTPUT RESULT TO CONSOLE
print(result)
# <a>
# <b>
# <c>Hello</c>
# <d>1234</d>
# </b>
# <b>
# <c>foo</c>
# <d>5678</d>
# </b>
#</a>
Run Code Online (Sandbox Code Playgroud)
不太清楚你的第二个查询。但是如果需要从不同的 XML 文档(对应于不同的 SQL 表)进行查询,XSLT 维护了该document()函数并且可以在包括参数在内的大多数地方调用。调整下面的 XPath。
<xsl:param name="c_val">
<xsl:value-of select="document('other.xml')/a/b/c[1]">
</xsl:param>
Run Code Online (Sandbox Code Playgroud)
如果不是c_val从应用层传递,请务必在 Python 中删除该参数,否则您将覆盖上面。
| 归档时间: |
|
| 查看次数: |
223 次 |
| 最近记录: |