Andreas G.
Andreas G.

Reputation: 3

How to exclude xml object using xslt with dependencies

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

Answers (2)

Andreas G.
Andreas G.

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

Daniel Haley
Daniel Haley

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

Related Questions