0

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.

  • if 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>&#10004;</xsl:text>
                      </xsl:when>
                      <xsl:when test="NodeArgs/@status = 'Failed'">
                        <xsl:text>&#10008;</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>
0

2 Answers 2

1

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 :

  1. Identity template (<xsl:template match="node()|@*">) copy every node as it is in the source XML
  2. The other template overrides the identity template rule. It is selecting Step/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.
Sign up to request clarification or add additional context in comments.

5 Comments

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.
@PankajJaju I can see that from your XML sample, and the XSLT in my answer worked for the same.
Now the XSLT you posted doesn't correspond to the XML sample. From the first glance, there is nothing match this template selector in your XML : /Report/Doc/DIter/Action. Try to keep focus on the main problem being asked here, I'm not going to check the entire XSLT you have
Actually, i posted only the relevant bit of the xml i am tranforming but forgot to update the xsl code before posting it in my question. Anyways, i have update the xsl code in the question
Still error when I run your XSL against the XML sample here : freeformatter.com/xsl-transformer.html . What's the problem that come when you try to accommodate this answer (just the 2nd xsl:template maybe) into your XSL?
0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.