Jake Ballard
Jake Ballard

Reputation: 43

XSLT - Delete node based on a child element's attribute?

I am trying to delete a node based on a combination of particular child element attribute values. In the example input below, I want to delete the entire 'cfb-score' node if the vis-rank rank and home-rank rank are both '0'. I have tried many expressions, but can't seem to come up with a solution. Some times I can get it to delete absolutely all of the <cfb-scores>. Sometimes it does nothing.

    <cfb-score>
    <gamecode code="201509030004" global-id="1526672"/>
    <source id="1"/>
    <gametype id="1" type="Regular Season" detail="" round="" round-name=""/>
    <gamestate status-id="4" status="Final" quarter="4" minutes="" seconds="" team-possession-id="" yards-from-goal="" down="" distance="" segment-number="4" active-state="false"/>
    <outcome-visit outcome-id="2" outcome="Loss" conf-outcome-id="0" conference-outcome="No game"/>
    <outcome-home outcome-id="1" outcome="Win" conf-outcome-id="0" conference-outcome="No game"/>
    <vis-name name="Braves" alias="Alc"/>
    <vis-conf conference="Southwestern Athletic" abbrev="SWAC" id="23"/>
    <vis-rank rank="0" playoff-rank=""/>
    <vis-score score="6" timeouts-left="0"/>
    <home-name name="Yellow Jackets" alias="GaTech"/>
    <home-conf conference="Atlantic Coast" abbrev="ACC" id="1"/>
    <home-rank rank="16" playoff-rank=""/>
    <home-score score="69" timeouts-left="2"/>
    </cfb-score>
    <cfb-score>
    <gamecode code="201509030202" global-id="1528079"/>
    <source id="1"/>
    <gametype id="1" type="Regular Season" detail="" round="" round-name=""/>
    <gamestate status-id="4" status="Final" quarter="4" minutes="" seconds="" team-possession-id="" yards-from-goal="" down="" distance="" segment-number="4" active-state="false"/>
    <outcome-visit outcome-id="2" outcome="Loss" conf-outcome-id="0" conference-outcome="No game"/>
    <outcome-home outcome-id="1" outcome="Win" conf-outcome-id="0" conference-outcome="No game"/>
    <vis-name name="Wildcats" alias="Vill"/>
    <vis-conf conference="Colonial Athletic Association" abbrev="CAA" id="98"/>
    <vis-rank rank="0" playoff-rank=""/>
    <vis-score score="15" timeouts-left="0"/>
    <home-name name="Huskies" alias="UConn"/>
    <home-conf conference="American Athletic Conference" abbrev="AAC" id="122"/>
    <home-rank rank="0" playoff-rank=""/>
    <home-score score="20" timeouts-left="2"/>
    </cfb-score>

I guess I should point out that the XML above is the OUTPUT of what my style-sheet is already doing, which involves a lot of pruning, some renaming, and a little restructuring. My full XSLT + a sample of the original input is below.

statxform.xslt:

<!--STATS.COM >> PADS XML TRANSFORMER -BY JAKE BALLARD 2015-->
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<!--Copy all nodes into the workspace-->
<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>
<!--Delete stuff we don't care about-->
<xsl:template match="team-city|team-code|quarter|record|date|time|local-game-date|local-time|week|coverage|bowl|stadium"/>
<!--We need to rename stuff in the visiting-team 
and home-team nodes with a unique prefix so they 
are still distinguishible after flattening-->
<!--Rename Visitor Children-->
<xsl:template match="visiting-team/team-name">
    <vis-name>
        <xsl:apply-templates select="@*|visiting-team/team-name"/>
    </vis-name>
</xsl:template>
<xsl:template match="visiting-team/team-conference">
    <vis-conf>
        <xsl:apply-templates select="@*|visiting-team/team-conference"/>
    </vis-conf>
</xsl:template>
<xsl:template match="visiting-team/team-rank">
    <vis-rank>
        <xsl:apply-templates select="@*|visiting-team/team-rank"/>
    </vis-rank>
