Home > Mobile >  XSLT transformation of multiple "flat" XML files into tree-like XML. Continuation - 2 xml
XSLT transformation of multiple "flat" XML files into tree-like XML. Continuation - 2 xml

Time:08-13

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>
  • Related