Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations biv343 on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

XSL Functions?

Status
Not open for further replies.

allywilson

Technical User
Nov 27, 2002
157
GB
Hi,
I've just started using XML and XSL, and at the moment I've still got the whole HTML/JavaScript methodology stuck in my head.

What I'm trying to do is embed a number of quicktime movies onto one page. Now, the embed tag requires multiple attributes. I can do it but only if I specify all of the attributes on each tag...what I'd like to be able to do is just put a function that calls all of the same attributes used for the previous embed tags (like a javascript function would be able to do).

Here's what the XML doc looks like:

<?xml version="1.0" encoding="ISO-8859-1"?>
<?xml-stylesheet type="text/xsl" href="02.xsl"?>
<movies>
<properties>
<sourcemovie1>test2.3gp</sourcemovie1>
<width1>176</width1>
<height1>160</height1>
<controller1>TRUE</controller1>
<autoplay1>FALSE</autoplay1>
<loop1>FALSE</loop1>
<cache1>FALSE</cache1>
<type1>video/quicktime</type1>
</properties>
</movies>

Pretty basic right?

So...now this parts a bit longer, but this is what I am having to do for the XSL doc (keep in mind this example only shows me setting the attributes for just ONE embed tag - and I wanna do loads.):

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="
<xsl:template match="/">
<html>
<body>
<xsl:for-each select="movies/properties">
<embed>
<xsl:attribute name="src">
<xsl:value-of select="sourcemovie1"/>
</xsl:attribute>
<xsl:attribute name="width">
<xsl:value-of select="width1"/>
</xsl:attribute>
<xsl:attribute name="height">
<xsl:value-of select="height1"/>
</xsl:attribute>
<xsl:attribute name="controller">
<xsl:value-of select="controller1"/>
</xsl:attribute>
<xsl:attribute name="autoplay">
<xsl:value-of select="autoplay1"/>
</xsl:attribute>
<xsl:attribute name="loop">
<xsl:value-of select="loop1"/>
</xsl:attribute>
<xsl:attribute name="cache">
<xsl:value-of select="cache1"/>
</xsl:attribute>
<xsl:attribute name="type">
<xsl:value-of select="type1"/>
</xsl:attribute>
</embed>
</xsl:for-each>
</body>
</html>
</xsl:template>

</xsl:stylesheet>


I've been trying to figure out how to do it with attribute-sets - but so far I've been unlucky in all attempts with it.

Anyone think they can walk me through using attribute-sets, or maybe showing me how the hell you write functions in XSL that are similar to javascript?

Cheers,

Ally
 
You cannot make 'functions' in xsl like in a programming language.
The idea is that in your xml-file all similar entities are made in the same structure, with xsl you can format such a structure.
So, if your xml looks like
Code:
<movies>
 <properties>
  <sourcemovie>test ONE</sourcemovie>
  <width>176</width>
  ...
 </properties>
 <properties>
  <sourcemovie>test TWO</sourcemovie>
  <width>176</width>
  ...
 </properties>
</movies>
you can have 1 template display them all:
Code:
<xsl:template match="properties">
 <embed>
  <xsl:attribute name="src">
    <xsl:value-of select="sourcemovie"/>
  </xsl:attribute>
  <xsl:attribute name="width">
    <xsl:value-of select="width"/>
  </xsl:attribute>
  ...
 </embed>
</xsl:template>
 
Oh, and I didnt try, but shouldn't <embed> be:
<xsl:element name="embed">?
 
Well, I can see what you're talking about but, the problem I have with that is that it still means an awful lot of typing, and a very large document. I was hoping to cut down on that.

