3

xsl: I need to split and get the X position param, @class attribute 2nd param:

Input XML:

<root>
    <div class="zone zona_central ui-sortable">
        <div class="region contenedor_3col ui-sortable">
            <div style="position: relative; left: 0px; top: 0px;" class="destacado">
                <p class="id_contenido">567662</p>
                <p class="tipo_contenido">destacado</p>
                <p class="titulo">destacado: Home Actualidad ES</p>
            </div>
        </div>
    </div>
</root>

output XML that I NEED:

<zone type="zona_central">
    <region type="contenedor_3col">
        <destacado>
            <id_contenido>567662</id_contenido>
            <tipo_contenido>destacado</tipo_contenido>
            <titulo>destacado: Home Actualidad ES</titulo>
        </destacado>
    </region>
</zone>

i have this xsl:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/root">    
    <xsl:for-each select="div[contains(@class, 'zone')]">       
        <zone style="">
            <xsl:for-each select="div[contains(@class, 'region')]">
                <region style="">
                    <xsl:for-each select="div[contains(@class, 'destacado')]">
                        <destacado>                         
                            <id_contenido><xsl:value-of select="p[@class='id_contenido']"/></id_contenido>
                            <tipo_contenido><xsl:value-of select="p[@class='tipo_contenido']"/></tipo_contenido>
                            <titulo><xsl:value-of select="p[@class='titulo']"/></titulo>                            
                        </destacado>
                    </xsl:for-each>
                </region>
            </xsl:for-each>                             
        </zone>
    </xsl:for-each>
</xsl:template> 
</xsl:stylesheet>

output XML that I HAVE with previous XSL, i don't know how i can get second param of CLASS ATTRIBUTE :(

<zone type="">
    <region type="">
        <destacado>
            <id_contenido>567662</id_contenido>
            <tipo_contenido>destacado</tipo_contenido>
            <titulo>destacado: Home Actualidad ES</titulo>
        </destacado>
    </region>
</zone>

Solution:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/root">    
    <xsl:for-each select="div[contains(@class, 'zone')]">       
        <xsl:element name="zone">
            <xsl:attribute name="type">
                <xsl:value-of select="substring-before(substring-after(@class, ' '), ' ')"/>
            </xsl:attribute>            
            <xsl:for-each select="div[contains(@class, 'region')]">
                <xsl:element name="region">
                    <xsl:attribute name="type">
                        <xsl:value-of select="substring-before(substring-after(@class, ' '), ' ')"/>
                    </xsl:attribute>

                    <xsl:for-each select="div[contains(@class, 'destacado')]">
                        <destacado>                         
                            <id_contenido><xsl:value-of select="p[@class='id_contenido']"/></id_contenido>
                            <tipo_contenido><xsl:value-of select="p[@class='tipo_contenido']"/></tipo_contenido>
                            <titulo><xsl:value-of select="p[@class='titulo']"/></titulo>                            
                        </destacado>
                    </xsl:for-each>
                </xsl:element>              
            </xsl:for-each>                             
        </xsl:element>
    </xsl:for-each>
</xsl:template> 
</xsl:stylesheet>
ZiTAL
  • 3,466
  • 8
  • 35
  • 50

2 Answers2

4

A more generic XSLT 1.0 solution with templates.

<xsl:template match="root">
  <xsl:apply-templates select="*"/>
</xsl:template>

<xsl:template match="*[@class]">
  <xsl:variable name="name">
    <xsl:choose>
      <xsl:when test="contains(@class, ' ')">
        <xsl:value-of select="substring-before(@class, ' ')"/>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="@class"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:variable>
  <xsl:variable name="type">
    <xsl:variable name="tail" select="substring-after(@class, ' ')"/>
    <xsl:choose>
      <xsl:when test="contains($tail, ' ')">
        <xsl:value-of select="substring-before($tail, ' ')"/>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="$tail"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:variable>
  <xsl:element name="{$name}">
    <xsl:if test="string($type)">
      <xsl:attribute name="type">
        <xsl:value-of select="$type"/>
      </xsl:attribute>
    </xsl:if>
    <xsl:apply-templates/>
  </xsl:element>
</xsl:template>

If you have elements other than root that do not have a class attribute, add a template for them.

XSLT 2.0 solution is:

<xsl:template match="root">
  <xsl:apply-templates select="*"/>
</xsl:template>

<xsl:template match="*[@class]">
  <xsl:variable name="class" select="tokenize(@class, '\s')"/>
  <xsl:element name="{$class[1]}">
    <xsl:if test="count($class) > 1">
      <xsl:attribute name="type" select="$class[2]"/>
    </xsl:if>
    <xsl:apply-templates/>
  </xsl:element>
</xsl:template>
jelovirt
  • 5,844
  • 8
  • 38
  • 49
  • +1 for generality and for showing the XSLT 2.0 answer even tho the OP is currently using XSLT 1.0. – LarsH Jun 02 '11 at 13:45
3

You could use substring-before() and substring-after() to split the class attribute's value at the spaces. E.g.

substring-before(substring-after(@class, ' '), ' ')

would give the second token in @class. This assumes that your tokens are separated by single spaces (not general "whitespace"). In your code, you would put this within an Attribute Value Template :

<zone type="{substring-before(substring-after(@class, ' '), ' ')}">

XSLT 2.0, if you can use that, has the more flexible tokenize() function, e.g.

tokenize(@class, ' ')[2]

again returns the second, space-separated token, but the pattern (' ') for separator can be any regexp.

LarsH
  • 27,481
  • 8
  • 94
  • 152
  • it works but i don't know how i can put it inside of attribute :facepalm: – ZiTAL Jun 02 '11 at 03:53
  • @ZiTAL: ok, I added a sample to show how to put it into your XSLT in an ATV. – LarsH Jun 02 '11 at 03:56
  • i write the solution before you post, tokenize doen't work for me but the first one YES, thank you very much, i put the solution at the bottom of question :) – ZiTAL Jun 02 '11 at 04:02
  • @ZiTAL: sure, you can use `` and ``, but it is a lot more verbose. – LarsH Jun 02 '11 at 04:19
  • 3
    You can use `normalize-space` to make this solution work even if the `class` attribute contains leading or trailing whitespace, tabs, multiple spaces in a row, or the like. For instance, if `class` contains the value `" strange spacing here "`, you could extract "spacing" with the expression `substring-before(substring-after(normalize-space(@class), ' '), ' ')`. – markusk Jun 02 '11 at 06:18