I am trying to create a transformation that will map a flat structure ( with parent/child ids) into a hierarchical structure. I have included a simple request and responses examples below. The actual data has over 500 elements. Any help would be really appreciated! Thanks!
Validation Rules:
Offer can be in top level
Offer can be under package
Offer can be under group
Request:
<!-- offer with no parents(group or package) if No package_id or group ID in ffer element-->
<offer>
<namevaluepair>
<name>type</name>
<value>offer</value>
</namevaluepair>
<namevaluepair>
<name>id</name>
<value>OFR1</value>
</namevaluepair>
</offer>
<!-- type package P1 & P2 representation-->
<offer>
<namevaluepair>
<name>type</name>
<value>package</value>
</namevaluepair>
<namevaluepair>
<name>id</name>
<value>P1</value>
</namevaluepair>
</offer>
<offer>
<namevaluepair>
<name>type</name>
<value>package</value>
</namevaluepair>
<namevaluepair>
<name>id</name>
<value>P2</value>
</namevaluepair>
</offer>
<!-- offer under package but not in group-->
<offer>
<namevaluepair>
<name>type</name>
<value>offer</value>
</namevaluepair>
<namevaluepair>
<name>id</name>
<value>OFRP1</value>
</namevaluepair>
<namevaluepair>
<name>package_id</name>
<value>P1</value>
</namevaluepair>
</offer>
<!-- offers under package but not in group-->
<offer>
<namevaluepair>
<name>type</name>
<value>offer</value>
</namevaluepair>
<namevaluepair>
<name>id</name>
<value>OFRP2</value>
</namevaluepair>
<namevaluepair>
<name>package_id</name>
<value>P2</value>
</namevaluepair>
</offer>
<!-- type groups G1P1 and G1P2 representations,
group G1P1 is part of package P1 and this group G1P2 is part of package P2-->
<offer>
<namevaluepair>
<name>type</name>
<value>group</value>
</namevaluepair>
<namevaluepair>
<name>id</name>
<value>G1P1</value>
</namevaluepair>
<namevaluepair>
<name>package_id</name>
<value>P1</value>
</namevaluepair>
</offer>
<offer>
<namevaluepair>
<name>type</name>
<value>group</value>
</namevaluepair>
<namevaluepair>
<name>id</name>
<value>G2P2</value>
</namevaluepair>
<namevaluepair>
<name>package_id</name>
<value>P2</value>
</namevaluepair>
</offer>
<!-- offer OFRG1P1 under group G1P1 as parent AND G1P1 is under P1 package-->
<offer>
<namevaluepair>
<name>type</name>
<value>offer</value>
</namevaluepair>
<namevaluepair>
<name>id</name>
<value>OFRG1P1</value>
</namevaluepair>
<namevaluepair>
<name>group_id</name>
<value>G1P1</value>
</namevaluepair>
</offer>
<!-- offer OFRG1P1 under group G2P2 as parent AND grp G2P2 is under P2 package-->
<offer>
<namevaluepair>
<name>type</name>
<value>offer</value>
</namevaluepair>
<namevaluepair>
<name>id</name>
<value>OFRG2P2</value>
</namevaluepair>
<namevaluepair>
<name>group_id</name>
<value>G2P2</value>
</namevaluepair>
</offer>
Output:
<offers>
<!-- offer with no parents(group or package)-->
<offer ID="OFR1"/>
<packages>
<package ID="P1">
<groups>
<group ID="G1P1">
<offer ID="OFRG1P1"/>
</group>
</groups>
<offer ID="OFR1P1"/>
</package>
<package ID="P2">
<groups>
<group ID="G2P2">
<offer ID="OFRG2P2"/>
</group>
</groups>
<offer ID="OFR1P2"/>
</package>
</packages>
</offers>
Here is a XSLT 1.0 solution, utilizing keys.
The stylesheet declares four keys for finding different objects:
top level objects by their type (package or offer),
groups by their package id,
offers belonging to a package by their package id, and
offers belonging to a group by their group id.
At the top level, the stylesheet processes the top-level offers and packages. At the package level, the stylesheet processes the groups and offers belonging to that package. At the group level, the system processes the offers belonging to that group.
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:key name="top-level-objects-by-type"
match="offer[not(namevaluepair[name='package_id'])]
[not(namevaluepair[name='group_id'])]"
use="namevaluepair[name='type']/value"/>
<xsl:key name="groups-by-package-id"
match="offer[namevaluepair[name='type' and value='group']]"
use="namevaluepair[name='package_id']/value"/>
<xsl:key name="offers-by-package-id"
match="offer[namevaluepair[name='type' and value='offer']]"
use="namevaluepair[name='package_id']/value"/>
<xsl:key name="offers-by-group-id"
match="offer[namevaluepair[name='type' and value='offer']]"
use="namevaluepair[name='group_id']/value"/>
<xsl:template match="/">
<offers>
<xsl:apply-templates select="key('top-level-objects-by-type', 'offer')"/>
<packages>
<xsl:apply-templates select="key('top-level-objects-by-type', 'package')"/>
</packages>
</offers>
</xsl:template>
<xsl:template match="offer[namevaluepair[name='type' and value='package']]">
<xsl:variable name="id" select="namevaluepair[name='id']/value"/>
<package ID="{$id}">
<groups>
<xsl:apply-templates select="key('groups-by-package-id', $id)"/>
</groups>
<xsl:apply-templates select="key('offers-by-package-id', $id)"/>
</package>
</xsl:template>
<xsl:template match="offer[namevaluepair[name='type' and value='group']]">
<xsl:variable name="id" select="namevaluepair[name='id']/value"/>
<group ID="{$id}">
<xsl:apply-templates select="key('offers-by-group-id', $id)"/>
</group>
</xsl:template>
<xsl:template match="offer[namevaluepair[name='type' and value='offer']]">
<offer ID="{namevaluepair[name='id']/value}"/>
</xsl:template>
</xsl:stylesheet>
Related
I am trying to replicate the example located here Click Here
However, I am unable to achieve the desired results.
The output is not at all getting generated as per desired.
The input I have used :
<?xml version="1.0" encoding="UTF-8" ?>
<Order xmlns="http://www.book.org">
<Bundle>
<authors>
<author>
<authorId>100</authorId>
<authorName>Kathisiera</authorName>
</author>
<author>
<authorId>200</authorId>
<authorName>Bates</authorName>
</author>
<author>
<authorId>300</authorId>
<authorName>Gavin King</authorName>
</author>
</authors>
<books>
<book>
<orderId>1111</orderId>
<bookName>Head First Java</bookName>
<bookAuthorId>100</bookAuthorId>
</book>
<book>
<orderId>5555</orderId>
<bookName>Head First Servlets</bookName>
<bookAuthorId>200</bookAuthorId>
</book>
<book>
<orderId>1111</orderId>
<bookName>Hibernate In Action</bookName>
<bookAuthorId>300</bookAuthorId>
</book>
</books>
</Bundle>
</Order>
**The Schema I have used in for my transformation**
<!-- begin snippet: js hide: false console: true babel: false -->
The XSLT I am using for my transformation :
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0"
xmlns:socket="http://www.oracle.com/XSL/Transform/java/oracle.tip.adapter.socket.ProtocolTranslator"
xmlns:oracle-xsl-mapper="http://www.oracle.com/xsl/mapper/schemas"
xmlns:dvm="http://www.oracle.com/XSL/Transform/java/oracle.tip.dvm.LookupValue"
xmlns:mhdr="http://www.oracle.com/XSL/Transform/java/oracle.tip.mediator.service.common.functions.MediatorExtnFunction"
xmlns:oraxsl="http://www.oracle.com/XSL/Transform/java"
xmlns:oraext="http://www.oracle.com/XSL/Transform/java/oracle.tip.pc.services.functions.ExtFunc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xp20="http://www.oracle.com/XSL/Transform/java/oracle.tip.pc.services.functions.Xpath20"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xref="http://www.oracle.com/XSL/Transform/java/oracle.tip.xref.xpath.XRefXPathFunctions"
xmlns:ns0="http://www.book.org"
exclude-result-prefixes="oracle-xsl-mapper xsi xsd xsl ns0 socket dvm mhdr oraxsl oraext xp20 xref">
<oracle-xsl-mapper:schema>
<!--SPECIFICATION OF MAP SOURCES AND TARGETS, DO NOT MODIFY.-->
<oracle-xsl-mapper:mapSources>
<oracle-xsl-mapper:source type="XSD">
<oracle-xsl-mapper:schema location="../Schemas/BooksOrder.xsd"/>
<oracle-xsl-mapper:rootElement name="Order" namespace="http://www.book.org"/>
</oracle-xsl-mapper:source>
</oracle-xsl-mapper:mapSources>
<oracle-xsl-mapper:mapTargets>
<oracle-xsl-mapper:target type="XSD">
<oracle-xsl-mapper:schema location="../Schemas/BooksOrder.xsd"/>
<oracle-xsl-mapper:rootElement name="Order" namespace="http://www.book.org"/>
</oracle-xsl-mapper:target>
</oracle-xsl-mapper:mapTargets>
<!--GENERATED BY ORACLE XSL MAPPER 12.2.1.2.0(XSLT Build 161003.0739.0018) AT [THU JAN 23 13:13:32 IST 2020].-->
</oracle-xsl-mapper:schema>
<!--User Editing allowed BELOW this line - DO NOT DELETE THIS LINE-->
<xsl:key name="k" match="ns0:Order/ns0:Bundle/ns0:books/ns0:book" use="ns0:orderId"/>
<xsl:key name="a" match="ns0:Order/ns0:Bundle/ns0:books/ns0:author" use="ns0:authorId"/>
<xsl:template match="/ns0:Order">
<xsl:copy>
<xsl:apply-templates select="//ns0:books"/>
</xsl:copy>
</xsl:template>
<xsl:template match="//ns0:books">
<xsl:apply-templates select="ns0:book[generate-id(.) = generate-id(key('k', ns0:orderId))]"/>
</xsl:template>
<xsl:template match="ns0:book">
<Bundle>
<authors>
<xsl:apply-templates select="key('a', string(key('k', ns0:orderId)/ns0:bookAuthorId ))" />
</authors>
<books>
<xsl:copy-of select="key('k', ns0:orderId)"/>
</books>
</Bundle>
</xsl:template>
<xsl:template match="ns0:author">
<xsl:copy-of select="."/>
</xsl:template>
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
However the output I am getting is :
<?xml version = '1.0' encoding = 'UTF-8'?>
<Order xmlns="http://www.book.org" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.book.org file:/C:/JDeveloper/mywork/SOADevelopment/XsltLearner/SOA/Schemas/BooksOrder.xsd">
<Bundle>
<authors/>
<books>
<book>
<orderId>1111</orderId>
<bookName>Head First Java</bookName>
<bookAuthorId>100</bookAuthorId>
</book>
<book>
<orderId>1111</orderId>
<bookName>Hibernate In Action</bookName>
<bookAuthorId>300</bookAuthorId>
</book>
</books>
</Bundle>
<Bundle>
<authors/>
<books>
<book>
<orderId>5555</orderId>
<bookName>Head First Servlets</bookName>
<bookAuthorId>200</bookAuthorId>
</book>
</books>
</Bundle>
</Order>
The node is not getting populated.
I have tried using copy-of to see the output for the second key but it prints nothing.
Could you please suggest me where I am going wrong.
Any Idea what I am doing incorrect?
Please help
Thanks!
The pattern for the key would <xsl:key name="a" match="ns0:Order/ns0:Bundle/ns0:authors/ns0:author" use="ns0:authorId"/>, as far as I understand your posted document sample. I would also remove the string call in any use of the key function e.g. use <xsl:apply-templates select="key('a', key('k', ns0:orderId)/ns0:bookAuthorId )"/>.
I have a large XML file to transform using XSLT to append the integer position of sibling node . I’m using XSLT3 streaming and accumulators. I did get desired output. However, my code looks so lengthy that I’m unable to simplify my code. I also need to group same sibling nodes as sibling nodes in the source xml is not grouped always. Could someone help me here please?
Requirement: Sibling nodes such as Positions, Payments etc.. need to be appended with their corresponding integer position such as <Locations1>, <Locations2>etc.<Payments1>,< Payments2> etc..
Now that I have declared two accumulators, each for each sibling nodes. However, my source XML has many sibling nodes.. I’m not sure if I need to use as many accumulators and template match as my sibling nodes.
Input XML
``
<?xml version="1.0" encoding="UTF-8"?>
<Members>
<Member>
<Name>
<fname>Fred</fname>
<id>1234</id>
</Name>
<Locations>
<name>Chicago</name>
<days>3</days>
<hours>24</hours>
</Locations>
<Locations>
<name>Chicago</name>
<days>3</days>
<hours>24</hours>
</Locations>
<Payments>
<amount>1000</amount>
<currency>USD</currency>
</Payments>
<Payments>
<amount>1000</amount>
<currency>USD</currency>
</Payments>
<Locations>
<name>New York</name>
<days>5</days>
<hours>40</hours>
</Locations>
<Locations>
<name>Boston</name>
<days>4</days>
<hours>32</hours>
</Locations>
</Member>
<Member>
<Name>
<fname>Jack</fname>
<id>4567</id>
</Name>
<Locations>
<name>New York</name>
<days>5</days>
<hours>30</hours>
</Locations>
<Locations>
<name>Chicago</name>
<days>3</days>
<hours>24</hours>
</Locations>
<Payments>
<amount>1500</amount>
<currency>USD</currency>
</Payments>
<Payments>
<amount>1800</amount>
<currency>USD</currency>
</Payments>
</Member>
</Members>
``
Expected Output
``
<?xml version="1.0" encoding="UTF-8"?>
<Members>
<Member>
<Name>
<fname>Fred</fname>
<id>1234</id>
</Name>
<Locations_1>
<name>Chicago</name>
<days>3</days>
<hours>24</hours>
</Locations_1>
<Locations_2>
<name>Chicago</name>
<days>3</days>
<hours>24</hours>
</Locations_2>
<Locations_3>
<name>New York</name>
<days>5</days>
<hours>40</hours>
</Locations_3>
<Locations_4>
<name>Boston</name>
<days>4</days>
<hours>32</hours>
</Locations_4>
<Payments_1>
<amount>1000</amount>
<currency>USD</currency>
</Payments_1>
<Payments_2>
<amount>1000</amount>
<currency>USD</currency>
</Payments_2>
</Member>
<Member>
<Name>
<fname>Jack</fname>
<id>4567</id>
</Name>
<Locations_1>
<name>New York</name>
<days>5</days>
<hours>30</hours>
</Locations_1>
<Locations_2>
<name>Chicago</name>
<days>3</days>
<hours>24</hours>
</Locations_2>
<Payments_1>
<amount>1500</amount>
<currency>USD</currency>
</Payments_1>
<Payments_2>
<amount>1800</amount>
<currency>USD</currency>
</Payments_2>
</Member>
</Members>
``
Current code
``
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" version="3.0">
<xsl:output method="xml" indent="yes"/>
<xsl:mode streamable="yes" on-no-match="shallow-copy" use-accumulators="#all"/>
<xsl:accumulator name="loc-count" as="xs:integer" initial-value="0" streamable="yes">
<xsl:accumulator-rule match="Member" select="0"/>
<xsl:accumulator-rule match="Member/Locations" select="$value + 1"/>
</xsl:accumulator>
<xsl:accumulator name="pay-count" as="xs:integer" initial-value="0" streamable="yes">
<xsl:accumulator-rule match="Member" select="0"/>
<xsl:accumulator-rule match="Member/Payments" select="$value + 1"/>
</xsl:accumulator>
<xsl:template match="Locations">
<xsl:element name="Locations_{accumulator-before('loc-count')}">
<xsl:copy-of select="#* | node()"/>
</xsl:element>
</xsl:template>
<xsl:template match="Payments">
<xsl:element name="Payments_{accumulator-before('pay-count')}">
<xsl:copy-of select="#* | node()"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
``
Current Output
<?xml version="1.0" encoding="UTF-8"?>
<Members>
<Member>
<Name>
<fname>Fred</fname>
<id>1234</id>
</Name>
<Locations_1>
<name>Chicago</name>
<days>3</days>
<hours>24</hours>
</Locations_1>
<Locations_2>
<name>Chicago</name>
<days>3</days>
<hours>24</hours>
</Locations_2>
<Payments_1>
<amount>1000</amount>
<currency>USD</currency>
</Payments_1>
<Payments_2>
<amount>1000</amount>
<currency>USD</currency>
</Payments_2>
<Locations_3>
<name>New York</name>
<days>5</days>
<hours>40</hours>
</Locations_3>
<Locations_4>
<name>Boston</name>
<days>4</days>
<hours>32</hours>
</Locations_4>
</Member>
<Member>
<Name>
<fname>Jack</fname>
<id>4567</id>
</Name>
<Locations_1>
<name>New York</name>
<days>5</days>
<hours>30</hours>
</Locations_1>
<Locations_2>
<name>Chicago</name>
<days>3</days>
<hours>24</hours>
</Locations_2>
<Payments_1>
<amount>1500</amount>
<currency>USD</currency>
</Payments_1>
<Payments_2>
<amount>1800</amount>
<currency>USD</currency>
</Payments_2>
</Member>
</Members>
If you want to group the Member child elements by node-name() then I think you need to wrap the xsl:for-each-group into xsl:fork:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:map="http://www.w3.org/2005/xpath-functions/map"
xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="#all" version="3.0">
<xsl:strip-space elements="*"/>
<xsl:output indent="yes"/>
<xsl:mode on-no-match="shallow-copy" streamable="yes" use-accumulators="counters"/>
<xsl:accumulator name="counters" as="map(xs:QName, xs:integer)" initial-value="map{}" streamable="yes">
<xsl:accumulator-rule match="Member" select="map{}"/>
<xsl:accumulator-rule match="Member/*"
select="map:put($value, node-name(), if (map:contains($value, node-name())) then map:get($value, node-name()) + 1 else 1)"/>
</xsl:accumulator>
<xsl:template match="Member">
<xsl:copy>
<xsl:fork>
<xsl:for-each-group select="*" group-by="node-name()">
<xsl:apply-templates select="current-group()"/>
</xsl:for-each-group>
</xsl:fork>
</xsl:copy>
</xsl:template>
<xsl:template match="Member/*">
<xsl:element name="{node-name()}_{accumulator-before('counters')(node-name())}">
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
This approach only shows the grouping, it doesn't try to special case Name elements or some other way to not output an index if there is only one such element.
Firstly, my sympathy. XML that uses names like Payments_1 and Payments_2 is really bad news, someone is going to hate you for generating it like this. But if that's the kind of XML you've been told to produce, I guess it's not your job to question it.
As far as the requirements are concerned, you haven't made it clear whether the various kinds of sibling nodes are always grouped as in your example (all Locations, then all Payments, etc), or whether they can be interleaved.
One way you might be able to reduce the volume of code is by having a single accumulator holding a map. The map would use element names as the key and the current sibling count for that element as the value.
<accumulator name="counters" as="map(xs:QName, xs:integer)" initial-value="map{}">
<xsl:accumulator-rule match="Member" select="map{}"/>
<xsl:accumulator-rule match="Member/*" select="map:put($value, node-name(.), if (map:contains($value, node-name(.)) then map:get($value, node-name(.))+1 else 1"/>
</accumulator>
<xsl:template match="Members/*">
<xsl:element name="{name()}_{accumulator-before('counters')(node-name(.))}">
....
Another way to do the conditional map:put is
map:put($value, node-name(.), ($value(node-name(.)), 0)[1] + 1)
I have an issue trying to transform the following. The input has a parent-child relationship which is shown as levels below. The Parent_Identifier tag helps relate the children to the parent. What is the issue with the XSLT transformation? I've used a transformation which was referred to here in this post: Xslt group parent/child, but I can't seem to get it to work.
Input Document
<DBAdapterOutputCollection xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.oracle.com/pcbpel/adapter/db/DBAdapter">
<DBAdapterOutput>
<LEVEL>1</LEVEL>
<IDENTIFIER>9536162</IDENTIFIER>
<PARENT_IDENTIFIER xsi:nil="true"/>
<LINE_NUMBER>1.1.0</LINE_NUMBER>
</DBAdapterOutput>
<DBAdapterOutput>
<LEVEL>2</LEVEL>
<IDENTIFIER>9536165</IDENTIFIER>
<PARENT_IDENTIFIER>9536162</PARENT_IDENTIFIER>
<LINE_NUMBER>1.1.1</LINE_NUMBER>
<ORDER_NUMBER>1554828</ORDER_NUMBER>
</DBAdapterOutput>
<DBAdapterOutput>
<LEVEL>2</LEVEL>
<IDENTIFIER>9536173</IDENTIFIER>
<PARENT_IDENTIFIER>9536162</PARENT_IDENTIFIER>
<LINE_NUMBER>1.1.7</LINE_NUMBER>
<ORDER_NUMBER>1554828</ORDER_NUMBER>
</DBAdapterOutput>
<DBAdapterOutput>
<LEVEL>3</LEVEL>
<IDENTIFIER>1227973</IDENTIFIER>
<PARENT_IDENTIFIER>9536165</PARENT_IDENTIFIER>
<LINE_NUMBER>1.1.4</LINE_NUMBER>
<ORDER_NUMBER>1554828</ORDER_NUMBER>
</DBAdapterOutput>
<DBAdapterOutput>
<LEVEL>3</LEVEL>
<IDENTIFIER>1275015</IDENTIFIER>
<PARENT_IDENTIFIER>9536165</PARENT_IDENTIFIER>
<LINE_NUMBER>1.1.4</LINE_NUMBER>
<ORDER_NUMBER>1554828</ORDER_NUMBER>
</DBAdapterOutput>
</DBAdapterOutputCollection>
Expected Output Document
<WMSAssetInterface_Input xmlns="http://siebel.com/CustomUI">
<ListOfAsset xmlns="http://www.siebel.com/xml/ThinComergentAsset">
<ListOfAssetHeader>
<AssetHeader>
<IntegrationId>9536162 1.1.0</IntegrationId>
<ProductName>1.1.0</ProductName>
<ListOfAssetItem>
<AssetItem>
<IntegrationId>9536162 1.1.0 Level=1</IntegrationId>
<ProductName>1.1.0</ProductName>
<ListOfAssetItem>
<AssetItem>
<IntegrationId>9536165 1.1.1 Level=2</IntegrationId>
<ProductName>1.1.1</ProductName>
<ListOfAssetItem>
<AssetItem>
<IntegrationId>1227973 1.1.4 Level=3</IntegrationId>
<ProductName>1.1.4</ProductName>
</AssetItem>
<AssetItem>
<IntegrationId>1275015 1.1.4 Level=3</IntegrationId>
<ProductName>1.1.4</ProductName>
</AssetItem>
</ListOfAssetItem>
</AssetItem>
<AssetItem>
<IntegrationId>9536173 1.1.7 Level=2</IntegrationId>
<ProductName>1.1.7</ProductName>
</AssetItem>
</ListOfAssetItem>
</AssetItem>
</ListOfAssetItem>
</AssetHeader>
<ListOfAssetHeader>
</ListOfAsset>
</WMSAssetInterface_Input>
Here's the XSLT I'm trying to use; why isn't this working?
<xsl:stylesheet version="1.0" xmlns:ns0="http://xmlns.oracle.com/pcbpel/adapter/db/DBAdapter" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xsdLocal1="http://www.siebel.com/xml/ThinComergentAsset" xmlns:tns="http://siebel.com/CustomUI" exclude-result-prefixes="tns" >
<xsl:template match="/ns0:DBAdapterOutputCollection">
<tns:WMSAssetInterface_Input>
<xsdLocal1:ListOfAsset>
<xsdLocal1:ListOfAssetHeader>
<xsdLocal1:AssetHeader>
<xsdLocal1:IntegrationId>
<xsl:value-of select='concat(ns0:DBAdapterOutput/ns0:IDENTIFIER," ",ns0:DBAdapterOutput/ns0:LINE_NUMBER," Level=",ns0:DBAdapterOutput/ns0:LEVEL)'/>
</xsdLocal1:IntegrationId>
<xsdLocal1:ProductName>
<xsl:value-of select="ns0:DBAdapterOutput/ns0:LINE_NUMBER"/>
</xsdLocal1:ProductName>
<xsl:apply-templates select="ns0:DBAdapterOutputCollection/ns0:DBAdapterOutput[string-length(ns0:PARENT_IDENTIFIER)=0]" />
</xsdLocal1:AssetHeader>
</xsdLocal1:ListOfAssetHeader>
</xsdLocal1:ListOfAsset>
</tns:WMSAssetInterface_Input>
</xsl:template>
<xsl:template match="ns0:DBAdapterOutput">
<xsdLocal1:ListOfAssetItem>
<xsdLocal1:AssetItem>
<xsdLocal1:IntegrationId>
<xsl:value-of select='concat(ns0:IDENTIFIER," ",ns0:LINE_NUMBER," Level=",ns0:LEVEL)'/>
</xsdLocal1:IntegrationId>
<xsdLocal1:PartName>
<xsl:value-of select="ns0:LINE_NUMBER"/>
</xsdLocal1:PartName>
<xsl:variable name="children" select="parent::*/ns0:DBAdapterOutput[ns0:PARENT_IDENTIFIER=current()/ns0:IDENTIFIER]" />
<xsl:if test="$children">
<xsdLocal1:ListOfAssetItem>
<xsdLocal1:AssetItem>
<xsl:apply-templates select="$children" />
</xsdLocal1:AssetItem>
</xsdLocal1:ListOfAssetItem>
</xsl:if>
</xsdLocal1:AssetItem>
</xsdLocal1:ListOfAssetItem>
</xsl:template>
</xsl:stylesheet>
Two compile time errors:
The tns: prefix is not bound to any namespace.
This line from your style-sheet is nonsense.
<xsl:value-of select='concat(/ns0:IDENTIFIER," ",/ns0:LINE_NUMBER," Level=",/ns0:DBAdapterOutput/ns0:LEVEL')'/>
The close tag for your style-sheet is missing.
Update
I fixed a couple of errors in the style-sheet:
<xsl:template match="ns0:DBAdapterOutput/" /> is not valid. Remove the final / .
Similarly with <xsl:template match="/ns0:DBAdapterOutputCollection">
Update
The technique here is to use xsl:apply-templates recursively to drill down through the levels. Records are matched up with their parents just by comparing the two link fields, but an alternative method would be to use keys.
This XSLT 1.0 style-sheet...
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ns0="http://xmlns.oracle.com/pcbpel/adapter/db/DBAdapter"
xmlns:xsdLocal1="http://www.siebel.com/xml/ThinComergentAsset"
exclude-result-prefixes="xsl xsdLocal1 ns0">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<WMSAssetInterface_Input xmlns="http://siebel.com/CustomUI">
<ListOfAsset xmlns="http://www.siebel.com/xml/ThinComergentAsset">
<ListOfAssetHeader>
<xsl:apply-templates select="*/ns0:DBAdapterOutput[ns0:LEVEL=1]" />
</ListOfAssetHeader>
</ListOfAsset>
</WMSAssetInterface_Input>
</xsl:template>
<xsl:template match="ns0:DBAdapterOutput[ns0:LEVEL=1]"
xmlns="http://www.siebel.com/xml/ThinComergentAsset">
<AssetHeader>
<IntegrationId>
<xsl:value-of select="concat(ns0:IDENTIFIER,' ',ns0:LINE_NUMBER)" />
</IntegrationId>
<ProductName>
<xsl:value-of select="ns0:LINE_NUMBER" />
</ProductName>
<ListOfAssetItem>
<xsl:apply-templates select="../ns0:DBAdapterOutput
[ ns0:LEVEL=
(current()/ns0:LEVEL+1)]" />
</ListOfAssetItem>
</AssetHeader>
</xsl:template>
<xsl:template match="ns0:DBAdapterOutput[ns0:LEVEL > 1]"
xmlns="http://www.siebel.com/xml/ThinComergentAsset">
<AssetItem>
<IntegrationId>
<xsl:value-of select="concat(ns0:IDENTIFIER,' ',ns0:LINE_NUMBER,
' Level=', ns0:LEVEL/text()-1)" />
</IntegrationId>
<ProductName>
<xsl:value-of select="ns0:LINE_NUMBER" />
</ProductName>
<xsl:if test="../ns0:DBAdapterOutput
[ns0:PARENT_IDENTIFIER = current()/ns0:IDENTIFIER]">
<ListOfAssetItem>
<xsl:apply-templates select="../ns0:DBAdapterOutput
[ns0:PARENT_IDENTIFIER = current()/ns0:IDENTIFIER]" />
</ListOfAssetItem>
</xsl:if>
</AssetItem>
</xsl:template>
</xsl:stylesheet>
...when applied to the sample input, will yield...
<WMSAssetInterface_Input xmlns="http://siebel.com/CustomUI">
<ListOfAsset xmlns="http://www.siebel.com/xml/ThinComergentAsset">
<ListOfAssetHeader>
<AssetHeader>
<IntegrationId>9536162 1.1.0</IntegrationId>
<ProductName>1.1.0</ProductName>
<ListOfAssetItem>
<AssetItem>
<IntegrationId>9536165 1.1.1 Level=1</IntegrationId>
<ProductName>1.1.1</ProductName>
<ListOfAssetItem>
<AssetItem>
<IntegrationId>1227973 1.1.4 Level=2</IntegrationId>
<ProductName>1.1.4</ProductName>
</AssetItem>
<AssetItem>
<IntegrationId>1275015 1.1.4 Level=2</IntegrationId>
<ProductName>1.1.4</ProductName>
</AssetItem>
</ListOfAssetItem>
</AssetItem>
<AssetItem>
<IntegrationId>9536173 1.1.7 Level=1</IntegrationId>
<ProductName>1.1.7</ProductName>
</AssetItem>
</ListOfAssetItem>
</AssetHeader>
</ListOfAssetHeader>
</ListOfAsset>
</WMSAssetInterface_Input>
This is slightly different to your stated expected output, but only because, IMHO, of mistakes in the listed expected output. I believe that this delivers what you want.
First, an observation about the unreadability of the code -- please in future questions provide well indented code with short lines!
There is one major issue that can be easily corrected.
Change this:
<xsl:apply-templates select=
"ns0:DBAdapterOutputCollection/ns0:DBAdapterOutput
[string-length(ns0:PARENT_IDENTIFIER)=0]" />
to this:
<xsl:apply-templates select=
"ns0:DBAdapterOutput
[string-length(ns0:PARENT_IDENTIFIER)=0]" />
The XSLT instruction that has to be modified is in a template with current node the top
ns0:DBAdapterOutputCollection element. It specifies that templates should be applied to any of its grand-children ns0:DBAdapterOutput element that satisfies the condition in the predicate and that is a child of any ns0:DBAdapterOutputCollection child of the current node.
However, the current node (the top ns0:DBAdapterOutputCollection element) has no children ns0:DBAdapterOutputCollection children and the no nodes are selected for execution by this xsl:apply-templates instruction.
After the above simple code-change is made, the result from the transformation seems like what probably is wanted:
<?xml version="1.0" encoding="utf-8"?>
<tns:WMSAssetInterface_Input xmlns:tns="http://siebel.com/CustomUI" xmlns:ns0="http://xmlns.oracle.com/pcbpel/adapter/db/DBAdapter" xmlns:xsdLocal1="http://www.siebel.com/xml/ThinComergentAsset">
<xsdLocal1:ListOfAsset>
<xsdLocal1:ListOfAssetHeader>
<xsdLocal1:AssetHeader>
<xsdLocal1:IntegrationId>9536162 1.1.0 Level=1</xsdLocal1:IntegrationId>
<xsdLocal1:ProductName>1.1.0</xsdLocal1:ProductName>
<xsdLocal1:ListOfAssetItem>
<xsdLocal1:AssetItem>
<xsdLocal1:IntegrationId>9536162 1.1.0 Level=1</xsdLocal1:IntegrationId>
<xsdLocal1:PartName>1.1.0</xsdLocal1:PartName>
<xsdLocal1:ListOfAssetItem>
<xsdLocal1:AssetItem>
<xsdLocal1:ListOfAssetItem>
<xsdLocal1:AssetItem>
<xsdLocal1:IntegrationId>9536165 1.1.1 Level=2</xsdLocal1:IntegrationId>
<xsdLocal1:PartName>1.1.1</xsdLocal1:PartName>
<xsdLocal1:ListOfAssetItem>
<xsdLocal1:AssetItem>
<xsdLocal1:ListOfAssetItem>
<xsdLocal1:AssetItem>
<xsdLocal1:IntegrationId>1227973 1.1.4 Level=3</xsdLocal1:IntegrationId>
<xsdLocal1:PartName>1.1.4</xsdLocal1:PartName>
</xsdLocal1:AssetItem>
</xsdLocal1:ListOfAssetItem>
<xsdLocal1:ListOfAssetItem>
<xsdLocal1:AssetItem>
<xsdLocal1:IntegrationId>1275015 1.1.4 Level=3</xsdLocal1:IntegrationId>
<xsdLocal1:PartName>1.1.4</xsdLocal1:PartName>
</xsdLocal1:AssetItem>
</xsdLocal1:ListOfAssetItem>
</xsdLocal1:AssetItem>
</xsdLocal1:ListOfAssetItem>
</xsdLocal1:AssetItem>
</xsdLocal1:ListOfAssetItem>
<xsdLocal1:ListOfAssetItem>
<xsdLocal1:AssetItem>
<xsdLocal1:IntegrationId>9536173 1.1.7 Level=2</xsdLocal1:IntegrationId>
<xsdLocal1:PartName>1.1.7</xsdLocal1:PartName>
</xsdLocal1:AssetItem>
</xsdLocal1:ListOfAssetItem>
</xsdLocal1:AssetItem>
</xsdLocal1:ListOfAssetItem>
</xsdLocal1:AssetItem>
</xsdLocal1:ListOfAssetItem>
</xsdLocal1:AssetHeader>
</xsdLocal1:ListOfAssetHeader>
</xsdLocal1:ListOfAsset>
</tns:WMSAssetInterface_Input>
I am converting a xml using xslt.
Original XML is
<Content>
<book>
<customData>
<CustomDataElement>
<title>book-name</title>
<value>Java</value>
</CustomDataElement>
<CustomDataElement>
<title>genre</title>
<value>Programming</value>
</CustomDataElement>
</customData>
</book>
<authors>
<author>
<name>authorOne</name>
<country>US</country>
</author>
</authors>
<book>
<customData>
<CustomDataElement>
<title>book-name</title>
<value>Stranger</value>
</CustomDataElement>
<CustomDataElement>
<title>genre</title>
<value>Fiction</value>
</CustomDataElement>
</customData>
</book>
<authors>
<author>
<name>authorthree</name>
<country>UK</country>
</author>
</authors>
</Content>
and my xslt is as follows
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
<xsl:template match="/">
<xsl:for-each select="Content/book">
<media>
<book>
<xsl:apply-templates select="customData/CustomDataElement[title = 'book-name']" />
</book>
<genre>
<xsl:apply-templates select="customData/CustomDataElement[title = 'genre']" />
</genre>
<author>
<xsl:value-of select="../authors/author/name" />
</author>
</media>
</xsl:for-each>
</xsl:template>
<xsl:template match="CustomDataElement">
<xsl:value-of select="value" />
</xsl:template>
</xsl:stylesheet>
This gives me output as
<?xml version="1.0"?>
<media>
<book>Java</book>
<genre>Programming</genre>
<author>authorOne</author>
</media>
<media>
<book>Stranger</book>
<genre>Fiction</genre>
<author>authorOne</author>
</media>
I want the authors name from the tag 'authors\author' which follows the book tag.
what i am missing here ? pls help
Instead of
<xsl:value-of select="../authors/author/name" />
try
<xsl:value-of select="following-sibling::authors[1]/author/name" />
Since you are in the context of a book node, this xpath says to look for the first ([1]) following sibling authors node, and to select the author/name from that.
I'm new in xml, sorry for the dumb question. I'm trying to create xsl template to convert Source xml to Destination. Actually it's almost done but I don't know how to enumerate <creator>'s correctly (creator#affil in Destination xml).
Source:
<?xml version="1.0" encoding="iso-8859-1"?>
<CREATORS>
<PERSON ROLE="CONTACT">
<PREFIX>Prof</PREFIX>
<FIRST_NAME>Mike</FIRST_NAME>
<MIDDLE_INITIALS>J</MIDDLE_INITIALS>
<LAST_NAME>Petrov</LAST_NAME>
<SUFFIX/>
<POSITION>Director</POSITION>
<EMAIL_1>pontorez#pontorez.ru</EMAIL_1>
<EMAIL_2>webmaster#pontorez.ru</EMAIL_2>
<URL>www.pontorez.ru</URL>
<MOBILE_PHONE/>
<ADDRESS>
<DEPARTMENT/>
<ORGANISATION>Example</ORGANISATION>
<ADDRESS_1>Finch Pavilion</ADDRESS_1>
<ADDRESS_2>Middle Way</ADDRESS_2>
<CITY>Oxford</CITY>
<ZIP>OX9 7LG</ZIP>
<REGION/>
<COUNTRY CODE="GB">UK</COUNTRY>
<PHONE_1>+380 6245 716300</PHONE_1>
<PHONE_2/>
<FAX_1>+380 6245 716311</FAX_1>
<FAX_2/>
</ADDRESS>
<FOOTNOTE/>
</PERSON>
<PERSON ID="7091" ROLE="AUTHOR">
<PREFIX>Prof</PREFIX>
<FIRST_NAME>Mike</FIRST_NAME>
<MIDDLE_INITIALS>J</MIDDLE_INITIALS>
<LAST_NAME>Petrov</LAST_NAME>
<SUFFIX/>
<POSITION>Director</POSITION>
<EMAIL_1>pontorez#pontorez.ru</EMAIL_1>
<EMAIL_2>webmaster#pontorez.ru</EMAIL_2>
<URL>www.pontorez.ru</URL>
<MOBILE_PHONE/>
<ADDRESS>
<DEPARTMENT/>
<ORGANISATION>Example</ORGANISATION>
<ADDRESS_1>Finch Pavilion</ADDRESS_1>
<ADDRESS_2>Middle Way</ADDRESS_2>
<CITY>Oxford</CITY>
<ZIP>OX9 7LG</ZIP>
<REGION/>
<COUNTRY CODE="GB">UK</COUNTRY>
<PHONE_1>+380 6245 716300</PHONE_1>
<PHONE_2/>
<FAX_1>+380 6245 716311</FAX_1>
<FAX_2/>
</ADDRESS>
<FOOTNOTE>Author footnote</FOOTNOTE>
</PERSON>
<PERSON ID="7094" ROLE="AUTHOR">
<PREFIX>Mrs</PREFIX>
<FIRST_NAME>Anne</FIRST_NAME>
<MIDDLE_INITIALS/>
<LAST_NAME>Spencer</LAST_NAME>
<SUFFIX/>
<POSITION/>
<EMAIL_1>aspencer#Hardware.co.uk</EMAIL_1>
<EMAIL_2/>
<URL/>
<MOBILE_PHONE/>
<ADDRESS>
<DEPARTMENT/>
<ORGANISATION>Example</ORGANISATION>
<ADDRESS_1>SEO R&D Programme</ADDRESS_1>
<ADDRESS_2>Finch Pavilion, Middle Way</ADDRESS_2>
<CITY>Oxford</CITY>
<ZIP>OX9 7LG</ZIP>
<REGION>Oxfordshire</REGION>
<COUNTRY CODE="GB">UK</COUNTRY>
<PHONE_1>+380 6245 716300</PHONE_1>
<PHONE_2/>
<FAX_1>+380 6245 716311</FAX_1>
<FAX_2/>
</ADDRESS>
<FOOTNOTE/>
</PERSON>
<PERSON ID="15756" ROLE="AUTHOR">
<PREFIX>Mr</PREFIX>
<FIRST_NAME>Ed</FIRST_NAME>
<MIDDLE_INITIALS/>
<LAST_NAME>Gantos</LAST_NAME>
<SUFFIX/>
<POSITION>Senior Medical Statistician</POSITION>
<EMAIL_1>santos#xxx.org.uk</EMAIL_1>
<EMAIL_2/>
<URL>http://www.isds.sxo.ac.uk/</URL>
<MOBILE_PHONE/>
<ADDRESS>
<DEPARTMENT>Head of SEO Support</DEPARTMENT>
<ORGANISATION>Centre for Statistics in Software</ORGANISATION>
<ADDRESS_1>Pearson College</ADDRESS_1>
<ADDRESS_2>Linton Road</ADDRESS_2>
<CITY>Oxford</CITY>
<ZIP>OX9 6UD</ZIP>
<REGION/>
<COUNTRY CODE="GB">UK</COUNTRY>
<PHONE_1>+380 6245 112404</PHONE_1>
<PHONE_2/>
<FAX_1>+380 6245 112424</FAX_1>
<FAX_2/>
</ADDRESS>
<FOOTNOTE/>
</PERSON>
<PERSON ID="7092" ROLE="AUTHOR">
<PREFIX>Dr</PREFIX>
<FIRST_NAME>Sherry</FIRST_NAME>
<MIDDLE_INITIALS/>
<LAST_NAME>Wilson</LAST_NAME>
<SUFFIX/>
<POSITION/>
<EMAIL_1>wilson#Hardware.co.uk</EMAIL_1>
<EMAIL_2/>
<URL/>
<MOBILE_PHONE/>
<ADDRESS>
<DEPARTMENT/>
<ORGANISATION>Example</ORGANISATION>
<ADDRESS_1>SEO R&D Programme</ADDRESS_1>
<ADDRESS_2>Finch Pavilion, Middle Way</ADDRESS_2>
<CITY>Oxford</CITY>
<ZIP>OX9 7LG</ZIP>
<REGION>Oxfordshire</REGION>
<COUNTRY CODE="GB">UK</COUNTRY>
<PHONE_1>+380 6245 716300</PHONE_1>
<PHONE_2/>
<FAX_1>+380 6245 716311</FAX_1>
<FAX_2/>
</ADDRESS>
<FOOTNOTE/>
</PERSON>
<GROUP ID="????">
<GROUP_NAME>Bond team</GROUP_NAME>
<CONTACT_PERSON>Monica Bond</CONTACT_PERSON>
<EMAIL_1>mk#Hardware.dk</EMAIL_1>
<URL/>
<ADDRESS>
<DEPARTMENT>Nordic Hardware Centre</DEPARTMENT>
<ORGANISATION>Creyts, Dept 7512</ORGANISATION>
<ADDRESS_1>Blegdamsvej 219</ADDRESS_1>
<ADDRESS_2/>
<CITY>Copenhagen</CITY>
<ZIP>2900</ZIP>
<REGION/>
<COUNTRY CODE="DK">Denmark</COUNTRY>
<PHONE_1>+415 7667 7110</PHONE_1>
<PHONE_2>+415 1234 9429</PHONE_2>
<FAX_1>+415 7667 7007</FAX_1>
<FAX_2/>
</ADDRESS>
<FOOTNOTE>Group footnote</FOOTNOTE>
</GROUP>
<PERSON ID="3" ROLE="AUTHOR">
<PREFIX>Ms</PREFIX>
<FIRST_NAME>Monica</FIRST_NAME>
<MIDDLE_INITIALS/>
<LAST_NAME>Bond</LAST_NAME>
<SUFFIX/>
<POSITION>Director of the Hardware Information Management System</POSITION>
<EMAIL_1>mk#Hardware.dk</EMAIL_1>
<EMAIL_2/>
<URL>www.cc-ims.net</URL>
<MOBILE_PHONE/>
<ADDRESS>
<DEPARTMENT>Nordic Hardware Centre</DEPARTMENT>
<ORGANISATION>Creyts, Dept 7512</ORGANISATION>
<ADDRESS_1>Blegdamsvej 219</ADDRESS_1>
<ADDRESS_2/>
<CITY>Copenhagen</CITY>
<ZIP>2900</ZIP>
<REGION/>
<COUNTRY CODE="DK">Denmark</COUNTRY>
<PHONE_1>+415 7667 7110</PHONE_1>
<PHONE_2>+415 1234 9429</PHONE_2>
<FAX_1>+415 7667 7007</FAX_1>
<FAX_2/>
</ADDRESS>
<FOOTNOTE/>
</PERSON>
</CREATORS>
Destination:
<?xml version="1.0" encoding="utf-8"?>
<creatorGroup>
<creator affil="CD004002-aff-0001" creatorRole="author">
<forenames>Mike</forenames>
<surnamePrefix>J</surnamePrefix>
<surname>Petrov</surname>
<note id="CD004002-note-0001">
<p>Author footnote</p>
</note>
</creator>
<creator affil="CD004002-aff-0001" creatorRole="author">
<forenames>Anne</forenames>
<surname>Spencer</surname>
</creator>
<creator affil="CD004002-aff-0002" creatorRole="author">
<forenames>Ed</forenames>
<surname>Gantos</surname>
</creator>
<creator affil="CD004002-aff-0001" creatorRole="author">
<forenames>Sherry</forenames>
<surname>Wilson</surname>
</creator>
<creator affil="CD004002-aff-0003" type="collaboration" creatorRole="author">
<collab>Bond team</collab>
</creator>
<creator affil="CD004002-aff-0003" creatorRole="author">
<forenames>Monica</forenames>
<surname>Bond</surname>
</creator>
<creator affil="CD004002-aff-0001" creatorRole="contact">
<honorifics>Prof</honorifics>
<forenames>Mike</forenames>
<surnamePrefix>J</surnamePrefix>
<surname>Petrov</surname>
<jobTitle>Director</jobTitle>
<email>pontorez#pontorez.ru</email>
<email>webmaster#pontorez.ru</email>
</creator>
<affiliation id="CD004002-aff-0001" countryCode="GB">
<orgName>Example</orgName>
<address>
<street>Finch Pavilion</street>
<street>Middle Way</street>
<city>Oxford</city>
<country>UK</country>
<postCode>OX9 7LG</postCode>
</address>
</affiliation>
<affiliation id="CD004002-aff-0002" countryCode="GB">
<orgName>Centre for Statistics in Software</orgName>
<orgDiv>Head of SEO Support</orgDiv>
<address>
<street>Pearson College</street>
<street>Linton Road</street>
<city>Oxford</city>
<country>UK</country>
<postCode>OX9 6UD</postCode>
</address>
</affiliation>
<affiliation id="CD004002-aff-0003" countryCode="DK">
<collabContact>Monica Bond</collabContact>
<orgName>Creyts, Dept 7512</orgName>
<orgDiv>Nordic Hardware Centre</orgDiv>
<address>
<street>Blegdamsvej 219</street>
<city>Copenhagen</city>
<country>Denmark</country>
<postCode>2900</postCode>
</address>
</affiliation>
</creatorGroup>
XSL stylesheet that I created:
<?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:key name="affiliations" match="ORGANISATION" use="."/>
<xsl:template name="kreator">
<xsl:variable name="affid">
<!-- The numbering problem is in the below line: -->
<xsl:number format="0001" value="position()"/>
</xsl:variable>
<xsl:variable name="role">
<xsl:choose>
<xsl:when test="#ROLE='AUTHOR' or name()='GROUP'">author</xsl:when>
<xsl:otherwise>contact</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<creator affil="CD004002-aff-{$affid}">
<xsl:if test="GROUP_NAME!=''">
<xsl:attribute name="type">collaboration</xsl:attribute>
</xsl:if>
<xsl:attribute name="creatorRole">
<xsl:value-of select="$role"/>
</xsl:attribute>
<xsl:if test="$role='contact'">
<honorifics>
<xsl:value-of select="PREFIX"/>
</honorifics>
</xsl:if>
<xsl:if test="GROUP_NAME!=''">
<collab>
<xsl:value-of select="GROUP_NAME"/>
</collab>
</xsl:if>
<xsl:if test="FIRST_NAME">
<forenames>
<xsl:value-of select="FIRST_NAME"/>
</forenames>
</xsl:if>
<xsl:if test="MIDDLE_INITIALS!=''">
<surnamePrefix>
<xsl:value-of select="MIDDLE_INITIALS"/>
</surnamePrefix>
</xsl:if>
<xsl:if test="LAST_NAME">
<surname>
<xsl:value-of select="LAST_NAME"/>
</surname>
</xsl:if>
<xsl:if test="FOOTNOTE!='' and name()='PERSON'">
<note id="CD004002-note-{$affid}">
<p>
<xsl:value-of select="FOOTNOTE"/>
</p>
</note>
</xsl:if>
<xsl:if test="$role='contact'">
<jobTitle><xsl:value-of select="POSITION"/></jobTitle>
<email><xsl:value-of select="EMAIL_1"/></email>
<email><xsl:value-of select="EMAIL_2"/></email>
</xsl:if>
</creator>
<xsl:text>
</xsl:text>
</xsl:template>
<xsl:template match="/CREATORS">
<xmp>
<creatorGroup>
<!-- list of creators: -->
<xsl:for-each select="PERSON[#ROLE='AUTHOR'] | GROUP">
<xsl:call-template name="kreator"/>
</xsl:for-each>
<xsl:for-each select="PERSON[#ROLE='CONTACT']">
<xsl:call-template name="kreator"/>
</xsl:for-each>
<!-- list of affiliations: -->
<xsl:for-each select="//ORGANISATION[generate-id(.)=generate-id(key('affiliations', .))]">
<affiliation>
<xsl:attribute name="id">
CD004002-aff-000<xsl:value-of select="position()"/>
</xsl:attribute>
<xsl:attribute name="countryCode">
<xsl:value-of select="../COUNTRY/#CODE"/>
</xsl:attribute>
<xsl:if test="../../CONTACT_PERSON">
<collabContact>
<xsl:value-of select="../../CONTACT_PERSON"/>
</collabContact>
</xsl:if>
<orgName>
<xsl:value-of select="."/>
</orgName>
<xsl:if test="../DEPARTMENT!=''">
<orgDiv>
<xsl:value-of select="../DEPARTMENT"/>
</orgDiv>
</xsl:if>
<address>
<street>
<xsl:value-of select="../ADDRESS_1"/>
</street>
<xsl:if test="../ADDRESS_2!=''">
<street>
<xsl:value-of select="../ADDRESS_2"/>
</street>
</xsl:if>
<city>
<xsl:value-of select="../CITY"/>
</city>
<country>
<xsl:value-of select="../COUNTRY"/>
</country>
<postCode>
<xsl:value-of select="../ZIP"/>
</postCode>
</address>
</affiliation>
<xsl:text>
</xsl:text>
</xsl:for-each>
</creatorGroup>
</xmp>
</xsl:template>
</xsl:stylesheet>
I.e. I want to get <creator> numbering like the below:
<creator affil="CD004002-aff-0001" creatorRole="author"/>
<creator affil="CD004002-aff-0001" creatorRole="author"/>
<creator affil="CD004002-aff-0002" creatorRole="author"/>
<creator affil="CD004002-aff-0001" creatorRole="author"/>
<creator affil="CD004002-aff-0003" type="collaboration" creatorRole="author"/>
<creator affil="CD004002-aff-0003" creatorRole="author"/>
<creator affil="CD004002-aff-0001" creatorRole="contact"/>
While my current XSL stylesheet produces wrong #affil's:
<creator affil="CD004002-aff-0004" creatorRole="author"/>
<creator affil="CD004002-aff-0004" creatorRole="author"/>
<creator affil="CD004002-aff-0001" creatorRole="author"/>
<creator affil="CD004002-aff-0004" creatorRole="author"/>
<creator affil="CD004002-aff-0002" type="collaboration" creatorRole="author"/>
<creator affil="CD004002-aff-0002" creatorRole="author"/>
<creator affil="CD004002-aff-0004" creatorRole="contact"/>
Can you help please? Thanks.
Your problem is that when you do:
<xsl:call-template name="kreator" />
then you do it in the context of the <PERSON> or <GROUP> you are currently handling.
This means that position() will tell you the position of those elements. It cannot magically know that you are interested in the position of the first <ORGANISATION> that matches the current one.
And this means you must iterate all <ORGANISATION>s much the same way you do it to calculate the <affiliation> attribute #id:
<xsl:variable name="affid">
<xsl:variable name="org" select="ADDRESS/ORGANISATION" />
<xsl:for-each select="//ORGANISATION[
generate-id()
=
generate-id(key('affiliations', .)[1])
]">
<xsl:if test=". = $org">
<xsl:number format="0001" value="position()"/>
</xsl:if>
</xsl:for-each>
</xsl:variable>
Note the use of <xsl:if> to make sure that the variable eventually contains only one value, even though you are looking through all of them.
For larger documents, you could introduce another key:
<xsl:key name="organisations" match="ORGANISATION" use="'all'" />
and use that as a drop-in replacement for all the comparatively inefficient "//ORGANISATION" expressions, e.g. instead of:
<xsl:for-each select="//ORGANISATION">
<!-- ... -->
</xsl:for-each>
use:
<xsl:for-each select="key('organisations', 'all')">
<!-- ... -->
</xsl:for-each>