Is there anyway that I can get all of the attibutes into an attribute-set? That way I can just call on the attribute-set (which'll set the width, height, etc, etc.) and then I can just manually add the src to each embed tag anyway.

I've never tried <xsl:element name="embed"> before. Like I said, just new to the XML families. Still tangled up in my HTML ways just a bit.
 
Have you tried:
Code:
<embed src="{sourcemovie1}"
       width="{width1}"
       height="{height1}"
       controller="{controller1}"
       autoplay="{autoplay1}"
       loop="{loop1}"
       cache="{cache1}"
       type"{type1}"/>

personally, I can't ever get:
<xsl:attribute name="attribute">
<xsl:value-of select="xmlvalue"/>
</xsl:attribute>

To work right...

the attribute="{xmlvalue}" has been my solution so far...

Good Luck ;-)


PROGRAMMER: (n) Red-eyed, mumbling mammal capable of conversing with inanimate objects.
 
The only problem with that method is that i might as well just leave the tag as i would in html. i'm really just looking for a way to reduce the size of the code. JavaScript's good for it but, I'm using this as an idea to expand into XML based technologies.

Cheers though mate, I'll have to remember that way of doing things.

~A~
 
what exactly are you trying to do?

if you get a chance, click on my logo below to go to my site...

I have used several methods of XML to build my site...

The home page is html using XML for a Data Source Object to populate the table...

If you click on the "Links" link, there is one at the bottom of the list called "XML Version"

when you click it, you might notice the extension in the address bar changes from .html to .xml

And though it looks the same, if you view the source, it is just the xml with a referce to a xslt sheet which transforms the output to html...

I set up a few xslt's for different styles of pages... but each one has 2 or 3 xml pages that use that same xslt...

The text, links, and pictures, as well as the navigation menu, are all XML driven...

To update the site, I simply change the xml, without touching any of the html components...

This might give you a few ideas...

Good Luck ;-)


PROGRAMMER: (n) Red-eyed, mumbling mammal capable of conversing with inanimate objects.
 
hmmm... I don't think I hit the point in the above post... here is a more direct solution:

instead of setting your xml up like this:
Code:
<?xml version="1.0" encoding="ISO-8859-1"?>
<?xml-stylesheet type="text/xsl" href="02.xsl"?>
<movies>
    <properties>
        <sourcemovie1>test2.3gp</sourcemovie1>
        <width1>176</width1>
        <height1>160</height1>
        <controller1>TRUE</controller1>
        <autoplay1>FALSE</autoplay1>
        <loop1>FALSE</loop1>
        <cache1>FALSE</cache1>
        <type1>video/quicktime</type1>
    </properties>
</movies>

set it up like this:
Code:
<?xml version="1.0" encoding="ISO-8859-1"?>
<?xml-stylesheet type="text/xsl" href="02.xsl"?>
<movies>
    <properties>
        <sourcemovie>test1.3gp</sourcemovie>
        <width>176</width>
        <height>160</height>
        <controller>TRUE</controller>
        <autoplay>FALSE</autoplay>
        <loop>FALSE</loop>
        <cache>FALSE</cache>
        <type>video/quicktime</type>
    </properties>
    <properties>
        <sourcemovie>test2.3gp</sourcemovie>
        <width>176</width>
        <height>160</height>
        <controller>TRUE</controller>
        <autoplay>FALSE</autoplay>
        <loop>FALSE</loop>
        <cache>FALSE</cache>
        <type>video/quicktime</type>
    </properties>
    <properties>
        <sourcemovie>test3.3gp</sourcemovie>
        <width>176</width>
        <height>160</height>
        <controller>TRUE</controller>
        <autoplay>FALSE</autoplay>
        <loop>FALSE</loop>
        <cache>FALSE</cache>
        <type>video/quicktime</type>
    </properties>
</movies>

*Note: there is no reason to number your tags, in this case anyway...

or, in the above case, if they are all the same size and player, hard code what you can, and just store the changing values...

