Folks,
I've got badly stuck with something that I thought would be easy: I have a page and I want to display a PDF that's stored in my media collection.
I can link to a PDF using the standard toolbar but to embed a PDF, I have to turn to xslt and macro code.
This is what I have:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xsl:Stylesheet [ <!ENTITY nbsp " "> ]>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxml="urn:schemas-microsoft-com:xslt"
xmlns:umbraco.library="urn:umbraco.library"
exclude-result-prefixes="msxml umbraco.library">
<xsl:output method="xml" omit-xml-declaration="yes"/>
<xsl:param name="currentPage"/>
<xsl:template match="/">
<xsl:variable name="pdfFile" select="$currentPage/data [#alias='pdfFile']"/>
<xsl:if test="$pdfFile!= '' ">
<embed width="796" height="1032">
<xsl:attribute name="src">
<xsl:value-of select="umbraco.library:GetMedia(./data [#alias = 'pdfFile'], 'false')/data [#alias = 'umbracoFile']"/>
</xsl:attribute>
</embed>
</xsl:if>
</xsl:template></xsl:stylesheet>
But it's not working - I get nothing on the page. I've looked for solutions to this (perhaps my reference to GetMedia is wrong) but I can't find anything that'll help me.
Oh, my macro is using pdfFile as the parameter and is set as mediaCurrent.
I'm using Umbraco 4.7.1
Any pointers, help or advice would be great.
Thanks!
Actually, it's pretty easy.
Here it is documented for anyone using Umbraco 4.7.x and who needs to display pdf files:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xsl:Stylesheet [ <!ENTITY nbsp " "> ]>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxml="urn:schemas-microsoft-com:xslt"
xmlns:umbraco.library="urn:umbraco.library"
exclude-result-prefixes="msxml umbraco.library">
<xsl:output method="xml" omit-xml-declaration="yes" />
<xsl:param name="currentPage"/>
<xsl:param name="pdf" select="/macro/pdfFile"/>
<xsl:template match="/">
<embed width="100%" height="500">
<xsl:attribute name="src">
<xsl:value-of select="$pdf/File/umbracoFile"/>
</xsl:attribute>
</embed>
</xsl:template>
</xsl:stylesheet>
For clarification, you will also need a macro (name unimportant) that uses this xslt. You will also have to add a parameter to the macro called pdfFile, click on the 'show' checkbox and then save it all.
The width and height of the embed can, of course, be set to whatever suits you.
Have fun.
Related
I am trying to create an empty file through xslt.
The input sample is:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Businessman>
<siblings>
<sibling>John </sibling>
</siblings>
<child> Pete </child>
<child> Ken </child>
</Businessman>
When the input contains any presence of 'child' tags, it should produce the file AS IS. When the input does not have any 'child' tag, I need an empty file (0 byte file) created.
This is what I tried:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" />
<xsl:template match="#*|node()">
<xsl:choose>
<xsl:when test="/Businessman/child">
<xsl:copy>
<xsl:apply-templates select="#*|node()" />
</xsl:copy>
</xsl:when>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
This gives the file unchanged when there is any 'child' tag present. But did not produce any empty file when there is no 'child' tag.
The file I need to test will look like:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Businessman>
<siblings>
<sibling>John </sibling>
</siblings>
</Businessman>
Any help would be great!
Thanks
If you want the processor to go to the trouble of opening the output file, you have to give it something to write to the output file. Try an empty text node. And you only need to make the decision 'copy or not?' once.
One way to make the decision just once and produce empty output if the condition is not met would be to replace your template with:
<xsl:template match="/">
<xsl:choose>
<xsl:when test="/Businessman/child">
<xsl:copy-of select="*"/>
</xsl:when>
<xsl:otherwise>
<xsl:text/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
This works as expected with xsltproc. (If you find yourself getting a file containing an XML declaration and nothing else, try adjusting the parameters on xsl:output.)
But when I have found myself with a similar situation (perform this transform if condition C holds, otherwise ...), I have simply added a template for the document node that would look something like this for your case:
<xsl:choose>
<xsl:when test="/Businessman/child">
<xsl:apply-templates/>
</
<xsl:otherwise>
<xsl:message terminate="yes">No children in this input, dying ...</
</
</
That way I get no output at all rather than zero-length output.
Simple enough - Just don't try to do everything in one template, don't forget to omit the xml declaration and get the xpath right:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes" />
<xsl:template match="/">
<xsl:apply-templates />
</xsl:template>
<xsl:template match="Businessman[child]" priority="9">
<xsl:element name="Businessman">
<xsl:apply-templates />
</xsl:element>
</xsl:template>
<xsl:template match="Businessman" priority="0" />
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
I need a parameter to be send to a template to help with processing the right nodes in an external second xml file (this to keep the amount of templates small).
I've found that the following code send the parameter and processes it correctly:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes"/>
<xsl:template match="/">
This is text1
<xsl:apply-templates mode="my-mode">
<xsl:with-param name="testParam" select="'TEST_PARAMETER'"/>
</xsl:apply-templates>
This is text2
</xsl:template>
<xsl:template match="DialStats" mode="my-mode">
<xsl:param name="testParam" />
<br></br>
This is text 3<br></br>
<xsl:value-of select="$testParam" /><br></br>
This is text 4<br></br>
</xsl:template>
</xsl:stylesheet>
When I implement the second file I've found that the following no longer passes the parameter:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes"/>
<xsl:template match="/">
This is text1
<xsl:apply-templates select="document('file://D:/DATA/Marquee/DATA/MarqueeStats.xml')" mode="my-mode">
<xsl:with-param name="testParam" select="'TEST_PARAMETER'"/>
</xsl:apply-templates>
This is text2
</xsl:template>
<xsl:template match="DialStats" mode="my-mode">
<xsl:param name="testParam" />
<br></br>
This is text 3<br></br>
<xsl:value-of select="$testParam" /><br></br>
This is text 4<br></br>
</xsl:template>
It calls the template correctly, as I can see both the lines with 'This is text x". So the parameter is gone. I did find some articles suggesting the match= needs to be set, so I matched that with the xml root:
<DialStats>
<Countries Country="Denmark">
<Products Product="MR">
. . .
Any suggestions on how to resolve this?
BTW this is just the basics I need to get right as a lot more code need to be added.
Could you explain how to set xpath of a node as the value to a xslt variable . I also want to display the value and then pass it as a parameter to a JS Function. Thanks for all your Help.
XPath expressions are not values, so they cannot be bound to variables. You can of course put an XPath expression in a string. There's no standard way in XSLT to execute an XPath expression held in a string, but many implementations have an extension function (such as xx:evaluate()) to do it.
It helps to explain what problem you are trying to solve, not what technique you are trying to use to solve it. Then we could suggest alternative and perhaps better approaches.
Sample Input XML:
<?xml version="1.0" encoding="utf-8"?>
<root>
<child>
<trial>test</trial>
</child>
</root>
Model code to pass XPath of current node to inline JS function:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl" xmlns:js="urn:js">
<xsl:output method="xml" indent="yes"/>
<msxsl:script language="JScript" implements-prefix="js">
<![CDATA[
function test(something)
{
//code here
}
]]>
</msxsl:script>
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="trial">
<xsl:copy>
<xsl:variable name="xpath">
<xsl:for-each select="ancestor-or-self::*">
<xsl:value-of select="name()"/>
<xsl:if test="not(position()=last())">
<xsl:value-of select="'/'"/>
</xsl:if>
</xsl:for-each>
</xsl:variable>
<xsl:apply-templates select="js:test($xpath)"/> <!--Passed value $xpath to funciton test-->
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
having return value as
return (something);
will output:
<?xml version="1.0" encoding="utf-8"?>
<root>
<child>
<trial>root/child/trial</trial>
</child>
</root>
I'm working on an xsl template in shipworks. I was able to make this simple code to create a text file 'pick list' that I could use.
<!DOCTYPE xsl:stylesheet [ <!ENTITY nl "
"> ]>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:sw="http://www.interapptive.com/shipworks" extension-element-prefixes="sw">
<xsl:import href="ShipWorks2\System\Common" />
<xsl:output method="text" encoding="utf-8" />
<!-- -->
<!-- Start of processing -->
<!-- -->
<xsl:template match="/">
<xsl:for-each select="//Order/Item">
<xsl:sort order="descending" select="../Total" data-type="number" />
<xsl:sort order="descending" select="../Number" data-type="number" />
<xsl:value-of select="SKU" />,<xsl:value-of select="Quantity" /><xsl:text>
</xsl:text>
</xsl:for-each>
</xsl:template>
Yeah, I know, really great huh!? Hey, that took me forever to get right! As you can see, it's making a list of SKUs. Well, each of my SKU's looks something like this:
BLAH-BLAH-PRODUCTSKU
I was wondering if there was a way to get ONLY the 'PRODUCTSKU' out of that value, and cut off everything before the last - character.
In looking around online, I saw the substring-after-last function. I'm wondering if I could use that? I tried putting that in there, but I think I'm missing something in regards to a declaration or whatnot.
In the place of
<xsl:value-of select="SKU" />
Replace the below code. It should work,
<xsl:variable name="input">
<xsl:value-of select="SKU" />
</xsl:variable>
<xsl:value-of select="replace($input,'^(.)+?(PRODUCTSKU)$','$2')"/>
I'm trying to parse out a FlowDocument that has a couple specific template match cases that I'm having trouble with.
So, for the Xaml document below (this was created by opening Word, creating the text, then copying into a WPF richtextbox and extracting the FlowDocument Xaml).
<FlowDocument PagePadding="5,0,5,0" AllowDrop="True" NumberSubstitution.CultureSource="User" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<Span xml:lang="en-us">
<Span.TextDecorations>
<TextDecoration Location="Underline" />
</Span.TextDecorations>
List Item 2
</Span>
<Run>
<Run.TextDecorations>
<TextDecoration Location="Underline" />
</Run.TextDecorations>
List Item 3
</Run>
</FlowDocument>
Using the following Xslt, I'm trying to match the Span and Run tags that have a child node "TextDecoration" that has an attribute value "Location=Underline".
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:p="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
exclude-result-prefixes="msxsl">
<xsl:output method="html" indent="yes"/>
<xsl:template match="/">
<html>
<body>
<xsl:apply-templates />
</body>
</html>
</xsl:template>
<xsl:template match="p:FlowDocument">
<xsl:apply-templates />
</xsl:template>
<xsl:template match="p:Run/Run.TextDecorations/TextDecoration[#Location='Underline']">
<u>
<xsl:apply-templates />
</u>
</xsl:template>
</xsl:stylesheet>
I realize the above statement will not work, and if it actually did it would probably select the child node, not the parent node that I'm looking to get to.
The output I'm trying to get is the following:
<html xmlns:p="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<body>
<u>List Item 2</u>
<u>List Item 3</u>
</body>
</html>
I'm also having issues just matching "p:Run/Run.TextDecorations" element. Using Visual Studio, and stepping through the execution, it never finds the node I'm trying to find.
Any hints are welcome! Thanks!
There are a couple of ways you could match them. For example, you could specify the full path to descendant node you want to check for
<xsl:template
match="p:Run[p:Run.TextDecorations/p:TextDecoration/#Location='Underline']">
Or if you want to be less explicitly, and just check there was descendant matching at some level, you could do the following
<xsl:template
match="p:Span[descendant::p:TextDecoration/#Location='Underline']">
Do note the use of the namespace prefix on all elements in the XPath condition.
So, given the following XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:p="http://schemas.microsoft.com/winfx/2006/xaml/presentation" exclude-result-prefixes="msxsl p">
<xsl:output method="html" indent="yes"/>
<xsl:template match="/">
<html>
<body>
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
<xsl:template match="p:Run[p:Run.TextDecorations/p:TextDecoration/#Location='Underline']">
<u>
<xsl:apply-templates/>
</u>
</xsl:template>
<xsl:template match="p:Span[descendant::p:TextDecoration/#Location='Underline']">
<u>
<xsl:apply-templates/>
</u>
</xsl:template>
<xsl:template match="p:FlowDocument">
<xsl:apply-templates/>
</xsl:template>
</xsl:stylesheet>
When applied to your sample XML, the following is output:
<html>
<body>
<u> List Item 2 </u>
<u> List Item 3 </u>
</body>
</html>