</xsl:template>    
<xsl:template match="visiting-team/linescore">
    <vis-score>
        <xsl:apply-templates select="@*|visiting-team/linescore"/>
    </vis-score>
</xsl:template>
<!--Rename Home Children-->
<xsl:template match="home-team/team-name">
    <home-name>
        <xsl:apply-templates select="@*|home-team/team-name"/>
    </home-name>
</xsl:template>
<xsl:template match="home-team/team-conference">
    <home-conf>
        <xsl:apply-templates select="@*|home-team/team-conference"/>
    </home-conf>
</xsl:template>
<xsl:template match="home-team/team-rank">
    <home-rank>
        <xsl:apply-templates select="@*|home-team/team-rank"/>
    </home-rank>
</xsl:template>    
<xsl:template match="home-team/linescore">
    <home-score>
        <xsl:apply-templates select="@*|home-team/linescore"/>
    </home-score>
</xsl:template>
<!--Delete Parent Nodes for Visiting Team and Home Team, 
but keep contents under <cfb-score> so PADS has a unified table to peruse-->    
<xsl:template match="visiting-team" >
<xsl:apply-templates select="*" />
</xsl:template>
<xsl:template match="home-team" >
<xsl:apply-templates select="*" />
</xsl:template>
<xsl:template match="cfb-score/*[@rank = '0' ]"/>
<!--ROLL TIDE-->
</xsl:stylesheet>

In the last template, you can see my latest attempt at filtering the non-ranked games. It appears to do nothing.

input.xml sample:

