2FaceMan
2FaceMan

Reputation: 483

Xsl:attribute Add Element based on child Element attribute value

I have to add Element Main/Years/Year/Notification/@UniqueId="27" & Main/Years/Year/@IsFailFlag = "Y" , Only if Main/Years/Year/Month/Extn/@Flag !=''. and I have to copy Main/Years/Year/Month for such cases.

XML
<?xml version="1.0" encoding="UTF-8"?>
<Main>
   <Years>
      <Year>
         <Month ActualDate="" Type="C" FailText="">
            <Extn Flag="A" />
            <Details>
               <Line A="a" B="3" C="1" />
            </Details>
         </Month>
         <Month ActualDate="" Type="C" FailText="">
            <Extn Flag="B" />
            <Details>
               <Line A="a" B="3" C="1" />
            </Details>
         </Month>
         <Month ActualDate="" Type="C" FailText="">
            <Extn Flag="" />
            <Details>
               <Line A="a" B="3" C="1" />
            </Details>
         </Month>
      </Year>
   </Years>
</Main>

My XSL

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
   <xsl:output method="xml" indent="yes" />
   <xsl:strip-space elements="*" />
   <xsl:template match="/">
      <LoadShipment>
         <xsl:for-each select="/Main/Years/Year/Month/Extn">
            <xsl:if test="@Flag != ''">
               <xsl:attribute name="IsFailFlag">
                  <xsl:value-of select="'Y'" />
               </xsl:attribute>
               <Notification>
                  <xsl:attribute name="UniqueId">
                     <xsl:value-of select="'27'" />
                  </xsl:attribute>
               </Notification>
               <xsl:copy-of select=".." />
            </xsl:if>
         </xsl:for-each>
      </LoadShipment>
   </xsl:template>
</xsl:stylesheet>

I am getting repeated Notification as its inside for loop and i cant move it out becuase then it will always get populated irrespective of the condition

Output

<?xml version="1.0" encoding="UTF-8"?>
<LoadShipment IsFailFlag="Y">
   <Notification UniqueId="27" />
   <Month ActualDate="" Type="C" FailText="">
      <Extn Flag="A" />
      <Details>
         <Line A="a" B="3" C="1" />
      </Details>
   </Month>
   <Notification UniqueId="27" />
   <Month ActualDate="" Type="C" FailText="">
      <Extn Flag="B" />
      <Details>
         <Line A="a" B="3" C="1" />
      </Details>
   </Month>
</LoadShipment>

Expected Output

<?xml version="1.0" encoding="UTF-8"?>
<LoadShipment IsFailFlag="Y">
   <Notification UniqueId="27" />
   <Month ActualDate="" Type="C" FailText="">
      <Extn Flag="A" />
      <Details>
         <Line A="a" B="3" C="1" />
      </Details>
   </Month>
    <Month ActualDate="" Type="C" FailText="">
      <Extn Flag="B" />
      <Details>
         <Line A="a" B="3" C="1" />
      </Details>
   </Month>
</LoadShipment>

Upvotes: 0

Views: 131

Answers (1)

JLRishe
JLRishe

Reputation: 101748

How's this:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output method="xml" indent="yes" />
  <xsl:strip-space elements="*" />

  <xsl:template match="/">
    <xsl:variable name="badMonths"
                  select="Main/Years/Year/Month[Extn/@Flag != '']" />

    <LoadShipment>
      <xsl:if test="$badMonths">
        <xsl:attribute name="IsFailFlag">Y</xsl:attribute>
        <Notification UniqueId="27" />

        <xsl:copy-of select="$badMonths" />
      </xsl:if>
    </LoadShipment>
  </xsl:template>

</xsl:stylesheet>

When run on your sample input, the result is:

<LoadShipment IsFailFlag="Y">
  <Notification UniqueId="27" />
  <Month ActualDate="" Type="C" FailText="">
    <Extn Flag="A" />
    <Details>
      <Line A="a" B="3" C="1" />
    </Details>
  </Month>
  <Month ActualDate="" Type="C" FailText="">
    <Extn Flag="B" />
    <Details>
      <Line A="a" B="3" C="1" />
    </Details>
  </Month>
</LoadShipment>

Or a different approach that's a little more "XSLT-esque" (same result):

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output method="xml" indent="yes" />
  <xsl:strip-space elements="*" />

  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()" />
    </xsl:copy>
  </xsl:template>

  <xsl:template match="/*">
    <xsl:variable name="badMonths"
                  select="Years/Year/Month[Extn/@Flag != '']" />

    <LoadShipment>
      <xsl:apply-templates select="(.)[$badMonths]" mode="failed" />
      <xsl:apply-templates select="$badMonths" />
    </LoadShipment>
  </xsl:template>

  <xsl:template match="*" mode="failed">
    <xsl:attribute name="IsFailFlag">Y</xsl:attribute>
    <Notification UniqueId="27" />
  </xsl:template>

</xsl:stylesheet>

Upvotes: 1

Related Questions