Reputation: 1
I'm new to the forum and even (little bit) new to xsl; I need help to solve a little problem with an XML code: please take a look at the structure below.
*********************************
<ProductRevision id="id45" **************>
<ApplicationRef **************/>
<UserData *********>
<UserValue title="title1" value="11111 000 000"/>
<UserValue title="object_name" value="test name1"/>
</UserData>
</ProductRevision>
<ProductRevision id="id50" ***********>
<ApplicationRef **************/>
<UserData id="id46">
<UserValue title="title1" value="22222 000 000"/>
<UserValue title="object_name" value="test name2"/>
</UserData>
</ProductRevision>
*******************************************
<GeneralRelation id="id49" subType="TestType" relatedRefs="#id2 #id45">
<ApplicationRef **************/>
<UserData ********>
<UserValue title="ds5_amont" type="int" value="3"/>
<UserValue title="ds5_cavities" type="int" value="2"/>
</UserData>
</GeneralRelation>
<GeneralRelation id="id49" subType="TestType" relatedRefs="#id2 #id50">
<ApplicationRef ***********/>
<UserData **********>
<UserValue title="ds5_amont" type="int" value="2"/>
<UserValue title="ds5_cavities" type="int" value="3"/>
</UserData>
</GeneralRelation>
As you can see, the ProductRevision nodes contain an id value; this value identifies two corresponding GeneralRelation nodes, which contain the UserValues ds5_amont and ds5_cavities. I use the following piece of .xsl code to display the values of title1 and object_name of all the ProductRevision nodes:
<xsl:for-each select="//plm:ProductRevision[@subType = 'XXXXX']">
<xsl:variable name="part" select="./plm:UserData/plm:UserValue[@title='object_name']/@value" />
<xsl:variable name="identnr" select="./plm:UserData/plm:UserValue[@title='title1']/@value" />
<Row>
<Cell ss:StyleID="s73">
<Data ss:Type="String">
<xsl:value-of select="$part"/>
</Data>
</Cell>
<Cell ss:StyleID="s73">
<Data ss:Type="String">
<xsl:value-of select="$identnr"/>
</Data>
</Cell>
</Row>
Now, for each ProductRevision, I need to display the corresponding ds5_amont and ds5_cavities values, contained in the corresponding nodes identified by the id45 and id50 values. These properties must be printed next to the cells which display the $part and $identnr variables. I've not been able to find the solution so far, any help will be highly appreciated! Thanks!
EDIT
Sorry guys, I cannot learn in 2 seconds how to reproduce an Excel table on your forum. The result should be simply like that: for each Product revision, there should be one row showing object_name****title1****ds5_amont****ds5_cavities Sorry again, hope it is clear enough ;-)
Upvotes: 0
Views: 1199
Reputation: 1
Thank you all for your contributions. Finally, this is the solution I've used. I guess yours were all very sophisticated and professional solutions, but for a beginner like me, it's necessary to simplify the code, in a way that even the errors are easily identifiable. But I can tell you that I will study a lot on those solutions! First of all, identify the correct ProductRevision nodes by the subType attribute; then, display the two variables in context of the ProductRevision nodes, and store the id in the pid variable:
<xsl:template match="//plm:ProductRevision[@subType='DS5_PartRevision']">
<xsl:variable name="part" select="./plm:UserData/plm:UserValue[@title='object_name']/@value" />
<xsl:variable name="identnr" select="./plm:UserData/plm:UserValue[@title='ds5_s_serien_identnr']/@value" />
<xsl:variable name="pid" select="@id"/>
<Row>
<Cell ss:StyleID="s73">
<Data ss:Type="String">
<xsl:value-of select="$part"/>
</Data>
</Cell>
<Cell ss:StyleID="s73">
<Data ss:Type="String">
<xsl:value-of select="$identnr"/>
</Data>
</Cell>
Once the first ProductRevision node is processed, check all the GeneralRelation nodes; for each node, create the variable relref and store a portion of the value of the relatedRefs attribute. Only the value after " #" (space-#) will be stored:
<xsl:for-each select="/plm:PLMXML/plm:GeneralRelation">
<xsl:variable name="relref" select="substring-after(@relatedRefs,' #')"/>
<xsl:choose>
<xsl:when test="$relref=$pid">
<Cell ss:StyleID="s73">
<Data ss:Type="String">
<xsl:value-of select="./plm:UserData/plm:UserValue[@title='ds5_amont']/@value"/>
</Data>
</Cell>
<Cell ss:StyleID="s73">
<Data ss:Type="String">
<xsl:value-of select="./plm:UserData/plm:UserValue[@title='ds5_cavities']/@value"/>
</Data>
</Cell>
</xsl:when>
</xsl:choose>
</xsl:for-each>
</Row>
For each GeneralRelation node, compare the values of pid and relref : if those are matching, get the values of the two properties in context of the GeneralRelation node (therefore the ./plm/ notation) and display them in the correct row (of the corresponding ProductRevision).
Upvotes: 0
Reputation: 1882
You want to process those GeneralRelation
elements having the @id
value of your current ProductRevision
element in the list of theirs @relatedRefs
attribute. In XSLT 1.0 you use contains
and current
functions like this:
/root
/GeneralRelation
[contains
(concat(@relatedRefs,' '),
concat('#',current()/@id,' ')
)
]
This input:
<root>
<ProductRevision id="id45">
<ApplicationRef />
<UserData>
<UserValue title="title1" value="11111 000 000" />
<UserValue title="object_name" value="test name1" />
</UserData>
</ProductRevision>
<ProductRevision id="id50">
<ApplicationRef />
<UserData id="id46">
<UserValue title="title1" value="22222 000 000" />
<UserValue title="object_name" value="test name2" />
</UserData>
</ProductRevision>
<GeneralRelation id="id49" subType="TestType"
relatedRefs="#id2 #id45">
<ApplicationRef />
<UserData>
<UserValue title="ds5_amont" type="int" value="453" />
<UserValue title="ds5_cavities" type="int" value="452" />
</UserData>
</GeneralRelation>
<GeneralRelation id="id49" subType="TestType"
relatedRefs="#id2 #id50">
<ApplicationRef />
<UserData>
<UserValue title="ds5_amont" type="int" value="502" />
<UserValue title="ds5_cavities" type="int" value="503" />
</UserData>
</GeneralRelation>
</root>
And this transformation
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes" />
<xsl:variable name="vGeneralRelation"
select="/root/GeneralRelation" />
<xsl:template match="text()|GeneralRelation" />
<xsl:template match="root">
<table>
<xsl:apply-templates />
</table>
</xsl:template>
<xsl:template match="ProductRevision">
<Row>
<xsl:apply-templates
select="*|$vGeneralRelation[
contains(concat(@relatedRefs,' '),
concat('#',current()/@id,' '))]/*" />
</Row>
</xsl:template>
<xsl:template
match="UserValue[@title[.='object_name' or .='title1' or .='ds5_cavities' or .='ds5_amont']]">
<Cell>
<xsl:value-of select="@value" />
</Cell>
</xsl:template>
</xsl:stylesheet>
Produce this output
<?xml version="1.0" encoding="utf-8"?>
<table>
<Row>
<Cell>11111 000 000</Cell>
<Cell>test name1</Cell>
<Cell>453</Cell>
<Cell>452</Cell>
</Row>
<Row>
<Cell>22222 000 000</Cell>
<Cell>test name2</Cell>
<Cell>502</Cell>
<Cell>503</Cell>
</Row>
</table>
Check working example at http://xsltransform.net/6qaFCEU
Upvotes: 1
Reputation: 117140
Using the libxslt
processor, you can take advantage of the EXSLT str:tokenize()
extension function.
Consider the following simplified example:
XML
<root>
<ProductRevision id="id45">
<ApplicationRef/>
<UserData>
<UserValue title="title1" value="11111 000 000"/>
<UserValue title="object_name" value="test name1"/>
</UserData>
</ProductRevision>
<ProductRevision id="id50">
<ApplicationRef/>
<UserData id="id46">
<UserValue title="title1" value="22222 000 000"/>
<UserValue title="object_name" value="test name2"/>
</UserData>
</ProductRevision>
<GeneralRelation id="id49" subType="TestType" relatedRefs="#id2 #id45">
<ApplicationRef/>
<UserData>
<UserValue title="ds5_amont" type="int" value="453"/>
<UserValue title="ds5_cavities" type="int" value="452"/>
</UserData>
</GeneralRelation>
<GeneralRelation id="id49" subType="TestType" relatedRefs="#id2 #id50">
<ApplicationRef/>
<UserData>
<UserValue title="ds5_amont" type="int" value="502"/>
<UserValue title="ds5_cavities" type="int" value="503"/>
</UserData>
</GeneralRelation>
</root>
XSLT 1.0 + EXSLT
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:str="http://exslt.org/strings"
extension-element-prefixes="str">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:key name="relation" match="GeneralRelation" use="str:tokenize(@relatedRefs, ' ')" />
<xsl:template match="/root">
<table>
<xsl:for-each select="ProductRevision">
<Row>
<!-- ProductRevision -->
<Cell>
<xsl:value-of select="UserData/UserValue[@title='object_name']/@value"/>
</Cell>
<Cell>
<xsl:value-of select="UserData/UserValue[@title='title1']/@value"/>
</Cell>
<!-- GeneralRelation -->
<xsl:variable name="relation" select="key('relation', concat('#', @id))" />
<Cell>
<xsl:value-of select="$relation/UserData/UserValue[@title='ds5_amont']/@value"/>
</Cell>
<Cell>
<xsl:value-of select="$relation/UserData/UserValue[@title='ds5_cavities']/@value"/>
</Cell>
</Row>
</xsl:for-each>
</table>
</xsl:template>
</xsl:stylesheet>
Result
<?xml version="1.0" encoding="UTF-8"?>
<table>
<Row>
<Cell>test name1</Cell>
<Cell>11111 000 000</Cell>
<Cell>453</Cell>
<Cell>452</Cell>
</Row>
<Row>
<Cell>test name2</Cell>
<Cell>22222 000 000</Cell>
<Cell>502</Cell>
<Cell>503</Cell>
</Row>
</table>
Upvotes: 1