<?xml version="1.0" encoding="UTF-8"?>
<sports-statistics>
<sports-scores>
<date year="2015" month="9" date="5" day="6"/>
<time hour="23" minute="32" second="09" timezone="Eastern" utc-hour="-4" utc-minute="00"/>
<version number="6"/>
<league global-id="16" name="College Football" alias="CFB" display-name=""/>
<season season="2015"/>
    <cfb-scores>
 <cfb-score>
   <date year="2015" month="9" date="3" day="4"/>
   <time hour="18" minute="00" timezone="Eastern" utc-hour="-4" utc-minute="00"/>
   <local-game-date year="2015" month="9" date="3" day="4"/>
   <local-time hour="18" minute="00"/>
   <week week="2"/>
   <gamecode code="201509030070" global-id="1526673"/>
   <coverage level="30"/>
   <source id="2"/>
   <gametype id="1" type="Regular Season" detail="" round="" round-name=""/>
   <stadium name="Bank of America Stadium" city="Charlotte" state="North Carolina" state-id="33" country-name="United States" country-id="1" id="1022" global-id="3098"/>
   <bowl id="0" name="" full-name=""/>
   <gamestate status-id="4" status="Final" quarter="4" minutes="" seconds="" team-possession-id="" yards-from-goal="" down="" distance="" segment-number="4" active-state="false"/>
   <outcome-visit outcome-id="2" outcome="Loss" conf-outcome-id="0" conference-outcome="No game"/>
   <outcome-home outcome-id="1" outcome="Win" conf-outcome-id="0" conference-outcome="No game"/>
   <visiting-team>
     <team-name name="Tar Heels" alias="UNC"/>
     <team-city city="North Carolina"/>
     <team-code id="6" global-id="3412" division="1"/>
     <team-conference conference="Atlantic Coast" abbrev="ACC" id="1"/>
     <team-rank rank="0" playoff-rank=""/>
     <record wins="0" losses="1" ties="0" pct=".000"/>
     <linescore score="13" timeouts-left="0">
        <quarter quarter="1" score="7"/>
        <quarter quarter="2" score="6"/>
        <quarter quarter="3" score="0"/>
        <quarter quarter="4" score="0"/>
     </linescore>
   </visiting-team>
   <home-team>
     <team-name name="Gamecocks" alias="SC"/>
     <team-city city="South Carolina"/>
     <team-code id="70" global-id="3475" division="1"/>
     <team-conference conference="Southeastern" abbrev="SEC" id="8"/>
     <team-rank rank="0" playoff-rank=""/>
     <record wins="1" losses="0" ties="0" pct="1.000"/>
     <linescore score="17" timeouts-left="2">
        <quarter quarter="1" score="0"/>
        <quarter quarter="2" score="10"/>
        <quarter quarter="3" score="0"/>
        <quarter quarter="4" score="7"/>
     </linescore>
   </home-team>
 </cfb-score>
 <cfb-score>
   <date year="2015" month="9" date="3" day="4"/>
   <time hour="18" minute="00" timezone="Eastern" utc-hour="-4" utc-minute="00"/>
   <local-game-date year="2015" month="9" date="3" day="4"/>
   <local-time hour="18" minute="00"/>
   <week week="2"/>
   <gamecode code="201509030210" global-id="1530288"/>
   <coverage level="30"/>
   <source id="1"/>
   <gametype id="1" type="Regular Season" detail="" round="" round-name=""/>
   <stadium name="Bright House Networks Stadium" city="Orlando" state="Florida" state-id="9" country-name="United States" country-id="1" id="2213" global-id="5790"/>
   <bowl id="0" name="" full-name=""/>
   <gamestate status-id="4" status="Final" quarter="4" minutes="" seconds="" team-possession-id="" yards-from-goal="" down="" distance="" segment-number="4" active-state="false"/>
   <outcome-visit outcome-id="1" outcome="Win" conf-outcome-id="0" conference-outcome="No game"/>
   <outcome-home outcome-id="2" outcome="Loss" conf-outcome-id="0" conference-outcome="No game"/>
   <visiting-team>
     <team-name name="Golden Panthers" alias="FIU"/>
     <team-city city="FIU"/>
     <team-code id="2307" global-id="5090" division="1"/>
     <team-conference conference="Conference USA" abbrev="CUSA" id="72"/>
     <team-rank rank="0" playoff-rank=""/>
     <record wins="1" losses="0" ties="0" pct="1.000"/>
     <linescore score="15" timeouts-left="1">
        <quarter quarter="1" score="3"/>
        <quarter quarter="2" score="0"/>
        <quarter quarter="3" score="6"/>
        <quarter quarter="4" score="6"/>
     </linescore>
   </visiting-team>
   <home-team>
     <team-name name="Knights" alias="UCF"/>
     <team-city city="UCF"/>
     <team-code id="210" global-id="3615" division="1"/>
     <team-conference conference="American Athletic Conference" abbrev="AAC" id="122"/>
     <team-rank rank="0" playoff-rank=""/>
     <record wins="0" losses="1" ties="0" pct=".000"/>
     <linescore score="14" timeouts-left="0">
        <quarter quarter="1" score="7"/>
        <quarter quarter="2" score="7"/>
        <quarter quarter="3" score="0"/>
        <quarter quarter="4" score="0"/>
     </linescore>
   </home-team>
 </cfb-score>
 </cfb-scores>
 </sports-scores>
 </sports-statistics>

Upvotes: 0

Views: 118

Answers (1)

michael.hor257k
michael.hor257k

Reputation: 117165

(Edited)

I want to delete the entire 'cfb-score' node if the 'vis-rank rank' and 'home-rank rank' are both '0'.

[groan] Why don't you formulate the requirement with respect to the input? That is:

Delete the cfb-score node if @rank is 0 in both visiting-team/team-rank and home-team/team-rank.

Which is easy to achieve using:

<xsl:template match="cfb-score[visiting-team/team-rank/@rank=0 and home-team/team-rank/@rank=0]"/>

BTW, your stylesheet has this comment next to the identity transform template:

<!--Copy all nodes into the workspace-->

That is a misconception. There is no "workspace" here. The template establishes a default rule, which other templates with higher priority may override. Eventually each node is processed only once, by the template that matches it best.

I am mentioning this because I believe it's the same misconception that caused the initial confusion here: the stylesheet reads only the input.

Upvotes: 1

Related Questions