Please suggest to get the absolute path of each documents which are collected thru xslt collection.
Posted script is able to give the required absolute path, but I have used two collections (it may take unnecessary memory to store info of all articles twice, one collection for collecting info and other one to collect document-uri()s).
XMLs:
D:/DocumentPath/Project-01/2016/ABC/Test.xml
<article>
<title>First article</title>
<tag1>The tag 1</tag1>
<tag3>The tag 3</tag3>
</article>
D:/DocumentPath/Project-01/2016/DEF/Test.xml
<article>
<title>Second article</title>
<tag2>The tag 2</tag2>
<tag3>The tag 3</tag3>
</article>
and other XMLs....
XSLT 2.0:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>
<xsl:variable name="varDocuments">
<xsl:copy-of select="collection('file:///D:/DocumentPath/Project-01/2016/?select=*.xml;recurse=yes')
[matches(document-uri(.), '2016/([A-z]+)/.*?.xml')]"/>
</xsl:variable>
<xsl:variable name="varDocuments1">
<xsl:copy-of select="collection('file:///D:/DocumentPath/Project-01/2016/?select=*.xml;recurse=yes')
[matches(document-uri(.), '2016/([A-z]+)/.*?.xml')]/document-uri(.)"/>
</xsl:variable>
<xsl:template match="#*|node()">
<xsl:copy><xsl:apply-templates select="#*|node()"/></xsl:copy>
</xsl:template>
<xsl:template match="/">
<Table border="1">
<TR><TH>Position</TH><TH>Title</TH><TH>Tag1</TH><TH>Tag2</TH><TH>Tag3</TH><TH>Tag4</TH><TH>Path</TH></TR>
<xsl:for-each select="$varDocuments">
<xsl:for-each select="article">
<TR>
<xsl:variable name="varPos" select="position()"/>
<td><xsl:value-of select="position()"/></td>
<td><xsl:value-of select="title"/></td>
<td><xsl:value-of select="count(descendant::tag1)"/></td>
<td><xsl:value-of select="count(descendant::tag2)"/></td>
<td><xsl:value-of select="count(descendant::tag3)"/></td>
<td><xsl:value-of select="count(descendant::tag4)"/></td>
<td><xsl:value-of select="normalize-space(tokenize($varDocuments1, 'file:/')[position()=$varPos + 1])"/></td>
</TR>
</xsl:for-each>
</xsl:for-each>
</Table>
</xsl:template>
</xsl:stylesheet>
Required result:
<Table border="1">
<TR>
<TH>Position</TH>
<TH>Title</TH>
<TH>Tag1</TH>
<TH>Tag2</TH>
<TH>Tag3</TH>
<TH>Tag4</TH>
<TH>Path</TH>
</TR>
<TR>
<td>1</td>
<td>First article</td>
<td>1</td>
<td>0</td>
<td>1</td>
<td>0</td>
<td>D:/DocumentPath/Project-01/2016/ABC/Test.xml</td>
</TR>
<TR>
<td>2</td>
<td>Second article</td>
<td>0</td>
<td>1</td>
<td>1</td>
<td>0</td>
<td>D:/DocumentPath/Project-01/2016/DEF/Test.xml</td>
</TR>
<TR>
<td>3</td>
<td>Third article</td>
<td>1</td>
<td>0</td>
<td>0</td>
<td>2</td>
<td>D:/DocumentPath/Project-01/2016/GHI/Test.xml</td>
</TR>
</Table>
I would first suggest to change
<xsl:variable name="varDocuments">
<xsl:copy-of select="collection('file:///D:/DocumentPath/Project-01/2016/?select=*.xml;recurse=yes')
[matches(document-uri(.), '2016/([A-z]+)/.*?.xml')]"/>
</xsl:variable>
to at least
<xsl:variable name="varDocuments" select="collection('file:///D:/DocumentPath/Project-01/2016/?select=*.xml;recurse=yes')
[matches(document-uri(.), '2016/([A-z]+)/.*?.xml')]"/>
as there does not seem to be a need to pull in the documents with collection and then create an additional copy with copy-of.
With that correction, when you process each document with with <xsl:for-each select="$varDocuments">, you can simply there read out the document-uri(.) now, as you are processing the documents pulled in and not any copy assembled.
Related
Here is some XSL script:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msa="http://www.publictalksoftware.co.uk/msa">
<xsl:output method="html" indent="yes" version="4.01"
doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
doctype-public="//W3C//DTD XHTML 1.0 Transitional//EN"/>
<xsl:variable name="DutyHistory" select="document('DutyAssignHistory.XML')"/>
<xsl:template match="/">
<html>
<head>
<title>Test</title>
</head>
<body>
<xsl:for-each select="MeetingWorkBook/Meeting">
<p>
<xsl:value-of select ="Date/#ThisWeek"/>
</p>
<xsl:variable name="Week" select="Date/#ThisWeek"/>
<table>
<tr>
<td>Sound</td>
<td>
<xsl:value-of select="$DutyHistory/msa:DutyAssignmentHistory/msa:DutyAssignments/msa:DutyAssignmentEntry[#Week=$Week and #Mode='Weekend']/msa:Assignment[#Index='1' and #IndexType='Fixed']"/>
</td>
</tr>
<tr>
<td>Platform</td>
<td>
<xsl:value-of select="$DutyHistory/msa:DutyAssignmentHistory/msa:DutyAssignments/msa:DutyAssignmentEntry[#Week=$Week and #Mode='Weekend']/msa:Assignment[#Index='5' and #IndexType='Fixed']"/>
</td>
</tr>
<tr>
<td>Left Mike</td>
<td>
<xsl:value-of select="$DutyHistory/msa:DutyAssignmentHistory/msa:DutyAssignments/msa:DutyAssignmentEntry[#Week=$Week and #Mode='Weekend']/msa:Assignment[#Index='7' and #IndexType='Fixed']"/>
</td>
</tr>
<tr>
<td>Right Mike</td>
<td>
<xsl:value-of select="$DutyHistory/msa:DutyAssignmentHistory/msa:DutyAssignments/msa:DutyAssignmentEntry[#Week=$Week and #Mode='Weekend']/msa:Assignment[#Index='8' and #IndexType='Fixed']"/>
</td>
</tr>
<tr>
<td>Public Talk Chairman</td>
<td>
<xsl:value-of select="$DutyHistory/msa:DutyAssignmentHistory/msa:DutyAssignments/msa:DutyAssignmentEntry[#Week=$Week and #Mode='Weekend']/msa:Assignment[#Index='4' and #IndexType='Custom']"/>
</td>
</tr>
<tr>
<td>Watchtower Reader</td>
<td>
<xsl:value-of select="$DutyHistory/msa:DutyAssignmentHistory/msa:DutyAssignments/msa:DutyAssignmentEntry[#Week=$Week and #Mode='Weekend']/msa:Assignment[#Index='5' and #IndexType='Custom']"/>
</td>
</tr>
</table>
</xsl:for-each>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
As you can see it is linking in another XML document for reference. Here is one example of that linked in file:
<?xml version="1.0" encoding="utf-8"?>
<DutyAssignmentHistory xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.publictalksoftware.co.uk/msa">
<DutyAssignments>
<DutyAssignmentEntry Date="2018-01-04" Week="W20180101" Template="0" Mode="Midweek">
<Assignment Index="2" IndexType="Fixed">Name 1</Assignment>
<Assignment Index="5" IndexType="Fixed">Name 2</Assignment>
<Assignment Index="7" IndexType="Fixed">Name 3</Assignment>
<Assignment Index="8" IndexType="Fixed">Name 4</Assignment>
<Assignment Index="13" IndexType="Fixed">Name 5</Assignment>
<Assignment Index="14" IndexType="Fixed">Name 6</Assignment>
</DutyAssignmentEntry>
</DutyAssignments>
</DutyAssignmentHistory>
Potentially a user might want to reference the information in the XML and display it however they like but I am wanting to show them the simplest method.
As you can see there are several criteria:
Week (WYYYYMMDD)
Mode (Midweek, Weekend or Weekly)
Template(0 or higher)
The above will filter to the right week of assignments. Then, to identify the actual assignment:
Index (numeric value)
IndexType (Fixed, CustomFixed or Custom)
Can I use templates in any way (perhaps with variables) to simplify the code as it is getting repetative?
You could use a template and pass parameters, or in XSLT 2.0 or higher you could also define a function, which makes it much easier to use and saves some typing. But for what you are currently doing, a variable and some predicate filters seems to be the most simple and easy.
The most simple and easy way would be to bind a variable with the weekend assignments, and then apply your predicate filter to select the one with the #Index and #IndexType:
<xsl:variable name="Week" select="Date/#ThisWeek"/>
<xsl:variable name="weekend-assignments"
select="$DutyHistory/msa:DutyAssignmentHistory/msa:DutyAssignments
/msa:DutyAssignmentEntry[#Week=$Week and #Mode='Weekend']/msa:Assignment"/>
<table>
<tr>
<td>Sound</td>
<td>
<xsl:value-of select="$weekend-assignments[#Index='1' and #IndexType='Fixed']"/>
</td>
</tr>
If you make the variable hold an unfiltered set of Assignment elements, you could perform all of the filtering in the predicates:
<xsl:variable name="Week" select="Date/#ThisWeek"/>
<xsl:variable name="assignments"
select="$DutyHistory/msa:DutyAssignmentHistory/msa:DutyAssignments
/msa:DutyAssignmentEntry/msa:Assignment"/>
<table>
<tr>
<td>Sound</td>
<td>
<xsl:value-of
select="$assignments[#Index='1' and #IndexType='Fixed']
[..[#Week=$Week and #Mode='Weekend' and #Template='0']]"/>
</td>
</tr>
If you want to consolidate the logic for generating the columns, you could define a template for msa:Assignment:
<xsl:template match="msa:Assignment">
<td>
<xsl:value-of select="."/>
</td>
</xsl:template>
And then use it like this:
<table>
<tr>
<td>Sound</td>
<xsl:apply-templates select="$weekend-assignments[#Index='1' and #IndexType='Fixed']"/>
If you want to consolidate the logic for generating rows, you could define a template for msa:Assignment and send in a parameter for the first column:
<xsl:template match="msa:Assignment">
<xsl:param name="label"/>
<tr>
<td><xsl:value-of select="$label"/></td>
<td>
<xsl:value-of select="."/>
</td>
</tr>
</xsl:template>
And then use it like this:
<table>
<xsl:apply-templates select="$weekend-assignments[#Index='1' and #IndexType='Fixed']">
<xsl:with-param name="label" select="'Sound'"/>
</xsl:apply-templates>
I have a flat XML structure looking like this:
<root>
<header>First header</header>
<type1>Element 1:1</type1>
<type2>Element 1:2</type2>
<header>Second header</header>
<type1>Element 2:1</type1>
<type3>Element 3:1</type3>
<header>Third header</header>
<type1>Element 3:1</type1>
<type2>Element 3:2</type2>
<type1>Element 3:3</type1>
<type2>Element 3:4</type2>
</root>
Essentialy there is an unknown number of headers. Under each header there is an unknown number of elements (tree different types). There can be zero to many elements of each type under each header. I do not have control over this structure so I can't change/improve it.
What I'm trying to generate is this HTML:
<h2>First header</h2>
<table>
<tr>
<th>Type 1</th>
<td>Element 1:1</td>
</tr>
<tr>
<th>Type 2</th>
<td>Element 1:2</td>
</tr>
</table>
<h2>Second header</h2>
<table>
<tr>
<th>Type 1</th>
<td>Element 2:1</td>
</tr>
<tr>
<th>Type 3</th>
<td>Element 2:2</td>
</tr>
</table>
<h2>third header</h2>
<table>
<tr>
<th>Type 1</th>
<td>Element 3:1</td>
</tr>
<tr>
<th>Type 2</th>
<td>Element 3:2</td>
</tr>
<tr>
<th>Type 1</th>
<td>Element 3:3</td>
</tr>
<tr>
<th>Type 2</th>
<td>Element 3:4</td>
</tr>
</table>
Each header will be an HTML header (level 2) and then I want all the other elements until the next header to be shown in a table.
My first idea is to make a template that matches the header elements:
<xsl:template match="header">
<h2><xsl:value-of select="text()" /></h2>
<table>
???
</table>
</xsl:template>
I'm thinking I could replace "???" with code iterating through all the following siblings until the next header element and turn them into table rows.
Is that a good idea?
If it is, how do I do it?
If it isn't, what's a better solution?
I'm using XSLT 1.0.
One way to achieve this to use a key, to group the non-header elements by their first preceding header element
<xsl:key name="type" match="*[not(self::header)]" use="generate-id(preceding-sibling::header[1])" />
You would then start off by selecting just header elements
<xsl:apply-templates select="header" />
And within the template that matches this header element, you can then get all the type elements that correspond to the header by using the key
<xsl:for-each select="key('type', generate-id())">
Try this XSLT
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html" indent="yes" />
<xsl:key name="type" match="*[not(self::header)]" use="generate-id(preceding-sibling::header[1])" />
<xsl:template match="root">
<xsl:apply-templates select="header" />
</xsl:template>
<xsl:template match="header">
<h2><xsl:value-of select="." /></h2>
<table>
<xsl:for-each select="key('type', generate-id())">
<tr>
<th><xsl:value-of select="local-name()" /></th>
<th><xsl:value-of select="." /></th>
</tr>
</xsl:for-each>
</table>
</xsl:template>
</xsl:stylesheet>
Note, this doesn't include the issue of converting the node name type1 to Type 1, but I will leave that exercise for you....
I have a Library object that contains a collection of Books... The Library object has properties like Name, Address, Phone... While the Book object has properties like ISDN, Title, Author, and Price.
XML looks something like this...
<Library>
<Name>Metro Library</Name>
<Address>1 Post Rd. Brooklyn, NY 11218</Address>
<Phone>800 976-7070</Phone>
<Books>
<Book>
<ISDN>123456789</ISDN>
<Title>Fishing with Luke</Title>
<Author>Luke Miller</Author>
<Price>18.99</Price>
</Book>
<Book>
<ISDN>234567890</ISDN>
<Title>Hunting with Paul</Title>
<Author>Paul Worthington</Author>
<Price>28.99</Price>
</Book>
...
And more books
...
</Books>
</Library>
I have a template with space for only 10 per page for example. There can be hundreds of books in the list of Books... So I need to limit the number of books and repeat the template every 10 books.
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<body>
<div>
<table>
<tr>
<td>NAME</td>
<td><xsl:value-of select="/Library/Name"/></td>
</tr>
<tr>
<td>ADDRESS</td>
<td><xsl:value-of select="/Library/Address"/></td>
</tr>
<tr>
<td>PHONE</td>
<td><xsl:value-of select="/Library/Phone"/></td>
</tr>
</table>
<table>
<xsl:for-each select="/Library/Books/Book">
<tr>
<td><xsl:value-of select="position()"/></td>
<td><xsl:value-of select="ISDN"/></td>
<td><xsl:value-of select="Title"/></td>
<td><xsl:value-of select="Author"/></td>
<td><xsl:value-of select="Price"/></td>
</tr>
</xsl:for-each>
</table>
</div>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
How can I get the Library information to appear on all repeating pages and add 10 books per page?... First page has Library info with Books 1 thru 10, Second page has Library info with Books 11 thru 20, and so on??
Thanks
For starters, try not to use for-each, apply-templates allows the engine to optimise the order that events are processed.
It appears that you are calling this stylesheet from some other system, so the approach I've taken is to define a pagination param. In the host language, when you call this just change the root parameter. This then allows you to select the require pages in this line here:
Books/Book[($page - 1)*10 < position() and position() <= ($page)*10]
This should do the trick.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:param name="page" select="1"/>
<xsl:template match="/Library">
<html>
<body>
<div>
<table>
<tr>
<td>NAME</td>
<td>
<xsl:value-of select="/Name"/>
</td>
</tr>
<tr>
<td>ADDRESS</td>
<td>
<xsl:value-of select="/Address"/>
</td>
</tr>
<tr>
<td>PHONE</td>
<td>
<xsl:value-of select="/Phone"/>
</td>
</tr>
</table>
<table>
<xsl:apply-templates select="Books/Book[($page - 1)*10 < position() and position() <= ($page)*10]"/>
</table>
</div>
</body>
</html>
</xsl:template>
<xsl:template match="/Book">
<tr>
<td>
<xsl:value-of select="position()"/>
</td>
<td>
<xsl:value-of select="ISDN"/>
</td>
<td>
<xsl:value-of select="Title"/>
</td>
<td>
<xsl:value-of select="Author"/>
</td>
<td>
<xsl:value-of select="Price"/>
</td>
</tr>
</xsl:template>
</xsl:stylesheet>
I'm using XSL1.0. My editor/debugger is OxygenXML with Saxon (OxygenXML can't debug with MSXML) and it will deployed to work with a 3rd party app that only uses MSXML. This means I can't use a variable containing a nodeset if I want to be able to debug.
The problem could probably be expressed as how to sequentially number output of the following -
<xsl:for-each select="node1">
<xsl:variable name="current_ID" select="ID">
<xsl:for-each select="sub_node1">
<xsl:value-of select="../ID"/>-<xsl:value-of select="Sub_ID"/>
</xsl:for-each>
</xsl:for-each>
understanding that I cannot simply use this in my scenario:
<xsl:for-each select="node1/sub_node1">
<xsl:value-of select="position()"/>
</xsl:for-each>
Below is a manufactured example that shows the problem I'm trying to solve as part of a much larger XSL/XML combo. I basically need to create manufacturing instructions. All nodes in the XML with the exception of products/versions (by qty) are in the correct order and I cannot change it. I need to generate the same set of sequential numbers from 3 different XSL's. My current context will always be shipments/deliveries/delivery_products (i.e. my XSL has to process the nodes in the seq shown). I need to produce a list of products sorted by version qty and their deliveries. Each row should have a sequential no (1-4) in example below
<shipments>
<product>
<name>Product 1</name>
<prod_id>P1</prod_id>
<version>
<version_id>P1_V1</version_id>
<qty>8800</qty>
</version>
<version>
<version_id>P1_V2</version_id>
<qty>1100</qty>
</version>
<version>
<version_id>P1_V3</version_id>
<qty>100</qty>
</version>
</product>
<product>
<name>Product 2</name>
<prod_id>P2</prod_id>
<version>
<version_id>P2_V1</version_id>
<qty>5000</qty>
</version>
<version>
<version_id>P2_V2</version_id>
<qty>5000</qty>
</version>
<version>
<version_id>P2_V3</version_id>
<qty>2000</qty>
</version>
</product>
<deliveries>
<del_id>1</del_id>
<destination>Miami</destination>
<delivery_products>
<version_id>P1_V1</version_id>
<qty>8000</qty>
</delivery_products>
<delivery_products>
<version_id>P2_V1</version_id>
<qty>5000</qty>
</delivery_products>
</deliveries>
<deliveries>
<del_id>2</del_id>
<destination>New York</destination>
<delivery_products>
<version_id>P1_V1</version_id>
<qty>800</qty>
</delivery_products>
<delivery_products>
<version_id>P2_V2</version_id>
<qty>1000</qty>
</delivery_products>
</deliveries>
Expected output is below. Note seq # starts from 1 and counts up to 4
<table>
<thead>
<tr>
<td class="col_head">
Seq
</td>
<td class="col_head">
Version
</td>
<td class="col_head">
Destination
</td>
<td class="col_head">
Qty
</td>
</tr>
</thead>
<tr>
<td colspan="4" class="rev_heading">Product 1</td>
</tr>
<tr>
<td>1</td>
<td>P1_V1</td>
<td>Miami</td>
<td>8000</td>
</tr>
<tr>
<td>2</td>
<td>P1_V1</td>
<td>New York</td>
<td>800</td>
</tr>
<tr>
<td colspan="4" class="rev_heading">Product 2</td>
</tr>
<tr>
<td>3</td>
<td>P2_V1</td>
<td>Miami</td>
<td>5000</td>
</tr>
<tr>
<td>4</td>
<td>P2_V2</td>
<td>New York</td>
<td>5000</td>
</tr>
</table>
Here's my XSL so far (just stuck a position() in for a place holder for the seq #)
<?xml version="1.0" encoding="UTF-8"?>
<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 method="html" doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"/>
<xsl:template match="shipments">
<html>
<head>
<title>Seq Test</title>
<style type="text/css">
table {border: 1px solid black; border-collapse: collapse;}
td {border: 1px solid black; padding: 1px 5px 1px 5px;}
.col_head {font-weight: 600;}
.rev_heading {color: red; text-align: center; padding-top: 15px;}
</style>
</head>
<body>
<table>
<thead>
<tr>
<!-- SEQ# -->
<td class="col_head">
Seq
</td>
<!-- Imprint/Version -->
<td class="col_head">
Version
</td>
<!-- Ship to -->
<td class="col_head">
Destination
</td>
<!-- Qty -->
<td class="col_head">
Qty
</td>
</tr>
</thead>
<xsl:for-each select="product">
<xsl:sort data-type="number" select="qty"/>
<xsl:for-each select="version">
<xsl:variable name="curr_version" select="version_id"/>
<xsl:if test="position() = 1">
<tr>
<td colspan="4" class="rev_heading">
<xsl:value-of select="../name"/>
</td>
</tr>
</xsl:if>
<xsl:for-each select="../../deliveries/delivery_products[version_id = $curr_version]">
<tr >
<!-- SEQ# -->
<td>
<xsl:value-of select="position()"/>
</td>
<!-- Version -->
<td>
<xsl:value-of select="version_id"/>
</td>
<!-- Ship to -->
<td>
<xsl:value-of select="../destination"/>
</td>
<!-- QTY -->
<td>
<xsl:value-of select="qty"/>
</td>
</tr>
</xsl:for-each>
</xsl:for-each>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
I'm using XSL1.0. My editor/debugger is OxygenXML with Saxon
(OxygenXML can't debug with MSXML) and it will deployed to work with a
3rd party app that only uses MSXML. This means I can't use a variable
containing a nodeset if I want to be able to debug.
You can still use oXygen and the EXSLT node-set() function.
When you are finished, simply change the namespace-uri from "http://exslt.org/common" to "urn:schemas-microsoft-com:xslt"
Here is a short example of this technique. Suppose you are finished debugging the below transformation:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="http://exslt.org/common">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/*">
<xsl:variable name="vrtfPass1">
<xsl:apply-templates select="num[. mod 3 = 0]"/>
</xsl:variable>
<xsl:copy-of select="sum(ext:node-set($vrtfPass1)/*)"/>
</xsl:template>
<xsl:template match="num">
<xsl:copy-of select="."/>
</xsl:template>
</xsl:stylesheet>
Then you make the change from the EXSLT namespace-uri to the MSXSL namespace uri:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="urn:schemas-microsoft-com:xslt">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/*">
<xsl:variable name="vrtfPass1">
<xsl:apply-templates select="num[. mod 3 = 0]"/>
</xsl:variable>
<xsl:copy-of select="sum(ext:node-set($vrtfPass1)/*)"/>
</xsl:template>
<xsl:template match="num">
<xsl:copy-of select="."/>
</xsl:template>
</xsl:stylesheet>
Finally, you run this last transformation with MSXML and it produces exactly the same result as the initial transformation that uses EXSLT:
18
I want to perform division of tables into three in my xslt code dynamically.
Give me structure to append my text at specific node like if i am having 100 nodes i need to append my text at 33rd 66th nodes .
My XSLT code :
<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">
<xsl:key name="routes-by-origin" match="/schedules/Routes/org" use="./text()"/>
<xsl:template match="schedules" name="Main">
<html>
<head></head>
<body>
<table>
<tr> <td> Heading </td> </tr>
<table>
<xsl:for-each select="Routes/org[generate-id(.) = generate-id(key('routes-by-origin',.)[1])]">
<xsl:value-of select="./text()"/>
<xsl:apply-templates select="//Routes[org/text() = current()/text()]"/>
</xsl:for-each>
</table>
</xsl:template>
Template design called from above template
<xsl:template match="Routes">
<xsl:value-of select="des/text()"/>
<xsl:variable name="via" select="Via/text()"/>
<xsl:value-of select="Flgno/text()"/>
</xsl:template>
</xsl:stylesheet>
Input Document
<schedules>
<Routes>
<org>Agartala</org>
<des>Bangalore</des>
<Flgno>SG 872</Flgno>
<Via>CCU, HYD</Via>
</Routes>
<Routes>
<org>Agartala</org>
<des>Guwahati</des>
<Flgno>SG 873</Flgno>
<Via> BOM </Via>
</Routes>
<Routes>
<org>Agartala</org>
<des>Hyderabad</des>
<Flgno>SG 872</Flgno>
<Via>CCU</Via>
</Routes>
<Routes>
<org>Agartala</org>
<des>Kolkata</des>
<Flgno>SG 872</Flgno>
<Via> - </Via>
</Routes>
<Routes>
<org>Agartala</org>
<des>Kolkata</des>
<Flgno>SG 874</Flgno>
<Via> - </Via>
</Routes>
<Routes>
<org>Agartala</org>
<des>Mumbai</des>
<Flgno>SG 874</Flgno>
<Via>CCU</Via>
</Routes>
<Routes>
<org>Ahmedabad</org>
<des>Bangalore</des>
<Flgno>SG 528</Flgno>
<Symbols> - </Symbols>
<Via>BOM</Via>
</Routes>
</schedules>
Expected Result
My output should be in three tables in one page:
in first table
first 2 records
second table - next 2 records
third table last 3 records
2 records
2 records
3 records
<table>
<table>
<tr>
<td>Agartala</td>
<td>Bangalore</td>
<td>SG 872</td>
<td>CCU</td>
</tr>
<tr>
<td> Agartala</td>
<td>Guwahati</td>
<td>SG 87</td>
<td>BOM</td>
</tr>
</table>
<table>
<tr>
<td>Agartala</td>
<td>Hyderabad</td>
<td>SG 872 </td>
<td>CCU</td>
</tr>
<tr>
<td>Agartala</td>
<td>Kolkatta</td>
<td>SG 872</td>
<td> - </td>
</tr>
</table>
<table>
<tr>
<td> Agartala</td>
<td>Kolkatta</td>
<td>SG 874</td>
<td> - </td>
</tr>
<tr>
<td>Agartala</td>
<td>Mumbai</td>
<td>SG 874 </td>
<td>CCU</td>
</tr>
<tr>
<td>Agartala</td>
<td>Bangalore</td>
<td>SG 528</td>
<td>BOM</td>
</tr>
</table>
</table>
Note : My input data is dynamic
This XSLT 1.0 style-sheet is a copy of Dimitre's solution here, slightly tweaked for the OP's particular data and having the 3rd table have ceil( row-count / 3) rows.
XSLT 1.0 Solution
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:variable name="prowLimit" select="floor(count(/*/Routes) div 3)" />
<xsl:template match="/">
<table>
<xsl:apply-templates select="*/Routes" />
</table>
</xsl:template>
<xsl:template match="Routes">
<xsl:if test="(position() mod $prowLimit = 1) and
(position() < (3 * $prowLimit + 1))">
<xsl:variable name="is-last-table" select="position() - (2*$prowLimit)" />
<table>
<xsl:for-each select=".|following-sibling::Routes[
not(position() > $prowLimit - 1) or ($is-last-table > 0)]" >
<tr>
<td><xsl:value-of select="org" /></td>
<td><xsl:value-of select="des" /></td>
<td><xsl:value-of select="Flgno" /></td>
<td><xsl:value-of select="Via" /></td>
</tr>
</xsl:for-each>
</table>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
XSLT 2.0 Solution
It gets easier in XSLT 2.0 ...
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fn="http://www.w3.org/2005/xpath-functions"
exclude-result-prefixes="xsl fn">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<xsl:variable name="prowLimit" select="floor(count(/*/Routes) div 3)" />
<table>
<xsl:for-each-group select="*/Routes"
group-adjacent="fn:min((floor((position() - 1) div $prowLimit),2))" >
<table>
<xsl:apply-templates select="current-group()" />
</table>
</xsl:for-each-group>
</table>
</xsl:template>
<xsl:template match="Routes">
<tr>
<td><xsl:value-of select="org" /></td>
<td><xsl:value-of select="des" /></td>
<td><xsl:value-of select="Flgno" /></td>
<td><xsl:value-of select="Via" /></td>
</tr>
</xsl:template>
</xsl:stylesheet>