Solved

"Back references" in XML / XSLT

Posted on 2003-11-17
6
330 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 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
The Ultimate Checklist to Optimize Your Website

Websites are getting bigger and complicated by the day. Video, images, custom fonts are all great for showcasing your product/service. But the price to pay in terms of reduced page load times and ultimately, decreased sales, can lead to some difficult decisions about what to cut.

 
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

Secure Your WordPress Site: 5 Essential Approaches

WordPress is the web's most popular CMS, but its dominance also makes it a target for attackers. Our eBook will show you how to:

Prevent costly exploits of core and plugin vulnerabilities
Repel automated attacks
Lock down your dashboard, secure your code, and protect your users

Question has a verified solution.

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

This article covers the basics of the Sass, which is a CSS extension language. You will learn about variables, mixins, and nesting.
JavaScript has plenty of pieces of code people often just copy/paste from somewhere but never quite fully understand. Self-Executing functions are just one good example that I'll try to demystify here.
Viewers will learn about the regular for loop in Java and how to use it. Definition: Break the for loop down into 3 parts: Syntax when using for loops: Example using a for loop:
Explain concepts important to validation of email addresses with regular expressions. Applies to most languages/tools that uses regular expressions. Consider email address RFCs: Look at HTML5 form input element (with type=email) regex pattern: T…

688 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