Reputation: 5471
I am trying to update one node's attribute based on other node's value.
My XML:
<Report>
<Action rID="T4">
<Step rID="T5">
<Obj ><![CDATA[BAR]]></Obj>
<Details ><![CDATA[Total files to compare = 1]]></Details>
<Time><![CDATA[05/06/2015 - 20:41:07]]></Time>
<TimeTick>1433533267</TimeTick>
<NodeArgs eType="User" icon="5" nRep="8" Source="Action1" status="Done" SourceLine="-1" >
<Disp><![CDATA[BAR]]></Disp>
</NodeArgs>
</Step>
<Step rID="T7">
<Obj ><![CDATA[File 1 : Passed]]></Obj>
<Details ><![CDATA[Baseline = C:\Baseline\BAR\1759982021.xml
Outbound = C:\Outbound\BAR\1759982021.xml]]></Details>
<Time><![CDATA[05/06/2015 - 20:41:07]]></Time>
<TimeTick>1433533267</TimeTick>
<NodeArgs eType="User" icon="5" nRep="10" status="Passed" Source="Action1" SourceLine="-1" >
<Disp><![CDATA[File 1 : Passed]]></Disp>
</NodeArgs>
</Step>
<Step rID="T9">
<Obj ><![CDATA[PASS]]></Obj>
<Details ><![CDATA[]]></Details>
<Time><![CDATA[05/06/2015 - 20:41:08]]></Time>
<TimeTick>1433533268</TimeTick>
<NodeArgs eType="User" icon="5" nRep="12" status="Information" Source="Action1" SourceLine="-1" >
<Disp><![CDATA[PASS]]></Disp>
</NodeArgs>
</Step>
<Step rID="T71">
<Obj><![CDATA[MSP]]></Obj>
<Details><![CDATA[Total files to compare = 1]]></Details>
<Time><![CDATA[06/06/2015 - 20:58:02]]></Time>
<TimeTick>1433620682</TimeTick>
<NodeArgs eType="User" icon="5" nRep="74" Source="Action1" SourceLine="-1">
<Disp><![CDATA[MSP]]></Disp>
</NodeArgs>
</Step>
<Step rID="T72">
<Obj><![CDATA[File 1 : Passed]]></Obj>
<Details><![CDATA[Baseline = C:\Baseline\MSP\G82164M1225983TN000073914GEU9.xml
Outbound = C:\Outbound\MSP\G82164M1225983TN000073914GEU9.xml]]>
</Details>
<Time><![CDATA[06/06/2015 - 20:58:02]]></Time>
<TimeTick>1433620682</TimeTick>
<NodeArgs eType="User" icon="5" nRep="75" status="Passed" Source="Action1" SourceLine="-1">
<Disp><![CDATA[File 1 : Failed]]></Disp>
</NodeArgs>
</Step>
<Step rID="T73"><Obj> <![CDATA[FAIL]]></Obj>
<Details><![CDATA[]]></Details>
<Time><![CDATA[06/06/2015 - 20:58:02]]></Time>
<TimeTick>1433620682</TimeTick>
<NodeArgs eType="User" icon="5" nRep="76" status="Information" Source="Action1" SourceLine="-1">
<Disp><![CDATA[FAIL]]></Disp>
</NodeArgs>
</Step>
</Action>
</Report>
My output would be HTML. In my XML, there may be numerous blocks of Steps. For each block of steps, there would only be one Done and Information steps. So for each block of Done steps, the Information step informs if the block is PASS/FAIL. Hence i wanted to transform the XML to XML and then to HTML without hardcoding the CDATA.
Step/NodeArgs[@status='Information']/Disp = PASS
then Step/NodeArgs[@status='Done']/Disp
should be PASSBAR
.Even if I can change Status = Done
to Status = PASSDone
, that would also be useful.
My XSL so far
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output encoding="utf-8" method="html" omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/Report/Action">
<html>
<head>
<style type="text/css">
body { font-family:Tahoma; font-size:9pt; }
h2 {color: #b48608; font-style: italic; text-align: center; text-decoration: underline;}
table { table-layout: auto; }
table, th, td { font-family:Tahoma; font-size:9pt; padding:5px; border-collapse:collapse; vertical-align:top; border:1px solid black; white-space:nowrap; }
th, tr.Venue { text-align:left; background-color:#D3D3D3; font-weight: bold; }
td.Passed { font-size:11pt; color:Green; text-align:center; }
td.Failed { font-size:11pt; color:Red; text-align:center; }
tr.Passed { background-color:#AAEEAA; font-weight:bold; }
tr.Failed { background-color:#FFAAAA; font-weight:bold; }
</style>
</head>
<body>
<table>
<th>Venues</th>
<th>Status</th>
<xsl:variable name="VenueTestStatus" select="Step/NodeArgs[@status='Information']/Disp"/>
<xsl:variable name="VenueName" select="Step/NodeArgs[@status='Done']/Disp"/>
<xsl:for-each select="$VenueTestStatus">
<xsl:variable name="i" select="position()"/>
<tr>
<xsl:if test="$VenueTestStatus[$i]='PASS'">
<xsl:attribute name="class">Passed</xsl:attribute>
</xsl:if>
<xsl:if test="$VenueTestStatus[$i]='FAIL'">
<xsl:attribute name="class">Failed</xsl:attribute>
</xsl:if>
<td>
<a>
<xsl:attribute name="href">
<xsl:value-of select="concat('#',$VenueName[$i])" />
</xsl:attribute>
<xsl:value-of select="$VenueName[$i]" />
</a>
</td>
<td>
<xsl:value-of select="$VenueTestStatus[$i]" />
</td>
</tr>
</xsl:for-each>
</table>
<br/>
<hr/>
<br/>
<table>
<xsl:for-each select="Step">
<xsl:if test="NodeArgs/@status != 'Information'">
<tr>
<xsl:variable name="IsVenueRow">
<xsl:value-of select="NodeArgs/Disp" disable-output-escaping="no"/>
</xsl:variable>
<xsl:if test="not(starts-with($IsVenueRow, 'File'))">
<xsl:attribute name="class">Venue</xsl:attribute>
</xsl:if>
<td>
<xsl:variable name="StatusSymbol">
<xsl:value-of select="NodeArgs/@status" disable-output-escaping="no"/>
</xsl:variable>
<xsl:attribute name="class">
<xsl:value-of select="$StatusSymbol" />
</xsl:attribute>
<xsl:choose>
<xsl:when test="NodeArgs/@status = 'Passed'">
<xsl:text>✔</xsl:text>
</xsl:when>
<xsl:when test="NodeArgs/@status = 'Failed'">
<xsl:text>✘</xsl:text>
</xsl:when>
</xsl:choose>
</td>
<td>
<xsl:choose>
<xsl:when test="not(starts-with($IsVenueRow, 'File'))">
<a>
<xsl:attribute name="name">
<xsl:value-of select="$IsVenueRow" />
</xsl:attribute>
<xsl:value-of select="$IsVenueRow" />
</a>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$IsVenueRow" />
</xsl:otherwise>
</xsl:choose>
</td>
</tr>
</xsl:if>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
Upvotes: 0
Views: 150
Reputation: 89325
One possible XSL 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:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Action[Step/NodeArgs[@status='Information']/Disp = 'PASS']/Step/NodeArgs[@status='Done']/Disp">
<xsl:copy>
<xsl:text><![CDATA[PASSBAR]]></xsl:text>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Brief explanation :
<xsl:template match="node()|@*">
) copy every node as it is in the source XMLStep/NodeArgs[@status='Done']/Disp
elements where corresponding Step/NodeArgs[@status='Information']/Disp
element value equals "PASS"
, and replace the selected Disp
element value with <![CDATA[PASSBAR]]>
in the output XML.Upvotes: 1
Reputation: 11223
I think you want an identity transform, then build <Disp/>
based on your criteria:
<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:template match="node()|@*" >
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Disp">
<Disp>
<xsl:choose>
<xsl:when test="../../NodeArgs[@status='Information']">
PASS
</xsl:when>
<xsl:when test="../../NodeArgs[@status='Done']">
PASSBAR
</xsl:when>
<xsl:otherwise>
<!-- Copy this (Disp) tree as is -->
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:otherwise>
</xsl:choose>
</Disp>
</xsl:template>
</xsl:stylesheet>
This is the identity transform part:
<xsl:template match="node()|@*" >
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
by itself, it would just copy the source document as it was.
By matching on <Disp/>
:
<xsl:template match="Disp">
we can stop the processor from just copying <Disp/>
and interject our own version of it:
<Disp>
<xsl:choose>
<xsl:when test="...">
and if nothing matches our <xsl:when/>
conditions, we start the identity transform again:
<xsl:otherwise>
<!-- Copy this (Disp) tree as is -->
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:otherwise>
to continue with the node/attribute-for-node/attribute copy.
Upvotes: 0