Code:
<?xml version="1.0" encoding="ISO-8859-1"?>
<?xml-stylesheet type="text/xsl" href="02.xsl"?>
<movies>
    <properties>
        <sourcemovie>test1.3gp</sourcemovie>
        <width>176</width>
        <height>160</height>
    </properties>
    <properties>
        <sourcemovie>test2.3gp</sourcemovie>
        <width>176</width>
        <height>160</height>
    </properties>
    <properties>
        <sourcemovie>test3.3gp</sourcemovie>
        <width>176</width>
        <height>160</height>
    </properties>
</movies>

Then use this in your xsl:
Code:
<xsl:for-each select="//properties">
<embed src="{sourcemovie}"
       width="{width}"
       height="{height}"
       controller="TRUE"
       autoplay="FALSE"
       loop="FALSE"
       cache="FALSE"
       type"video/quicktime" /><br />
</xsl:for-each>

That will place them all on one page...

You can experiment with that a little such as using it in tables and such...
Code:
<table>
<xsl:for-each select="//properties">
<tr><td>
<embed src="{sourcemovie}"
       width="{width}"
       height="{height}"
       controller="TRUE"
       autoplay="FALSE"
       loop="FALSE"
       cache="FALSE"
       type"video/quicktime" />
</td></tr>
</xsl:for-each>
</table>



PROGRAMMER: (n) Red-eyed, mumbling mammal capable of conversing with inanimate objects.
 
What I've got at the moment (not online unfortunately) is an HTML site and, so far, I've been building the XSL to mimick its looks (but eventually I intend to just place the XML online).

I can create the entire site using XML/XSL, but I was hoping to redude its size a little, as it's a hell of a lot larger than its HTML equivalent, and also using it to be able to edit it a lot easier and faster, without resorting to trawling through code (or using a WYSIWYG editor) to do so.

I can get the <xsl:attribute name="whatever"><xsl:value-of select="whatever"/></xsl:attribute> to work fine, I just find it annoying that I have to use three tags everytime I want to add another attribute to the tag (im this case <embed>).

The way I'd like to be able to do it (this isn't real XSL) is:

<embed>
<xsl:attributes name="all_the_attributes"/>
</embed>

Obviously the name "all_the_attributes" would be defined at the start of the document to show whereabouts in the XML doc everything is, then call them whenever I wanted them with "<xsl:attributes name="all_the_attributes"/>"

I've probably not made myself very clear I know, sorry!


~A~
 
this might be of interest to you...

<xsl:include href="URI">

I believe you could set up an XSL sheet as a "Function" then use this as a sort of "Call" method...

In this case, you would setup an XSL to tranform your XML to an <embed> tag...

Then Place the <xsl:include> tag where you want to call it...

Let me know if it works the way you want ;-)


PROGRAMMER: (n) Red-eyed, mumbling mammal capable of conversing with inanimate objects.
 
That looks a lot more promising, trying to find examples of it in a working environment is pretty difficult though.

Cheers mate!

~A~
 
nah...

I used one recently to get the total of QTY * PRICE fields...

Such as...
Code:
Product   Qty   Price   Total
Product   Qty   Price   Total
Product   Qty   Price   Total
Product   Qty   Price   Total
                  [b]Grand Total[/b]

Where Total is calculated by QTY * Price and Grand Total is the sum of the Totals...

Here is where I learned it, and is a very good example...

Basically...
A function such as: (In a BASIC style notation)
Code:
Function Total(Items, RunningTotal)
  If Not(Items) Then
    Total = RunningTotal
  Else
    Dim CurrentTotal
    CurrentTotal = RunningTotal + ("Items[1]/QTY" * "Items[1]/Cost")
    Total = Total("Items[position()>1]", CurrentTotal)
  End If
End Function

Looks Like this in XSL...
Code:
  <xsl:template name="Total">
    <xsl:param name="Items"/>
    <xsl:param name="RunningTotal"/>
    <xsl:choose>
      <xsl:when test="not($Items)">
        <xsl:copy-of select="$RunningTotal"/>
      </xsl:when>
      <xsl:otherwise>
        <xsl:variable name="CurrentTotal" select="$RunningTotal + ($Items[1]/QTY * $Items[1]/Cost)"/>
        <xsl:call-template name="Total">
          <xsl:with-param name="Items" select="$Items[position()>1]"/>
          <xsl:with-param name="RunningTotal" select="$CurrentTotal"/>
        </xsl:call-template>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

