XSLT convert HTML table to XML structured elements - html

I have this HTML table:
<?xml version="1.0" encoding="UTF-8"?>
<table class="names">
<tbody>
<tr class="names">
<td>
<p><strong class="strong">name</strong></p>
</td>
<td>
<p><strong class="strong">surname</strong></p>
</td>
<td>
<p><strong class="strong">aff</strong></p>
</td>
</tr>
<tr class="names">
<td>
<p><span class="contrib">John</span></p>
</td>
<td>
<p><span class="contrib">Smith</span></p>
</td>
<td>
<p><span class="contrib">1,3</span></p>
</td>
</tr>
<tr class="names">
<td>
<p><span class="contrib">Michael</span></p>
</td>
<td>
<p><span class="contrib">Jordan</span></p>
</td>
<td>
<p><span class="contrib">1,2</span></p>
</td>
</tr>
</tbody>
</table>
I would like to transform it to structured XML elements like this:
<contrib>
<person>
<name>John</name>
<surname>Smith</surname>
<number>1</number>
<number>3</number>
</person>
<person>
<name>Michael</name>
<surname>Jordan</surname>
<number>1</number>
<number>2</number>
</person>
</contrib>
And I created this XSLT so far:
<xsl:template name="article-meta">
<contrib>
<person>
<name>
<xsl:value-of select=".//td[1]//span[#class='contrib']"/>
</name>
<surname>
<xsl:value-of select=".//td[2]//span[#class='contrib']"/>
</surname>
<xsl:for-each select="//td[3]//span[#class='contrib']">
<number><xsl:value-of select="normalize-space(.)"/></number>
</xsl:for-each>
</person>
</contrib>
</xsl:template>
I've been playing the whole day, but it seems I'm unable to produce multiple xml blocks. I'm always getting all results inside single element. Is it even possible somehow to create the wanted structure above if all <span> elements inside <td> cells only have class "contrib" and nothing else? Also, the last cell should be tokenized I believe, but I also don't know how to address it.

Is there a reason why you cannot do simply:
XSLT 2.0
<xsl:stylesheet version="2.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="/table">
<contrib>
<xsl:for-each select="tbody/tr[position() > 1]">
<person>
<name>
<xsl:value-of select="td[1]"/>
</name>
<surname>
<xsl:value-of select="td[2]"/>
</surname>
<xsl:for-each select="tokenize(td[3], ',')">
<number>
<xsl:value-of select="."/>
</number>
</xsl:for-each>
</person>
</xsl:for-each>
</contrib>
</xsl:template>
</xsl:stylesheet>

Related

Turn XML with XSLT to aHTML order Table

