This is a continuation of the previous question. XSLT transformation of multiple "flat" XML files into tree-like XML
I tried to build xml from more object files and got a problem.
what we have:
file 1.xml is $doc1 -main objects
<?xml version="1.0" encoding="utf-8"?>
<ADDRESSOBJECTS>
<OBJECT OBJECTID="105037985" NAME="OLDER OTHER PARENT" LEVEL="2" ISACTIVE="0" />
<OBJECT OBJECTID="105037985" NAME="OTHER PARENT" LEVEL="2" ISACTIVE="1" />
<OBJECT OBJECTID="1171388" NAME="OLDER PARENT" LEVEL="2" ISACTIVE="0" />
<OBJECT OBJECTID="1171388" NAME="PARENT" LEVEL="2" ISACTIVE="1" />
<OBJECT OBJECTID="1171421" NAME="CHILD 1" LEVEL="6" ISACTIVE="1" />
<OBJECT OBJECTID="1171502" NAME="OLDER CHILD 2" LEVEL="6" ISACTIVE="0" />
<OBJECT OBJECTID="1171502" NAME="CHILD 2" LEVEL="6" ISACTIVE="1" />
<OBJECT OBJECTID="11715021" NAME="CHILD 21" LEVEL="7" ISACTIVE="1" />
<OBJECT OBJECTID="1171612" NAME="CHILD 3" LEVEL="4" ISACTIVE="1" />
<OBJECT OBJECTID="1171731" NAME="CHILD 4" LEVEL="4" ISACTIVE="1" />
<OBJECT OBJECTID="1171761" NAME="CHILD 5" LEVEL="6" ISACTIVE="1" />
</ADDRESSOBJECTS>
file 2.xml is $doc2 - object hierarchy
<?xml version="1.0" encoding="utf-8"?>
<ITEMS>
<ITEM OBJECTID="1170420" PARENTOBJID="1171380" ISACTIVE="1" />
<ITEM OBJECTID="1170423" PARENTOBJID="1171380" ISACTIVE="1" />
<ITEM OBJECTID="1171421" PARENTOBJID="1171388" ISACTIVE="1" />
<ITEM OBJECTID="1171421" PARENTOBJID="1171388" ISACTIVE="0" />
<ITEM OBJECTID="1171502" PARENTOBJID="1171388" ISACTIVE="1" />
<ITEM OBJECTID="1171612" PARENTOBJID="1171388" ISACTIVE="1" />
<ITEM OBJECTID="1171731" PARENTOBJID="1171388" ISACTIVE="1" />
<ITEM OBJECTID="1171761" PARENTOBJID="1171388" ISACTIVE="1" />
<ITEM OBJECTID="11715021" PARENTOBJID="1171502" ISACTIVE="1" />
<ITEM OBJECTID="90000001" PARENTOBJID="11715021" ISACTIVE="1" />
<ITEM OBJECTID="90000002" PARENTOBJID="11715021" ISACTIVE="1" />
<ITEM OBJECTID="90000003" PARENTOBJID="1171761" ISACTIVE="1" />
<ITEM OBJECTID="90000004" PARENTOBJID="1171761" ISACTIVE="1" />
<ITEM OBJECTID="90000005" PARENTOBJID="1171421" ISACTIVE="1" />
</ITEMS>
file 3.xml is $doc3 - yet another objects are simple entities
<?xml version="1.0" encoding="utf-8"?>
<SUBOBJECTS>
<SUBOBJECT OBJECTID="90000001" SUBOBJECTNUM="1" SUBOBJECTTYPE="9" ISACTIVE="1" />
<SUBOBJECT OBJECTID="90000002" SUBOBJECTNUM="2" SUBOBJECTTYPE="9" ISACTIVE="1" />
<SUBOBJECT OBJECTID="90000003" SUBOBJECTNUM="3" SUBOBJECTTYPE="9" ISACTIVE="1" />
<SUBOBJECT OBJECTID="90000004" SUBOBJECTNUM="4" SUBOBJECTTYPE="9" ISACTIVE="1" />
<SUBOBJECT OBJECTID="90000005" SUBOBJECTNUM="5" SUBOBJECTTYPE="9" ISACTIVE="1" />
</SUBOBJECTS>
and 4th file - 4.xml is $doc4 - parameters of simple entities
<?xml version="1.0" encoding="utf-8"?>
<PARAMS>
<PARAM OBJECTID="90000001" CHANGEIDEND="0" TYPE="IND" VALUE="412784" UPDATEDATE="2019-07-10" STARTDATE="2012-07-26" ENDDATE="2079-06-06" />
<PARAM OBJECTID="90000001" CHANGEIDEND="50098691" TYPE="OKTMO" VALUE="63649101" UPDATEDATE="2019-07-10" STARTDATE="2012-07-26" ENDDATE="2016-06-30" />
<PARAM OBJECTID="90000001" CHANGEIDEND="0" TYPE="OKTMO" VALUE="63649101126" UPDATEDATE="2019-12-08" STARTDATE="2016-06-30" ENDDATE="2079-06-06" />
</PARAMS>
I hope I did not get confused and the hierarchy was given correctly in the examples. The output should be like this:
<ROOT OBJECTID="105037985" NAME="OTHER PARENT" LEVEL="2" ISACTIVE="1" />
<ROOT OBJECTID="1171388" NAME="PARENT" LEVEL="2" ISACTIVE="1" />
<ELEMENT OBJECTID="1171421" NAME="CHILD 1" LEVEL="6" ISACTIVE="1">
<SIMPLEENTITY OBJECTID="90000005" NAME="5" LEVEL="10" ISACTIVE="1" />
</ELEMENT>
<ELEMENT OBJECTID="1171502" NAME="CHILD 2" LEVEL="6" ISACTIVE="1">
<SUBELEMENT OBJECTID="11715021" NAME="CHILD 21" LEVEL="7" ISACTIVE="1">
<SIMPLEENTITY OBJECTID="90000001" NAME="1" LEVEL="10" ISACTIVE="1" />
<SIMPLEENTITY OBJECTID="90000002" NAME="2" LEVEL="10" ISACTIVE="1" />
</SUBELEMENT>
</ELEMENT>
<ELEMENT OBJECTID="1171612" NAME="CHILD 3" LEVEL="4" ISACTIVE="1" />
<ELEMENT OBJECTID="1171731" NAME="CHILD 4" LEVEL="4" ISACTIVE="1" />
<ELEMENT OBJECTID="1171761" NAME="CHILD 5" LEVEL="6" ISACTIVE="1">
<SIMPLEENTITY OBJECTID="90000003" NAME="3" LEVEL="10" ISACTIVE="1" />
<SIMPLEENTITY OBJECTID="90000004" NAME="4" LEVEL="10" ISACTIVE="1" />
</ELEMENT>
</ROOT>
That is, SUBOBJECT aka SIMPLEENTITY can belong to both OBJECT[@LEVEL = (7,8)] and OBJECT[@LEVEL = 6]
The resulting XSL file looks like this (files 2 - 4 are included in the XSL for convenience):
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="3.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all"
expand-text="yes">
<!--
file 1.xml is $doc1 -main objects
file 2.xml is $doc2 - object hierarchy
file 3.xml is $doc3 - yet another objects are simple entities
file 4.xml is $doc4 - parameters of simple entities
PS: $doc2, $doc3, $doc4 see below at the end
-->
<xsl:output indent="yes"/>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:key name="child" match="ITEM[@ISACTIVE=1]" use="@PARENTOBJID"/>
<xsl:key name="object" match="OBJECT[@ISACTIVE=1]" use="@OBJECTID"/>
<xsl:key name="subobject" match="SUBOBJECT[@ISACTIVE=1]" use="@OBJECTID"/>
<xsl:key name="param" match="PARAM[@CHANGEIDEND=0]" use="@OBJECTID"/>
<xsl:variable name="doc1" select="/"/>
<xsl:template match="/">
<xsl:apply-templates select="ADDRESSOBJECTS/OBJECT[@LEVEL = 2 and @ISACTIVE=1]"/>
</xsl:template>
<xsl:template match="OBJECT[@LEVEL = 2]">
<ROOT>
<xsl:apply-templates select="@*, key('child', @OBJECTID, $doc2)/key('object', @OBJECTID, $doc1)"/>
</ROOT>
</xsl:template>
<xsl:template match="OBJECT[@LEVEL = (4,5)]">
<ELEMENT>
<xsl:apply-templates select="@*, key('child', @OBJECTID, $doc2)/key('object', @OBJECTID, $doc1)"/>
</ELEMENT>
</xsl:template>
<xsl:template match="OBJECT[@LEVEL = 6]">
<ELEMENT>
<xsl:apply-templates select="@*, key('child', @OBJECTID, $doc2)/key('object', @OBJECTID, $doc1)"/>
<!-- xsl:apply-templates select="@*, key('child', @OBJECTID, $doc2)/key('subobject', @OBJECTID, $doc3)"/ -->
</ELEMENT>
</xsl:template>
<xsl:template match="OBJECT[@LEVEL = (7,8)]">
<SUBELEMENT>
<xsl:apply-templates select="@*, key('child', @OBJECTID, $doc2)/key('object', @OBJECTID, $doc1)"/>
<xsl:apply-templates select="@*, key('child', @OBJECTID, $doc2)/key('subobject', @OBJECTID, $doc3)"/>
</SUBELEMENT>
</xsl:template>
<xsl:template match="SUBOBJECT">
<SIMPLEENTITY>
<xsl:attribute name="OBJECTID" select="@OBJECTID"/>
<xsl:attribute name="NAME" select="@SUBOBJECTNUM"/>
<xsl:attribute name="LEVEL" select="10"/>
<xsl:attribute name="ISACTIVE" select="@ISACTIVE"/>
<xsl:apply-templates select="@TYPE|@VALUE, key('subobject', @OBJECTID, $doc3)/key('param', @OBJECTID, $doc4)"/>
</SIMPLEENTITY>
</xsl:template>
<xsl:template match="PARAM">
<xsl:attribute name="{@TYPE}" select="@VALUE"/>
</xsl:template>
<xsl:param name="doc2">
<ITEMS>
<ITEM OBJECTID="1170420" PARENTOBJID="1171380" ISACTIVE="1" />
<ITEM OBJECTID="1170423" PARENTOBJID="1171380" ISACTIVE="1" />
<ITEM OBJECTID="1171421" PARENTOBJID="1171388" ISACTIVE="1" />
<ITEM OBJECTID="1171421" PARENTOBJID="1171388" ISACTIVE="0" />
<ITEM OBJECTID="1171502" PARENTOBJID="1171388" ISACTIVE="1" />
<ITEM OBJECTID="1171612" PARENTOBJID="1171388" ISACTIVE="1" />
<ITEM OBJECTID="1171731" PARENTOBJID="1171388" ISACTIVE="1" />
<ITEM OBJECTID="1171761" PARENTOBJID="1171388" ISACTIVE="1" />
<ITEM OBJECTID="11715021" PARENTOBJID="1171502" ISACTIVE="1" />
<ITEM OBJECTID="90000001" PARENTOBJID="11715021" ISACTIVE="1" />
<ITEM OBJECTID="90000002" PARENTOBJID="11715021" ISACTIVE="1" />
<ITEM OBJECTID="90000003" PARENTOBJID="1171761" ISACTIVE="1" />
<ITEM OBJECTID="90000004" PARENTOBJID="1171761" ISACTIVE="1" />
<ITEM OBJECTID="90000005" PARENTOBJID="1171421" ISACTIVE="1" />
</ITEMS>
</xsl:param>
<xsl:param name="doc3">
<SUBOBJECTS>
<SUBOBJECT OBJECTID="90000001" SUBOBJECTNUM="1" SUBOBJECTTYPE="9" ISACTIVE="1" />
<SUBOBJECT OBJECTID="90000002" SUBOBJECTNUM="02" SUBOBJECTTYPE="9" ISACTIVE="0" />
<SUBOBJECT OBJECTID="90000002" SUBOBJECTNUM="2" SUBOBJECTTYPE="9" ISACTIVE="1" />
<SUBOBJECT OBJECTID="90000003" SUBOBJECTNUM="3" SUBOBJECTTYPE="9" ISACTIVE="1" />
<SUBOBJECT OBJECTID="90000004" SUBOBJECTNUM="4" SUBOBJECTTYPE="9" ISACTIVE="1" />
<SUBOBJECT OBJECTID="90000005" SUBOBJECTNUM="5" SUBOBJECTTYPE="9" ISACTIVE="1" />
</SUBOBJECTS>
</xsl:param>
<xsl:param name="doc4">
<PARAMS>
<PARAM OBJECTID="90000001" CHANGEIDEND="0" TYPE="IND" VALUE="412784" UPDATEDATE="2019-07-10" STARTDATE="2012-07-26" ENDDATE="2079-06-06" />
<PARAM OBJECTID="90000001" CHANGEIDEND="50098691" TYPE="OKTMO" VALUE="63649101" UPDATEDATE="2019-07-10" STARTDATE="2012-07-26" ENDDATE="2016-06-30" />
<PARAM OBJECTID="90000001" CHANGEIDEND="0" TYPE="OKTMO" VALUE="63649101126" UPDATEDATE="2019-12-08" STARTDATE="2016-06-30" ENDDATE="2079-06-06" />
</PARAMS>
</xsl:param>
</xsl:stylesheet>
Everything seems to be working. But... The problem is to map SIMPLEENTITY to OBJECT[@LEVEL = 6] If I include the line
<xsl:apply-templates select="@*, key('child', @OBJECTID, $doc2)/key('subobject', @OBJECTID, $doc3)"/>
into the match="OBJECT[@LEVEL = 6]" template (51st line), then an error occurs:
Error at char 2 in expression in xsl:apply-templates/@select on line 51 column 108 of tt4.xsl: XTDE0410 An attribute node (OBJECTID) cannot be created after a child of the containing element. Most recent element start tag was output at line 63 of module tt4.xsl In template rule with match="OBJECT[@LEVEL eq 6]" on line 48 of tt4.xsl invoked by xsl:apply-templates at file:/home/sergey/Projects/xslt/tt4.xsl#38 In template rule with match="OBJECT[@LEVEL eq 2]" on line 36 of tt4.xsl invoked by xsl:apply-templates at file:/home/sergey/Projects/xslt/tt4.xsl#33 In template rule with match="/" on line 32 of tt4.xsl An attribute node (OBJECTID) cannot be created after a child of the containing element. Most recent element start tag was output at line 63 of module tt4.xsl
I can't figure out how to fix it :(
CodePudding user response:
I think you simply want
<xsl:template match="OBJECT[@LEVEL = 6]">
<ELEMENT>
<xsl:apply-templates select="@*, key('child', @OBJECTID, $doc2)/key('object', @OBJECTID, $doc1), key('child', @OBJECTID, $doc2)/key('subobject', @OBJECTID, $doc3)"/>
</ELEMENT>
</xsl:template>