Jeroen Beerstra
Jeroen Beerstra

Reputation: 190

xslt transformation from xhtml to custom xml

For a custom application I need to transform xhtml to (custom) xml. After some experimentation I decided to give php5's XSLT functionality a try, but so far I'm unable to transform nested p tags to their xml equivalent.

Basicly we have code like this:

<p>Some text</p>
<ol>
   <li><p>Some more text</p></li>
   ..
</ol>

This needs to be transformed to:

<par>Some text</par>
<list>
  <li><par>Some more text</par></li>
  ..
</list>

The real problem is: I need to include inline tags, so xsl:value-of is no option and instead I use xsl:copy-of. So far I have templates for ol|ul and p and the result is this:

<par>Some text</par>
<list>
  <li><p>Some more text</p></li>
  ..
</list>

Anybody some tips how to achieve what I really want just by using a more complex xslt?

Upvotes: 1

Views: 386

Answers (3)

Robert Rossney
Robert Rossney

Reputation: 96920

If you start with the identity transform, the general pattern for transforming elements with one name into elements of another is this:

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

Two things of note:

  1. Generally, unless you know for certain that the element you're transforming has no attributes (or you actively intend to strip off the attributes), you should use the select attribute shown; don't just use <xsl:apply-templates/>. Attributes aren't child nodes, and thus applying templates without a select attribute doesn't apply templates to them.

  2. Unless you really enjoy typing, there is almost never a reason to use <xsl:element>. The exception is when you're generating the output element's name programmatically.

Which, actually, you could do if you wanted to get all fancy-shmancy:

<xsl:template match="*">
   <xsl:variable name="new_name">
      <xsl:when test="name()='p'>par</xsl:when>
      <xsl:when test="name()='ol'>list</xsl:when>
      <xsl:when test="name()='li'>item</xsl:when>
      <xsl:otherwise><xsl:value-of select="name()"/></xsl:otherwise>
   </xsl:variable>
   <xsl:element name="{$new_name}">
      <xsl:apply-templates select="@*|node()"/>
   </xsl:element>
</xsl:template>

Upvotes: 1

dacracot
dacracot

Reputation: 22398

Here you go...

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
    <xsl:output method="xml" indent="yes"/>
    <!-- ============================================== -->
    <xsl:template match="/">
        <xsl:apply-templates/>
    </xsl:template>
    <!-- ============================================== -->
    <xsl:template match="p">
        <xsl:element name="par">
            <xsl:apply-templates/>
        </xsl:element>
    </xsl:template>
    <!-- ============================================== -->
    <xsl:template match="ol">
        <xsl:element name="list">
            <xsl:apply-templates/>
        </xsl:element>
    </xsl:template>
    <!-- ============================================== -->
    <xsl:template match="li">
        <xsl:element name="li">
            <xsl:apply-templates/>
        </xsl:element>
    </xsl:template>
    <!-- ============================================== -->
</xsl:stylesheet>

Upvotes: 1

Oded
Oded

Reputation: 499382

You can use nested <xsl:element> tags to output inline tags as you propose.

Something like:

<xsl:element name="li">
  <xsl:element name="p">
   some text
  </xsl:element>
</xsl:element>

Upvotes: 0

Related Questions