i need yout help. I'm struggle with XSLT: I have for example an XML file like this:
<Adresses>
<Person id="1">
<Name>Bott</Name>
<Vorname>Nils</Vorname>
</Person>
<Person id="2">
<Name>Hubert</Name>
<Vorname>Hubertus</Vorname>
</Person>
<Person id="3">
<Name>Large</Name>
<Vorname>Lars</Vorname>
</Person>
<Numbers>
<number>
<id>1</id>
<tel>12354</tel>
</number>
<number>
<id>3</id>
<tel>32354</tel>
</number>
<number>
<id>2</id>
<tel>22354</tel>
</number>
</Numbers>
</Adresses>
And i have to transform to a order HTML Table.
The HTML Table should look like folowwing (Ordering after ID):
<table>
<tr>
<th>Name</th>
<th>Vorname</th>
<th>Tel</th>
</tr>
<tr>
<th>Bott</th>
<th>Nils</th>
<th>12354</th>
</tr>
</table>
My Problem is i don't know how to ckeck: Choose the number where Peron.id = number.id .... It would be realy great if someone could give me a full example for this problem. At web search it is always not so complicated in the tutorials ;-( .... I'm learning XSLT and just know some rules like apply-templates match="Person" .... but how is it possible in such a statement to call a other template wich select the coorect number?
I try to start with that:
<xsl:template match="/">
<html>
<body>
<xsl:for-each select="Adresses/Person">
<xsl:call-template name="curPos">
</xsl:call-template>
<xsl:value-of select="Name"/>
<xsl:value-of select="Vorname"/>
</xsl:for-each>
</body>
</html>
</xsl:template>
<xsl:template name="curPos" match="Person">
<xsl:value-of select="position()"/><br> </br>
</xsl:template>
My Problem is i don't know how to ckeck: Choose the number where
Peron.id = number.id ....
That's exactly what keys are for:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="num" match="number" use="id" />
<xsl:template match="/Adresses">
<html>
<body>
<table>
<tr>
<th>Name</th>
<th>Vorname</th>
<th>Tel</th>
</tr>
<xsl:for-each select="Person">
<tr>
<td>
<xsl:value-of select="Name"/>
</td>
<td>
<xsl:value-of select="Vorname"/>
</td>
<td>
<xsl:value-of select="key('num', #id)/tel"/>
</td>
</tr>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
Note that your table structure assumes each person has only one phone number (as in your example). However, the XML structure suggests there is a one-to-many relationship between persons and phone numbers, so you might want to consider changing:
<td>
<xsl:value-of select="key('num', #id)/tel"/>
</td>
to:
<td>
<xsl:for-each select="key('num', #id)">
<xsl:value-of select="tel"/>
<br/>
</xsl:for-each>
</td>
I have got the following XSLT 2.0 solution for you:
<xsl:template name="makeTable">
<table>
<tr>
<th>Name</th>
<th>Vorname</th>
<th>Tel</th>
</tr>
<xsl:for-each select="/Adresses/Person">
<tr>
<td><xsl:value-of select="Name"/></td>
<td><xsl:value-of select="Vorname"/></td>
<td><xsl:value-of select="../Numbers/number[id = current()/#id]/tel"/></td>
</tr>
</xsl:for-each>
</table>
</xsl:template>
Now, for the explanation as far as I understand the problem you have is finding the correct XPath expression for selecting the correct telephone number. The most important code snipped in this case is this line:
<td>
<xsl:value-of select="../Numbers/number[id = current()/#id]/tel"/>
</td>
In XSLT 2.0 - I'm not sure about XSLT 1.0 - you can refer to the current loop element with the current() function in an XPath.
To select the telephone number I filter for the number on the condition of its id being equal to the current loop elements attribute id and then getting this node's child tel to get the actual number.

XSL to transform XML to HTML, filter elements from multiple structures for the same element value

