bdanger
bdanger

Reputation: 63

xslt Converting text nodes to attributes

I have made an xslt script that will take any xml script and convert the text nodes within the elements to attributes of those elements. The elements will only have child elements or text nodes but wouldnt have attributes or anything else e.g

 <example>
    <A>12</A>
     <B></B>
  <example>

should end up looking like:

  <example>
    <A Val='12'></A>
    <B></B>
  <example>

here is my script it basically has two ifs saying if the element has a text node make a new element with the same name but make the text an attribute otherwise if it doesnt just copy the element

<xsl:stylesheet version="1.0"  xmlns:xsl="http://www.w3.org/1999/XSL  /Transform">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
         <xsl:for-each select="*">
                <xsl:when test="./text()"/>
                           <xsl:element name="{local-name()}" >
                        <xsl:attribute name="Val">
                              <xsl:value-of select="normalize- space(text())"/>
                         </xsl:attribute>
                    </xsl:element>
                    </xsl:when>
                    <xsl:otherwise>
                             <xsl:copy-of select="."/>
                   </xsl:otherwise>         
             </xsl:for-each>
    </xsl:template>

The xmls will be more complex than my example.

Upvotes: 0

Views: 1280

Answers (1)

Daniel Haley
Daniel Haley

Reputation: 52858

Instead of doing an xsl:for-each (pull approach), I'd use a push approach...

XML Input

<example>
    <A>12</A>
    <A>some a text <B>some b text</B> more a text</A>
    <B></B>
</example>

XSLT 1.0

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

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

  <xsl:template match="*[text()]">
    <xsl:variable name="text">
      <xsl:apply-templates select="text()"/>
    </xsl:variable>
    <xsl:copy>
      <xsl:attribute name="Val">
        <xsl:value-of select="normalize-space($text)"/>
      </xsl:attribute>
      <xsl:apply-templates select="@*|*"/>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

XML Output

<example>
   <A Val="12"/>
   <A Val="some a text more a text">
      <B Val="some b text"/>
   </A>
   <B/>
</example>

Upvotes: 2

Related Questions