Reputation: 59
Say I have the code below in my XML file and I would like to display the following infomation in rows: creationDate - serviceName - problemCode - division.
<foi:serviceInfo rdf:ID="SI1">
<foi:serviceName>Sewer</foi:serviceName>
<foi:problemCode>SI1</foi:problemCode>
<foi:division>Water</foi:division>
</foi:serviceInfo>
<foi:serviceInfo rdf:ID="SI2">
<foi:serviceName>Recycling</foi:serviceName>
<foi:problemCode>SI2</foi:problemCode>
<foi:division>Solid Waste</foi:division>
</foi:serviceInfo>
<foi:serviceRequest rdf:ID="R1">
<foi:creationDate>29 03 2013</foi:creationDate>
<foi:servicing rdf:resource="#SI1"/>
</foi:serviceRequest>
<foi:serviceRequest rdf:ID="R2">
<foi:creationDate>29 06 2013</foi:creationDate>
<foi:servicing rdf:resource="#SI2"/>
</foi:serviceRequest>
I am able to display the information from serviceRequest in rows, however, I do not know how to link the resource in foi:servicing to the ID of serviceInfo (in order to get at the attributes contained in serviceInfo, and subsequently display it).
Upvotes: 0
Views: 131
Reputation: 243529
This shorter transformation uses a key for X-referencing and produces the wanted results in a table:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:foi="some:foi" xmlns:rdf="some:rdf" exclude-result-prefixes="foi rdf">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="kSIById" match="foi:serviceInfo" use="concat('#',@rdf:ID)"/>
<xsl:template match="/*">
<table border="1"><xsl:apply-templates/></table>
</xsl:template>
<xsl:template match="/*/*" priority="-1"/>
<xsl:template match="/*/foi:serviceRequest">
<tr>
<td><xsl:apply-templates select="foi:creationDate"/></td>
<xsl:apply-templates select="key('kSIById', foi:servicing/@rdf:resource)/*"/>
</tr>
</xsl:template>
<xsl:template match="foi:serviceInfo/*">
<td><xsl:value-of select="."/></td>
</xsl:template>
</xsl:stylesheet>
When applied on the provided source XML (wrapped in a single top element and with namespaces defined):
<root xmlns:foi="some:foi" xmlns:rdf="some:rdf">
<foi:serviceInfo rdf:ID="SI1">
<foi:serviceName>Sewer</foi:serviceName>
<foi:problemCode>SI1</foi:problemCode>
<foi:division>Water</foi:division>
</foi:serviceInfo>
<foi:serviceInfo rdf:ID="SI2">
<foi:serviceName>Recycling</foi:serviceName>
<foi:problemCode>SI2</foi:problemCode>
<foi:division>Solid Waste</foi:division>
</foi:serviceInfo>
<foi:serviceRequest rdf:ID="R1">
<foi:creationDate>29 03 2013</foi:creationDate>
<foi:servicing rdf:resource="#SI1"/>
</foi:serviceRequest>
<foi:serviceRequest rdf:ID="R2">
<foi:creationDate>29 06 2013</foi:creationDate>
<foi:servicing rdf:resource="#SI2"/>
</foi:serviceRequest>
</root>
produces the wanted, correct result:
<table border="1">
<tr>
<td>29 03 2013</td>
<td>Sewer</td>
<td>SI1</td>
<td>Water</td>
</tr>
<tr>
<td>29 06 2013</td>
<td>Recycling</td>
<td>SI2</td>
<td>Solid Waste</td>
</tr>
</table>
Upvotes: 1
Reputation: 101730
The preferred approach to cross-referencing data in XSLT is to use an <xsl:key>
. The Following XSLT should do it:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:foi="foifoifoi" xmlns:rdf="rdfrdf"
exclude-result-prefixes="foi rdf">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:key name="kService" match="foi:serviceInfo" use="@rdf:ID"/>
<xsl:template match="/*">
<div>
<xsl:apply-templates select="foi:serviceRequest" />
</div>
</xsl:template>
<xsl:template match="foi:serviceRequest">
<xsl:variable name="referenceId"
select="substring(foi:servicing/@rdf:resource, 2)" />
<xsl:variable name="info" select="key('kService', $referenceId)[1]"/>
<div>
<xsl:value-of select="foi:creationDate"/>
<xsl:apply-templates select="$info/*" />
</div>
</xsl:template>
<xsl:template match="foi:serviceInfo/*">
<xsl:value-of select="concat(' - ', .)"/>
</xsl:template>
</xsl:stylesheet>
(I had to make up namespaces for foi
and rdf
since you didn't indicate them. Please substitute in the right URIs). When run on this XML (with a root node added):
<root xmlns:foi="foifoifoi" xmlns:rdf="rdfrdf">
<foi:serviceInfo rdf:ID="SI1">
<foi:serviceName>Sewer</foi:serviceName>
<foi:problemCode>SI1</foi:problemCode>
<foi:division>Water</foi:division>
</foi:serviceInfo>
<foi:serviceInfo rdf:ID="SI2">
<foi:serviceName>Recycling</foi:serviceName>
<foi:problemCode>SI2</foi:problemCode>
<foi:division>Solid Waste</foi:division>
</foi:serviceInfo>
<foi:serviceRequest rdf:ID="R1">
<foi:creationDate>29 03 2013</foi:creationDate>
<foi:servicing rdf:resource="#SI1"/>
</foi:serviceRequest>
<foi:serviceRequest rdf:ID="R2">
<foi:creationDate>29 06 2013</foi:creationDate>
<foi:servicing rdf:resource="#SI2"/>
</foi:serviceRequest>
</root>
This produces:
<div>
<div>29 03 2013 - Sewer - SI1 - Water</div>
<div>29 06 2013 - Recycling - SI2 - Solid Waste</div>
</div>
Main points:
xsl:key
to allow locating foi:serviceInfo
by a certain ID
.key()
function to find a related foi:serviceInfo
by ID. The [1]
at the end limits this to the first match. I wasn't sure if there's a possibility there could be more than one match, but is there?foi:serviceInfo
as a hyphen plus the element value.Upvotes: 0
Reputation: 402
This is a bit of an inelegant solution and would require extra work for extending to data sets that differ in their structure (although it will work for any number of serviceInfo and serviceRequest elements arranged in your sample data set). Its virtue is that it involves use of apply-templates rather than for-each. Using apply-templates is the best practice. Also, I didn't know the right namespaces to use so I just made some up.
This XSLT
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:foi="http://www.foi.com"
xmlns:rdf="http://www.rdf.com"
exclude-result-prefixes="foi rdf"
version="2.0">
<!-- Identity template -->
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:variable name="newLine"><xsl:text>
</xsl:text></xsl:variable>
<xsl:template match="/">
<xsl:value-of select="$newLine"/><table><xsl:value-of select="$newLine"/>
<xsl:apply-templates select="//foi:creationDate"/>
</table><xsl:value-of select="$newLine"/>
</xsl:template>
<xsl:template match="foi:creationDate">
<xsl:variable name="resourceId" select="replace(../foi:servicing/@rdf:resource,'#','')"/>
<xsl:message>BAH <xsl:value-of select="$resourceId"/></xsl:message>
<tr><xsl:value-of select="$newLine"/>
<td><xsl:apply-templates/></td><xsl:value-of select="$newLine"/>
<td><xsl:apply-templates select="//foi:serviceName[parent::*[@rdf:ID=$resourceId]]"/></td><xsl:value-of select="$newLine"/>
<td><xsl:apply-templates select="//foi:problemCode[parent::*[@rdf:ID=$resourceId]]"/></td><xsl:value-of select="$newLine"/>
<td><xsl:apply-templates select="//foi:division[parent::*[@rdf:ID=$resourceId]]"/></td><xsl:value-of select="$newLine"/>
</tr><xsl:value-of select="$newLine"/>
</xsl:template>
<xsl:template match="foi:serviceName">
<xsl:apply-templates select="@* | node()" />
</xsl:template>
<xsl:template match="foi:problemCode">
<xsl:apply-templates select="@* | node()" />
</xsl:template>
<xsl:template match="foi:division">
<xsl:apply-templates select="@* | node()" />
</xsl:template>
</xsl:stylesheet>
When applied on this XML document: (note: I added a root element)
<root>
<foi:serviceInfo rdf:ID="SI1">
<foi:serviceName>Sewer</foi:serviceName>
<foi:problemCode>SI1</foi:problemCode>
<foi:division>Water</foi:division>
</foi:serviceInfo>
<foi:serviceInfo rdf:ID="SI2">
<foi:serviceName>Recycling</foi:serviceName>
<foi:problemCode>SI2</foi:problemCode>
<foi:division>Solid Waste</foi:division>
</foi:serviceInfo>
<foi:serviceRequest rdf:ID="R1">
<foi:creationDate>29 03 2013</foi:creationDate>
<foi:servicing rdf:resource="#SI1"/>
</foi:serviceRequest>
<foi:serviceRequest rdf:ID="R2">
<foi:creationDate>29 06 2013</foi:creationDate>
<foi:servicing rdf:resource="#SI2"/>
</foi:serviceRequest>
</root>
Produces the desired result:
<tr>
<td>29 03 2013</td>
<td>Sewer</td>
<td>SI1</td>
<td>Water</td>
</tr>
<tr>
<td>29 06 2013</td>
<td>Recycling</td>
<td>SI2</td>
<td>Solid Waste</td>
</tr>
</table>
A brief explanation:
Upvotes: 1