Identity transformation problem... xml to xml transform
Here should go questions about transforming XML with XSLT and FOP.
-
- Posts: 6
- Joined: Fri Jul 07, 2006 10:34 pm
Identity transformation problem... xml to xml transform
I already have a piece of code that will copy every attribute and node into a new xml document which is great! Here is the code:
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
In my xml file the <radiobutton> nodes are missing an attribute called 'text' that needs to be added during the transform. The 'text' attribute must be copied from the <dataitem> node higher up in the xml.
A really simple example xml could look like this:
BEFORE:
<datasource id="LikertScale">
<dataitem text="Unimportant" value="1"/>
</datasource>
<datasource id="RandomScale">
<dataitem text="High Importance" value="1"/>
</datasource>
<radiobutton groupname="1" datasource="LikertScale" dataitem="1" showlabel="false" />
AFTER the transform:
<datasource id="LikertScale">
<dataitem text="Unimportant" value="1"/>
</datasource>
<datasource id="RandomScale">
<dataitem text="High Importance" value="1"/>
</datasource>
<radiobutton groupname="1" datasource="LikertScale" dataitem="1" showlabel="false" text="Unimportant" />
**The only difference is the new attribute called "text" has been added to the <radiobutton>. If the "text" attribute was already ready there in the <radiobutton> then it shouldn't get added.
The "text" attribute was copied from the <dataitem> text attribute higher up in the xml. In order to find the right "text" value, xsl must compare dataitem attribute in <radiobutton> with the value attribute in <dataitem>. XSL should only look at <dataitem> nodes that are nested inside the appropriate <datasource>. In my example <datasource> id attribute matches <radiobutton> datasource attribute ("LikertScale"). If I were to change the <radiobutton> datasource attribute to "RandomScale", then the "text" attribute that should be copied is "High Importance".
If anyone has the slightest clue how to grapple this problem, I would greatly appreciate any help!
Thanks![/b]
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
In my xml file the <radiobutton> nodes are missing an attribute called 'text' that needs to be added during the transform. The 'text' attribute must be copied from the <dataitem> node higher up in the xml.
A really simple example xml could look like this:
BEFORE:
<datasource id="LikertScale">
<dataitem text="Unimportant" value="1"/>
</datasource>
<datasource id="RandomScale">
<dataitem text="High Importance" value="1"/>
</datasource>
<radiobutton groupname="1" datasource="LikertScale" dataitem="1" showlabel="false" />
AFTER the transform:
<datasource id="LikertScale">
<dataitem text="Unimportant" value="1"/>
</datasource>
<datasource id="RandomScale">
<dataitem text="High Importance" value="1"/>
</datasource>
<radiobutton groupname="1" datasource="LikertScale" dataitem="1" showlabel="false" text="Unimportant" />
**The only difference is the new attribute called "text" has been added to the <radiobutton>. If the "text" attribute was already ready there in the <radiobutton> then it shouldn't get added.
The "text" attribute was copied from the <dataitem> text attribute higher up in the xml. In order to find the right "text" value, xsl must compare dataitem attribute in <radiobutton> with the value attribute in <dataitem>. XSL should only look at <dataitem> nodes that are nested inside the appropriate <datasource>. In my example <datasource> id attribute matches <radiobutton> datasource attribute ("LikertScale"). If I were to change the <radiobutton> datasource attribute to "RandomScale", then the "text" attribute that should be copied is "High Importance".
If anyone has the slightest clue how to grapple this problem, I would greatly appreciate any help!
Thanks![/b]
-
- Posts: 6
- Joined: Fri Jul 07, 2006 10:34 pm
More clarification
Realistically the xml/xml output could look more like this:
BEFORE:
<datasource id="LikertScale">
<dataitem text="Unimportant" value="1"/>
<dataitem text="Don't Care" value="2"/>
<dataitem text="Unsure" value="3"/>
<dataitem text="NA" value="4"/>
</datasource>
<datasource id="RandomScale">
<dataitem text="High Importance" value="1"/>
</datasource>
<radiobutton groupname="1" datasource="LikertScale" dataitem="1" showlabel="false" />
<radiobutton groupname="1" datasource="LikertScale" dataitem="2" showlabel="false" />
AFTER the transform:
<datasource id="LikertScale">
<dataitem text="Unimportant" value="1"/>
<dataitem text="Don't Care" value="2"/>
<dataitem text="Unsure" value="3"/>
<dataitem text="NA" value="4"/>
</datasource>
<datasource id="RandomScale">
<dataitem text="High Importance" value="1"/>
</datasource>
<radiobutton groupname="1" datasource="LikertScale" dataitem="1" showlabel="false" text="Unimportant" />
<radiobutton groupname="1" datasource="LikertScale" dataitem="2" showlabel="false" text="Don't Care" />
There could be N <radiobutton> nodes and N <datasource> nodes, and N <dataitem> nodes.
BEFORE:
<datasource id="LikertScale">
<dataitem text="Unimportant" value="1"/>
<dataitem text="Don't Care" value="2"/>
<dataitem text="Unsure" value="3"/>
<dataitem text="NA" value="4"/>
</datasource>
<datasource id="RandomScale">
<dataitem text="High Importance" value="1"/>
</datasource>
<radiobutton groupname="1" datasource="LikertScale" dataitem="1" showlabel="false" />
<radiobutton groupname="1" datasource="LikertScale" dataitem="2" showlabel="false" />
AFTER the transform:
<datasource id="LikertScale">
<dataitem text="Unimportant" value="1"/>
<dataitem text="Don't Care" value="2"/>
<dataitem text="Unsure" value="3"/>
<dataitem text="NA" value="4"/>
</datasource>
<datasource id="RandomScale">
<dataitem text="High Importance" value="1"/>
</datasource>
<radiobutton groupname="1" datasource="LikertScale" dataitem="1" showlabel="false" text="Unimportant" />
<radiobutton groupname="1" datasource="LikertScale" dataitem="2" showlabel="false" text="Don't Care" />
There could be N <radiobutton> nodes and N <datasource> nodes, and N <dataitem> nodes.
-
- Posts: 4141
- Joined: Fri Mar 28, 2003 2:12 pm
Post by sorin_ristache »
Hello,
You can find below a stylesheet that adds the appropriate text attribute:
Regards,
Sorin
You can find below a stylesheet that adds the appropriate text attribute:
Code: Select all
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="node() | @*">
<xsl:copy>
<xsl:apply-templates select="node() | @*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="radiobutton">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:if test="not(@text)">
<xsl:attribute name="text">
<xsl:value-of select="preceding-sibling::datasource[@id = current()/@datasource]/dataitem[@value = current()/@dataitem]/@text"/>
</xsl:attribute>
</xsl:if>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Sorin
-
- Posts: 6
- Joined: Fri Jul 07, 2006 10:34 pm
The text attribute is "", but it did get added.
I'm confused on what is happening inside the <xsl:value-of> statement. The XSL code appears to be correct, but I don't understand what is happening after the first current()/@datasource.
The text attribute is getting added, but its contents are empty.
Thanks for providing a full code example! That's always very helpful.
The text attribute is getting added, but its contents are empty.
Thanks for providing a full code example! That's always very helpful.
-
- Posts: 6
- Joined: Fri Jul 07, 2006 10:34 pm
Got it working
I changed the value-of to read this instead:
<xsl:value-of select="//item/child::datasource[@id = current()/@datasource]/dataitem[@value = current()/@dataitem]/@text"/>
Now the text attribute contains the correct value!
I wonder if there is a cleaner way to do this (make it easier to read), like use a <xsl:apply-templates select="//item/child::datasource..."/> or similar to break up the XPath somehow.
<xsl:value-of select="//item/child::datasource[@id = current()/@datasource]/dataitem[@value = current()/@dataitem]/@text"/>
Now the text attribute contains the correct value!
I wonder if there is a cleaner way to do this (make it easier to read), like use a <xsl:apply-templates select="//item/child::datasource..."/> or similar to break up the XPath somehow.
-
- Site Admin
- Posts: 2095
- Joined: Thu Jan 09, 2003 2:58 pm
An easier to read and better wrt performance solution is below. It uses xsl:key to define a map between dataitem#datasource and the corresponding dataitem. Then in the radiobutton just uses the key to get the dataitem referred by that radio button.
Add
and change the value-of in the text attribute as below:
Best Regards,
George
Add
Code: Select all
<xsl:key name="di" match="dataitem" use="concat(@value, '#', ../@id)"/>
Code: Select all
<xsl:attribute name="text">
<xsl:value-of select="key('di', concat(@dataitem, '#', @datasource))/@text"/>
</xsl:attribute>
George
Jump to
- Oxygen XML Editor/Author/Developer
- ↳ Feature Request
- ↳ Common Problems
- ↳ DITA (Editing and Publishing DITA Content)
- ↳ SDK-API, Frameworks - Document Types
- ↳ DocBook
- ↳ TEI
- ↳ XHTML
- ↳ Other Issues
- Oxygen XML Web Author
- ↳ Feature Request
- ↳ Common Problems
- Oxygen Content Fusion
- ↳ Feature Request
- ↳ Common Problems
- Oxygen JSON Editor
- ↳ Feature Request
- ↳ Common Problems
- Oxygen PDF Chemistry
- ↳ Feature Request
- ↳ Common Problems
- Oxygen Feedback
- ↳ Feature Request
- ↳ Common Problems
- Oxygen XML WebHelp
- ↳ Feature Request
- ↳ Common Problems
- XML
- ↳ General XML Questions
- ↳ XSLT and FOP
- ↳ XML Schemas
- ↳ XQuery
- NVDL
- ↳ General NVDL Issues
- ↳ oNVDL Related Issues
- XML Services Market
- ↳ Offer a Service