I have a several pages sequences in my xsl file. An xsl-template is called inside each page sequence. Inside each template I have a block that contains a variable that I need to be incremented if the block is executed....I tried to use a global variable but I found in many posts here we cannot increment a global variable in xsl-fo...Can SomeOne please guides me How to do that ?
My xsl-file is something like this:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format" version="1.0"
xmlns:pdf="http://xmlgraphics.apache.org/fop/extensions/pdf">
<xsl:output encoding="UTF-8" indent="yes" method="xml"
standalone="no" omit-xml-declaration="no" />
<xsl:template match="analyseData">
<fo:page-sequence master-reference="simpleA6">
<fo:flow flow-name="xsl-region-body" border-collapse="collapse">
<xsl:call-template name="template1" />
</fo:flow>
</fo:page-sequence>
<fo:page-sequence master-reference="simpleA6">
<fo:flow flow-name="xsl-region-body" border-collapse="collapse">
<xsl:call-template name="template2" />
</fo:flow>
</fo:page-sequence>
<fo:page-sequence master-reference="simpleA6">
<fo:flow flow-name="xsl-region-body" border-collapse="collapse">
<xsl:call-template name="template3" />
</fo:flow>
</fo:page-sequence>
</xsl:template>
If you can come up with a pattern for all of the nodes in the source that need to be numbered and the numbering sequence is in the document order of the nodes in the source document, then you could use <xsl:number match="any" count="..." /> to do the counting. See https://www.w3.org/TR/xslt20/#numbering-based-on-position
If the count sequence doesn't match your source document or you can't find a pattern, then you're probably back to post-processing, as #kevin-brown suggests.
Well, there is very limited information here but I could guess.
Nothing stops you from using XSL and an identity-transform to modify some interim result.
So you could do what you are doing. Whenever you need to output this counter, why not write to the output <counter/>. Nothing more, just an empty tag that represents the counter.
Then write an identity-translate XSL that outputs the resulting file as is, except for a match on <counter>. This template would replace it with:
<fo:inline><xsl:value-of select="count(preceding::counter) + 1"/></fo:inline>
Note: you could maybe also use <xsl:number> here.
So you would do:
XML+XSL -> XSL FO with counters + XSL identity change counters -> XSL FO -> format with your formatter
Related
Need small help in creating a function with parameter and that can be used in my template. Tried many things but nothing worked out. Below is my sample code :
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0"
xmlns:math="http://exslt.org/math"
xmlns:func="http://exslt.org/functions"
xmlns:my="http://exslt.org/my"
exclude-result-prefixes="my"
extension-element-prefixes="my math func">
<xsl:output indent="yes" method="xml" />
<xsl:variable name="functionTest11">
<xsl:value-of select="my:calXY('aa')" />
</xsl:variable>
<xsl:template match="/">
<svg xmlns="http://www.w3.org/2000/svg">
<xsl:variable name="functionTest22">
<xsl:value-of select="my:calXY" />
</xsl:variable>
<xsl:comment>functionTest <xsl:copy-of
select="$functionTest22" /></xsl:comment>
</svg>
</xsl:template>
<func:function name="my:calXY">
<xsl:comment>functionHello </xsl:comment>
<xsl:param name="string1" select="''"/>
<func:result>
<xsl:value-of select="concat(10,'|',10)" />
</func:result>
</func:function>
</xsl:stylesheet>
I don't have convenient access (that I know of) to Xalan, which appears to be the XSLT processor you are using. So I cannot test any conjectures about the origin of your problem.
But it would surprise me a great deal if putting an output instruction like xsl:comment before the first (and only) xsl:param were correct. (It surprises me that you don't report any error messages from the stylesheet compiler. But it's clear from the error message you quote that Xalan has not successfully compiled the function.) It's not clear what you are trying to accomplish by having your function return both a comment node and the string value '10|10', but this is probably not the way to accomplish it.
On the assumption that the xsl:comment instruction is an attempt to verify that the function has in fact been evaluated, I'd try something like
<func:function name="my:calXY">
<xsl:param name="string1" select="''"/>
<func:result select="concat(10,'|',10)" />
</
[In an earlier version of this answer, I speculated that func:result is not needed here; my error. It does appear to be needed.]
You ask for a complete stylesheet. The following stylesheet functions as expected when run with xsltproc. (As I noted above, I don't have a convenient way to run Xalan.)
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0"
xmlns:func="http://exslt.org/functions"
xmlns:my="http://example.org/my"
exclude-result-prefixes="my"
extension-element-prefixes="func">
<xsl:output indent="yes" method="xml" />
<xsl:template match="/">
<xsl:message>Result is <xsl:value-of select="my:dummy('foo')"/></xsl:message>
<output>
<test><xsl:value-of select="my:dummy('bar')"/></test>
<test><xsl:value-of select="my:dummy('baz')"/></test>
</output>
</xsl:template>
<func:function name="my:dummy">
<xsl:param name="s" select="'foo'"/>
<func:result select="concat($s,'|',$s)" />
</func:function>
</xsl:stylesheet>
I'm an absolute beginner concerning xsl transformation and I have a problem one of you may can help me with. I have following xml block:
<Metrics>
<Metric name="DocAmount" value="123.21" currency="GBP" type="Total"/>
<Metric name="Invoices" value="113.21" currency="GBP" type="Total"/>
<Metric name="Credit" value="10.00" currency="GBP" type="Total"/>
</Metrics>
I have to escape the "<" and ">" from the inner elements "Metric" and keep at the same time all attributes with their values => I want to have this:
<Metrics>
<Metric name="DocAmount" value="123.21" currency="GBP" type="Total"/>
<Metric name="Invoices" value="113.21" currency="GBP" type="Total"/>
<Metric name="Credit" value="10.00" currency="GBP" type="Total"/>
</Metrics>
I already searched here in stackoverflow and found a way to escape the "<" and the ">" but with my xsl template the attributes arn't copied and I get this here:
<Metrics>
<Metric></Metric>
<Metric></Metric>
<Metric></Metric>
</Metrics>
To get this I used following xsl template definition:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" omit-xml-declaration="no" encoding="UTF-8"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Metric">
<xsl:value-of select="concat('<',name(),'>',.,'</',name(),'>')" />
</xsl:template>
</xsl:stylesheet>
Can anybody help me to setup a correct xsl template doing what I want to have?
Thanks a lot in advance for your help!
As your question is tagged as XSLT 2 and these days we have XSLT 3 and the main XSLT 2.0 implementations like Saxon 9 with Saxon 9.8 or Altova with Altova 2017 or 2018 have been updated to support XSLT 3 I think the easiest and most elegant solution is to move to XSLT 3 and use the XPath 3 serialize function:
<xsl:template match="Metric">
<xsl:value-of select="serialize(.)"/>
</xsl:template>
As your comment indicates you have namespaces in your input you don't want to be serialized you can use
<xsl:template match="Metric">
<xsl:variable name="copy" as="element(Metric)"><xsl:copy-of select="." copy-namespaces="no"/></xsl:variable>
<xsl:value-of select="serialize($copy)"/>
</xsl:template>
Is it possible to include only certain file Extensions when using an xslt file to transform heat harvesting components using wix? I know I can exclude file extensions with the following:
<xsl:key name="exe-search" match="wix:Component[contains(wix:File/#Source, '.pdb')]" use="#Id" /> <!--.pdb-->
but is it possible to include several file types and exclude everything else (for example: .exe, .dll, .xml)?
Thank you!
Sure. Inside the condition, you can use full expressions, like:
contains(wix:File/#Source, '.pdb')
or contains(wix:File/#Source, '.exe')
or contains(wix:File/#Source, '.dll')
or contains(wix:File/#Source, '.xml')
If it's just an handful, that should be maintainable. To aid readability, you can put newlines inside the match attribute value (or any attribute in general).
I would use it like this. Notice the poor man's ends-with trick.
The template matches unwanted Components and replaces them with nothing.
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:wi="http://schemas.microsoft.com/wix/2006/wi"
xmlns="http://schemas.microsoft.com/wix/2006/wi">
<xsl:template match="wi:Component[not(
contains(concat(wi:File/#Source,'|'), '.exe|') or
contains(concat(wi:File/#Source,'|'), '.config|'))]">
</xsl:template>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="#*"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Here's a heat command that it works with:
heat dir "%wix%\bin" -cg CompGroup -ag -t byext.xsl -o test.wxs
I want to achieve
Declare global variable having no value
<xsl:variable name="IsEqual"/>
Check variable value and change according to condition
<xsl:choose>
**// Checking value equal or not**
<xsl:when test="name=$name">
<xsl:choose>
**//Checking variable value**
<xsl:when test="$IsEqual !='Unequal'">
**//Setting variable value**
<xsl:variable name="IsEqual" Select="Equal"/>
</xsl:when>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
**//Setting variable value**
<xsl:variable name="IsEqual" Select="Unequal"/>
</xsl:otherwise>
</xsl:choose>
<xsl:value-of select="$IsEqual"/>
Expected output value of variable $IsEqual.. IF it is not possible then what is another way to achieve this? What should I use instead of variable?
"It's not a bug, it's a feature": XSLT variables are designed not to be changeable. Actually they could be named constants. Working around that is difficult, it can be done using parameters. In most cases that isn't necessary if you use the XSLT programming attempt, where the programm is driven by the data through templates.
The answer to your question is no.
Copied this (own) text from XML and Variables
#Sam: What do you want to accomplish using a global variable? Where do you want to check for equality? I have no idea what you want to do so I can only give you a general example.
Try this xml file:
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="test.xsl"?>
<root>
<data check="value1">This is data 1</data>
<data check="value2">This is data 2</data>
<data check="value3">This is data 3</data>
</root>
with this xslt file:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:variable name="v">value2</xsl:variable>
<xsl:template match="/">
<xsl:apply-templates select="root/data[#check = $v]"/>
</xsl:template>
<xsl:template match="data">
<xsl:value-of select="."/>
</xsl:template>
</xsl:stylesheet>
Only the second data element will show up as this one matches the global variable, which stays the same all the time. If you want different values to match with, you can put them into your data file instead using a variable and compare the different elements.
For testing just save the two files (test.xml and test.xsl) into one directory and open test.xml with your browser.
#Sam again: As you insist on changing an xslt variable I have to repeat that this can't be done. Maybe there is a way around using the environment xslt is running in. E.g. PHP, where you can pass functions into the script. I described the technique here: Can PHP communicate with XSLT?
The xslt spec says:
XSLT does not provide an equivalent to the Java assignment operator
x = "value";
because this would make it harder to create an implementation that processes a document other than in a batch-like way, starting at the beginning and continuing through to the end.
(See http://www.w3.org/TR/xslt#variables to prove my answer "no" to your question is correct :-)
My previous question[1] is related to this. I found the answer for that. Now I want to loop a variable length array with namespaces. My array:
<ns:array xmlns:ns="http://www.example.org">
<value>755</value>
<value>5861</value>
<value>4328</value>
<value>2157</value>
<value>1666</value>
</ns:array>
My XSLT code:(have added the namespace in the root)
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ns1="http://www.example.org">
<xsl:template match="/">
<xsl:variable name="number" select="ns:array" />
<xsl:for-each select="$number">
<xsl:value-of select="$number" />
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
[1]https://stackoverflow.com/questions/20287219/looping-a-variable-length-array-in-xslt
IMHO you confused yourself by introducing a variable called number which actually contains a node set of value tags. Then, as a consequence you used your variable as singe item/node which does not yield the desired result (presumingly, since you did not really tell us what you want to do with the values).
Also, I think your question does not really have anything to with namespace issues as such. You just have to make sure that the namespaces in your select expressions match the namespaces in your input file.
I would suggest to do without the variable and change the way you retrieve the current value:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ns1="http://www.example.org">
<xsl:template match="/">
<xsl:for-each select="ns:array">
<!-- Inside here you can work with the `value` tag as the _current node_.
There are two most likely ways to do this. -->
<!-- a) Copy the whole tag to the output: -->
<xsl:copy-of select="." />
<!-- or b1) Copy the text part contained in the tag to the output: -->
<xsl:value-of select="." />
<!-- If you want to be on the safe side with respect to white space
you can also use this b2). This would handle the case that your output
is required not to have any white space in it but your imput XML has
some. -->
<xsl:value-of select="normalize-space(.)" />
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>