Solved

"Back references" in XML / XSLT

Posted on 2003-11-17
6
325 Views
Last Modified: 2013-11-19
I am trying to write a XSLT transform to output a list of URLs. The URLs are shared folders on particular servers. The XML fragment containing the URLs appears below. I would like a neat way to combine the attribute called "name" with the href attribute in the output in such a way that I do not have to repeat the actual name of the server.

<machine name="MYSERVER">
<links>
<a href="file://MYSERVER/Share1">First Shared Folder</a>
<a href="file://MYSERVER/Share2">Second Shared Folder</a>
</links>
</machine>

Note the redundancy in the repeated string "MYSERVER". Perhaps the solution hinges on rewriting the <a> tags to read <a description="First Shared Folder">file://<machineName/>/Share1</a> and somehow replacing the machineName element in the output... but I can't get this to work!

Any ideas?
0
Comment
Question by:freshqwa
  • 4
  • 2
6 Comments
 
LVL 11

Expert Comment

by:petiex
ID: 9768284
So, you want the xsl to make it possible to have a simpler xml? With an xml that looks like this:

<machine name="MYSERVER">
<links>
<link foldername=Share1>First Shared Folder</link>
<link foldername=Share2>Second Shared Folder</link>
</links>
</machine>

You could generate a bulleted list of links for each machine with an xsl like this:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="/">
<xsl:apply-templates select="machine"/>
</xsl:template>

<xsl:template match="machine">
<xsl:variable name="servername"  select="@name"/>
<xsl:value-of select="@name">
<ul>
<xsl:for-each select="link">
<li><a href="{concat('file://', $servername, @foldername)}"><xsl:value-of select="."></a></li>
</xsl:for-each>
</ul>
</xsl:template>

</xsl:stylesheet>
0
 

Author Comment

by:freshqwa
ID: 9769903
Thanks for the suggestion... it's not quite what I am after but may be the only way to do it... There are actually a couple of places in my XML schema where I would like to be able to easily refer to an attribute of a parent node (in fact up to several levels back up the node tree).

I have been unable to find a syntax like the filesystem "dot dot" convention that will take my context back up a level. For example, I could use the following:

<machine name="MYSERVER">
<links>
<a description="First Shared Folder">file://<replaceMe path="../../@name"/>/Share1</a>
</links>
</machine>

If I could write a template for all "replaceMe" elements that would return the node refered to by the "path" attribute as a string. As I say, there are a few more instances where I would like to write "self referential" XML (ie repeating previous values in several places). I would rather not have to pass the value as a parameter all the way down through my templates to where it is needed, but this may be the only way.

Agh, is it just me or is XSL the most frustrating thing to use!
0
 
LVL 11

Expert Comment

by:petiex
ID: 9775061
Possibly the current() function is what you need. It refers to the initial context of a template, which is useful within for-each loops.

So, in the stylesheet of my previous post, you could use current()/@name in place of that $servername variable to the same effect. I've also fixed a couple or three fatal bugs in the stylesheet of my previous post:

XML:
<machine name="MYSERVER">
  <links>
     <link foldername=Share1>First Shared Folder</link>
     <link foldername=Share2>Second Shared Folder</link>
   </links>
</machine

XSL:
<?xml version="1.0" encoding="UTF-8"?>
 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output method="html"/>
   <xsl:template match="/">
     <html><body>
       <xsl:apply-templates select="machine"/>
     </body></html>
  </xsl:template>

  <xsl:template match="machine">
     <xsl:value-of select="@name"/>
     <ul>
         <xsl:for-each select="links/link">
             <li>
                 <a href="{concat('file://', current()/@name, @foldername)}">
                      <xsl:value-of select="."/>
                 </a>
             </li>
         </xsl:for-each>
    </ul>
  </xsl:template>

 </xsl:stylesheet>


OUTPUT:
<html>
<body>MYSERVER<ul>
<li>
<a href="file://Share1">First Shared Folder</a>
</li>
<li>
<a href="file://Share2">Second Shared Folder</a>
</li>
</ul>
</body>
</html>

If you think XSL is the most frustrating thing to use, stay away from XSL-FO. Bad mojo, that XSL-FO. :)
0
3 Use Cases for Connected Systems

Our Dev teams are like yours. They’re continually cranking out code for new features/bugs fixes, testing, deploying, testing some more, responding to production monitoring events and more. It’s complex. So, we thought you’d like to see what’s working for us.

 
LVL 11

Expert Comment

by:petiex
ID: 9775119
Uh, no, sorry that's not right at all. It turns out the current() function is only useful within a predicate.
0
 
LVL 11

Accepted Solution

by:
petiex earned 100 total points
ID: 9775249
So, like you said, you need to use the dot dot syntax. So, here's the best I can do:

XML:

<machine name="MYSERVER">
  <links>
     <link foldername=Share1>First Shared Folder</link>
     <link foldername=Share2>Second Shared Folder</link>
   </links>
</machine>

XSL:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html"/>
<xsl:template match="/">
<html><body>
<xsl:apply-templates select="machine"/>
</body></html>
</xsl:template>

<xsl:template match="machine">
<xsl:value-of select="@name"/>
<ul>
<xsl:for-each select="links/link">
<li><a href="{concat('file://', ../../@name, '/', @foldername)}"><xsl:value-of select="."/></a></li>
</xsl:for-each>
</ul>
</xsl:template>

</xsl:stylesheet>

OUTPUT:
<html>
<body>MYSERVER<ul>
<li>
<a href="file://MYSERVER/Share1">First Shared Folder</a>
</li>
<li>
<a href="file://MYSERVER/Share2">Second Shared Folder</a>
</li>
</ul>
</body>
</html>
0
 

Author Comment

by:freshqwa
ID: 9777233
Thanks for your time & effort, I can work with this solution... Cheers!
0

Featured Post

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

I will show you how to create a ASP.NET Captcha control without using any HTTP HANDELRS or what so ever. you can easily plug it into your web pages. For Example a = 2 + 3 (where 2 and 3 are 2 random numbers) Session("Answer") = 5 then we…
I found this questions asking how to do this in many different forums, so I will describe here how to implement a solution using PHP and AJAX. The logical flow for the problem should be: Write an event handler for the first drop down box to get …
This tutorial will teach you the core code needed to finalize the addition of a watermark to your image. The viewer will use a small PHP class to learn and create a watermark.
HTML5 has deprecated a few of the older ways of showing media as well as offering up a new way to create games and animations. Audio, video, and canvas are just a few of the adjustments made between XHTML and HTML5. As we learned in our last micr…

920 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

14 Experts available now in Live!

Get 1:1 Help Now