Is there any way to specify vertical row direction in XSL FO. If not, workaround is also fine. I want to achieve something like this:
C1
r1-c1
r2-c1
C2
r1-c2
r2-c2
C3
r1-c3
r2-c3
..
..
..
No, or not easily or automatically. Tables are defined to be "row-primary" (see https://www.w3.org/TR/xsl11/#fo_table).
You could possibly format an fo:table the way that you show by doing convoluted things with reference-orientation and writing-mode, but it would be fragile and probably wouldn't work with FOP.
A less fragile way would be to use XSLT to rearrange the table so that you write your XML as a 'column-primary' table and have the XSLT flip the table and generate row-primary fo:table-row and fo:table-cell that are in the correct sequence to produce the table that you want. You would, however, have to be careful about table cells that span multiple rows or columns.
To give an example on how to do this in xslt:
Given this source:
<?xml-stylesheet type="text/xsl" href="xsl.xsl"?>
<table>
<thead>
<row>
<entry>C1</entry>
<entry>C2</entry>
<entry>C3</entry>
</row>
</thead>
<tbody>
<row>
<entry>r1-c1</entry>
<entry>r1-c2</entry>
<entry>r1-c3</entry>
</row>
<row>
<entry>r2-c1</entry>
<entry>r2-c2</entry>
<entry>r2-c3</entry>
</row>
</tbody>
</table>
And this xslt:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format" >
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="table">
<fo:table>
<xsl:apply-templates select="tbody"/>
</fo:table>
</xsl:template>
<xsl:template match="tbody">
<!-- Since we use the header elements as context we store the current rows in a varable for quicker later use -->
<xsl:variable name="bodyrows" select="row"/>
<fo:table-body>
<xsl:for-each select="parent::table/thead/row/entry">
<xsl:variable name="position" select="position()"/>
<fo:table-row>
<xsl:apply-templates select="."/>
<xsl:apply-templates select="$bodyrows/entry[$position]"/>
</fo:table-row>
</xsl:for-each>
</fo:table-body>
</xsl:template>
<xsl:template match="entry">
<fo:table-cell>
<xsl:apply-templates select="." mode="font-weight"/>
<xsl:apply-templates/>
</fo:table-cell>
</xsl:template>
<xsl:template match="thead/row/entry" mode="font-weight">
<xsl:attribute name="font-weight" select="'bold'"/>
</xsl:template>
<xsl:template match="tbody/row/entry" mode="font-weight"/>
</xsl:stylesheet>
Will result in this fo-xml:
<?xml version="1.0" encoding="UTF-8"?>
<fo:table xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:table-body>
<fo:table-row>
<fo:table-cell font-weight="bold">C1</fo:table-cell>
<fo:table-cell>r1-c1</fo:table-cell>
<fo:table-cell>r2-c1</fo:table-cell>
</fo:table-row>
<fo:table-row>
<fo:table-cell font-weight="bold">C2</fo:table-cell>
<fo:table-cell>r1-c2</fo:table-cell>
<fo:table-cell>r2-c2</fo:table-cell>
</fo:table-row>
<fo:table-row>
<fo:table-cell font-weight="bold">C3</fo:table-cell>
<fo:table-cell>r1-c3</fo:table-cell>
<fo:table-cell>r2-c3</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table>
Related
I want to create a table Which contain two columns as product type and number of quantity in XSL-Fo.
In the XML input file Type node contain 00 then in the table the product should be come like "Other"
if Type element value is
00 then "Other" like wise
51 = Business Loan – General
05 = Personal Loan
I want to see all product in alphabetical ascending odder.
This is my Input XML
<product>
<months>
<Type>00</Type>
<Number>2</Number>
</months>
<months>
<Type>51</Type>
<Number>2</Number>
</months>
<months>
<Type>05</Type>
<Number>1</Number>
</months>
</product>
I tried this Here
quantity
<fo:table>
<fo:table-body>
<fo:table-row>
<fo:table-cell>
<fo:block >Product Type</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block>Quantity</fo:block>
</fo:table-cell>
<xsl:for-each select=" Product/months">
<xsl:variable name="Variable" select="Type"></xsl:variable>
<fo:table-row>
<fo:table-cell>
<fo:block >
<xsl:choose>
<xsl:when test="Type[contains(text(),'05')]">
Personal Loan
</xsl:when>
<xsl:when test="ProductType[contains(text(),'55')]">
Business Loan – General
</xsl:when>
<xsl:when test="ProductType[contains(text(),'00')]">
Other
</xsl:when>
</xsl:choose>
</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block>
<xsl:value-of select="Number"/>
</fo:block>
</fo:table-cell>
</xsl:for-each>
</fo:table-body>
</fo:table>
I got the O/p like below
Product Type | Quantity
-----------------------------------------------------------
Other | 2
Business Loan – General | 2
Personal Loan | 1
but Actual Expected OUT/PUT is this
Product Type | Quantity
-----------------------------------------------------------
Business Loan – General | 2
Other | 2
Personal Loan | 1
If can use XSLT 2.0, you can create a variable to hold elements that represent your mappings
<xsl:variable name="products">
<map-entry key="05">Personal Loan</map-entry>
<map-entry key="51">Business Loan – General</map-entry>
<map-entry key="00">Other</map-entry>
</xsl:variable>
Then you can use a key to look these up by the key attribute
<xsl:key name="map" match="map-entry" use="#key" />
You would then use this key in a sort, like so:
<xsl:for-each select="product/months">
<xsl:sort select="key('map', Type, $products)" />
(As an aside, do make sure you use the correct case, as in your XSLT you were using Product, not product)
Try this XSLT, which you can see in action at http://xsltfiddle.liberty-development.net/pPzifoQ
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:fo="http://www.w3.org/1999/XSL/Format"
exclude-result-prefixes="xs"
version="2.0">
<xsl:output method="xml" indent="yes" />
<xsl:variable name="products">
<map-entry key="05">Personal Loan</map-entry>
<map-entry key="51">Business Loan – General</map-entry>
<map-entry key="00">Other</map-entry>
</xsl:variable>
<xsl:key name="map" match="map-entry" use="#key" />
<xsl:template match="/">
<fo:table>
<fo:table-body>
<fo:table-row>
<fo:table-cell>
<fo:block>Product Type</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block>Quantity</fo:block>
</fo:table-cell>
</fo:table-row>
<xsl:for-each select="product/months">
<xsl:sort select="key('map', Type, $products)" />
<fo:table-row>
<fo:table-cell>
<fo:block>
<xsl:value-of select="key('map', Type, $products)" />
</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block>
<xsl:value-of select="Number"/>
</fo:block>
</fo:table-cell>
</fo:table-row>
</xsl:for-each>
</fo:table-body>
</fo:table>
</xsl:template>
</xsl:stylesheet>
Note, if you can use XSLT 3.0, there is a dedicated "map" function you can use, which slightly simplifies things
Try this XSLT 3.0, which you can see in action at http://xsltfiddle.liberty-development.net/bnnZVx
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:fo="http://www.w3.org/1999/XSL/Format"
exclude-result-prefixes="xs"
version="3.0">
<xsl:output method="xml" indent="yes" />
<xsl:variable name="products" as="map(xs:string, xs:string)">
<xsl:map>
<xsl:map-entry key="'05'" select="'Personal Loan'"/>
<xsl:map-entry key="'51'" select="'Business Loan – General'"/>
<xsl:map-entry key="'00'" select="'Other'"/>
</xsl:map>
</xsl:variable>
<xsl:template match="/">
<fo:table>
<fo:table-body>
<fo:table-row>
<fo:table-cell>
<fo:block>Product Type</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block>Quantity</fo:block>
</fo:table-cell>
</fo:table-row>
<xsl:for-each select="product/months">
<xsl:sort select="$products(Type)" />
<fo:table-row>
<fo:table-cell>
<fo:block>
<xsl:value-of select="$products(Type)" />
</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block>
<xsl:value-of select="Number"/>
</fo:block>
</fo:table-cell>
</fo:table-row>
</xsl:for-each>
</fo:table-body>
</fo:table>
</xsl:template>
</xsl:stylesheet>
There are several ways you could look at this. For example, you could avoid sorting altogether - esp. if you only have 3 possible product types - by applying templates to each type in turn.
Here's a simplified example:
XSLT 1.0
<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:strip-space elements="*"/>
<xsl:template match="/product">
<table>
<tr>
<th>Product Type</th>
<th>Quantity</th>
</tr>
<xsl:apply-templates select="months[Type='51']"/>
<xsl:apply-templates select="months[Type='00']"/>
<xsl:apply-templates select="months[Type='05']"/>
</table>
</xsl:template>
<xsl:template match="months">
<tr>
<td>
<xsl:choose>
<xsl:when test="Type='51'">Business Loan – General</xsl:when>
<xsl:when test="Type='05'">Personal Loan</xsl:when>
<xsl:when test="Type='00'">Other</xsl:when>
</xsl:choose>
</td>
<td>
<xsl:value-of select="Number"/>
</td>
</tr>
</xsl:template>
</xsl:stylesheet>
Another option is to sort by custom order - again, using the codes in their intended order:
XSLT 1.0
<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:strip-space elements="*"/>
<xsl:template match="/product">
<table>
<tr>
<th>Product Type</th>
<th>Quantity</th>
</tr>
<xsl:variable name="sort-order">|51|00|05|</xsl:variable>
<xsl:for-each select="months">
<xsl:sort select="string-length(substring-before($sort-order, concat('|', Type, '|')))" data-type="number"/>
<tr>
<td>
<xsl:choose>
<xsl:when test="Type='51'">Business Loan – General</xsl:when>
<xsl:when test="Type='05'">Personal Loan</xsl:when>
<xsl:when test="Type='00'">Other</xsl:when>
</xsl:choose>
</td>
<td>
<xsl:value-of select="Number"/>
</td>
</tr>
</xsl:for-each>
</table>
</xsl:template>
</xsl:stylesheet>
I've been working on CSV to XML conversions using this style-sheet:
XSLT 2.0 to convert CSV to XML format
I needed to account for both comma and pipe delimiters so I changed the style sheet to this:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="csv-uri" as="xs:string" select="'file:///c:/test.csv'"/>
<xsl:template match="/" name="csv2xml">
<Entity>
<Rows>
<xsl:choose>
<xsl:when test="unparsed-text-available($csv-uri)">
<xsl:variable name="csv" select="unparsed-text($csv-uri)" />
<xsl:variable name="pipe" select="'\|'"/>
<xsl:analyze-string select="replace($csv,$pipe,',')" regex='\r\n?|\n' >
<xsl:non-matching-substring>
<xsl:if test="not(position()=0)" >
<Row>
<xsl:for-each select="tokenize(.,',')" >
<xsl:element name="Column_{position()}">
<xsl:value-of select="."/>
</xsl:element>
</xsl:for-each>
</Row>
</xsl:if>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="error">
<xsl:text>Error reading file: "</xsl:text>
<xsl:value-of select="$csv-uri"/>
</xsl:variable>
<xsl:message>
<xsl:value-of select="$error"/>
</xsl:message>
<xsl:value-of select="$error"/>
</xsl:otherwise>
</xsl:choose>
</Rows>
</Entity>
</xsl:template>
</xsl:stylesheet>
However, I've been having some difficulty accounting for quoted values from the input.
Currently if a row in the csv is:
1,2,3,4,5,"testing,1,1,1"
red,white,blue,green
dogs|cats|rabbits
the "testing,1,1,1" gets split into 4 columns into the CSV instead of one column.
output:
<?xml version="1.0" encoding="UTF-8"?>
<Entity>
<Rows>
<Row>
<Column_1>1</Column_1>
<Column_2>2</Column_2>
<Column_3>3</Column_3>
<Column_4>4</Column_4>
<Column_5>5</Column_5>
<Column_6>"testing</Column_6>
<Column_7>1</Column_7>
<Column_8>1</Column_8>
<Column_9>1"</Column_9>
</Row>
<Row>
<Column_1>red</Column_1>
<Column_2>white</Column_2>
<Column_3>blue</Column_3>
<Column_4>green</Column_4>
</Row>
<Row>
<Column_1>dogs</Column_1>
<Column_2>cats</Column_2>
<Column_3>rabbits</Column_3>
</Row>
</Rows>
</Entity>
I've done some research and using regex='("[^"]*")+' can accomplish this. But I'm not entirely sure how to implement this without removing something I have that I need (maybe probably in the Analyze-string block?). I need help please! Its probably something simple, so please school me or point me in the right direction. Any advice would be helpful.
You can just add another xsl:analyze-string to process the xsl:non-matching-substring from the first xsl:analyze-string...
CSV Input
1,2,3,4,5,"testing,1,1,1"
red,white,blue,green
dogs|cats|rabbits
Modified XSLT 2.0
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="csv-uri" as="xs:string" select="'file:///c:/users/dhaley/desktop/so.csv'"/>
<xsl:template match="/" name="csv2xml">
<Entity>
<Rows>
<xsl:choose>
<xsl:when test="unparsed-text-available($csv-uri)">
<xsl:variable name="csv" select="unparsed-text($csv-uri)" />
<xsl:variable name="pipe" select="'\|'"/>
<xsl:analyze-string select="replace($csv,$pipe,',')" regex='\r\n?|\n' >
<xsl:non-matching-substring>
<xsl:if test="not(position()=0)" >
<Row>
<xsl:analyze-string select="." regex=""([^"]*)",?|([^,]+),?">
<xsl:matching-substring>
<xsl:element name="Column_{position()}">
<xsl:value-of select="normalize-space(concat(regex-group(1),regex-group(2)))"/>
</xsl:element>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:element name="Column_{position()}"/>
</xsl:non-matching-substring>
</xsl:analyze-string>
</Row>
</xsl:if>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="error">
<xsl:text>Error reading file: "</xsl:text>
<xsl:value-of select="$csv-uri"/>
</xsl:variable>
<xsl:message>
<xsl:value-of select="$error"/>
</xsl:message>
<xsl:value-of select="$error"/>
</xsl:otherwise>
</xsl:choose>
</Rows>
</Entity>
</xsl:template>
</xsl:stylesheet>
XML Output
<Entity>
<Rows>
<Row>
<Column_1>1</Column_1>
<Column_2>2</Column_2>
<Column_3>3</Column_3>
<Column_4>4</Column_4>
<Column_5>5</Column_5>
<Column_6>testing,1,1,1</Column_6>
</Row>
<Row>
<Column_1>red</Column_1>
<Column_2>white</Column_2>
<Column_3>blue</Column_3>
<Column_4>green</Column_4>
</Row>
<Row>
<Column_1>dogs</Column_1>
<Column_2>cats</Column_2>
<Column_3>rabbits</Column_3>
</Row>
</Rows>
</Entity>
The regex from the second xsl:analyze-string is using captured substrings to ignore the quotes and the comma. Here's an easier to read version:
"([^"]*)",?|([^,]+),?
If you want to keep the quotes, move them inside the parens:
("[^"]*"),?|([^,]+),?
Silly, simple question. When I output text, it still get the tabs based on my formatted/indented XSL structure. How do I instruct the transformer to ignore the spacing in the stylesheet while still keeping it neatly formatted?
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="/">
<xsl:apply-templates select="Foo/Bar"></xsl:apply-templates>
</xsl:template>
<xsl:template match="Bar">
<xsl:for-each select="AAA"><xsl:for-each select="BBB"><xsl:value-of select="Label"/>|<xsl:value-of select="Value"/><xsl:text>
</xsl:text></xsl:for-each></xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Produces output line by line with no tabs:
SomeLabel|SomeValue
SomeLabel|SomeValue
SomeLabel|SomeValue
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="/">
<xsl:apply-templates select="Foo/Bar"></xsl:apply-templates>
</xsl:template>
<xsl:template match="Bar">
<xsl:for-each select="AAA">
<xsl:for-each select="BBB">
<xsl:value-of select="Label"/>|<xsl:value-of select="Value"/>
<xsl:text>
</xsl:text>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Produces output with tabs:
SomeLabel|SomeValue
SomeLabel|SomeValue
SomeLabel|SomeValue
Update:
Adding this does not fix it:
<xsl:output method="text" indent="no"/>
<xsl:strip-space elements="*"></xsl:strip-space>
This is contrived, but you can imagine the XML looks like this:
<Foo>
<Bar>
<AAA>
<BBB>
<Label>SomeLabel1</Label>
<Value>SomeValue1</Value>
</BBB>
<BBB>
<Label>SomeLabel2</Label>
<Value>SomeValue2</Value>
</BBB>
<BBB>
<Label>SomeLabel3</Label>
<Value>SomeValue3</Value>
</BBB>
</AAA>
</Bar>
</Foo>
What you could try is wrapping all your current text nodes in xsl:text. For example, try this
<xsl:for-each select="BBB">
<xsl:value-of select="Label"/>
<xsl:text>|</xsl:text>
<xsl:value-of select="Value"/>
<xsl:text>|</xsl:text>
</xsl:for-each>
Alternatively, you could make use of the concat function.
<xsl:for-each select="BBB">
<xsl:value-of select="concat(Label, '|')"/>
<xsl:value-of select="concat(Value, '|')"/>
</xsl:for-each>
You could even combine the two statements into one if you wanted
<xsl:for-each select="BBB">
<xsl:value-of select="concat(Label, '|', Value, '|')"/>
</xsl:for-each>
EDIT: If you prefer not to enter the separator | so many times, you make use of template matching to output the fileds. First, replace the value-of with apply-templates like so
<xsl:for-each select="BBB">
<xsl:apply-templates select="Label"/>
<xsl:apply-templates select="Value"/>
<xsl:text>
</xsl:text>
</xsl:for-each>
Then you would have one specific template to match Label, where you wouldn't need to output the separator, and another more generic template matching any child of BBB
<xsl:template match="BBB/Label" priority="1">
<xsl:value-of select="." />
</xsl:template>
<xsl:template match="BBB/*">
<xsl:text>|</xsl:text><xsl:value-of select="." />
</xsl:template>
(The priority here is needed to ensure Label is matched by the first template, and not the general one). Of course, you could also not do apply-templates on Label in this case, and just do xsl:value-of for that one.
Furthermore, if the fields were being output in the order they appear in the XML, you could simplify the for-each to just this
<xsl:for-each select="BBB">
<xsl:apply-templates />
<xsl:text>
</xsl:text>
</xsl:for-each>
Is it possible to have a for-each in which the counter is an attribute value (not a node list)?
Here is what I am trying to do, handling colspan in tables (doesn't work):
<xsl:for-each select=".//tr[1]//td">
<xsl:choose>
<xsl:when test="#colspan">
<xsl:for-each select="#colspan">
<fo:table-column/>
</xsl:for-each>
</xsl:when>
<xsl:otherwise><fo:table-column/></xsl:otherwise>
</xsl:choose>
</xsl:for-each>
Thanks!
In XSLT 2.0:
<xsl:for-each select="1 to xs:integer(#colspan)">
<fo:table-column/>
</xsl:for-each>
In XSLT 1.0:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="table[#colspan]">
<fo:table>
<xsl:call-template name="generate"/>
</fo:table>
</xsl:template>
<xsl:template name="generate">
<xsl:param name="pTimes" select="#colspan"/>
<xsl:if test="$pTimes > 0">
<fo:table-column/>
<xsl:call-template name="generate">
<xsl:with-param name="pTimes" select="$pTimes -1"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on the following XML document:
<table colspan="3"/>
the wanted, correct result is produced:
<fo:table xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:table-column/>
<fo:table-column/>
<fo:table-column/>
</fo:table>
I'm working with some XML where the nodes have lots of attributes, and I'm creating an FO PDF file (report) using XSL. I'm trying to create a template that takes a specific attribute on the current node, and create an fo:block that will have some basic formatting.
Here is a template that creates a big list of all the attributes and values on one node.
XSL:
<xsl:template name="createAttributeAndValueList">
<xsl:param name="node" select="." />
<xsl:for-each select="$node/#*">
<fo:block>
<xsl:value-of select="concat(name(),': ')"/>
<xsl:value-of select="."/>
</fo:block>
</xsl:for-each>
</xsl:template>
However, there are times when I only want to get one or two of these attributes out, instead of all of them off the node. I'm guessing this is something that would be really obvious, but that I haven't figured out yet due to my inexperience.
I am trying to do the same formatting, but I just can't seem to get the syntax right to be able to pass in my value to the parameter, and get what I want. Here's what I have:
XSL:
<xsl:template name="createAttributeValuePair">
<xsl:param name="attribute" select="." />
<xsl:for-each select="#*">
<fo:block>
<xsl:value-of select="concat(name(),': ')"/>
<xsl:value-of select="."/>
</fo:block>
</xsl:for-each>
</xsl:template>
And here's how I'm trying to call it:
XSL:
<fo:block font-weight="normal" margin-left="6pt">
<xsl:call-template name="createAttributeValuePair">
<xsl:with-param name="attribute"
select="/device:DevicePatientEncounter/device:Encounter/
device:Followup/#UnderlyingRhythm"/>
</xsl:call-template>
</fo:block>
where my XML looks like this:
<DevicePatientEncounter xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
GeneratedTime="2011-12-14T13:36:05"
EncounterDate="2011-11-15T11:04:54"
xmlns="device">
<Encounter>
<Followup UnderlyingRhythm="Sinus bradycardia"
UnderlyingRhythmRateBpm="44"
IsPmDependent="false"
PresentingRhythm="Atrial fibrillation"
BatteryChargeSeconds="5"
AutoCapFrequency="3 Years"
LastCapacitorFormDate="2011-10-25T00:00:00"
BatteryLongevity="0"
BatteryVoltage="11"
BatteryStatus="MOL"/>
</Encounter>
</DevicePatientEncounter>
A few notes:
You're passing an attribute to createAttributeValuePair but you never do anything with the parameter
You're looping over #* in this template, but the template seems designed to output the name and value of a single attribute
In addition, call-template does not change the current node, so it's not really clear what element's attributes are being iterated in the loop
I'm guessing you're looking for something like this:
<xsl:template name="createAttributeValuePair">
<xsl:param name="attribute" select="."/>
<fo:block>
<xsl:value-of select="concat(name($attribute),': ')"/>
<xsl:value-of select="$attribute"/>
</fo:block>
</xsl:template>
Here's a complete demo:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format"
xmlns:device="device">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:template match="/">
<fo:block font-weight="normal" margin-left="6pt">
<xsl:call-template name="createAttributeValuePair">
<xsl:with-param name="attribute"
select="/device:DevicePatientEncounter/device:Encounter/
device:Followup/#UnderlyingRhythm"/>
</xsl:call-template>
</fo:block>
</xsl:template>
<xsl:template name="createAttributeValuePair">
<xsl:param name="attribute" select="."/>
<fo:block>
<xsl:value-of select="concat(name($attribute),': ')"/>
<xsl:value-of select="$attribute"/>
</fo:block>
</xsl:template>
</xsl:stylesheet>
The following output is produced when given your example XML:
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:device="device"
font-weight="normal"
margin-left="6pt">
<fo:block>UnderlyingRhythm: Sinus bradycardia</fo:block>
</fo:block>