Variables in XSLT

Discussion in 'XML' started by Carles Company Soler, Nov 2, 2006.

  1. Hello,
    I want to store the value of an attribute in a XSL variable. I do it this
    way:

    <xsl:variable name="aux" select="@x" />

    But I don't get anything in the variable... What do I get wrong?

    Thanks!
     
    Carles Company Soler, Nov 2, 2006
    #1
    1. Advertising

  2. Carles Company Soler wrote:

    > I want to store the value of an attribute in a XSL variable. I do it this
    > way:
    >
    > <xsl:variable name="aux" select="@x" />
    >
    > But I don't get anything in the variable... What do I get wrong?


    We need to know what is the context node (e.g. whether it is an element
    node and has an attribute named "x"), then we need to see where you read
    out the attribute value.


    --

    Martin Honnen
    http://JavaScript.FAQTs.com/
     
    Martin Honnen, Nov 2, 2006
    #2
    1. Advertising

  3. Martin Honnen wrote:

    > Carles Company Soler wrote:
    >
    >> I want to store the value of an attribute in a XSL variable. I do it this
    >> way:
    >>
    >> <xsl:variable name="aux" select="@x" />
    >>
    >> But I don't get anything in the variable... What do I get wrong?

    >
    > We need to know what is the context node (e.g. whether it is an element
    > node and has an attribute named "x"), then we need to see where you read
    > out the attribute value.
    >
    >


    Ooops. Right, I'll send everything. It's a very simple stylesheet to
    transform a custom DTD to SVG. I'll mark the place where the variable is
    used with a line of * :

    --8<---------DTD-------8<---

    <!ELEMENT graph (sujet|relation)*>
    <!ELEMENT sujet (nom?,type)>
    <!ELEMENT relation (nom)>
    <!ELEMENT nom (#PCDATA)>
    <!ELEMENT type (#PCDATA)>
    <!ATTLIST sujet id ID #IMPLIED>
    <!ATTLIST sujet x CDATA #REQUIRED>
    <!ATTLIST sujet y CDATA #REQUIRED>
    <!ATTLIST relation from IDREFS #REQUIRED>
    <!ATTLIST relation to IDREF #REQUIRED>
    <!ATTLIST relation x CDATA #REQUIRED>
    <!ATTLIST relation y CDATA #REQUIRED>
    <!ATTLIST relation dir (r|l|d|u) #REQUIRED>

    --8<-------------------8<---

    --8<------XML---------8<------

    <!DOCTYPE graph SYSTEM "graph.dtd">
    <?xml-stylesheet type="text/xsl" href="transform3.xsl"?>
    <graph>
    <sujet id="a" x="2" y="1">
    <nom>Tintin</nom>
    <type>livre</type>
    </sujet>
    <sujet id="b" x="0" y="0">
    <nom>Jacques</nom>
    <type>personne</type>
    </sujet>
    <sujet id="c" x="0" y="2">
    <nom>Marie</nom>
    <type>personne</type>
    </sujet>
    <relation from="b c" to="a" x="1" y="1" dir="r">
    <nom>envoyer</nom>
    </relation>
    </graph>

    --8<---------------8<--------

    ----8<------XSL-------8<-------

    <?xml version="1.0" encoding="ISO-8859-1"?>
    <xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns="http://www.w3.org/2000/svg">
    <xsl:eek:utput method="xml" indent="yes"
    doctype-public="-//W3C//DTD SVG 1.1//EN"
    doctype-system="http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"/>
    <xsl:variable name="xper" select="200" />
    <xsl:variable name="yper" select="100" />
    <xsl:template match="/">
    <svg width="100%" height="100%" version="1.1"
    xmlns="http://www.w3.org/2000/svg">

    <!-- Arrow head -->

    <marker id="Triangle"
    viewBox="0 0 10 10" refX="10" refY="5"
    markerUnits="strokeWidth"
    markerWidth="4" markerHeight="3"
    orient="auto">
    <path d="M 0 0 L 10 5 L 0 10 z" />
    </marker>

    <xsl:apply-templates />

    </svg>
    </xsl:template>

    <!-- Sujet boxes -->
    <xsl:template match="sujet">
    <rect x="{@x*$xper+10}" y="{@y*$yper+10}" height="30" width="150"
    style="fill:blue;stroke:black;stroke-width:2;opacity:0.5" />

    <text x="{@x*$xper+15}" y="{@y*$yper+28}"
    style="font-size:10px;font-weight:bold"><xsl:value-of select="type" /> :
    <xsl:value-of select="nom" /></text>
    </xsl:template>

    <!-- Arrows for each direction -->

    ********************
    <xsl:template match="relation">
    <xsl:variable name="aux" select="@x" />
    <xsl:variable name="auy" select="@y" />
    <rect x="{@x*$xper+10}" y="{@y*$yper+10}" ry="5" height="30" width="150"
    style="fill:yellow;stroke:black;stroke-width:2;opacity:0.5" />

    <text x="{@x*$xper+15}" y="{@y*$yper+28}"
    style="font-size:10px;font-weight:bold"><xsl:value-of
    select="nom" /></text>
    <xsl:choose>
    <xsl:when test="@dir='l'">
    <xsl:for-each select="id(@from)">
    <line x1="{@x*$xper+10}" y1="{@y*$yper+25}" x2="{$aux*$xper+160}"
    y2="{$auy*$yper+25}" style="stroke:rgb(99,99,99);stroke-width:2"
    marker-end="url(#Triangle)" />
    </xsl:for-each>
    <line x1="{@x*$xper+10}" y1="{@y*$yper+25}" x2="{id(@to)/@x*$xper+160}"
    y2="{id(@to)/@y*$yper+25}" style="stroke:rgb(99,99,99);stroke-width:2"
    marker-end="url(#Triangle)" />
    </xsl:when>
    *******************************
    <xsl:when test="@dir='r'">
    <xsl:for-each select="id(@from)">
    <line x1="{@x*$xper+160}" y1="{@y*$yper+25}" x2="{$aux*$xper+10}"
    y2="{$auy*$yper+25}" style="stroke:rgb(99,99,99);stroke-width:2"
    marker-end="url(#Triangle)" />
    </xsl:for-each>
    <line x1="{@x*$xper+160}" y1="{@y*$yper+25}" x2="{id(@to)/@x*$xper+10}"
    y2="{id(@to)/@y*$yper+25}" style="stroke:rgb(99,99,99);stroke-width:2"
    marker-end="url(#Triangle)" />
    </xsl:when>

    <xsl:when test="@dir='d'">
    <xsl:for-each select="id(@from)">
    <line x1="{@x*$xper+85}" y1="{@y*$yper+40}" x2="{$aux*$xper+85}"
    y2="{$auy*$yper+10}" style="stroke:rgb(99,99,99);stroke-width:2"
    marker-end="url(#Triangle)" />
    </xsl:for-each>
    <line x1="{@x*$xper+85}" y1="{@y*$yper+40}" x2="{id(@to)/@x*$xper+85}"
    y2="{id(@to)/@y*$yper+10}" style="stroke:rgb(99,99,99);stroke-width:2"
    marker-end="url(#Triangle)" />
    </xsl:when>

    <xsl:when test="@dir='u'">
    <xsl:for-each select="id(@from)">
    <line x1="{@x*$xper+85}" y1="{@y*$yper+10}" x2="{$aux*$xper+85}"
    y2="{$auy*$yper+30}" style="stroke:rgb(99,99,99);stroke-width:2"
    marker-end="url(#Triangle)" />
    </xsl:for-each>
    <line x1="{@x*$xper+85}" y1="{@y*$yper+10}" x2="{id(@to)/@x*$xper+85}"
    y2="{id(@to)/@y*$yper+30}" style="stroke:rgb(99,99,99);stroke-width:2"
    marker-end="url(#Triangle)" />
    </xsl:when>

    </xsl:choose>
    </xsl:template>

    </xsl:stylesheet>

    -------8<--------8<---------

    The fact is that it works when I use xalan as XSLT processor, but when I try
    to use Firefox's one it doesn't work very well.

    Thanks!
     
    Carles Company Soler, Nov 2, 2006
    #3
  4. Carles Company Soler wrote:

    > <line x1="{@x*$xper+10}" y1="{@y*$yper+25}" x2="{id(@to)/@x*$xper+160}"
    > y2="{id(@to)/@y*$yper+25}" style="stroke:rgb(99,99,99);stroke-width:2"
    > marker-end="url(#Triangle)" />


    One problem with Firefox is certainly that you use an external DTD
    (which Firefox' XML parser does not read at all as it is a non
    validating parser) but then you are using the XPath id function which
    depends on the parser having information about attribute types. That way
    for Firefox and those line attributes you get e.g. x2="NaN" y2="NaN".

    For Firefox you either need to define those ID attributes in the
    internal subset of the DTD or you need to use other ways than the XPath
    id function to reference those values.


    --

    Martin Honnen
    http://JavaScript.FAQTs.com/
     
    Martin Honnen, Nov 2, 2006
    #4
  5. Martin Honnen wrote:

    > Carles Company Soler wrote:
    >
    >> <line x1="{@x*$xper+10}" y1="{@y*$yper+25}" x2="{id(@to)/@x*$xper+160}"
    >> y2="{id(@to)/@y*$yper+25}" style="stroke:rgb(99,99,99);stroke-width:2"
    >> marker-end="url(#Triangle)" />

    >
    > One problem with Firefox is certainly that you use an external DTD
    > (which Firefox' XML parser does not read at all as it is a non
    > validating parser) but then you are using the XPath id function which
    > depends on the parser having information about attribute types. That way
    > for Firefox and those line attributes you get e.g. x2="NaN" y2="NaN".
    >
    > For Firefox you either need to define those ID attributes in the
    > internal subset of the DTD or you need to use other ways than the XPath
    > id function to reference those values.
    >
    >


    Thanks. I'll investigate from here. Greetings!
     
    Carles Company Soler, Nov 2, 2006
    #5
  6. Carles Company Soler

    Guest

    Carles Company Soler wrote:
    > Ooops. Right, I'll send everything. It's a very simple
    > stylesheet to transform a custom DTD to SVG. I'll mark
    > the place where the variable is used with a line of * :


    Marking it with a <!-- ********* --> would've been a better
    idea.

    > <!-- Sujet boxes -->
    > <xsl:template match="sujet">
    > <rect x="{@x*$xper+10}" y="{@y*$yper+10}" height="30"
    > width="150"
    > style="fill:blue;stroke:black;stroke-width:2;opacity:0.5"
    > />


    Do you realize your code is quite unreadable? Just a bit of
    indentation would help enormously.

    > <!-- Arrows for each direction -->


    The very idea strikes me as dubious. Determining the
    direction shouldn't be all that tricky without the extra
    attribute. (As long as you don't try to do anything
    *seriously* tricky with your data.)

    > <xsl:template match="relation">
    > <xsl:variable name="aux" select="@x" />
    > <xsl:variable name="auy" select="@y" />
    > <rect x="{@x*$xper+10}" y="{@y*$yper+10}" ry="5"
    > height="30" width="150"
    > style="fill:yellow;stroke:black;stroke-width:2;opacity:0.5"
    > />
    >
    > <text x="{@x*$xper+15}" y="{@y*$yper+28}"
    > style="font-size:10px;font-weight:bold"><xsl:value-of
    > select="nom" /></text>
    > <xsl:choose>
    > <xsl:when test="@dir='l'">
    > <xsl:for-each select="id(@from)">


    Note that you can replace id(@foo) with:

    //*[@id]
    [
    contains
    (
    concat(' ',concat(current()/@foo,' ')),
    concat(' ',concat(@id,' '))
    )
    ]

    ....AND you don't need to validate. You just need to know
    what to use as an ID.

    > <line x1="{@x*$xper+10}" y1="{@y*$yper+25}"
    > x2="{$aux*$xper+160}" y2="{$auy*$yper+25}"
    > style="stroke:rgb(99,99,99);stroke-width:2"
    > marker-end="url(#Triangle)" />
    > </xsl:for-each>
    > <line x1="{@x*$xper+10}" y1="{@y*$yper+25}"
    > x2="{id(@to)/@x*$xper+160}" y2="{id(@to)/@y*$yper+25}"
    > style="stroke:rgb(99,99,99);stroke-width:2"
    > marker-end="url(#Triangle)" />
    > </xsl:when>


    [x4]

    I wonder if this rings any bells for you?

    Hint #1: You wrote the code to do pretty much the same
    bloody thing no less than *four* times.

    Hint #2: It's a good idea to separate details of
    presentation from the basic logic.

    Hint #3: It's a good idea not to stuff everything into a
    single template k pages long. Or, as in your case, n pages
    long.

    Drop the <xsl:choose>. Use <xsl:template>s with nicely
    tweaked matches -- that what XPath is for. Move the gcd
    into a separate named template. Consider using
    attribute-sets.

    --
    Pavel Lepin
     
    , Nov 3, 2006
    #6
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Stylus Studio
    Replies:
    0
    Views:
    714
    Stylus Studio
    Aug 3, 2004
  2. Benjamin Hillsley
    Replies:
    3
    Views:
    1,700
    Dimitre Novatchev
    Sep 25, 2003
  3. ted
    Replies:
    1
    Views:
    641
    Laurens
    Jan 26, 2004
  4. Replies:
    2
    Views:
    729
    Henry S. Thompson
    Oct 19, 2005
  5. Replies:
    9
    Views:
    986
Loading...

Share This Page