Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium

x
?
Solved

"Back references" in XML / XSLT

Posted on 2003-11-17
6
Medium Priority
?
333 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
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
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 400 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

Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

Question has a verified solution.

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

Preface This article introduces an authentication and authorization system for a website.  It is understood by the author and the project contributors that there is no such thing as a "one size fits all" system.  That being said, there is a certa…
SASS allows you to treat your CSS code in a more OOP way. Let's have a look on how you can structure your code in order for it to be easily maintained and reused.
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…
The viewer will learn the basics of jQuery, including how to invoke it on a web page. Reference your jQuery libraries: (CODE) Include your new external js/jQuery file: (CODE) Write your first lines of code to setup your site for jQuery.: (CODE)
Suggested Courses

564 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