I am a newcomer to XML/XSLT and, so far, in searching SO and the W3SChools sites for clever stuff on Meunchian grouping I haven't been able to grasp an effective solution to my challenge.
Essentially I have one large XML file exported from a database (which means I can't directly edit the XML) which contains invoicing information.
I want to utilise XSLT (1.0) to apply a transformation of the XML into HTML (I am using Saxon) so that each invoice is displayed as a table. However, in the XML, there are many product lines which relate to the same invoice (denoted by the <invoiceNum> element as the identifier).
I don't want to have to create & display a new table for each product line which is part of the same invoice. In my current XSL file, I am trying to create a table for the first instance of a duplicated <invoiceNum> element, and then add only the unique elements from successive product lines (<ProductID>, <ProductName>, <ProductDescription> etc.) and leave out the duplicated shipping information.
In the XML code snippet, you can see the layout of the XML. In the XSL snippet, I hope you can see how I am trying to construct the table. For each successive <invoices_snet> instance in the XML file, I want to add just the product information to the table through the transformation. Using for-each on the <invoices_snet> element simply creates a new table each time.
Should I use conditional logic here, compare the equality of the value of the <invoices_snet> element, use templates?
Your help is much appreciated!
<database>
<invoices>
<invoices_snet>
<invoiceNum NAME="invoiceNum" TYPE="SMALLINT">368</invoiceNum>
<ProductID NAME="ProductID" TYPE="VARCHAR">SS106</ProductID>
<ProductName NAME="ProductName" TYPE="VARCHAR">Senna Sunglasses</ProductName>
<ProductDescription NAME="ProductDescription" TYPE="VARCHAR">Lively sunglasses</ProductDescription>
<Quantity NAME="Quantity" TYPE="SMALLINT">34</Quantity>
<UnitPrice NAME="UnitPrice" TYPE="CURRENCY">40.0000</UnitPrice>
<ExtendedPrice NAME="ExtendedPrice" TYPE="CURRENCY">1360.0000</ExtendedPrice>
<contactName NAME="contactName" TYPE="VARCHAR">Jeff</contactName>
<shippingStreet NAME="shippingStreet" TYPE="VARCHAR">11 Acacia Avenue</shippingStreet>
<shippingCity NAME="shippingCity" TYPE="VARCHAR">Huddersfield</shippingCity>
<shippingCounty NAME="shippingCounty" TYPE="VARCHAR">Yorkshire</shippingCounty>
<shippingPostcode NAME="shippingPostcode" TYPE="VARCHAR">YO12 8LA</shippingPostcode>
<saleDate NAME="salesDate" TYPE="DATETIME">30. Mar. 16</saleDate>
</invoices_snet>
<invoices_snet>
<invoiceNum NAME="invoiceNum" TYPE="SMALLINT">368</invoiceNum>
<ProductID NAME="ProductID" TYPE="VARCHAR">SS368</ProductID>
<ProductName NAME="ProductName" TYPE="VARCHAR">Senna T-shirts</ProductName>
<ProductDescription NAME="ProductDescription" TYPE="VARCHAR">T-shirts of beige colour with cream piping</ProductDescription>
<Quantity NAME="Quantity" TYPE="SMALLINT">20</Quantity>
<UnitPrice NAME="UnitPrice" TYPE="CURRENCY">15.00</UnitPrice>
<ExtendedPrice NAME="ExtendedPrice" TYPE="CURRENCY">300.00</ExtendedPrice>
<contactName NAME="contactName" TYPE="VARCHAR">Jeff</contactName>
<shippingStreet NAME="shippingStreet" TYPE="VARCHAR">11 Acacia Avenue</shippingStreet>
<shippingCity NAME="shippingCity" TYPE="VARCHAR">Huddersfield</shippingCity>
<shippingCounty NAME="shippingCounty" TYPE="VARCHAR">Yorkshire</shippingCounty>
<shippingPostcode NAME="shippingPostcode" TYPE="VARCHAR">YO12 8LA</shippingPostcode>
<saleDate NAME="salesDate" TYPE="DATETIME">30. Mar. 16</saleDate>
</invoices_snet>
</invoices>
</database>
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/database">
<html>
<head>
<title>Invoice</title>
<link rel="stylesheet" href="invoicingCSS.css"/>
</head>
<body>
<h1>Invoice</h1>
<br></br>
<xsl:for-each select="invoices/invoices_snet">
<h2>Order for Invoice Number: <xsl:value-of select="invoiceNum"/> </h2>
<table>
<tr>
<th>Product ID</th>
<th>Product Name</th>
<th>Product Description</th>
<th>Quantity</th>
<th>Unit Price</th>
<th>Extended Price</th>
<th>Contact Name</th>
<th>Shipping Address</th>
<th>Sales Date</th>
</tr>
<tr>
<td>
<xsl:value-of select="ProductID"/>
</td>
<td>
<xsl:value-of select="ProductName"/>
</td>
<td>
<xsl:value-of select="ProductDescription"/>
</td>
<td>
<xsl:value-of select="Quantity"/>
</td>
<td>
<xsl:value-of select="UnitPrice"/>
</td>
<td>
<xsl:value-of select="ExtendedPrice"/>
</td>
<td>
<xsl:value-of select="contactName"/>
</td>
<td>
<xsl:value-of select="concat(
shippingStreet,' ',
shippingCity,', ',
shippingCounty,', ',
shippingPostcode)"
/>
</td>
<td>
<xsl:value-of select="saleDate"/>
</td>
</tr>
</table>
</xsl:for-each>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
Grouping is much easier to do in XSLT 2.0, with its built-in xsl:for-each-group instruction.
Try this as your starting point:
XSLT 2.0
<xsl:stylesheet version="2.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:variable name="theader">
<tr>
<th>ProductID</th>
<th>Quantity</th>
<!-- add more as required -->
</tr>
</xsl:variable>
<xsl:template match="/database">
<html>
<xsl:for-each-group select="invoices/invoices_snet" group-by="invoiceNum">
<table border="1">
<xsl:copy-of select="$theader"/>
<xsl:apply-templates select="current-group()"/>
</table>
</xsl:for-each-group>
</html>
</xsl:template>
<xsl:template match="invoices_snet">
<tr>
<td>
<xsl:value-of select="ProductID"/>
</td>
<td>
<xsl:value-of select="Quantity"/>
</td>
<!-- add more as required -->
</tr>
</xsl:template>
</xsl:stylesheet>
<xsl:template match="invoices_snet">
<tr>
<td>
<xsl:value-of select="ProductID"/>
</td>
<td>
<xsl:value-of select="Quantity"/>
</td>
</tr>
</xsl:template>
</xsl:stylesheet>
First do you self a favor and have a look for xslt grouping for XSLT 1.0 this will be muenchian grouping e.g. this
And here the basic structure for a adaption to your xml:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml"/>
<xsl:key name="kinvoices_snet" match="invoices_snet" use="invoiceNum"/>
<xsl:template match="invoices">
<xsl:for-each select="invoices_snet [
count ( key('kinvoices_snet',./invoiceNum)[1] | . ) = 1 ]">
<xsl:variable name="this" select="." />
<g>
<gh>
<xsl:value-of select="invoiceNum" />
</gh>
<!-- group stuff -->
<xsl:for-each select=" key('kinvoices_snet',$this/invoiceNum)">
<!-- group member stuff -->
<gm>
<xsl:value-of select="ProductID" />
</gm>
</xsl:for-each>
</g>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

