0

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:

  • Accept some kind of a parameter of what is to be shown: the category, the subcategory etc.

  • Count the <card>'s that would be shown.

    1. If we load only types and TOC, we get 2 cards (we always show them)
      • If we load only types and subtypes, we get 10 cards.
      • If we load types, subtypes and titles, we show 100 cards.
      • If we load everything, we show 300 cards.

    Nokia cannot handle more than 120 cards, so we just stop on level 3.

    If XML changes and level 3 requires 130 cards, we should stop on level 2.

  • Don't show a <card> if it is below certain level

  • Replace the # (inner links) with / (outer links) if the card is not to be shown.

Is it possible to do in a single XSL file?

Quassnoi
  • 413,100
  • 91
  • 616
  • 614
  • Will there only ever be one level of URL? Slash + keyword, that's it? Does that not lead to ambiguity? Or is the URL structured? – Tomalak Aug 26 '09 at 13:46
  • No, it won't. It was designed to hold all cards at once and they need to have distinct names. The problem just arose when testing. – Quassnoi Aug 26 '09 at 13:47
  • So I can trust the @names will be unique across all category/subcategory/node/record elements? – Tomalak Aug 26 '09 at 15:32
  • `@Tomalak`: absolutely. In fact, the `id`'s are `typeGUID`, `subGUID`, `nameGUID` etc, I used real names just for brevity. – Quassnoi Aug 26 '09 at 15:39
  • Okay. And these limits you speak of - are they completely to be handled in the XSL or are they in the base data? E.g.: Are there no more than 8 subtypes (8+2=10 cards incl. toc and a-z)? – Tomalak Aug 26 '09 at 16:05
  • `@Tomalak`: There are `3` fixed cards (`TOC`, `a-z` and the list of types) that need to be shown on every page. `A-Z` always contains links to `15` other cards (which, in their turn, list the authors under the correponding letter ranges, like `A-C`, `D-E` etc.). Consider this number fixed. `Type list` lists subtypes, and subtypes lists authors. There are about `10` types and `200` subtypes, these numbers may vary (i. e. not known in compile time). – Quassnoi Aug 26 '09 at 16:17
  • It sure sounds possible from what I can see. I'll have a look into this tomorrow (it's 18:30 here now, I'm off). – Tomalak Aug 26 '09 at 16:31
  • I'm sorry, but I seems I'm still missing something. What's the difference between the TOC and the "list of types"? In your Nokia sample, you link to "#video" in the TOC, but there is no card with that @id (unlike "#music", which has a card). So this can't really work, can it? – Tomalak Aug 27 '09 at 16:39
  • `@Tomalak`: fixed. The `TOC` is a fixed card which just links to `A-Z` and the list of types. Of course it's not music and games in reality, but I'm bound by an `NDA` and can't post the real data here so this is just a messy obfuscation. However, `TOC` and `A-Z` are really `TOC` and `A-Z`. Hope it makes more sense now :) – Quassnoi Aug 27 '09 at 17:39
  • Yes it does. :) It is late again and I have to go. Bear with me, I hope you are not running against a deadline or so. – Tomalak Aug 27 '09 at 18:33

3 Answers3

1

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.

Pavel Minaev
  • 99,783
  • 25
  • 219
  • 289
0

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. ^.^

Ben Blank
  • 54,908
  • 28
  • 127
  • 156
0

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.

frankodwyer
  • 13,948
  • 9
  • 50
  • 70
  • In fact, what I want is to have a reusable template, so if I want to change the card layout I do it in one place (for both `Nokia` and normal browsers). I know about params and chooses, I just can't use them properly, everything I get looks like a terrible mess. – Quassnoi Aug 26 '09 at 17:04
  • yes but this will still be just one xsl file, with a bunch of xsl:template components to descend the xml input. I think of xsl:template as a subroutine or procedure/function. – frankodwyer Aug 26 '09 at 17:13