Want to win a PS4? Go Premium and enter to win our High-Tech Treats giveaway. Enter to Win

x
?
Solved

"Back references" in XML / XSLT

Posted on 2003-11-17
6
Medium Priority
?
332 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
Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

 
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

Independent Software Vendors: 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!

Question has a verified solution.

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

The Confluence of Individual Knowledge and the Collective Intelligence At this writing (summer 2013) the term API (http://dictionary.reference.com/browse/API?s=t) has made its way into the popular lexicon of the English language.  A few years ago, …
Originally, this post was published on Monitis Blog, you can check it here . In business circles, we sometimes hear that today is the “age of the customer.” And so it is. Thanks to the enormous advances over the past few years in consumer techno…
Viewers will learn one way to get user input in Java. Introduce the Scanner object: Declare the variable that stores the user input: An example prompting the user for input: Methods you need to invoke in order to properly get  user input:
The viewer will learn how to create and use a small PHP class to apply a watermark to an image. This video shows the viewer the setup for the PHP watermark as well as important coding language. Continue to Part 2 to learn the core code used in creat…

610 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