How to display data in one table with 4 columns.Note: Two xsl:for-each statements are used

I could really use some help as I've been trying for over 2 weeks. So far, I can display 3 columns whose attributes are testName,duration & outcome. While the final attribute "storage" is appended to the generated table. How do you display all the attributes into one table with 4 columns (testName,duration,outcome & storage)?
Thanks in advance for any help.
xsl:for-each select="/cruisecontrol/build/t:TestRun/t:Results/t:UnitTestResult"
<tr>
<td>
<xsl:value-of select="#testName"/>
</td>
<td>
<xsl:value-of select="#duration"/>
</td>
<td>
<xsl:value-of select="#outcome"/>
</td>
</tr>
</xsl:for-each>
xsl:for-each select="/cruisecontrol/build/t:TestRun/t:TestDefinitions/t:UnitTest"
<tr>
<td>
<xsl:value-of select="#storage"/>
</td>
</tr>
Without seeing the actual XML (posting a sample of the TestRun portion of the document would be useful), you can try:
<?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">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<table>
<xsl:apply-templates select="//build/Results/UnitTestResult"/>
</table>
</xsl:template>
<xsl:template match="//build/Results/UnitTestResult">
<xsl:variable name="ParentPosition" select="position()" />
<tr>
<td>
<xsl:value-of select="$ParentPosition"/>
</td>
<td>
<xsl:value-of select="#testName"/>
</td>
<td>
<xsl:value-of select="#duration"/>
</td>
<td>
<xsl:value-of select="#outcome"/>
</td>
<td>
<xsl:value-of select="ancestor::Results/TestDefinitions/UnitTest[$ParentPosition]/#storage"/>
</td>
</tr>
</xsl:template>
</xsl:stylesheet>
Note the use of position() and how it can be used as a variable in the <xsl:value-of select. Also note how you can use apply-templates to avoid xsl:for-each. This is cleaner as the top down approach keeps the correct position() in the hierarchy.
I've applied it to this XML (a well-formed version of the content you added earlier with the namespaces removed for simplicity - you may have to add them back in, although I didn't need to with the above stylesheet.
<?xml version="1.0" encoding="utf-8" ?>
<cruisecontrol project="RetailBuildAll">
<request source="IntervalTrigger" buildCondition="ForceBuild">
IntervalTrigger
triggered a build (ForceBuild)
</request>
<modifications />
<build date="2010-03-18 13:50:10" buildtime="00:52:57" error="true" buildcondition="ForceBuild">
TestRun id="9dede87a-1e32-4796-a706-bd8c9484df6d"
name="lx00551#ROCPWBUILDER41 2010-03-18 14:25:08"
runUser="EKC1\lx00551"
xmlns="http://microsoft.com/schemas/VisualStudio/TeamTest/2006">>
<Results>
<UnitTestResult executionId="71197f46-0ce1-46bb-896c-94de56a8341d" testId="e0b1d5ad-1f54-e491-58ed-227d74752b17" testName="_AmountDueNotSet" computerName="ROCPWBUILDER41" duration="00:00:01.8571146" startTime="2010-03-18T14:25:13.1997766-04:00" endTime="2010-03-18T14:25:15.4653871-04:00" testType="13cdc9d9-ddb5-4fa4-a97d-d965ccfc6d4b" outcome="Passed" testListId="8c84fa94-04c1-424b-9868-57a2d4851a1d">
<Output>
</Output>
</UnitTestResult>
<UnitTestResult executionId="d23eb331-6f98-4d6e-b5ac-6cadf5cbc23e" testId="1284c514-fede-0eec-dca9-4a83d1df9eb0" testName="_AmountDueSet" computerName="ROCPWBUILDER41" duration="00:00:00.3020513" startTime="2010-03-18T14:25:15.4653871-04:00" endTime="2010-03-18T14:25:15.7778851-04:00" testType="13cdc9d9-ddb5-4fa4-a97d-d965ccfc6d4b" outcome="Passed" testListId="8c84fa94-04c1-424b-9868-57a2d4851a1d">
<Output>
</Output>
</UnitTestResult>
<TestDefinitions>
<UnitTest name="SaveToArchiveItemThrowsExceptionWhenNotValid" storage="\retail\bin\DATA.retailplatform.imaging.imageobjectstest.dll" id="95af8a39-34e8-7b01-de6a-a647d9ee4053">
<Css projectStructure="" iteration="" />
<Owners>
<Owner name="" />
</Owners>
<Execution id="700c3770-242a-4ee3-af98-110d2c31a1d7" />
<TestMethod codeBase="x:/Retail/bin/DATA.RetailPlatform.Imaging.ImageObjectsTest.DLL" adapterTypeName="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestAdapter, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.Adapter" className="DATA.RetailPlatform.Imaging.ImageObjects.LayeredImageTest, DATA.RetailPlatform.Imaging.ImageObjectsTest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" name="SaveToArchiveItemThrowsExceptionWhenNotValid"
expectedException="DATA.RetailPlatform.ShoppingCart.Conversion.InvalidForSaveToArchiveItemException, DATA.RetailPlatform.ShoppingCart.Conversion, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
</UnitTest>
<UnitTest name="_RemoveEntryTitleMatchWhileNotUpgrading" storage="\retail\bin\softwaremanifesttest.dll" id="f0444c96-9751-23f2-2e5f-43114f036ed8">
<Css projectStructure="" iteration="" />
<Owners>
<Owner name="" />
</Owners>
<Execution id="a1411bf5-8ee4-4e37-ba24-10398a325950" />
<TestMethod codeBase="x:/Retail/bin/SoftwareManifestTest.DLL" adapterTypeName="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestAdapter, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.Adapter" className="SoftwareManifestTest.SoftwareManifestManagerTest, SoftwareManifestTest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" name="_RemoveEntryTitleMatchWhileNotUpgrading" />
</UnitTest>
</TestDefinitions>
</Results>
</build>
</cruisecontrol>

