dinakar
dinakar

Reputation: 125

check element has value in xslt

how to get the value of an element in xslt. suppose my xml like this,

<comp>
 <link ref=1>1997</link>
 <link ref=2><?LINK 2008?></link>
</comp>

i need output like this,

<comp>
  <link ssref=1/><num>1997</num>
  <link ssref=2/><num>2008</num>
</comp>

if the link has value i need to get that value, if it has like this <?LINK 2008?> i just need year from that. i used following xsl but it's not working.

<xsl:template match ="link">
<xsl:element name ="{local-name(.)}">
  <xsl:attribute name ="sshref">
    <xsl:value-of select ="@ref"/>
  </xsl:attribute>
    </xsl:element>
<xsl:if test="text()">
  <xsl:element name ="num">
    <xsl:value-of select ="link"/>
  </xsl:element>
</xsl:if>
</template>

i know this xsl wrong i just posted for some reference. thanks in advance.

Upvotes: 0

Views: 3603

Answers (3)

Tomalak
Tomalak

Reputation: 338406

The simplest XSLT transformation you could do looks like this

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

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

  <xsl:template match="link/text() | link/processing-instruction()">
    <num><xsl:value-of select="normalize-space()" /></num>
  </xsl:template>

  <xsl:template match="link/@ref">
     <xsl:attribute name="ssref"><xsl:value-of select="."/></xsl:attribute>
  </xsl:template>
</xsl:stylesheet>

It transforms

<comp>
 <link ref="1">1997</link>
 <link ref="2"><?LINK 2008?></link>
</comp>

into the desired result.

<comp>
 <link ssref="1"><num>1997</num></link>
 <link ssref="2"><num>2008</num></link>
</comp>

Upvotes: 2

Tim C
Tim C

Reputation: 70648

Firstly, your XML isn't well-formed, as attributes should be enclosed in apostrophes or quotes, but I am guessing that may be a simple typo.

As for the specific issue is a processing-instruction, and so your xsl:if that checks for text() will not pick this up.

You've also got an issue where you do <xsl:value-of select="link" /> because your current context is already on the link element, and so this is looking for another link element that is the child of the current one. You probably just want want to do something like this

<xsl:value-of select="." />

So, you could re-write your template like so

<xsl:template match="link">
    <xsl:element name="{local-name(.)}">
        <xsl:attribute name="sshref">
            <xsl:value-of select="@ref"/>
        </xsl:attribute>
        <xsl:if test="text()|processing-instruction()">
            <xsl:element name="num">
                <xsl:apply-templates select="text()|processing-instruction()"/>
            </xsl:element>
        </xsl:if>
    </xsl:element>
</xsl:template>

<xsl:template match="processing-instruction()">
    <xsl:value-of select="."/>
</xsl:template>

However, it is worth noting it is often better to avoid the use of xsl:if elements, and use the power of template matching instead. Try this alternate XSLT instead.

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

   <xsl:template match="link[text()|processing-instruction()]">
      <link>
         <num>
            <xsl:apply-templates select="text()|processing-instruction()"/>
         </num>
      </link>
   </xsl:template>

   <xsl:template match="link/@ref">
      <xsl:attribute name="ssref">
         <xsl:value-of select="."/>
      </xsl:attribute>
   </xsl:template>

   <xsl:template match="processing-instruction()">
      <xsl:value-of select="."/>
   </xsl:template>

   <xsl:template match="@*|node()[not(self::processing-instruction())]">
      <xsl:copy>
         <xsl:apply-templates select="@*|node()"/>
      </xsl:copy>
   </xsl:template>
</xsl:stylesheet>

When applied to the following XMK

<comp>
   <link ref="1">1997</link>
   <link ref="2"><?LINK 2008?></link>
</comp>

The following is output:

<comp>
   <link sshref="1">
      <num>1997</num>
   </link>
   <link sshref="2">
      <num>2008</num>
   </link>
</comp>

Do note there is no need to use xsl:element unless you want a dynamically named element.

Upvotes: 3

John Bax
John Bax

Reputation: 447

Your XML is not well formatted, it should be like this:

<comp>
  <link ref="1">1997</link>
  <link ref="2"><?LINK 2008?></link>
</comp>

and then you can use the following XSLT to get your desired result:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="/">
    <xsl:element name="comp">
      <xsl:apply-templates/>
    </xsl:element>
  </xsl:template>
  <xsl:template match="comp/link">
    <xsl:element name="{local-name(.)}">
      <xsl:attribute name="sshref"><xsl:value-of select="@ref"/></xsl:attribute>
    </xsl:element>
    <xsl:if test="text()|processing-instruction()">
      <xsl:element name="num">
        <xsl:apply-templates select="text()|processing-instruction()"/>
      </xsl:element>
    </xsl:if>
  </xsl:template>
  <xsl:template match="processing-instruction()">
    <xsl:value-of select="."/>
  </xsl:template>
</xsl:stylesheet>

Upvotes: 1

Related Questions