Reputation: 3
I've the following input xml
<?xml version="1.0" encoding="UTF-8"?>
<root>
<technicalAssets>
<composedId>
<id>A1</id>
</composedId>
<technicalName>TestA1</technicalName>
<prerequisites>
<technicalAssetPrerequisites>
<technicalAssetIds>
<composedId>
<id>B1</id>
</composedId>
</technicalAssetIds>
</technicalAssetPrerequisites>
</prerequisites>
</technicalAssets>
<technicalAssets>
<composedId>
<id>A2</id>
</composedId>
<technicalName>TestA2</technicalName>
</technicalAssets>
<technicalAssets>
<composedId>
<id>B1</id>
</composedId>
<technicalName>TestB1</technicalName>
</technicalAssets>
<products>
<entitlementRules>
<technicalAssetId>
<composedId>
<id>A1</id>
</composedId>
</technicalAssetId>
</entitlementRules>
</products>
</root>
I would like to apply an XSLT transformation that lists only the technicalAssets
that are either referenced in the products or those which are referenced by them.
How can I achieve that? Expected Output:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<technicalAssets>
<composedId>
<id>A1</id>
</composedId>
<technicalName>TestA1</technicalName>
<prerequisites>
<technicalAssetPrerequisites>
<technicalAssetIds>
<composedId>
<id>B1</id>
</composedId>
</technicalAssetIds>
</technicalAssetPrerequisites>
</prerequisites>
</technicalAssets>
<technicalAssets>
<composedId>
<id>B1</id>
</composedId>
<technicalName>TestB1</technicalName>
</technicalAssets>
<products>
<entitlementRules>
<technicalAssetId>
<composedId>
<id>A1</id>
</composedId>
</technicalAssetId>
</entitlementRules>
</products>
</root>
I'm currently using the following xslt, but it copies the node technicalAssets inside product node where the technicalAssetId appears. That is not what I need.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="technicalAssets"/>
<xsl:template match="technicalAssetId">
<xsl:copy>
<xsl:apply-templates/>
<xsl:for-each select="/root/technicalAssets[composedId/id/text() = current()/composedId/id/text()]">
<xsl:copy-of select="."/>
</xsl:for-each>
</xsl:copy>
</xsl:template>
<xsl:template match="node() | @*">
<xsl:copy>
<xsl:apply-templates select="node() | @*"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Upvotes: 0
Views: 82
Reputation: 3
I've solved it like this now:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="technicalAssets[composedId/id != //entitlementRules/technicalAssetId/composedId/id]"/>
</xsl:stylesheet>
Upvotes: 0
Reputation: 52888
You could use an xsl:key
to select all composedId/id
's that aren't direct children of technicalAssets
.
You can then use key()
in a predicate in a template that matches technicalAssets
to check to see if there isn't a key that matches composedId/id
.
So instead of trying to copy what you want to keep, you remove what you don't want to keep.
Example...
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="ids" match="*[not(self::technicalAssets)]/composedId/id" use="."/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="technicalAssets[not(key('ids',composedId/id))]"/>
</xsl:stylesheet>
Fiddle: http://xsltfiddle.liberty-development.net/6rewNya
Upvotes: 1