xsl transform: problem with Ampersand URL parameters - xslt

I'm having issues with transforming XSL with parameters in a URL. I'm at a point that I can't change the C# code anymore, only can make changes to xsl file.
C# code:
string xml = "<APPLDATA><APPID>1052391</APPID></APPLDATA>";
XmlDocument oXml = new XmlDocument();
oXml.LoadXml(xml);
XslTransform oXslTransform = new XslTransform();
oXslTransform.Load(#"C:\Projects\Win\ConsoleApps\XslTransformTest\S15033.xsl");
StringWriter oOutput = new StringWriter();
oXslTransform.Transform(oXml, null, oOutput)
XSL Code:
<body>
<xsl:variable name="app">
<xsl:value-of select="normalize-space(APPLDATA/APPID)" />
</xsl:variable>
<div id="homeImage" >
<xsl:attribute name="style">
background-image:url("https://server/image.gif?a=10&Id='<xsl:value-of disable-output-escaping="yes" select="$app" />'")
</xsl:attribute>
</div>
</body>
</html>
URL transformed:
https://server/image.gif?a=10&Id='1052391'
URL Expected:
https://server/image.gif?a=10&Id='1052391'
How do I fix this? The output (oOutput.ToString()) is being used in an email template so it's taking the URL transformed literally. When you click on this request (with the correct server name of course), the 403 (Access forbidden) error is being thrown.

The problem is not the ampersand but the single quotes around the id. If they have to be present they have to be url encoded.
So (assuming no quotes are needed around the id) this should work:
<body>
<xsl:variable name="app">
<xsl:value-of select="normalize-space(APPLDATA/APPID)" />
</xsl:variable>
<div id="homeImage" >
<xsl:attribute name="style">
<xsl:text disable-output-escaping="yes">background-image:url('https://server/image.gif?a=10&Id=</xsl:text>
<xsl:value-of disable-output-escaping="yes" select="$app" />
<xsl:text>')</xsl:text>
</xsl:attribute>
</div>
</body>

What you get is actually what you want. The ampersand must be escaped in HTML, no matter where it occurs. So this
<div
id="homeImage"
style="background-image:url("https://server/image.gif?a=10&Id='1052391'")"
></div>
acutally is valid HTML, while this
<div
id="homeImage"
style="background-image:url("https://server/image.gif?a=10&Id='1052391'")"
></div>
is not (check it in the validator). The error you receive must come from somewhere else.

Related

XSLT: templates without mode ignored in result-documents

I'm learning to use the mode attribute and must being doing something wrong. Apologies if this has been answered before but I'm not finding it here.
I want to process "title" elements separately depending on their context. For the main document, I want to add an "a" element inside of it:
<xsl:template match="title">
<div>
<xsl:value-of select="."/>
<a href="some_URL">some text
</a>
</div>
</xsl:template>
But elsewhere I'm creating result-documents where I just want the title:
<xsl:tamplate match="title" mode="print">
<div class="title">
<xsl:value-of select="."/>
</div>
</xsl:template>
In my main template match="/" I'm doing a for-each for each section, creating a result-document for each one:
<xsl:for-each select="/topic/body/bodydiv/section">
<xsl:result-document href="{$printoutfile}">
<html><head>some stuff</head><body>
<div class="section">
<xsl:apply-templates mode="print"/>
</div>
... more stuff...
</body</html>
</xsl:result-document>
</xsl:for-each>
Then I call everything else for the main document:
<html><head>stuff</head>
<body>
<div>
<xsl:apply-templates/>
</div>
</body>
</html>
The problem is this works for the result-document title but none of the rest of the result-document templates are used, since they don't have mode="print" on them. So the rest of the result-document all comes out as text.
Any idea what I need to do here? I'm obviously missing something basic.
thank you
Scott
You have not shown any of the other templates but if you expect the <xsl:apply-templates mode="print"/> to apply them then you need to have a mode="#all" on them. And if they do additional apply-templates then you need to use <xsl:apply-templates select="#current"/>. See http://www.w3.org/TR/xslt20/#modes for details.

XSLT Parsing error when using Umbraco GetMedia

I am trying to retrieve the url to an image using the GetMedia mediapicker.
The code below works fine:
<xsl:for-each select="umbraco.library:GetXmlNodeById(1123)/* [#isDoc]">
<article>
<img width="1822" height="600">
<xsl:attribute name="src">
<xsl:value-of select="umbraco.library:GetMedia(1139, 0)/umbracoFile" />
</xsl:attribute>
</img>
<div class="contents">
<h1>
<xsl:value-of select="bannerHeading1"/>
</h1>
</div>
</article>
</xsl:for-each>
However, if I replace the key line with this:
<xsl:value-of select="umbraco.library:GetMedia(bannerImage, 0)/umbracoFile" />
I get a parsing error with the exception being an OverflowException (Value was either too large or too small for an Int32), which suggests that it's not the 1139 that is being passed in.
Is there a way I can pass in the property I want? The value of "bannerImage" is 1139 as I want it to be?
Thanks for any help.
Further: This is the XML structure being returned by GetXMLNodeById:
<?xml version="1.0" encoding="utf-8" ?>
<HomepageBanner id="1141" parentID="1123" level="3" writerID="0" creatorID="0" nodeType="1124" template="1125" sortOrder="0" createDate="2013-08-12T15:53:48" updateDate="2013-08-12T15:54:18" nodeName="Members" urlName="members" writerName="admin" creatorName="admin" path="-1,1065,1123,1141" isDoc="">
<bannerImage>1139</bannerImage>
<bannerHeading1>Members Area</bannerHeading1>
<bannerHeading2>..the place for all your needs</bannerHeading2>
</HomepageBanner>
For anyone else trying to get an image from an item in a content folder, this is how I got it to work:
<xsl:for-each select="umbraco.library:GetXmlNodeById(1123)/* [#isDoc]">
<article>
<!-- Store the ID -->
<xsl:variable name="mediaId" select="bannerImage" />
<!-- Check the ID is numeric -->
<xsl:if test="number($mediaId) > 0">
<xsl:variable name="mediaNode" select="umbraco.library:GetMedia($mediaId, false())" />
<xsl:if test="string-length($mediaNode/umbracoFile) > 0">
<img src="{$mediaNode/umbracoFile}" width="1822" height="600" />
<div class="contents">
<h1>
<xsl:value-of select="bannerHeading1"/>
</h1>
</div>
</xsl:if>
</xsl:if>
</article>
</xsl:for-each>
You first need to check that the value is numeric and then, the bit that was failing me, you need to add the "/umbracoFile" part to your media node variable.
Thanks to the contributors who helped me in the right direction.

Umbraco NiceUrl ToLower

I'm trying to change the URL to lower in my href tag, here is my code:
<a href="{$url}{umbraco.library:NiceUrl(#id)}/{$AppendedID}/">
I've tried using Exslt.ExsltStrings:lowercase(node-set) with no joy as this throws an error. Does anyone have any suggestions?
The following expression should work:
Exslt.ExsltStrings:lowercase(concat($url, umbraco.library:NiceUrl(#id), '/', $AppendedID, '/'))
Testing with the following piece of code ....
<xsl:for-each select="$currentPage">
<xsl:variable name="url" select="'http://www.EXAMPLE.com'" />
<xsl:variable name="AppendedID" select="123" />
<a href="{Exslt.ExsltStrings:lowercase(concat($url, umbraco.library:NiceUrl(#id), '/', $AppendedID, '/'))}">
<xsl:value-of select="#nodeName" />
</a>
</xsl:for-each>
.... the rendered HTML should be along the lines of ....
Some Page
I don't know direct way to solve this except using Exslt.ExsltStrings:lowercase(node-set)
but is this throw error when you use it with umbraco.library:NiceUrl then you may try to make the string lower and store it in temp variable then use this temp variable directly.

How do I output html markup stored in a xsl:variable

I am trying to render markup stored in a variable but I am getting no joy. Reason its cached is because I am using this several times in the page
<xsl:variable name="imgHtml">
<figure>
<img src="{$img}" alt="" class="" />
<figcaption>
<p><xsl:value-of select="name" /></p>
Enlarge Image
</figcaption>
</figure>
</xsl:variable>
I then reference the variable using the value-of elment
<xsl:value-of select="$imgHtml" /> but for some reason, the HTML does not render. Don't be shy, I need the help. Thanks!
Use <xsl:copy-of select="$imgHtml"/>, value-of always creates a plain text node.
The other answers were not working for me, however this did:
<xsl:value-of select="$variable" disable-output-escaping="yes"/>

Using a link in XSL Files

I am completely new to XML so hopefully my explanations will make sense..
I am using an XSL file with 2 sections of HTML text, reading from 2 templates set up within the file.
The first text and associated template is a table, and I have set up a link within that. I want the link to then point to a picture that is part of the 2nd HTML text/template.
The link in the table is setup in that it appears as a link, underlined, etc. However it doesnt go anywhere when clicked.
The second section works fine on it's own, eg, pictures and text appears.
But what I cant figure out is how to actually get the link to work. I've tried numerous things but nothing has worked so far. And I-m not sure whether I am very close and just perhaps need to alter a line of code. Or whether I need to be doing something very different. Also, there are no error messages, and everything displays well, it's just the link itself that doesnt work.
<xsl:template match="portion">
<tr>
<td valign="top"><xsl:value-of select="food-description"/></td>
<td valign="top"><xsl:value-of select="food-number"/></td>
<!--the following is the link text-->
<td valign="top"><a><xsl:attribute name="href">#<xsl:value-of select="portion- photo/#file"/></xsl:attribute>
<xsl:value-of select="portion-photo/#file"/></a><br/>
</td>
</tr>
</xsl:template>
<xsl:template match="portion-photo">
<!--I know that this is the code that is not correct, however, believe it should be something similar-->
<a><xsl:attribute name="portion-photo"><xsl:value-of select="./#file"/></xsl:attribute></a>
<p><xsl:value-of select="../food-description"/>
<xsl:value-of select="./#file"/></p>
<img>
<xsl:attribute name="src"><xsl:value-of select="./#file"/></xsl:attribute>
<xsl:attribute name="width"><xsl:value-of select="ceiling(./#w div v2)"/></xsl:attribute>
<xsl:attribute name="height"><xsl:value-of select="ceiling(./#h div 2)"/></xsl:attribute>
</img>
</xsl:template>
Something like the following should work. Just add the missing name attribute to the anchor element:
<xsl:template match="portion">
...
<a href="#{portion-photo/#file}">
<xsl:value-of select="portion-photo/#file"/>
</a>
...
</xsl:template>
<xsl:template match="portion-photo">
<a name="{#file}">
<xsl:value-of select="#file"/>
</a>
</xsl:template>
However, you have to ensure that #file evaluates to a valid anchor name. If the values of all file attributes are unique, you could also create save IDs with generate-id():
<xsl:template match="portion">
...
<a href="#{generate-id(portion-photo)}">
<xsl:value-of select="portion-photo/#file"/>
</a>
...
</xsl:template>
<xsl:template match="portion-photo">
<a name="{generate-id()}">
<xsl:value-of select="#file"/>
</a>
</xsl:template>