Xsl Preserving output text order

I’m using XSLT to convert xml documents that contains complex structure of data, free text etc. into a HTML document.
Documents that I process can be with or without structural items, and if present structural tags can be nested arbitrarily. Data tags can refers to
any type of goods, so I don’t know in advance the content of the XML doc.

Documents looks like

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<?xml-stylesheet type="text/xsl" href="my.xsl"?>
  <elementStructure type="tag">
     The following items are cars: 
    <Car id="12" type="data" value="Ferrari"> this is a sport car.
     <structureLev2 type="tag">
       <Model id="432" value="458" />
      <Rim id="55" value="wheels of car" type="data"> 
      <Tire id="234" value="front" type="data">
       <Note id="33" value="special tire" type="data"/> size of front is less that rear.
       <TypeTire id="44" value="radial tire" type="data"/>
  <elementStructure type="tag">
    Other text
    <Car id="22" type="data" value="Ford">
      this is a family car.
      <structureLev2 type="tag">
        <Model id="872" value="Mondeo" />
        <Rim id="45" value="wheels of car" type="data">
          <Tire id="734" value="front" type="data">
            <Note id="63" value="normal tire" type="data"/> spare tire could be replaced by run-flat.
            <TypeTire id="84" value="tubeless tire" type="data"/>

The desiderata HTML document should looks something like:

 Some text....
  <li>Car - Ferrari (this is a sport car.)</li>
  <li>Rim - wheels of the car:</li>
    <li>Tire - front Note: special tire (size of front is less than rear).</li>
    <li>TypeTire - radial tire

Actually I don’t know if it is a good solution but since I don’t know if my xml contains or not structural tags, I used a “switch” to choose between two main templates.

<?xml version="1.0"?>
 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
 <xsl:output method="html"/>
 <xsl:strip-space elements="*"/>
 <xsl:template match="doc">
     <xsl:when test="//*[@type='tag']">
       <xsl:call-template name="stuct" />
       <xsl:call-template name="plain" />
 <xsl:template match="doc/*[@type='tag']" name="stuct">
   <xsl:value-of select="text()"/>
    <xsl:apply-templates mode="str"/>
 <xsl:template match="doc/*[@type='tag']" mode="str">
    <xsl:call-template name="dataElem"/>
    <xsl:apply-templates mode="str"/>
 <xsl:template match="doc/*[@type='data']" name="dataElem">
  <xsl:for-each select="descendant::node()[not(@type='tag')]">
   <xsl:value-of select="name(.)"/>: <xsl:value-of select="@value" /> (<xsl:value-of select="text()"/>)<br/>
 <xsl:template match="doc/*[@type='data']" name="plain">
    <xsl:call-template name="dataElem" />

Among all the problems that I got, starting from the code itself 🙂 one problem that arises is about the text. I want that the text beetween tags possibly appears one time only, and after the “parsed” element. Is it possible?

Source: New Questions

1 Comment

  1. Digin Dominic

    It is difficult to discern the logic of the required transformation from a single, incomplete example. Moreover, I suspect that the provided output is actually incorrect – as there is no apparent reason for promoting “Rim” to be a sibling of “Car’ when in the original document it is a child thereof.

    Perhaps something like this could work for you:

    XSLT 1.0

    When applied to your example input, the result will be:

    The following items are cars:

    Car - Ferrari (this is a sport car.)

    Rim - wheels of car

    Tire - front (size of front is less that rear.)

    Note - special tire
    TypeTire - radial tire

    Other text

    Car - Ford (this is a family car.)

    Rim - wheels of car

    Tire - front (spare tire could be replaced by run-flat.)

    Note - normal tire
    TypeTire - tubeless tire


Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.