Is there a way in XSL 1.0 to hand over variables or parameters using XSL fo:external-graphic like I would do when I'm using xsl:call-template
I know how I could work around the problem but I just wanted to know if there is a way I am not seeing.
If your SVGs are small enough, you could use fo:instream-foreign-object. (If the SVGs are very large, the size of the XSL-FO file might become a problem.)
main.xsl:
<xsl:import href="svg/svg_graphic.xsl" />
<xsl:template match="some/context">
<fo:instream-foreign-object>
<xsl:call-template name="make-svg">
<xsl:with-param name="param-a" select="..." />
</call-template>
</fo:instream-foreign-object>
</xsl:template>
svg_graphic.xsl:
<xsl:template name="make-svg">
<xsl:param name="param-a" select="..." />
<svg:svg>
...
</svg:svg>
</xsl:template>
<fo:external-graphic src="svg/svg_graphic.xsl" /> is not going to work. Inside your XSLT stylesheet, the elements in the XSL-FO namespace are just literal result elements. They are copied to the result tree, and they are not otherwise acted on by the XSLT processor. XSLT-specific attributes on literal result elements (where the attribute in the XSLT namespace and is defined as meaning something when used on literal result elements) are acted on by the XSLT processor. Attribute value templates ({...}) in attribute values of literal attributes (and some XSLT-defined attributes) are acted on by the XSLT processor.
There is no XSLT 1.0 way to get the XSLT processor to run another stylesheet based on the value of an XSL-FO-defined attribute.
There's also no XSLT 1.0 way to generate multiple result documents from one run of a stylesheet. Your XSLT processor probably has a processor-specific (or EXSLT) way to do that. The extension, if it exists, might not let you generate part of the XSL-FO result document, generate an SVG result document, and then go back to generating more of the XSL-FO document.
Related
With several xml documents containing topic elements and only one file containing a topic element with attribute product="OPTION".
I'd like to write OPTION if the attribute is set for the topic and TOTO if no attribute exists for the topic.
The problem is that actally if at least one file contains the attribute product="OPTION" OPTION is written on every generated pdf page.
<xsl:template name="insertBodyEvenHeader">
<xsl:param as="xs:string" name="flow-name" select="'even-body-header'" />
<fo:static-content flow-name="{$flow-name}">
<fo:block xsl:use-attribute-sets="__body__even__header">
<xsl:choose>
<xsl:when test="topic/#product='OPTION'">
<fo:inline xsl:use-attribute-sets="title__option">
<xsl:text>OPTION</xsl:text>
</fo:inline>
</xsl:when>
<xsl:otherwise>TOTO</xsl:otherwise>
</xsl:choose>
</fo:block>
</fo:static-content>
</xsl:template>
Would you be so kind to help me dealing with that test? thansks, best regards
It is likely that your context for this template is something above topic (which makes sense because you test on topic/#product). That is why if you have 10 topic elements and one has #product='OPTION' then the WHEN is true.
If that is true and you want to test on current topic being output, then you would use retrieve-marker in the header and then create markers in the topic template and pull those markers into header.
Your choose would then become #product (because you are in the topic template) and you would just drop an fo:marker that would have your choose inside, then use fo:retrieve-marker and some retrieve-position depending on how you want them to be processed. If a topic always starts a page then you would use first-including-carryover.
I am using FOP library to generate pdf from a xml file, able to generate all the data(except image) with dynamic info passed through another xml. Its not allowing me to pass image value as below
<fo:inline>
<fo:external-graphic content-width="109.5pt"
content-height="50.25pt"
src="<xsl:value-of select="paymentno" />"
</fo:external-graphic >
</fo:inline>
where xml data which is being passed dynamically is
`<tns:paymentno>
"url("data:image/auto;base64,iVBORw0KGgoAAAANSUhEUgAAAFUAAAAoCAIAAAAAKyESAAAAYUlEQVR42u3PQQoAIAgEwP7/6YIiEC3oGownjWVjWt/T5qwlvqQz5utyKzkGUvJYlX55aahnjOUAPz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/P/+H/gGaQxUFTT6pUgAAAABJRU5ErkJggg==;")"</tns:paymentno>`
One more thing, if i am passing static value(of image) directly to xsl then i am able to get image in my pdf.
Please do provide me with solution if you have any idea asap
Your XSL is incorrect. You cannot just put xsl:value-of inline. See this answer for inspiration to write the template.
Inserting a base64 encoded image into xsl-fo file while using apache-poi
You will be passing your result to an XSL function, so you can just read the value directly.
<fo:inline>
<fo:external-graphic
content-width="109.5pt"
content-height="50.25pt"
src="url({paymentno})">
</fo:external-graphic >
</fo:inline>
If you really wanted to use value-of, then you will use it to set an xsl attribute. From memory this should be (untested):
<fo:inline>
<fo:external-graphic
content-width="109.5pt"
content-height="50.25pt">
<xsl:attribute name="src">
<xsl:value-of select="paymentno"/>
</xsl:attribute>
</fo:external-graphic>
</fo:inline>
I am trying to generate the following structure in an XSLT template.
<ns:e1>
<child1>some value<child1>
<child2>some value<child2>
<child3>some value<child3>
</ns:e1>
or
<ns:e2>
<child1>some value<child1>
<child2>some value<child2>
<child3>some value<child3>
</ns:e2>
or other elements ns:e3 etc (although finite), based on a template parameter (say type). Typically I could use an xls:choose construct. In such a case, I would be duplicating the child elements (whose values are also template parameters).
Is there a way in XSLT to dynamically assume the element name ns:e1 or ns:e2 so that I can put the child elements once in its parent. I could save maintenance effort later if I have change the child elements or values (change once in one place and avoid bugs due to human errors).
Thanks for your help in advance.
Yes, you may use the xsl:element instruction to do that.
Assuming you always want to have <child1>some value<child1><child2>some value<child2><child3>some value<child3> as children for your parent element, you could rewrite your code like so:
<xsl:variable name="elementName">
<!-- compute the element name here ... -->
</xsl:variable>
<!-- Here we create an element having the name computed in variable elementName -->
<xsl:element name="{$elementName}" namespace="http://www.anamespace.com/and/so/on">
<child1>some value<child1>
<child2>some value<child2>
<child3>some value<child3>
</xsl:element>
Is it possible to move the result generated by the XSLT processor. e.g. in the below case i wanted Benefit type="Main" and its child elements to be displayed before Benefit type="Rider"
Two separate templates are applied for Rider and Main, hence i think xsl:sort cannot be applied, since it sorts within a single collection.
<Policy>
<Benefit type="Rider">
<ProductAbbreviatedName>BBB</ProductAbbreviatedName>
<ProductCode>U30</ProductCode>
<ProductName>BBB</ProductName>
</Benefit>
<Benefit type="Main">
<ProductAbbreviatedName>AAA</ProductAbbreviatedName>
<ProductCode>231Y</ProductCode>
<ProductName>AAAA</ProductName>
</Benefit>
</Policy>
Kindly advice on some ideas to perform the desired output. Many thanks.
Just use in your code:
<xsl:apply-templates select="Benefit[#type='Main']"/>
<xsl:apply-templates select="Benefit[#type='Rider']"/>
I'm looking to use a variable as part of an XPath expression.
My problem might be the msxsl node-set function... not sure. But don't let that cloud your judgement... read on...
I'm using a .NET function to load up the content file, which is passed in via bespoke XML content. The #file results in an XML file.
The bespoke XML the sits on the page looks like :
<control name="import" file="information.xml" node="r:container/r:group[#id='set01']/r:item[1]" />
The XSL looks like :
<xsl:variable name="document">
<xsl:copy-of select="ext:getIncludedContent(#file)" />
</xsl:variable>
I'm then translating this to a node-set so I can query the document
<xsl:variable name="preset-xml" select="msxsl:node-set($document)" />
The source file I am loading in looks like :
<container>
<group id="set01">
<item>value01</item>
<item>value02</item>
<item>value03</item>
</group>
<group id="set02">
<item>value04</item>
<item>value05</item>
</group>
</container>
It works up until this point. I can see the source file being brought thru and output as XML.
My problem comes in when I am trying to query the source file with an XPath expression fed in from the content.
I've tried :
<xsl:value-of select="$preset-xml/#node" />
Clearly that doesn't work as it looks for #node as a direct child of the loaded in XML.
I've tried :
<xsl:variable name="node" select="#node" />
<xsl:value-of select="$preset-xml/$node" />
But it doesn't like the second variable.
I've tried concat($preset-xml,'/',$node), but that still draws out the entire document in the result.
The only way I can get this working at the moment is to write out the full expression in the template :
<xsl:value-of select="$preset-xml/r:container/r:group[#id='set01']/r:item[1]" />
Which correctly brings thru value01
But that is then a hard coded solution.
I want to develop a solution which can be manipulated from the content to suit any sort of imported content, with the parameters declared in the content file.
p.s. I'm using XSLT 1.0 because the tech admin won't change the Microsoft parser to support later versions of XSL, so any solution would need to be written with that in mind.
There is no feature similar to reflection in XSLT. MS XSLT engine, in particular, compiles XPath queries when the XSLT was loaded, not when it was applied to your XML document. There is a reason to this: it separates the code (XSLT) from the data (input XML).
What are you trying to achieve by mixing up code and data; are you sure you really need to execute an arbitrary XPath expression from the input XML? Think, for example, what if the user will pass in the #name equal to e.g. //*, and then you'll send to the output the content of the entire input XML document, which might contain some sensitive data.
If you really need to do the thing you described, you may write your own XSLT extension object, which will accept the document root and the XPath query and will return the latter applied to the former. Then you'll be able to call it like that:
<xsl:value-of select="myExtensionNs:apply-xpath($preset-xml, #node)"/>
As for your original attempt with concat($preset-xml,'/',$node), concat is the string concatenating function. You supply some arguments to it, and it returns the concatenation of its string representations. So, concat($preset-xml,'/',$node) will return the string value of $preset-xml, concatenated with /, concatenated with the string value of $node. If you were trying to write a needed XPath query, concat('$preset-xml','/',$node) would seem more logical (note the quotes); still, there is no way to evaluate the resulted string (e.g. $preset-xml/r:container/r:group[#id='set01']/r:item[1]) to the value of corresponging XPath query; it could only be sent to output.
One possible trick is to call an parametrized xsl:template which carries out the crucial select comparison part and evaluate it's output as string.
I had a similar problem (count all nodes of an arbitrary attribute value) which I solved this way (btw: $sd = 'document($filename)' so I load a secondary xml files content):
<xsl:template match="/">
<xsl:variable name="string_cntsuccess">
<xsl:for-each select="./Testcase">
<xsl:variable name="tcname" select="#location"/>
<xsl:for-each select="$sd//TestCase[#state='Passed']">
<xsl:call-template name="producedots">
<xsl:with-param name="name" select="$tcname"/>
</xsl:call-template>
</xsl:for-each>
</xsl:for-each>
</xsl:variable>
<xsl:variable name="cntsuccess" select="string-length($string_cntsuccess)"/>
</xsl:template>
<xsl:template name="producedots">
<xsl:param name="name"/>
<xsl:variable name="ename" select="#name"/>
<xsl:if test="$name = $ename">
<xsl:text>.</xsl:text>
</xsl:if>
</xsl:template>