XSLT - 如何存储一组从源文档中删除的元素以供重用
XSLT - How to store a set of elements removed from source document for reuse
鉴于以下 XML:
<root>
<group>
<e1>001</e1>
<e2>beep</e2>
<e2>bop</e2>
<e2>ork</e2>
<e2>ah</e2>
<e2>ah</e2>
</group>
<group>
<e1>002</e1>
<e2>beep</e2>
<e2>bop</e2>
<e2>ork</e2>
<e2>ah</e2>
<e2>ah</e2>
</group>
<group>
<e1>003</e1>
<e2>beep</e2>
<e2>bop</e2>
<e2>ork</e2>
<e2>ah</e2>
<e2>ah</e2>
</group>
<group>
<e1>004</e1>
<e2>beep</e2>
<e2>bop</e2>
<e2>ork</e2>
<e2>ah</e2>
<e2>ah</e2>
</group>
</root>
请注意,每个 'group' 元素中的 'e2' 个元素都是相同的,源文档中保证了这一点。
我正在尝试使用 XSLT 执行以下步骤:
- 保存 'e2' 个元素集的副本,
- 删除所有 'group' 元素,
- 创建一组默认的组元素,并在其中插入一组 e2
所需的输出如下所示:
<root>
<group>
<e1>default1</e1>
<e2>beep</e2>
<e2>bop</e2>
<e2>ork</e2>
<e2>ah</e2>
<e2>ah</e2>
</group>
<group>
<e1>default2</e1>
<e2>beep</e2>
<e2>bop</e2>
<e2>ork</e2>
<e2>ah</e2>
<e2>ah</e2>
</group>
</root>
源文档中'e1'的值是无关紧要的,输出文档中'e2'的值是提前知道的,是静态的。只有 'e2' 值是动态的,我需要确保它们都在那里。
我之前用一些硬编码值替换所有元素时使用过类似的模式:
<xsl:template match="node() | @*">
<xsl:copy>
<xsl:apply-templates select="node() | @*"/>
</xsl:copy>
</xsl:template>
<!-- Empty Template eliminates all but first 'group' element. -->
<xsl:template match="//group[preceding::group]"></xsl:template>
<xsl:template match="//group">
<xsl:element name="group">
<e1>default1</e1>
<!-- e2 elements inserted here somehow? -->
</xsl:element>
<xsl:element name="group">
<e1>default2</e1>
<!-- e2 elements inserted here somehow? -->
</xsl:element>
</xsl:template>
我尝试将这些元素存储到一个变量中,但没有任何内容插入到输出中 html:
<xsl:variable name="e2Elements" select="//group[1]/e2"></xsl:variable>
<xsl:template match="//group">
<xsl:element name="group">
<e1>default1</e1>
<xsl:copy-of select="$e2Elements" />
</xsl:element>
</xsl:template>
但我不确定如何将 e2 元素插入到值中。我正在使用 SaxonHE9.8N 并且可以访问 exslt 命名空间和 xslt2.0
最后我需要使用 copy-of 使我的变量成为元素的副本。以下是我的解决方案:
<xsl:template match="node() | @*">
<xsl:copy>
<xsl:apply-templates select="node() | @*"/>
</xsl:copy>
</xsl:template>
<xsl:variable name="e3Elements">
<xsl:copy-of select="//group[1]/e2" />
</xsl:variable>
<xsl:template match="group[preceding::group]"></xsl:template>
<xsl:template match="group">
<xsl:element name="group">
<xsl:element name="e1">default1</xsl:element>
<xsl:copy-of select="$e3Elements"></xsl:copy-of>
</xsl:element>
<xsl:element name="group">
<xsl:element name="e1">default2</xsl:element>
<xsl:copy-of select="$e3Elements"></xsl:copy-of>
</xsl:element>
</xsl:template>
您的解决方案实际上是对元素进行不必要的复制。你可以不复制它们,像这样:
<xsl:variable name="e3Elements" select="//group[1]/e2" />
另一个低效率是 <xsl:template match="group[preceding::group]"/>
使用前面的轴总是很昂贵,尤其是在模式中。明显的改进是用 preceding-sibling 替换它(搜索 preceding-sibling 轴比搜索 preceding 轴快得多)。但实际上你可以做得更好:将此设置为组的默认规则 (<xsl:template match="group"/>
),并使另一个规则仅匹配第一个组 (<xsl:template match="group[1]">...
)。
但实际上,也不需要匹配第一个组元素,因为您没有使用它的任何数据。
在文体上,<group>
比 <xsl:element name="group">
更受青睐,因为它更具可读性。
这将是我的 XSLT 3.0 解决方案:
<xsl:transform version="3.0" .... expand-text="yes">
<xsl:template match="/">
<xsl:variable name="e3Elements" select="//group[1]/e2"/>
<xsl:for-each select="'default1', 'default2'">
<group>
<e1>{.}</e1>
<xsl:copy-of select="$e3Elements"/>
</group>
</xsl:for-each>
</xsl:template>
</xsl:transform>
鉴于以下 XML:
<root>
<group>
<e1>001</e1>
<e2>beep</e2>
<e2>bop</e2>
<e2>ork</e2>
<e2>ah</e2>
<e2>ah</e2>
</group>
<group>
<e1>002</e1>
<e2>beep</e2>
<e2>bop</e2>
<e2>ork</e2>
<e2>ah</e2>
<e2>ah</e2>
</group>
<group>
<e1>003</e1>
<e2>beep</e2>
<e2>bop</e2>
<e2>ork</e2>
<e2>ah</e2>
<e2>ah</e2>
</group>
<group>
<e1>004</e1>
<e2>beep</e2>
<e2>bop</e2>
<e2>ork</e2>
<e2>ah</e2>
<e2>ah</e2>
</group>
</root>
请注意,每个 'group' 元素中的 'e2' 个元素都是相同的,源文档中保证了这一点。
我正在尝试使用 XSLT 执行以下步骤:
- 保存 'e2' 个元素集的副本,
- 删除所有 'group' 元素,
- 创建一组默认的组元素,并在其中插入一组 e2
所需的输出如下所示:
<root>
<group>
<e1>default1</e1>
<e2>beep</e2>
<e2>bop</e2>
<e2>ork</e2>
<e2>ah</e2>
<e2>ah</e2>
</group>
<group>
<e1>default2</e1>
<e2>beep</e2>
<e2>bop</e2>
<e2>ork</e2>
<e2>ah</e2>
<e2>ah</e2>
</group>
</root>
源文档中'e1'的值是无关紧要的,输出文档中'e2'的值是提前知道的,是静态的。只有 'e2' 值是动态的,我需要确保它们都在那里。
我之前用一些硬编码值替换所有元素时使用过类似的模式:
<xsl:template match="node() | @*">
<xsl:copy>
<xsl:apply-templates select="node() | @*"/>
</xsl:copy>
</xsl:template>
<!-- Empty Template eliminates all but first 'group' element. -->
<xsl:template match="//group[preceding::group]"></xsl:template>
<xsl:template match="//group">
<xsl:element name="group">
<e1>default1</e1>
<!-- e2 elements inserted here somehow? -->
</xsl:element>
<xsl:element name="group">
<e1>default2</e1>
<!-- e2 elements inserted here somehow? -->
</xsl:element>
</xsl:template>
我尝试将这些元素存储到一个变量中,但没有任何内容插入到输出中 html:
<xsl:variable name="e2Elements" select="//group[1]/e2"></xsl:variable>
<xsl:template match="//group">
<xsl:element name="group">
<e1>default1</e1>
<xsl:copy-of select="$e2Elements" />
</xsl:element>
</xsl:template>
但我不确定如何将 e2 元素插入到值中。我正在使用 SaxonHE9.8N 并且可以访问 exslt 命名空间和 xslt2.0
最后我需要使用 copy-of 使我的变量成为元素的副本。以下是我的解决方案:
<xsl:template match="node() | @*">
<xsl:copy>
<xsl:apply-templates select="node() | @*"/>
</xsl:copy>
</xsl:template>
<xsl:variable name="e3Elements">
<xsl:copy-of select="//group[1]/e2" />
</xsl:variable>
<xsl:template match="group[preceding::group]"></xsl:template>
<xsl:template match="group">
<xsl:element name="group">
<xsl:element name="e1">default1</xsl:element>
<xsl:copy-of select="$e3Elements"></xsl:copy-of>
</xsl:element>
<xsl:element name="group">
<xsl:element name="e1">default2</xsl:element>
<xsl:copy-of select="$e3Elements"></xsl:copy-of>
</xsl:element>
</xsl:template>
您的解决方案实际上是对元素进行不必要的复制。你可以不复制它们,像这样:
<xsl:variable name="e3Elements" select="//group[1]/e2" />
另一个低效率是 <xsl:template match="group[preceding::group]"/>
使用前面的轴总是很昂贵,尤其是在模式中。明显的改进是用 preceding-sibling 替换它(搜索 preceding-sibling 轴比搜索 preceding 轴快得多)。但实际上你可以做得更好:将此设置为组的默认规则 (<xsl:template match="group"/>
),并使另一个规则仅匹配第一个组 (<xsl:template match="group[1]">...
)。
但实际上,也不需要匹配第一个组元素,因为您没有使用它的任何数据。
在文体上,<group>
比 <xsl:element name="group">
更受青睐,因为它更具可读性。
这将是我的 XSLT 3.0 解决方案:
<xsl:transform version="3.0" .... expand-text="yes">
<xsl:template match="/">
<xsl:variable name="e3Elements" select="//group[1]/e2"/>
<xsl:for-each select="'default1', 'default2'">
<group>
<e1>{.}</e1>
<xsl:copy-of select="$e3Elements"/>
</group>
</xsl:for-each>
</xsl:template>
</xsl:transform>