Variables in XSLT

  • Thread starter Carles Company Soler
  • Start date
C

Carles Company Soler

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!
 
M

Martin Honnen

Carles said:
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.
 
C

Carles Company Soler

Martin said:
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!
 
M

Martin Honnen

Carles said:
<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.
 
C

Carles Company Soler

Martin said:
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!
 
P

p.lepin

Carles said:
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 * :

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

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,997
Messages
2,570,241
Members
46,831
Latest member
RusselWill

Latest Threads

Top