using XSL Transform XML data and their child elements in tabular format HTML

This is my test XML in this XML i have child element: INSTRUMENT and sub child element: INSTRUMENT/issuer and could be so on ...
5002199
10001
686184SE3
<INSTRUMENT>
<type>FI</type>
<issuer>
<FICode>123456</FICode>
<name>Test</name>
<city>SF</city>
<state>CA</state>
</issuer>
<issueDate>2011-06-22-05:00</issueDate>
<maturityDate>2016-06-22-05:00</maturityDate>
<firstCouponDate>2011-07-22-05:00</firstCouponDate>
<lastCouponDate>2016-05-22-05:00</lastCouponDate>
<couponRate>2.0</couponRate>
<paymentFrequency>12</paymentFrequency>
<callSchedule>
<notice>15</notice>
<timing>0</timing>
<call id="1">
<startDate>2011-12-22-05:00</startDate>
<type>2</type>
<freq>M</freq>
</call>
</callSchedule>
</INSTRUMENT>
<Commision>7.0</Commision>
<price>100.0</price>
I want to display this data in HTML tabular form, and run time the xml element could be any thing, so i can't hard code the element or subelement name
i was trying follwinf XSL
<xsl:template match="/">
<xsl:apply-templates />
</xsl:template>
<xsl:template match="*">
<table border="1" width="1000">
<tr>
<td class="section_head">Key</td>
<td class="section_head">Value</td>
</tr>
<xsl:for-each select="*" >
<tr>
<td>
<xsl:value-of select="name(.)" />
</td>
<td>
<xsl:value-of select="." />
</td>
</tr>
</xsl:for-each>
</table>
</xsl:template>
the HTM Child INSTRUMENT and issuer and callSchedule is comming in tabular form
is there any way i can iterate XSL recursivley to create HTML child table for XML child elements ?
Key
Value
ID
5002199
Code
10001
cusip
686184SE3
INSTRUMENT
FI 123456 Test SF CA 2011-06-22-05:00 2016-06-22-05:00 2011-07-22-05:00 2016-05-22-05:00 2.0 12 15 0 2011-12-22-05:00 100.0 2 M 2012-01-22-05:00 100.0 2012-02-22-05:00 100
Commision
7.0
price
100.0
alloc
100
I am not exactly sure what you are after here. It looks like you want to convert the nodes into name/value pairs and nest the html tables according to the XML hierarchy. Here is a bit of recursion that addresses the problem of not knowing the node names at runtime. Hopefully it well help you get started with this. If it is not what you are looking for you can use it to clarify your question:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes"/>
<xsl:template match="/">
<html>
<table>
<xsl:apply-templates/>
</table>
</html>
</xsl:template>
<xsl:template match="*[count(*) = 0]">
<tr>
<td>
<xsl:value-of select="name(.)" />
</td>
<td>
<xsl:value-of select="." />
</td>
</tr>
</xsl:template>
<xsl:template match="*[count(*) > 0]">
<tr>
<td>
<xsl:value-of select="name(.)" />
</td>
<td>
<table>
<xsl:apply-templates/>
</table>
</td>
</tr>
</xsl:template>
</xsl:stylesheet>

