lxml 查找最后一个可选 XML 元素
lxml finding last optional XML Element
我正在使用 LXML 来处理 XML 的现有块,我想要的是:
- 如果标签存在则更改元素值
- 如果不存在,则创建元素
(2) 的问题是:将元素插入块中的正确位置,其中大多数元素是可选的。注意:有一个定义结构的XSD。
例如,我想插入 <d>
,如果存在,它将在 <c>
之后,如果存在,则在 <b>
之后,如果存在,则在 <a>
之后
<OuterElement>
<a>value of a</a> --- Optional
<b>value of b</b> --- Optional
<c>value of c</c> --- Optional
<d>value of d</d>
<e>value of e</e> --- Optional
</OuterElement>
实现此目标的最巧妙/最简单的方法是什么?目前我正在使用 XPath 表达式循环元素 - 这感觉很老套。
一种方法是在 XSLT 中使用完整序列设置一个虚拟元素模板,然后在处理输入时,将虚拟元素推入一个模板,检查输入是否具有同名元素,如果有的话复制那个,否则从虚拟模板元素复制元素:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
exclude-result-prefixes="exsl"
version="1.0">
<xsl:param name="template">
<OuterElement>
<a></a>
<b></b>
<c></c>
<d></d>
<e></e>
</OuterElement>
</xsl:param>
<xsl:variable name="template-elements" select="exsl:node-set($template)/OuterElement/*"/>
<xsl:template match="OuterElement">
<xsl:copy>
<xsl:apply-templates select="$template-elements">
<xsl:with-param name="input" select="."/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="OuterElement/*">
<xsl:param name="input"/>
<xsl:choose>
<xsl:when test="$input/*[name() = name(current())]">
<xsl:copy-of select="$input/*[name() = name(current())]"/>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="."/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:output indent="yes"/>
</xsl:stylesheet>
不幸的是,对于 XSLT 1,我们需要使用 exsl:node-set
函数将参数结果树片段转换为节点集。
我正在使用 LXML 来处理 XML 的现有块,我想要的是:
- 如果标签存在则更改元素值
- 如果不存在,则创建元素
(2) 的问题是:将元素插入块中的正确位置,其中大多数元素是可选的。注意:有一个定义结构的XSD。
例如,我想插入 <d>
,如果存在,它将在 <c>
之后,如果存在,则在 <b>
之后,如果存在,则在 <a>
之后
<OuterElement>
<a>value of a</a> --- Optional
<b>value of b</b> --- Optional
<c>value of c</c> --- Optional
<d>value of d</d>
<e>value of e</e> --- Optional
</OuterElement>
实现此目标的最巧妙/最简单的方法是什么?目前我正在使用 XPath 表达式循环元素 - 这感觉很老套。
一种方法是在 XSLT 中使用完整序列设置一个虚拟元素模板,然后在处理输入时,将虚拟元素推入一个模板,检查输入是否具有同名元素,如果有的话复制那个,否则从虚拟模板元素复制元素:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
exclude-result-prefixes="exsl"
version="1.0">
<xsl:param name="template">
<OuterElement>
<a></a>
<b></b>
<c></c>
<d></d>
<e></e>
</OuterElement>
</xsl:param>
<xsl:variable name="template-elements" select="exsl:node-set($template)/OuterElement/*"/>
<xsl:template match="OuterElement">
<xsl:copy>
<xsl:apply-templates select="$template-elements">
<xsl:with-param name="input" select="."/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="OuterElement/*">
<xsl:param name="input"/>
<xsl:choose>
<xsl:when test="$input/*[name() = name(current())]">
<xsl:copy-of select="$input/*[name() = name(current())]"/>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="."/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:output indent="yes"/>
</xsl:stylesheet>
不幸的是,对于 XSLT 1,我们需要使用 exsl:node-set
函数将参数结果树片段转换为节点集。