Note that since you can't actually add values to variables in XSL, they used recursion to work around it...
Each time a value needs to be added, a new variable is created and passed back through the function until the list has been completed...

I use recursive functions all the time in VB, and C++... but it never occured to me to use them in XSL ;-)

OK... then to call a function... (Again in BASIC notation)
Code:
TotalValue = Total("//Part", 0)

Would look like this:
Code:
  <xsl:variable name="Items" select="//Part"/>
  <xsl:variable name="TotalValue">
    <xsl:call-template name="Total">
      <xsl:with-param name="Items" select="$Items"/>
      <xsl:with-param name="RunningTotal" select="0"/>
    </xsl:call-template>
  </xsl:variable>

Hope This Helps ;-)

Good Luck,
- Josh


PROGRAMMER: (n) Red-eyed, mumbling mammal capable of conversing with inanimate objects.
 
Thanks for that. I've not had much time to look into it though, as another problem has now occurred.

The problem being the differences between Firefox and IE.

Have a look at this page in IE and firefox:
IE displays it correctly but firefox doesn't.
I've tried everything!
Basically what I did was create the page in HTML using dreamweaver, then reverse coded it into XSL, so that's why the source is still full of HTML, was slowly removing it bit by bit. Then I noticed that firefox kept on adding spacing.

In a desperate move I created a smaller table beneath the main one and just added to image slices to it to see if I could get them to fit together - not a chance. Once again it works fine in IE, just not firefox (which is my browser of choice so it's a bit annoying).

I've tried removing all spaces from the table code (as I have it laid out to read easier). Changed the "cellspacing" and "cellpadding", gave it "valign" attributes to try and push them together. Makes no difference.

I've been so annoyed with it I've currently given up on everything else. The really weird part though is what I mentioned earlier. It displays fine when in a purely HTML/Javascript environment, just not when encased within XSL. ARGH!

~A~
 
Oh, and I just noticed your site doesn't pull the data for the table in firefox, but it does in IE...

Why did they introduce firefox? I love it, but I have to admit that life was simpler when the browser wars were over...and now they've gone and started them up again...
 
lol, I agree...

I wish all the browsers would just use a common set of functions...

I only use IE...
The majority of people who have PC's typically have windows, which comes with IE...

And IE seems to have more functionality, so I take advantage of the features it has, and if someone chooses to use a different browser, that's their problem...

I know that seems REALLY BIASED, but why should I limit myself because other people are boycotting Microsoft?

If the only reason you like FireFox, or one of the other new browsers, is because It has Tabbed windows...

You can use .Net to create your Own IE powered browser, with whatever features you want in aprox 10 minutes, with virtually no code... Tabs and all...

So for me, the browser wars are over...

If FireFox brings itself up to par with the rest, I might consider using it...

If I am just being naive, and missing a bigger point here, please inform me ;-)

Visit My Site
PROGRAMMER: (n) Red-eyed, mumbling mammal capable of conversing with inanimate objects.
 
lol, well, to be truthful I do prefer firefox over IE - but not because I don't like microsoft (I use windows, so what would be the point?).

I've found that firefox is a bit quicker when rendering, doesn't force me to windowsupdate whenever it thinks I should get up to date. Plus, it's a lot more innovative, IE has been sitting on its laurels for a long time, doesn't seem to want to try anything new.

Oh, and trying to make a page work for both can be an interesting puzzle :-Þ

~A~
 
>>Oh, and trying to make a page work for both can be an interesting puzzle

Yeah, I guess that is true ;-)

(Good luck with your puzzle :p)

Visit My Site
PROGRAMMER: (n) Red-eyed, mumbling mammal capable of conversing with inanimate objects.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top