Linking to an item in another node (XSLT)

I have an XML document with companies listed in it. I want to create a link with XSLT that contains the <link> child of the next node. Sorry if this is confusing..here is some sample XML of what i'm trying to obtain:
<portfolio>
<company>
<name>Dano Industries</name>
<link>dano.xml</link>
</company>
<company>
<name>Mike and Co.</name>
<link>mike.xml</link>
</company>
<company>
<name>Steve Inc.</name>
<link>steve.xml</link>
</company>
</portfolio>
I want two links, "BACK" and "NEXT". While currently on mike.xml, I want BACK to link to "dano.xml" and NEXT linked to "steve.xml"...etc..and have it dynamically change when on a different page based on the nodes around it. I want to do this because I may add and change the list as I go along, so I don't want to have to manually re-link everything.
How can I obtain this? Sorry I am new to XSLT, so please explain with solution if possible! Thanks in advance!
Based on your comments to Dimitre, I think what you're going to want to do is use the document() function to access your "master list" XML file.
What you are actually running the stylesheet on is the individual fragments (dano.xml, mike.xml, steve.xml), right?
I'll use "mike.xml" for an example. I don't know what the fragments look like so I had to make one up. You will need to be able to identify the correct <company> in the master list based on something in the fragment. In my example, the fragment has a <compName> element with the same value as the <name> element in the corresponding company in the master list XML.
Here is what the "master list" XML, "dano/mike/steve" XML, the stylesheet, and the resulting HTML look like:
master_list.xml:
<?xml version="1.0" encoding="UTF-8"?>
<portfolio>
<company>
<name>Dano Industries</name>
<link>dano.xml</link>
</company>
<company>
<name>Mike and Co.</name>
<link>mike.xml</link>
</company>
<company>
<name>Steve Inc.</name>
<link>steve.xml</link>
</company>
</portfolio>
dano.xml
<?xml version="1.0" encoding="UTF-8"?>
<fragment>
<compName>Dano Industries</compName>
<compInfo>Some info about Dano Industries</compInfo>
</fragment>
mike.xml:
<?xml version="1.0" encoding="UTF-8"?>
<fragment>
<compName>Mike and Co.</compName>
<compInfo>Some info about Mike and Co.</compInfo>
</fragment>
steve.xml
<?xml version="1.0" encoding="UTF-8"?>
<fragment>
<compName>Steve Inc.</compName>
<compInfo>Some info about Steve Inc.</compInfo>
</fragment>
stylesheet:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="fragment">
<xsl:variable name="name" select="compName"/>
<xsl:variable name="previous-file">
<xsl:value-of select="document('master_list.xml')/portfolio/company[name=$name]/preceding-sibling::company[1]/link"/>
</xsl:variable>
<xsl:variable name="next-file">
<xsl:value-of select="document('master_list.xml')/portfolio/company[name=$name]/following-sibling::company[1]/link"/>
</xsl:variable>
<html>
<xsl:apply-templates/>
<p>
<xsl:if test="not($previous-file='')">
Back
</xsl:if>
<xsl:if test="not($previous-file='') and not($next-file='')">
<xsl:text> | </xsl:text>
</xsl:if>
<xsl:if test="not($next-file='')">
Next
</xsl:if>
</p>
</html>
</xsl:template>
<xsl:template match="compName">
<h1><xsl:apply-templates/></h1>
</xsl:template>
<xsl:template match="compInfo">
<p><xsl:apply-templates/></p>
</xsl:template>
</xsl:stylesheet>
HTML for Dano (dano.htm:)
<html>
<h1>Dano Industries</h1>
<p>Some info about Dano Industries</p>
<p>Next</p>
</html>
HTML for Mike (mike.htm:)
<html>
<h1>Mike and Co.</h1>
<p>Some info about Mike and Co.</p>
<p>Back | Next</p>
</html>
HTML for Steve (steve.htm:)
<html>
<h1>Steve Inc.</h1>
<p>Some info about Steve Inc.</p>
<p>Back</p>
</html>
This transformation:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/*">
<html>
<table border="1">
<xsl:apply-templates/>
</table>
</html>
</xsl:template>
<xsl:template match="company">
<xsl:variable name="vPrevious"
select="preceding-sibling::company[1]/link"/>
<xsl:variable name="vNext"
select="following-sibling::company[1]/link"/>
<tr>
<td>
<xsl:value-of select="name"/>
</td>
<td>
 
<xsl:if test="$vPrevious">
Back
</xsl:if>
</td>
<td>
 
<xsl:if test="$vNext">
Next
</xsl:if>
</td>
</tr>
</xsl:template>
</xsl:stylesheet>
when applied on the provided XML document:
<portfolio>
<company>
<name>Dano Industries</name>
<link>dano.xml</link>
</company>
<company>
<name>Mike and Co.</name>
<link>mike.xml</link>
</company>
<company>
<name>Steve Inc.</name>
<link>steve.xml</link>
</company>
</portfolio>
produces the desired HTML table with "Back" and "Next" links:
<html>
<table border="1">
<tr>
<td>
Dano Industries
</td>
<td> </td>
<td>
Next
</td>
</tr>
<tr>
<td>
Mike and Co.
</td>
<td>
Back
</td>
<td>
Next
</td>
</tr>
<tr>
<td>
Steve Inc.
</td>
<td>
Back
</td>
<td> </td>
</tr>
</table>
</html>