如何使用XSL复制节点并更改其(原始和重复)嵌套子节点的值



我刚开始使用XSL,需要有经验的人的帮助。

我在XML中有一个节点a,其中包含大量内容。我想复制这个节点,通过它里面嵌套标签的值来识别它

在创建与节点A相同的节点A'后,我想更改标识节点A的标记的值:节点A和节点A'。两个节点的新值将不同。

这是我的源XML:

<businessFields>
<businessField>
<businessFieldID>
<namespace>
<name>foo</name>
</namespace>
<name>foobar</name>
</businessFieldID>
<datatype>java.lang.Boolean</datatype>
<value>false</value>
</businessField>
<businessField>
<businessFieldID>
<namespace>
<name>bar</name>
</namespace>
<name>foobar3</name>
</businessFieldID>
<datatype>java.lang.String</datatype>
<value>No</value>
</businessField>
<!-- some more businessField nodes-->
</businessFields>

我需要在/businessFields/businessFieldID/name标记中复制带有foobar值的节点,并且我想更改这两个节点的值。

我的XSL是这样的:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="//businessField[businessFieldID/name='foobar']">
<xsl:copy-of select="."/>
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>


<xsl:template match="//businessField[businessFieldID/name='foobar']/businessFieldID/name/text()">
<xsl:value-of select="'foobar1'"/>
</xsl:template>

</xsl:stylesheet>

因此,基本上我可以复制我感兴趣的节点,并更改所需名称标记的值,但仅限于其中一个节点。

以下是所需输出:

<?xml version="1.0" encoding="UTF-8"?>
<businessFields>
<businessField>
<businessFieldID>
<namespace>
<name>foo</name>
</namespace>
<name>foobar1</name>
</businessFieldID>
<datatype>java.lang.Boolean</datatype>
<value>false</value>
</businessField>
<businessField>
<businessFieldID>
<namespace>
<name>foo</name>
</namespace>
<name>foobar2</name>
</businessFieldID>
<datatype>java.lang.Boolean</datatype>
<value>false</value>
</businessField>
<businessField>
<businessFieldID>
<namespace>
<name>bar</name>
</namespace>
<name>foobar3</name>
</businessFieldID>
<datatype>java.lang.String</datatype>
<value>No</value>
</businessField>
</businessFields>

我尝试使用<xsl:for-each>迭代所有以foobar为值的节点,并根据position()更改值,但我搞砸了一些事情,它只是为所有节点更改了相同的名称。

这是我在stackoverflow上的第一个问题,英语不是我的母语,如果不清楚,很抱歉。请让我知道我能做些什么让我的问题变得更好,谢谢你的帮助。

如果我理解正确(这根本不确定(,你想做:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- identity transform -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="businessField[businessFieldID/name='foobar']">
<!-- original -->
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
<!-- duplicate -->
<xsl:copy>
<xsl:apply-templates select="@*|node()" mode="duplicate"/>
</xsl:copy>
</xsl:template>
<!-- identity transform for duplicates -->
<xsl:template match="@*|node()" mode="duplicate">
<xsl:copy>
<xsl:apply-templates select="@*|node()" mode="duplicate"/>
</xsl:copy>
</xsl:template>

<!-- modify original -->
<xsl:template match="businessField[businessFieldID/name='foobar']/businessFieldID/name/text()">
<xsl:text>foobar1</xsl:text>
</xsl:template>
<!-- modify duplicate -->
<xsl:template match="businessField[businessFieldID/name='foobar']/businessFieldID/name/text()" mode="duplicate">
<xsl:text>foobar2</xsl:text>
</xsl:template>

</xsl:stylesheet>

2021年的Saxon对我来说听起来像XSLT3,所以也许

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all"
version="3.0">

<xsl:param name="name-to-check" as="xs:string">foobar</xsl:param>

<xsl:param name="new-value" as="xs:string">foobar</xsl:param>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:template match="businessField[businessFieldID/name = $name-to-check]">
<xsl:copy>
<xsl:apply-templates>
<xsl:with-param name="suffix" tunnel="yes" select="1"/>
</xsl:apply-templates>
</xsl:copy>
<xsl:copy>
<xsl:apply-templates>
<xsl:with-param name="suffix" tunnel="yes" select="2"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>

<xsl:template match="businessField/businessFieldID/name[. = $name-to-check]/text()">
<xsl:param name="suffix" tunnel="yes"/>
<xsl:value-of select="$new-value || $suffix"/>
</xsl:template>

</xsl:stylesheet>

足够了。,甚至

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all"
version="3.0">

<xsl:param name="name-to-check" as="xs:string">foobar</xsl:param>

<xsl:param name="new-value" as="xs:string">foobar</xsl:param>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:template match="businessField[businessFieldID/name = $name-to-check]">
<xsl:apply-templates select="., ." mode="change"/>
</xsl:template>

<xsl:template match="businessField" mode="change">
<xsl:copy>
<xsl:apply-templates mode="#default">
<xsl:with-param name="suffix" tunnel="yes" select="position()"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>

<xsl:template match="businessField/businessFieldID/name[. = $name-to-check]/text()">
<xsl:param name="suffix" tunnel="yes"/>
<xsl:value-of select="$new-value || $suffix"/>
</xsl:template>

</xsl:stylesheet>

最新更新