I have a very simple input-file:
<?xml version="1.0" encoding="UTF-8"?>
<STEP-ProductInformation>
<Products>
<Product>
<Values>
<ValueGroup AttributeID="tec_att_ignore_basic_data_text">
<Value ID="Y" QualifierID="en-US">Yes</Value>
<Value ID="Y" QualifierID="de-DE">Yes</Value>
</ValueGroup>
<ValueGroup AttributeID="prd_att_description">
<Value QualifierID="en-US">
english text
</Value>
<Value QualifierID="de-DE">
german text
</Value>
</ValueGroup>
</Values>
</Product>
</Products>
</STEP-ProductInformation>
In my XSL transformation, I want to delete every Value
in the prd_att_description
-Value group, if there is a N
in the attribute: ignore_basic_data_text
.
This works fine so far, but if everything is deleted (so that there are no childs), I want to remove the whole ValueGroup as well.
My approach:
<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="*"/>
<xsl:key name="lov" match="ValueGroup[@AttributeID='tec_att_ignore_basic_data_text']/Value" use="@QualifierID" />
<!-- identity transform -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="ValueGroup[@AttributeID='prd_att_description']/Value[key('lov', @QualifierID)/@ID='Y']"/>
<xsl:template match="ValueGroup[@AttributeID='prd_att_description' and not(Value)]"/>
</xsl:stylesheet>
It simply isn't removing the empty <ValueGroup>
. I tried it with counting elements, with normalize-space(), with different templates, with different modes, but without success. I would assume the 2nd template isn't running over the result of the first template.
Any hints?
Well, the current version of XSLT is 3.0, there you could use xsl:where-populated
as follows:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="3.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all"
expand-text="yes">
<xsl:strip-space elements="*"/>
<xsl:output indent="yes"/>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:key name="lov" match="ValueGroup[@AttributeID='tec_att_ignore_basic_data_text']/Value" use="@QualifierID" />
<xsl:template match="ValueGroup[@AttributeID='prd_att_description']/Value[key('lov', @QualifierID)/@ID='Y']"/>
<xsl:template match="ValueGroup[@AttributeID='prd_att_description']">
<xsl:where-populated>
<xsl:next-match/>
</xsl:where-populated>
</xsl:template>
</xsl:stylesheet>
I don't think there is a direct equivalent in XSLT 1/2 but for your use case I think you basically want the empty template for ValueGroup
as
<xsl:template match="ValueGroup[@AttributeID='prd_att_description'][not(Value[not(key('lov', @QualifierID)/@ID='Y')])]"/>
and of course keep your
<xsl:template match="ValueGroup[@AttributeID='prd_att_description']/Value[key('lov', @QualifierID)/@ID='Y']"/>