在xslt中覆盖节点树中的节点

  • 本文关键字:节点 覆盖 xslt xslt
  • 更新时间 :
  • 英文 :


这是我的输入

<SimpleInput>
<variable1>1</variable1>
<variable2>2</variable2>
<variable3>3</variable3>
</SimpleInput>

这是我现在得到的输出

<Classes>
<ClassA>
<input1>overwrite 1</input1>
<input2>2</input2>
<input3>3</input3>
</ClassA>
<ClassB>
<input1>1</input1>
<input2>overwrite 2</input2>
<input3>3</input3>
</ClassB>
</Classes>

这就是我实现上述的方式

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="UTF-8" indent="yes" />

<xsl:variable name="myVar">
<input1><xsl:value-of select="/SimpleInput/variable1"/></input1>
<input2><xsl:value-of select="/SimpleInput/variable2"/></input2>
<input3><xsl:value-of select="/SimpleInput/variable3"/></input3>
</xsl:variable>
<xsl:template match="/">
<Classes>
<xsl:variable name="paramForClassA">
<input1><xsl:value-of select="'overwrite 1'"/></input1>
<input2><xsl:value-of select="/SimpleInput/variable2"/></input2>
<input3><xsl:value-of select="/SimpleInput/variable3"/></input3>
</xsl:variable>
<ClassA>
<xsl:call-template name="buildSection">
<xsl:with-param name="obj" select="$paramForClassA"/>
</xsl:call-template>
</ClassA>
<ClassB>
<xsl:variable name="paramForClassB">
<input1><xsl:value-of select="/SimpleInput/variable1"/></input1>
<input2><xsl:value-of select="'overwrite 2'"/></input2>
<input3><xsl:value-of select="/SimpleInput/variable3"/></input3>
</xsl:variable>
<xsl:call-template name="buildSection">
<xsl:with-param name="obj" select="$paramForClassB"/>
</xsl:call-template>
</ClassB>
</Classes>
</xsl:template>
<xsl:template name="buildSection">
<xsl:param name="obj" select="()"/>
<xsl:for-each select="$obj/*">
<xsl:element name="{name()}">
<xsl:copy-of select="@*|node()" />
</xsl:element>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

但我希望能够动态覆盖/创建我想要的节点,而无需在将其传递给buildSection模板之前重建整个节点树。

以下是我正在寻找的输出示例(ClassB上有一个额外的输入4,我无法用上面的代码实现(

<Classes>
<ClassA>
<input1>overwrite 1</input1>
<input2>2</input2>
<input3>3</input3>
</ClassA>
<ClassB>
<input1>1</input1>
<input2>overwrite 2</input2>
<input3>3</input3>
<input4>New Item</input4>
</ClassB>
</Classes>

与这里所做的类似,但如果节点不存在,我希望替换或添加节点本身。

在将参数传递给模板调用时,我希望克服当前设计的两个限制。

  1. 必要时向ClassX添加新元素
  2. 消除了重建整个节点树的需要(在某些情况下,节点树中可能有80多个变量(

构建模板实际上在一个单独的文件中,可以从多个调用方使用。如果我们在每个类中硬编码节点树构建逻辑(也在单独的文件中(,如果需要更新模板,那么我也需要更新所有调用方(最多可以是30个单独的调用方(。希望这能说明新设计的必要性。

理想情况下,在构建paramForX 时会出现这样的情况

<xsl:variable name="myReplacementsForA">
<input1>overwrite 1</input1>
</xsl:variable>
<xsl:variable name="myReplacementsForB">
<input2>overwrite 2</input2>
<input4>Add 4</input4>
</xsl:variable>
<xsl:variable name="paramForClassA">
<xsl:apply-templates select="$myVar" mode="add-or-replace-value">
<with-param name="replacements" select="$myReplacementsForA"/>
</xsl:apply-templates>
</xsl:variable>
<xsl:variable name="paramForClassB">
<xsl:apply-templates select="$myVar" mode="add-or-replace-value">
<with-param name="replacements" select="$myReplacementsForB"/>
</xsl:apply-templates>
</xsl:variable>

我设法做到了这一点。不确定它是否是最有效的

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="UTF-8" indent="yes" />
<xsl:variable name="myVar">
<input1><xsl:value-of select="/SimpleInput/variable1"/></input1>
<input2><xsl:value-of select="/SimpleInput/variable2"/></input2>
<input3><xsl:value-of select="/SimpleInput/variable3"/></input3>
</xsl:variable>
<xsl:template match="/">
<Classes>
<xsl:variable name="myReplacementsForA">
<input1>overwrite 1</input1>
</xsl:variable>
<xsl:variable name="paramForClassA">
<xsl:apply-templates mode="buildNewParam">
<xsl:with-param name="original" select="$myVar"/>
<xsl:with-param name="replacements" select="$myReplacementsForA"/>
</xsl:apply-templates>
</xsl:variable>
<ClassA>
<xsl:value-of select="$paramForClassA/item2"/>
<xsl:call-template name="buildSection">
<xsl:with-param name="obj" select="$paramForClassA"/>
</xsl:call-template>
</ClassA>
<ClassB>
<xsl:variable name="myReplacementsForB">
<input2>overwrite 2</input2>
<input4>Add 4</input4>
</xsl:variable>
<xsl:variable name="paramForClassB">
<xsl:apply-templates mode="buildNewParam">
<xsl:with-param name="original" select="$myVar"/>
<xsl:with-param name="replacements" select="$myReplacementsForB"/>
</xsl:apply-templates>
</xsl:variable>
<xsl:call-template name="buildSection">
<xsl:with-param name="obj" select="$paramForClassB"/>
</xsl:call-template>
</ClassB>
</Classes>
</xsl:template>
<xsl:template name="buildSection">
<xsl:param name="obj" select="()"/>
<xsl:for-each select="$obj/*">
<xsl:element name="{name()}">
<xsl:copy-of select="@*|node()" />
</xsl:element>
</xsl:for-each>
</xsl:template>
<xsl:template mode="buildNewParam" match=".">
<xsl:param name="original"/>
<xsl:param name="replacements"/>
<xsl:variable name="merged">
<xsl:for-each select="$original/*">
<xsl:element name="{name()}">
<xsl:copy-of select="@*|node()" />
</xsl:element>
</xsl:for-each>
<xsl:for-each select="$replacements/*">
<xsl:element name="{name()}">
<xsl:copy-of select="@*|node()" />
</xsl:element>
</xsl:for-each>
</xsl:variable>
<xsl:variable name="sorted">
<xsl:for-each select="$merged/*">
<xsl:sort select="name()"/>
<xsl:element name="{name()}">
<xsl:copy-of select="@*|node()" />
</xsl:element>
</xsl:for-each>
</xsl:variable>
<xsl:for-each select="$sorted/*">
<xsl:if test="name()!=name(following-sibling::node()[1])">
<xsl:element name="{name()}">
<xsl:copy-of select="@*|node()" />
</xsl:element>
</xsl:if>
</xsl:for-each>

</xsl:template>
</xsl:stylesheet>

最新更新