Quassnoi
Quassnoi

Reputation: 425401

Conditional XSLT transformation in PHP

I have a piece of XML data which I need to transform into WML.

It's something like this:

 <root>
  <category name="music"/>
  <subcategory name="classic"/>
  <subcategory name="rock"/>
  <subcategory name="Techno"/>
  <node type="music" subtype="classic" name="beethoven"/>
  <node type="music" subtype="classic" name="chopin"/>
  <record author="beethoven" name="moonlight sonata"/>
  …
 </root>

I cannot change the file structure.

Some Nokia mobile browsers cannot load lots of <card>'s into memory.

So, depending on the mobile browser, the WML page should be either a whole set of <card>'s, or some subset of <card>'s.

For instance, if I download a page with a normal browser, it should look like this:

<wml>
 <card id="TOC">
  <p><a href="#contents">Contents</a></p>
  <p><a href="#az">A-Z</a></p>
 </card>
 <card id="contents">
  <p><a href="#music">music</a></p>
  <p><a href="#video">video</a></p>
  <p><a href="#java">java</a></p>
 </card>
 <card id="az">
  <p><a href="#beethoven">beethoven</a></p>
  <p><a href="#chopin">chopin</a></p>
 </card>
 <card id="music">
  <p><a href="#classic">classic</a></p>
  <p><a href="#rock">rock</a></p>
  <p><a href="#Techno">Techno</a></p>
 </card>
 <card id="classic">
  <p><a href="#beethoven">beethoven</a></p>
  <p><a href="#chopin">chopin</a></p>
 </card>
 …
</wml>

, so that the user can browse without extra round-trips to the server.

However, when I use Nokia and visit the start page, the page should look like this:

http://example.com/

<wml>
 <card id="TOC">
  <p><a href="#contents">Contents</a></p>
  <p><a href="#az">A-Z</a></p>
 </card>
 <card id="contents">
  <p><a href="#music">music</a></p>
  <p><a href="#video">video</a></p>
  <p><a href="#java">java</a></p>
 </card>
 <card id="az">
  <p><a href="/beethoven">beethoven</a></p>
  <p><a href="/chopin">chopin</a></p>
 </card>
 <card id="music">
  <p><a href="/classic">classic</a></p>
  <p><a href="/rock">rock</a></p>
  <p><a href="/Techno">Techno</a></p>
 </card>
 <card id="video">
  <p><a href="/movies">Movies</a></p>
 </card>
 <card id="java">
  <p><a href="/games">Games</a></p>
 </card>
</wml>

, when I visit the href, it should show the inner contents:

http://example.com/classic

<wml>
 <card id="TOC">
  <p><a href="#contents">Contents</a></p>
  <p><a href="#az">A-Z</a></p>
 </card>
 <card id="contents">
  <p><a href="/music">music</a></p>
  <p><a href="/video">video</a></p>
  <p><a href="/java">java</a></p>
 </card>
 <card id="az">
  <p><a href="#beethoven">beethoven</a></p>
  <p><a href="#chopin">chopin</a></p>
 </card>
 <card id="classic">
  <p><a href="#beethoven">beethoven</a></p>
  <p><a href="#chopin">chopin</a></p>
 </card>
 …
</wml>

Basically, the XSLT should do the following things:

Is it possible to do in a single XSL file?

Upvotes: 0

Views: 262

Answers (3)

frankodwyer
frankodwyer

Reputation: 14048

My understanding is that XSL is turing complete so the answer to pretty much any 'is it possible?' question is going to be yes. The answer to 'are you going to like it?', maybe not so much :-)

A simple way to do it and keep it modular would to use <xsl:param> to pass in the control parameters, and <xsl:choose> to select the format you want to display, and then branch/delegate to specific templates or functions for each format.

Where your formats have things in common you can DRY it up by delegating those parts to their own templates or functions, reusing them in the higher level templates for the main formats. Divide and conquer basically.

edit: to be more specific about what I mean by delegating, I mean explicitly calling templates and parameterising them, e.g.:

   <xsl:call-template name="showcard">
     <xsl:with-param name="kind" select="nokia"/>
   </xsl:call-template>

With those templates in turn delegating to others, etc. You can also get a lot from value-of and apply-templates directing the flow to specific templates. Though your case is probably simpler, this may lead to more readable code.

Upvotes: 0

Ben Blank
Ben Blank

Reputation: 56572

I'd suggest creating variables which accumulatively count all the nodes of each "level" (type, subtype, title, …) and provide a parameter to your XSL indicating the maximum number of cards to generate. The XSL might look something like this:

<xsl:stylesheet …>
  <xsl:param name="max-cards" select="999999"/>

  <xsl:template match="/root">
    <!-- "2" here for the type/TOC cards -->
    <xsl:variable name="nSubs" select="2 + count(subcategory)"/>
    <xsl:variable name="nNodes" select="$nSubs + count(node)"/>
    <xsl:variable name="nRecs" select="$nNodes + count(record)"/>

    <!-- generate types & TOC here -->

    <xsl:if test="$nSubs < $max-cards">
        <!-- generate subtypes here -->
    </xsl:if>

    <xsl:if test="$nNodes < $max-cards">
        <!-- generate titles here -->
    </xsl:if>

    <xsl:if test="$nRecs < $max-cards">
        <!-- generate everything else here -->
    </xsl:if>
  </xsl:template>
</xsl:stylesheet>

Stylesheet parameters could be similarly used to restrict the generation of upper levels, but an example for that would be excessively long for SO. ^.^

Upvotes: 0

Pavel Minaev
Pavel Minaev

Reputation: 101595

I'm not sure what the question really is. As phrased, the answer is "yes, it is possible" - xsl:if and xsl:choose should be quite sufficient to handle all your conditions. You'll have to communicate restrictions (such as the fact that the result will go to a Nokia) to the stylesheet via parameters - see xsl:param.

Upvotes: 1

Related Questions