Reputation: 1571
I'm trying to do an xml trasformation with XSLT. I have the following xml:
<myxml>
<dataType1>
<value1>
A1
</value1>
<value2>
A2
</value2>
</dataType1>
<dataType1>
<value1>
B1
</value1>
<value2>
B2
</value2>
</dataType1>
<dataType2>
<value1>
A1
</value1>
<value3>
A3
</value3>
</dataType2>
<dataType2>
<value1>
B1
</value1>
<value3>
B3
</value3>
</dataType2>
each datatype2 has an element value1 that is a foreign key in the datatype2 so then I have to map this data based on the value1.
If exists a dataType1 with value1=A1 and a dataType2 with a value1=A1 then I have to create an xml with the values of value2 and value3 so the result will be the following:
<resultxml>
<data>
<value2>
A2
</value2>
<value3>
A3
</value3>
</data>
<data>
<value2>
B2
</value2>
<value3>
B3
</value3>
</data>
I thought about creating dynamically the variables while reading the dataType1 and then calling them when reading the datatype2 but as I read on some forum that is not possible so my question is: is possible to do what I explained? if yes which is the approach I have to follow (examples are welcome)
thanks in advance
Upvotes: 1
Views: 141
Reputation: 243469
This transformation:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="kType1" match="dataType1" use="normalize-space(value1)"/>
<xsl:template match="dataType2[key('kType1', normalize-space(value1))]">
<data>
<value2>
<xsl:value-of select="key('kType1', normalize-space(value1))/value2"/>
</value2>
<xsl:copy-of select="value3"/>
</data>
</xsl:template>
<xsl:template match="text()"/>
</xsl:stylesheet>
when applied on the provided XML document:
<myxml>
<dataType1>
<value1>
A1
</value1>
<value2>
A2
</value2>
</dataType1>
<dataType1>
<value1>
B1
</value1>
<value2>
B2
</value2>
</dataType1>
<dataType2>
<value1>
A1
</value1>
<value3>
A3
</value3>
</dataType2>
<dataType2>
<value1>
B1
</value1>
<value3>
B3
</value3>
</dataType2>
</myxml>
produces the wanted, correct result:
<data>
<value2>
A2
</value2>
<value3>
A3
</value3>
</data>
<data>
<value2>
B2
</value2>
<value3>
B3
</value3>
</data>
Upvotes: 1
Reputation: 167471
Here is an XSLT 2.0 stylesheet:
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
<xsl:key name="k1" match="dataType2" use="normalize-space(value1)"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* , node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="dataType1[key('k1', value1)]">
<data>
<xsl:apply-templates select="node() except value1, key('k1', normalize-space(value1))/*[not(self::value1)]"/>
</data>
</xsl:template>
<xsl:template match="dataType1[not(key('k1', normalize-space(value1)))] | dataType2"/>
</xsl:stylesheet>
When above stylesheet is applied on the input
<myxml>
<dataType1>
<value1>
A1
</value1>
<value2>
A2
</value2>
</dataType1>
<dataType1>
<value1>
B1
</value1>
<value2>
B2
</value2>
</dataType1>
<dataType2>
<value1>
A1
</value1>
<value3>
A3
</value3>
</dataType2>
<dataType2>
<value1>
B1
</value1>
<value3>
B3
</value3>
</dataType2>
</myxml>
with Saxon 9.4 then the result is
<?xml version="1.0" encoding="UTF-8"?><myxml>
<dataType1>
<value1>
A1
</value1>
<value2>
A2
</value2>
</dataType1>
<dataType1>
<value1>
B1
</value1>
<value2>
B2
</value2>
</dataType1>
</myxml>
With XSLT 1.0 you can't use a key inside of a match pattern so some more code is needed, I will add a sample later.
[edit] Here is an XSLT 1.0 stylesheet:
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:key name="k1" match="dataType2" use="normalize-space(value1)"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="dataType1">
<xsl:variable name="refs" select="key('k1', normalize-space(value1))"/>
<xsl:if test="$refs">
<data>
<xsl:apply-templates select="node()[not(self::value1)] | $refs/*[not(self::value1)]"/>
</data>
</xsl:if>
</xsl:template>
<xsl:template match="dataType2"/>
</xsl:stylesheet>
Upvotes: 1
Reputation: 1193
my proposal
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" encoding="UTF-8" indent="no" />
<xsl:template match="/">
<resultxml>
<xsl:for-each select="/myxml/dataType1">
<xsl:variable name="fk" select="value1" />
<data>
<xsl:copy-of select="value2" />
<xsl:copy-of select="/myxml/dataType2[value1 = $fk]/value3" />
</data>
</xsl:for-each>
</resultxml>
</xsl:template>
</xsl:stylesheet>
Upvotes: 1