I have few questions conserning XSLT to html conversion.
For some reason my xsl documents makes extra rows between every for-each loop. What can be the problem? Problem can be seen in html outputs.
Here's my xslt file
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html" encoding="utf-8" media-type="text/html" />
<xsl:template match="/">
<html>
<head>
<title>KT-linjan moduulit</title>
</head>
<body>
<h1>KT-linja info</h1>
<table border="double">
<caption>Moduulit taulukoituna</caption>
<tr>
<th>identifier</th>
<th>nimi</th>
<th>kuvaus</th>
</tr>
<xsl:for-each select="production_line/unit/*">
<tr>
<td>
<xsl:value-of select="#modID" />
</td>
<td>
<xsl:value-of select="name" />
</td>
<td>
<xsl:value-of select="description" />
</td>
</tr>
</xsl:for-each>
</table>
<p>
<b>HUOM:</b>
</p>
<p>ID's of the modules are unique!</p>
<p>References between modules are correct!</p>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
and XML file:
<production_line>
<unit>
<lift_module modID="LM001">
<name>Päätynostin PN1</name>
<description lang="fi">Nostaa paletin alakuljettimelta ylös Starter-moduulille</description>
<conveyor type="BELT" level="down" feed="in">
<description lang="fi">Palettikuljetin (ala)</description>
<stopper />
</conveyor>
<conveyor type="BELT" level="up" feed="out">
<description lang="fi">Palettikuljetin (ylä)</description>
<stopper />
</conveyor>
<lift_shelf>
<conveyor feed="in_out" type="BAND">
<description lang="fi">Palettikuljetin (hissitaso)</description>
<stopper />
</conveyor>
<description lang="fi">Liikkuva hissitaso</description>
</lift_shelf>
<sensor type="INDUCTIVE">
<amount>2</amount>
</sensor>
<chassis type="SAFETY" width="500" heigth="1200" length="700">
<sensor type="OPTIC">
<amount>1</amount>
</sensor>
</chassis>
</lift_module>
<connection fromIDREF="LM001" toIDREF="SM001" />
</unit>
<unit>
<starter_module modID="SM001">
<name>Starter-moduuli ST1</name>
<description lang="fi">Jakaa paletit kolmelle kuljettimelle</description>
<conveyor type="BELT">
<description lang="fi">Palettikuljetin (keski)</description>
<stopper />
</conveyor>
<conveyor type="BELT">
<description lang="fi">Palettikuljetin (syöttö1)</description>
<stopper />
</conveyor>
<conveyor type="BELT">
<description lang="fi">Palettikuljetin (syöttö2)</description>
<stopper />
</conveyor>
<crossing />
<crossing />
<crossing />
<sensor type="INDUCTIVE">
<amount>3</amount>
</sensor>
<sensor type="OPTIC">
<amount>3</amount>
</sensor>
</starter_module>
<connection fromIDREF="SM001" toIDREF="WM001" />
</unit>
<unit>
<workstation modID="WM001">
<name>Työasema TA1</name>
<description lang="fi">Sisältää vasemman ja oikean työpisteen</description>
<conveyor type="BELT">
<description lang="fi">Palettikuljetin (keski)</description>
<stopper />
</conveyor>
<conveyor type="BELT">
<description lang="fi">Palettikuljetin (vasen)</description>
<stopper>stoppari</stopper>
</conveyor>
<conveyor type="BELT">
<description lang="fi">Palettikuljetin (oikea)</description>
<stopper />
</conveyor>
<crossing />
<crossing />
<crossing />
<sensor type="INDUCTIVE">
<amount>6</amount>
</sensor>
<sensor type="OPTIC">
<amount>6</amount>
</sensor>
<switch type="push_button" operate="manual">send-painike</switch>
<switch type="switch" operate="manual">pause-kytkin</switch>
</workstation>
<connection fromIDREF="WM001" toIDREF="LM002" />
</unit>
<unit>
<lift_module modID="LM002">
<name>Päätynostin PN2</name>
<description lang="fi">Laskee paletin ylhäältä alas paluukuljettimelle</description>
<conveyor type="BELT" level="down" feed="out">
<description lang="fi">Palettikuljetin (ala)</description>
<stopper />
</conveyor>
<conveyor type="BELT" level="up" feed="in">
<description lang="fi">Palettikuljetin (ylä)</description>
<stopper />
</conveyor>
<lift_shelf>
<description lang="fi">Liikkuva hissitaso</description>
<conveyor type="BELT" feed="in_out">
<description lang="fi">Palettikuljetin (hissitaso)</description>
<stopper />
</conveyor>
</lift_shelf>
<sensor type="INDUCTIVE">
<amount>2</amount>
</sensor>
<chassis type="SAFETY" width="500" heigth="1200" length="700">
<sensor type="OPTIC">
<amount>2</amount>
</sensor>
</chassis>
</lift_module>
</unit>
</production_line>
On left is my table and on the right table in correct format.
I need to check if every identifier has unique attribute name (modID, for example LM001) and post if its unique or not. How should this check be performed?
I also need to check if iDREF atributes in XML file are properly linked. For example in the end of first node there is and check that it is correctly linked to the next modID. Any idea about this one?
It also seems to add unnecessary row between "ID's of the modules are unique!" and "References between modules are correct!" lines (where should be posted the answers of the checks).
Don't do <xsl:for-each select="production_line/unit/*">. That is too unspecific, it also matches the <connection> elements (which generate the empty rows).
Do this instead: <xsl:for-each select="production_line/unit/lift_module">.
To check whether all modID values are uniqe, try to select a duplicate:
<xsl:variable name="duplicateModIds" select="
//*/#modID[
. = preceding::*/#modID
or
. = following::*/#modID
]
" />
<xsl:choose>
<xsl:when test="$duplicateModIds">
<p>IDs of the modules are NOT unique!</p>
<!-- probably output $duplicateModIds, too -->
</xsl:when>
<xsl:otherwise>
<p>IDs of the modules are unique.</p>
</xsl:otherwise>
</xsl:choose>
Note that this can also be solved more elegantly through an XSL key, but for now the "duct tape" solution should be fine. Think about using keys when the performance of your transformation starts to drop or your requirements become more complex.
To check whether all connections are correct, simply try to select an incorrect one:
<xsl:variable name="incorrectRefs" select="
//connection[
#fromIDREF != ../*/#modID
or (
../following-sibling::unit[1]
and #toIDREF != ../following-sibling::unit[1]/*/#modID
)
]
" />
<xsl:choose>
<xsl:when test="$incorrectRefs">
<p>References between modules are NOT correct!</p>
<!-- probably output $incorrectRefs, too -->
</xsl:when>
<xsl:otherwise>
<p>References between modules are correct.</p>
</xsl:otherwise>
</xsl:choose>
also need to check if iDREF atributes in XM
Related
I got a HTML file to transform into a XML file using XSLT, where I need to grab only the first child node's date value to be used in the latter child nodes, since the latter child nodes do not have the data values and the tags will appear empty. I tried to use positioning to do that for the XSLT but to no avail.
The relevant HTML code is:
<tbody>
<tr>
<th rowspan="8" scope="rowgroup">2005DEC</th>
<th scope="row">Blemish on Card</th>
</tr>
<tr>
<th scope="row">Damaged</th>
</tr>
<tr>
<th rowspan="8" scope="rowgroup">2006JAN</th>
<th scope="row">Lost</th>
</tr>
<tr>
<th scope="row">Stolen</th>
</tr>
</tbody>
The relevant XSLT code is:
<xsl:for-each select="html/body/div/div/div/table/tbody/tr">
<Entry>
<xsl:choose>
<xsl:when test="th[#scope='rowgroup']">
<Year>
<xsl:value-of select="substring(th[#scope='rowgroup']/., 1, 4)" />
</Year>
<Month>
<xsl:value-of select="substring(th[#scope='rowgroup']/., 5, 3)" />
</Month>
</xsl:when>
<xsl:otherwise>
<Year>
<xsl:value-of select="substring(tr[1]/th[#scope='rowgroup']/., 1, 4)" />
</Year>
<Month>
<xsl:value-of select="substring(tr[1]/th[#scope='rowgroup']/., 5, 3)" />
</Month>
</xsl:otherwise>
</xsl:choose>
</Entry>
</xsl:for-each>
The XML code that is output is the following, which is not what I want as the second child node does not have the date value of the first child node and just shows up as an empty value tag for year and month:
<Entry>
<Year>2005</Year>
<Month>DEC</Month>
<Reason>Blemish on Card</Reason>
</Entry>
<Entry>
<Year/>
<Month/>
<Reason>Damaged</Reason>
</Entry>
<Entry>
<Year>2006</Year>
<Month>JAN</Month>
<Reason>Lost</Reason>
</Entry>
<Entry>
<Year/>
<Month/>
<Reason>Stolen</Reason>
</Entry>
What I need is:
<Entry>
<Year>2005</Year>
<Month>DEC</Month>
<Reason>Blemish on Card</Reason>
</Entry>
<Entry>
<Year>2005</Year>
<Month>DEC</Month>
<Reason>Damaged</Reason>
</Entry>
<Entry>
<Year>2006</Year>
<Month>JAN</Month>
<Reason>Lost</Reason>
</Entry>
<Entry>
<Year>2006</Year>
<Month>JAN</Month>
<Reason>Stolen</Reason>
</Entry>
How do I do that for my XSLT?
You have to navigate up first: substring(../tr[1]/th[#scope='rowgroup']/., 1, 4) if you want to select the data from the first row.
Based on your comments that is not what you want, if you want to select the data from the first preceding sibling row with a scope="rowgroup" attribute then one way, continuing with your approach is
<xsl:for-each select="//tbody/tr">
<Entry>
<xsl:choose>
<xsl:when test="th[#scope='rowgroup']">
<Year>
<xsl:value-of select="substring(th[#scope='rowgroup']/., 1, 4)" />
</Year>
<Month>
<xsl:value-of select="substring(th[#scope='rowgroup']/., 5, 3)" />
</Month>
</xsl:when>
<xsl:otherwise>
<Year>
<xsl:value-of select="substring(preceding-sibling::tr[th[#scope='rowgroup']][1]/th[#scope='rowgroup'], 1, 4)" />
</Year>
<Month>
<xsl:value-of select="substring(preceding-sibling::tr[th[#scope='rowgroup']][1]/th[#scope='rowgroup'], 5, 3)" />
</Month>
</xsl:otherwise>
</xsl:choose>
<xsl:for-each select="th[#scope='row']">
<Reason>
<xsl:value-of select="." />
</Reason>
</xsl:for-each>
</Entry>
</xsl:for-each>
although I might be easier to use for-each-group group-starting-with="tr[th[#scope = 'rowgroup']]" if you use an XSLT 2.0 processor.
I'm trying to import a submission.xml file generated from an ODK survey into Access. I'm using the 'XML import' function in MS Access and need to transform the data so that the each data set of a node that will be imported to a table will contain the ID of the survey.
I have a XML with the survey data that looks like this:
<SoLa_Tu_Insp_2016-03-13 id="SOLA-160313"
instanceID="uuid:63c27738-df02-4298-9090-7ab96d4e1ab2"
submissionDate="2016-04-08T02:11:47.600Z"
isComplete="true"
markedAsCompleteDate="2016-04-08T02:13:12.322Z"
xmlns="http://opendatakit.org/submissions">
<start>2016-04-08T23:47:50.615Z</start>
<end>2016-04-08T02:11:30.954Z</end>
<deviceid>353375050176865</deviceid>
<telnr />
<insp>
<objekt>25</objekt>
<objdel>212</objdel>
<objdel-tx>Bronstunneln</objdel-tx>
<datum>2016-04-08</datum>
<sign>MFR RLS</sign>
<anm>8</anm>
</insp>
<skdr>
<skd>
<metod>100</metod>
<ts>
<ts-nr>523</ts-nr>
<ts-typskada>Lucka - Lös - Takelement</ts-typskada>
<ts-kdel>15</ts-kdel>
<ts-kelem>1530</ts-kelem>
<ts-mtrl>13</ts-mtrl>
<ts-typ>35</ts-typ>
<ts-orsak>999</ts-orsak>
<ts-aktivitet>87</ts-aktivitet>
<ts-enhet>st</ts-enhet>
<ts-aktivitet-tx>Åtdragning</ts-aktivitet-tx>
<ts-mangd>1.0000000000</ts-mangd>
</ts>
<ovr>
<ovr-kdel />
<ovr-kdel-tx />
<ovr-kelem />
<ovr-kelem-tx />
<ovr-mtrl />
<ovr-mtrl-tx />
<ovr-typ />
<ovr-typ-tx />
<ovr-orsak />
<ovr-aktivitet />
<ovr-aktivitet-tx />
<ovr-enhet />
<ovr-mangd />
</ovr>
<kdel>15</kdel>
<kelem>1530</kelem>
<mtrl>13</mtrl>
<typ>35</typ>
<orsak>999</orsak>
<skd-tx>Gång/inspektionsbrygga etc / Lucka/dörr / Rostfritt stål / Lös / Övrigt</skd-tx>
<tk>3</tk>
<anm>Luckan håller på att ramla av</anm>
<aktivitet>87</aktivitet>
<mangd>1</mangd>
<enhet>st</enhet>
<sekt1>675</sekt1>
<sekt2 />
<lage>VT</lage>
<lage-tx />
<bildskada>1460073108135.jpg</bildskada>
<bildnr />
</skd>
<skd>
<metod>100</metod>
<ts>
<ts-nr>321</ts-nr>
<ts-typskada>f.a. sprutbetong - Läckage - Tak</ts-typskada>
<ts-kdel>6</ts-kdel>
<ts-kelem>665</ts-kelem>
<ts-mtrl>6</ts-mtrl>
<ts-typ>50</ts-typ>
<ts-orsak>129</ts-orsak>
<ts-aktivitet>45</ts-aktivitet>
<ts-enhet>kg</ts-enhet>
<ts-aktivitet-tx>Injektering</ts-aktivitet-tx>
<ts-mangd>5.0000000000</ts-mangd>
</ts>
<ovr>
<ovr-kdel />
<ovr-kdel-tx />
<ovr-kelem />
<ovr-kelem-tx />
<ovr-mtrl />
<ovr-mtrl-tx />
<ovr-typ />
<ovr-typ-tx />
<ovr-orsak />
<ovr-aktivitet />
<ovr-aktivitet-tx />
<ovr-enhet />
<ovr-mangd />
</ovr>
<kdel>6</kdel>
<kelem>665</kelem>
<mtrl>6</mtrl>
<typ>50</typ>
<orsak>129</orsak>
<skd-tx>Huvudbärverk / Tak ytförstärkning / Fiberarmerad sprutbetong / Läckage / Vatten</skd-tx>
<tk>2</tk>
<anm>3/s</anm>
<aktivitet>45</aktivitet>
<mangd>5</mangd>
<enhet>kg</enhet>
<sekt1>694</sekt1>
<sekt2>694</sekt2>
<lage>CT</lage>
<lage-tx>Kalk, järn,mangan utfälning droppar rikligt</lage-tx>
<bildskada />
<bildnr>4517</bildnr>
</skd>
<skd>
<metod>100</metod>
<ts>
<ts-nr>321</ts-nr>
<ts-typskada>f.a. sprutbetong - Läckage - Tak</ts-typskada>
<ts-kdel>6</ts-kdel>
<ts-kelem>665</ts-kelem>
<ts-mtrl>6</ts-mtrl>
<ts-typ>50</ts-typ>
<ts-orsak>129</ts-orsak>
<ts-aktivitet>45</ts-aktivitet>
<ts-enhet>kg</ts-enhet>
<ts-aktivitet-tx>Injektering</ts-aktivitet-tx>
<ts-mangd />
</ts>
<ovr>
<ovr-kdel />
<ovr-kdel-tx />
<ovr-kelem />
<ovr-kelem-tx />
<ovr-mtrl />
<ovr-mtrl-tx />
<ovr-typ />
<ovr-typ-tx />
<ovr-orsak />
<ovr-aktivitet />
<ovr-aktivitet-tx />
<ovr-enhet />
<ovr-mangd />
</ovr>
<kdel>6</kdel>
<kelem>665</kelem>
<mtrl>6</mtrl>
<typ>50</typ>
<orsak>129</orsak>
<skd-tx>Huvudbärverk / Tak ytförstärkning / Fiberarmerad sprutbetong / Läckage / Vatten</skd-tx>
<tk>1</tk>
<anm>Kalk, järn,mangan utfälning</anm>
<aktivitet>45</aktivitet>
<mangd />
<enhet>kg</enhet>
<sekt1>698</sekt1>
<sekt2 />
<lage>VT</lage>
<lage-tx>8/sek</lage-tx>
<bildskada />
<bildnr>4519-4520</bildnr>
</skd>
<skd>
<metod>100</metod>
<ts>
<ts-nr>513</ts-nr>
<ts-typskada>Lucka - Defekt - Takelement</ts-typskada>
<ts-kdel>15</ts-kdel>
<ts-kelem>1530</ts-kelem>
<ts-mtrl>13</ts-mtrl>
<ts-typ>48</ts-typ>
<ts-orsak>999</ts-orsak>
<ts-aktivitet>88</ts-aktivitet>
<ts-enhet>st</ts-enhet>
<ts-aktivitet-tx>Översyn</ts-aktivitet-tx>
<ts-mangd />
</ts>
<ovr>
<ovr-kdel />
<ovr-kdel-tx />
<ovr-kelem />
<ovr-kelem-tx />
<ovr-mtrl />
<ovr-mtrl-tx />
<ovr-typ />
<ovr-typ-tx />
<ovr-orsak />
<ovr-aktivitet />
<ovr-aktivitet-tx />
<ovr-enhet />
<ovr-mangd />
</ovr>
<kdel>15</kdel>
<kelem>1530</kelem>
<mtrl>13</mtrl>
<typ>48</typ>
<orsak>999</orsak>
<skd-tx>Gång/inspektionsbrygga etc / Lucka/dörr / Rostfritt stål / Defekt / Övrigt</skd-tx>
<tk>2</tk>
<anm>Går ej skruva saknas 2st skruvar</anm>
<aktivitet>88</aktivitet>
<mangd />
<enhet>st</enhet>
<sekt1>653</sekt1>
<sekt2 />
<lage>HT</lage>
<lage-tx>Nya skruvhål luckan som matchar</lage-tx>
<bildskada />
<bildnr>4523-4521</bildnr>
</skd>
<skd>
<metod>100</metod>
<ts>
<ts-nr>513</ts-nr>
<ts-typskada>Lucka - Defekt - Takelement</ts-typskada>
<ts-kdel>15</ts-kdel>
<ts-kelem>1530</ts-kelem>
<ts-mtrl>13</ts-mtrl>
<ts-typ>48</ts-typ>
<ts-orsak>999</ts-orsak>
<ts-aktivitet>88</ts-aktivitet>
<ts-enhet>st</ts-enhet>
<ts-aktivitet-tx>Översyn</ts-aktivitet-tx>
<ts-mangd>1.0000000000</ts-mangd>
</ts>
<ovr>
<ovr-kdel />
<ovr-kdel-tx />
<ovr-kelem />
<ovr-kelem-tx />
<ovr-mtrl />
<ovr-mtrl-tx />
<ovr-typ />
<ovr-typ-tx />
<ovr-orsak />
<ovr-aktivitet />
<ovr-aktivitet-tx />
<ovr-enhet />
<ovr-mangd />
</ovr>
<kdel>15</kdel>
<kelem>1530</kelem>
<mtrl>13</mtrl>
<typ>48</typ>
<orsak>999</orsak>
<skd-tx>Gång/inspektionsbrygga etc / Lucka/dörr / Rostfritt stål / Defekt / Övrigt</skd-tx>
<tk>2</tk>
<anm>Luckan behövs passas om</anm>
<aktivitet>88</aktivitet>
<mangd>1</mangd>
<enhet>st</enhet>
<sekt1>681</sekt1>
<sekt2 />
<lage>VT</lage>
<lage-tx>TV3 tidigare 2 skruv har sätts men mådet åtgärdas</lage-tx>
<bildskada />
<bildnr>4527</bildnr>
</skd>
<skd>
<metod>100</metod>
<ts>
<ts-nr>513</ts-nr>
<ts-typskada>Lucka - Defekt - Takelement</ts-typskada>
<ts-kdel>15</ts-kdel>
<ts-kelem>1530</ts-kelem>
<ts-mtrl>13</ts-mtrl>
<ts-typ>48</ts-typ>
<ts-orsak>999</ts-orsak>
<ts-aktivitet>88</ts-aktivitet>
<ts-enhet>st</ts-enhet>
<ts-aktivitet-tx>Översyn</ts-aktivitet-tx>
<ts-mangd>1.0000000000</ts-mangd>
</ts>
<ovr>
<ovr-kdel />
<ovr-kdel-tx />
<ovr-kelem />
<ovr-kelem-tx />
<ovr-mtrl />
<ovr-mtrl-tx />
<ovr-typ />
<ovr-typ-tx />
<ovr-orsak />
<ovr-aktivitet />
<ovr-aktivitet-tx />
<ovr-enhet />
<ovr-mangd />
</ovr>
<kdel>15</kdel>
<kelem>1530</kelem>
<mtrl>13</mtrl>
<typ>48</typ>
<orsak>999</orsak>
<skd-tx>Gång/inspektionsbrygga etc / Lucka/dörr / Rostfritt stål / Defekt / Övrigt</skd-tx>
<tk>3</tk>
<anm />
<aktivitet>88</aktivitet>
<mangd>1</mangd>
<enhet>st</enhet>
<sekt1>710</sekt1>
<sekt2 />
<lage>HT</lage>
<lage-tx>Nedre skruvhål passar inte</lage-tx>
<bildskada />
<bildnr>4543-4542</bildnr>
</skd>
</skdr>
<ritningar>212B2B01 212B2B02 212B2B03 212B2B04</ritningar>
<skd-antal>6</skd-antal>
<sekt-min>653</sekt-min>
<sekt-max>710</sekt-max>
<tk-min>1</tk-min>
<tk-max>3</tk-max>
<n0:meta xmlns:n0="http://openrosa.org/xforms">
<n0:instanceID>uuid:63c27738-df02-4298-9090-7ab96d4e1ab2</n0:instanceID>
<n0:instanceName>SöLä-25-212-2016-04-08-MFR RLS-4ae669a1-7d89-424a-bfab-26d506da0604</n0:instanceName>
</n0:meta>
At each 'skd' node I want to add the 'instanceID' attribute of the root element so that each 'skd' node will look something like:
<skdr>
<skd>
<id>uuid:63c27738-df02-4298-9090-7ab96d4e1ab2</id>
<metod>100</metod>
So I'm trying to use this XSL-file for the transformation, which is not working as intended:
xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes" encoding="utf-8"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<dataroot>
<xsl:apply-templates select="#*|node()"/>
</dataroot>
</xsl:template>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="//skd">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
<ID><xsl-copy-of select="/SoLa_Tu_Insp_2016-03-13/#instanceID"/></ID>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:template>
The result I get when using the above transformation is like this:
<?xml version="1.0" encoding="utf-8"?>
<dataroot>
<SoLa_Tu_Insp_2016-03-13 xmlns="http://opendatakit.org/submissions" id="SOLA-160313" instanceID="uuid:63c27738-df02-4298-9090-7ab96d4e1ab2" submissionDate="2016-04-08T02:11:47.600Z" isComplete="true" markedAsCompleteDate="2016-04-08T02:13:12.322Z">
<start>2016-04-08T23:47:50.615Z</start>
<end>2016-04-08T02:11:30.954Z</end>
<deviceid>353375050176865</deviceid>
<telnr/>
<insp>
<objekt>25</objekt>
<objdel>212</objdel>
<objdel-tx>Bronstunneln</objdel-tx>
<datum>2016-04-08</datum>
<sign>MFR RLS</sign>
<anm>8</anm>
</insp>
<skdr>
<skd>
<metod>100</metod>
<ts>
<ts-nr>523</ts-nr>
<ts-typskada>Lucka - Lös - Takelement</ts-typskada>
<ts-kdel>15</ts-kdel>
<ts-kelem>1530</ts-kelem>
<ts-mtrl>13</ts-mtrl>
<ts-typ>35</ts-typ>
<ts-orsak>999</ts-orsak>
<ts-aktivitet>87</ts-aktivitet>
<ts-enhet>st</ts-enhet>
<ts-aktivitet-tx>Åtdragning</ts-aktivitet-tx>
<ts-mangd>1.0000000000</ts-mangd>
</ts>
Thers is no 'instanceID' at each 'skd' node. I've tested the XPATHs at http://www.freeformatter.com/xpath-tester.html and it seems to be OK.
Anyone have any idea what I'm doing wrong here?
Your template does not match the skd element in the source XML document, because that element is in a namespace.
Try it this way instead:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:odk="http://opendatakit.org/submissions"
exclude-result-prefixes="odk">
<xsl:output indent="yes" encoding="utf-8"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<dataroot>
<xsl:apply-templates select="#*|node()"/>
</dataroot>
</xsl:template>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="odk:skd">
<xsl:copy>
<xsl:apply-templates select="#*"/>
<ID xmlns="http://opendatakit.org/submissions">
<xsl:value-of select="/odk:SoLa_Tu_Insp_2016-03-13/#instanceID"/>
</ID>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Additional notes:
Starting a match pattern with // is redundant;
xsl-copy-of is not a valid XSLT instruction;
Your version <xsl:apply-templates select="#*|node()"/> would have duplicated the child nodes.
I am trying to produce a HTML table from some XML I have got through a SQL query. The XML produced looks like the following:
<root>
<form attribute1="1" attribute2="1" />
<form attribute1="1" attribute2="2" />
<form attribute1="1" attribute2="3" />
<form attribute1="2" attribute2="1" />
<form attribute1="2" attribute2="2" />
<form attribute1="3" attribute2="1" />
</root>
The table I am trying to produce needs to have a header row for each unique attribute1 with rows underneath for each attribute2, something like this:
<attribute1="1" />
<attribute2="1" />
<attribute2="2" />
<attribute2="3" />
<attribute1="2" />
<attribute2="1" />
<attribute2="2" />
<attribute1="3" />
<attribute2="1" />
I don't have much experience using XML/XSLT but I am hoping it would be possible to do something like loop through the forms, create a header row for each unique attribute1 then create data rows associated to the unique attribute1 underneath.
If you can only use XSLT 1.0, try this XSLT for starters, which uses the Muenchian Grouping method
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes" />
<xsl:key name="form" match="form" use="#attribute1" />
<xsl:template match="root">
<xsl:copy>
<!-- Get first "form" element that occurs in each group -->
<xsl:for-each select="form[generate-id() = generate-id(key('form',#attribute1)[1])]">
<group>
<header><xsl:value-of select="#attribute1" /></header>
<!-- Get the "form" elements that make up the group -->
<xsl:apply-templates select="key('form', #attribute1)" />
</group>
</xsl:for-each>
</xsl:copy>
</xsl:template>
<xsl:template match="form">
<row><xsl:value-of select="#attribute2" /></row>
</xsl:template>
</xsl:stylesheet>
And here's some XSLT that can create an HTML table. This one is slightly more advanced as it works out the maximum number of columns for a row, and uses that in creating colspan attributes for the shorter rows
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html" doctype-public="XSLT-compat" omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />
<xsl:key name="form" match="form" use="#attribute1" />
<xsl:variable name="maxCells">
<xsl:for-each select="/root/form[generate-id() = generate-id(key('form',#attribute1)[1])]">
<xsl:sort select="count(key('form', #attribute1))" order="descending" />
<xsl:if test="position() = 1">
<xsl:value-of select="count(key('form', #attribute1))" />
</xsl:if>
</xsl:for-each>
</xsl:variable>
<xsl:template match="root">
<table border="1">
<!-- Get first "form" element that occurs in each group -->
<xsl:for-each select="form[generate-id() = generate-id(key('form',#attribute1)[1])]">
<tr>
<th colspan="{$maxCells}">
<xsl:value-of select="#attribute1" />
</th>
</tr>
<tr>
<!-- Get the "form" elements that make up the group -->
<xsl:apply-templates select="key('form', #attribute1)" />
</tr>
</xsl:for-each>
</table>
</xsl:template>
<xsl:template match="form">
<td>
<xsl:if test="position() = last()">
<xsl:attribute name="colspan">
<xsl:value-of select="$maxCells - count(key('form', #attribute1)) + 1" />
</xsl:attribute>
</xsl:if>
<xsl:value-of select="#attribute2" />
</td>
</xsl:template>
</xsl:stylesheet>
I'm trying to convert my XML into an XSL.
I succeeded in making the first part, but now I'm stuck on the second part. I'm trying to obtain a value from a key where it is defined somewhere else.
Maybe its easier to just show u :
Incoming XML file:
<?xml version="1.0" encoding="utf-16"?>
<AXFRoot>
<MAObject type="default" mdclass="PROGRAM">
<GUID dmname="">201406121715517010024191178005056B93D790000004460B00000D0F000989</GUID>
<Meta name="VRT_ESSENCE_DURATION" format="string" frate="">355280</Meta>
<Meta name="VRT_ESSENCE_AUDIO_CHANNELS" format="string" frate="">4</Meta>
<Meta name="VRT_CLIP_ID" format="string" frate="" />
<StratumEx name="VRT_CONTENT">
<Group orderidx="0" id="0" lastchanged="00010101000000">
<Segment id="0" contentid="999e584a-7192-45ff-8570-af6587e2938f" begin="0" end="8600" />
<Segment id="1" contentid="23502d29-a0b4-48c5-a8b2-596a195e2768" begin="8640" end="19760" />
<Segment id="2" contentid="b246ffb6-a56f-4e4e-8bd9-5da3b9cd7351" begin="19800" end="34840" />
<Segment id="3" contentid="1643dde7-3c5d-4675-a52e-77d00b70309b" begin="49000" end="49000" />
<Segment id="4" contentid="5ce3968f-5324-4172-90f3-bd6d22f696a7" begin="54800" end="58480" />
</Group>
</StratumEx>
<StratumEx name="VRT_ITEMS">
<Group orderidx="0" id="0" lastchanged="00010101000000">
<Segment id="0" contentid="328626e6-c794-494d-939a-39f7aa2e5a85" begin="11120" end="49200" />
<Segment id="1" contentid="1effe83f-7076-418f-b86f-cbd6ac6ba7ba" begin="81200" end="86600" />
</Group>
</StratumEx>
<StratumEx name="VRT_RESTRICTION" />
</MAObject>
<MAObject type="default" mdclass="S_VRT_CONTENT">
<GUID dmname="">999e584a-7192-45ff-8570-af6587e2938f</GUID>
<Meta name="VRT_CONTENT_TXT" format="string" frate="">Frag1</Meta>
</MAObject>
<MAObject type="default" mdclass="S_VRT_CONTENT">
<GUID dmname="">23502d29-a0b4-48c5-a8b2-596a195e2768</GUID>
<Meta name="VRT_CONTENT_TXT" format="string" frate="">Frag2</Meta>
</MAObject>
<MAObject type="default" mdclass="S_VRT_CONTENT">
<GUID dmname="">b246ffb6-a56f-4e4e-8bd9-5da3b9cd7351</GUID>
<Meta name="VRT_CONTENT_TXT" format="string" frate="">Frag3</Meta>
</MAObject>
<MAObject type="default" mdclass="S_VRT_CONTENT">
<GUID dmname="">1643dde7-3c5d-4675-a52e-77d00b70309b</GUID>
<Meta name="VRT_CONTENT_TXT" format="string" frate="">Frag4</Meta>
</MAObject>
<MAObject type="default" mdclass="S_VRT_CONTENT">
<GUID dmname="">5ce3968f-5324-4172-90f3-bd6d22f696a7</GUID>
<Meta name="VRT_CONTENT_TXT" format="string" frate="">Frag5</Meta>
</MAObject>
<MAObject type="default" mdclass="S_VRT_ITEMS">
<GUID dmname="">328626e6-c794-494d-939a-39f7aa2e5a85</GUID>
<Meta name="VRT_ITEMS_TXT" format="string" frate="">Frag6</Meta>
</MAObject>
<MAObject type="default" mdclass="S_VRT_ITEMS">
<GUID dmname="">1effe83f-7076-418f-b86f-cbd6ac6ba7ba</GUID>
<Meta name="VRT_ITEMS_TXT" format="string" frate="">Frag7</Meta>
</MAObject>
</AXFRoot>
Wanted result:
<MediaHAVEN_external_metadata version="1.0" name="VIAA">
<MDProperties>
<MEDIA_ID>201406121715517010024191178005056B93D790000004460B00000D0F000989</MEDIA_ID>
<VRT_ESSENCE_DURATION>355280</VRT_ESSENCE_DURATION>
<VRT_ESSENCE_AUDIO_CHANNELS>4</VRT_ESSENCE_AUDIO_CHANNELS>
<VRT_CLIP_ID></VRT_CLIP_ID>
</MDProperties>
<fragments>
<fragment>
<title>Frag1</title>
<original_start_z>0</original_start_z>
<original_end_z>8600</original_end_z>
</fragment>
<fragment>
<title>Frag2</title>
<original_start_z>8640</original_start_z>
<original_end_z>19760</original_end_z>
</fragment>
<fragment>
<title>Frag3</title>
<original_start_z>19800</original_start_z>
<original_end_z>34840</original_end_z>
</fragment>
<fragment>
<title>Frag4</title>
<original_start_z>49000</original_start_z>
<original_end_z>49000</original_end_z>
</fragment>
<fragment>
<title>Frag5</title>
<original_start_z>54800</original_start_z>
<original_end_z>58480</original_end_z>
</fragment>
<fragment>
<title>Frag6</title>
<original_start_z>11120</original_start_z>
<original_end_z>49200</original_end_z>
</fragment>
<fragment>
<title>Frag7</title>
<original_start_z>81200</original_start_z>
<original_end_z>86600</original_end_z>
</fragment>
</fragments>
</MediaHAVEN_external_metadata>
As you can see, those contentid's will do a lookup for the 'Frag' data. In my example: http://xsltransform.net/94hvTzt The 'Frag' data that you see right now, shouldn't belong there..
Could anyone point me in the correct direction?
Thanks!
Firstly, don't do this to create elements in XSLT...
<xsl:text disable-output-escaping="yes"><</xsl:text><xsl:value-of select="#name" /><xsl:text disable-output-escaping="yes">></xsl:text>
That way lies madness. If you want to create dynamically named elements, use the xsl:element command. You just need to do this....
<xsl:element name="{#name}">
<xsl:value-of select="."/>
</xsl:element>
But in answer to your question, to look up date from another location in your XML document, use an xsl:key
<xsl:key name="fragment" match="MAObject" use="GUID" />
To use this key, to look up the data, you would just do something like this (assuming you were positioned on a segment element)
<xsl:value-of select="key('fragment', #contentid)/Meta" />
Try this XSLT:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:key name="fragment" match="MAObject" use="GUID" />
<xsl:template match="/">
<MediaHAVEN_external_metadata version="1.0" name="VIAA">
<MDProperties>
<MEDIA_ID><xsl:value-of select="AXFRoot/MAObject[StratumEx]/GUID" /></MEDIA_ID>
<xsl:for-each select="AXFRoot/MAObject[StratumEx]/Meta">
<xsl:element name="{#name}">
<xsl:value-of select="."/>
</xsl:element>
</xsl:for-each>
</MDProperties>
<fragments>
<xsl:for-each select="AXFRoot/MAObject/StratumEx/Group/Segment">
<fragment>
<title><xsl:value-of select="key('fragment', #contentid)/Meta" /></title>
<original_start_z><xsl:value-of select="#begin" /></original_start_z>
<original_end_z><xsl:value-of select="#end" /></original_end_z>
</fragment>
</xsl:for-each>
</fragments>
</MediaHAVEN_external_metadata>
</xsl:template>
</xsl:stylesheet>
Or maybe this, to take a more template-based approach
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:key name="fragment" match="MAObject" use="GUID" />
<xsl:template match="/">
<MediaHAVEN_external_metadata version="1.0" name="VIAA">
<xsl:apply-templates select="AXFRoot/MAObject[StratumEx]" />
</MediaHAVEN_external_metadata>
</xsl:template>
<xsl:template match="MAObject">
<MDProperties>
<MEDIA_ID><xsl:value-of select="GUID" /></MEDIA_ID>
<xsl:apply-templates select="Meta" />
</MDProperties>
<fragments>
<xsl:apply-templates select="StratumEx/Group/Segment" />
</fragments>
</xsl:template>
<xsl:template match="Meta">
<xsl:element name="{#name}">
<xsl:value-of select="."/>
</xsl:element>
</xsl:template>
<xsl:template match="Segment">
<fragment>
<title><xsl:value-of select="key('fragment', #contentid)/Meta" /></title>
<original_start_z><xsl:value-of select="#begin" /></original_start_z>
<original_end_z><xsl:value-of select="#end" /></original_end_z>
</fragment>
</xsl:template>
</xsl:stylesheet>
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>