0

I have several files with data and I want to group some nodes and make one file. I have given only 2 sample files but it can be many. The input files are listed in an xml file as includes (list.xml).

Basically, the grouping should be done according to the of each file and each should be listed as node for that particular functional area.

Is this possible to do with XSLT? Maybe with more than one transformation?

File list : list.xml

<?xml version="1.0" encoding="UTF-8"?>
<index xmlns:xi="http://www.w3.org/2001/XInclude">
   <xi:include href="xml/models/1c8dca64-8b40-4e58-8581-5104f5ca3f3e.xml"/>
   <xi:include href="xml/models/7f10e39d-ca8c-4c17-9a0f-2dcbceaaed51.xml"/>
   <xi:include href="xml/models/2d90b9b4-793c-4d8b-9e06-0a93dfa738a2.xml"/>
   <xi:include href="xml/models/4ee7085e-8241-4dae-a095-38ede5fd7fb0.xml"/>
</index>

Input File 01 : 1c8dca64-8b40-4e58-8581-5104f5ca3f3e.xml

<model>
   <contains>
      <vertex>
         <functionalarea>Supply Chain</functionalarea>
         <breakdowns>
            <model>34c1e701-5a70-4493-b877-38624348947c</model>
         </breakdowns>
      </vertex>
      <vertex>
         <functionalarea>Supply Chain</functionalarea>
         <breakdowns>
            <model>25a39e71-aa59-4f63-9c09-8cc4e36bae72</model>
         </breakdowns>
      </vertex>
      <vertex>
         <functionalarea>Planning</functionalarea>
         <breakdowns>
            <model>45c0d6c3-a910-4050-b10e-f17eb7276c44</model>
         </breakdowns>
      </vertex>
   </contains>
</model>

Input File 02 : 7f10e39d-ca8c-4c17-9a0f-2dcbceaaed51.xml

<model>
   <contains>
      <vertex>
         <functionalarea>Supply Chain</functionalarea>
         <breakdowns>
            <model>58a77718-1e95-408b-a6ae-f185348ec310</model>
         </breakdowns>
      </vertex>
      <vertex>
         <functionalarea>Planning</functionalarea>
         <breakdowns>
            <model>87767baa-bab9-46dd-80d8-a0d0c3993429</model>
         </breakdowns>
      </vertex>
      <vertex>
         <functionalarea>Execution</functionalarea>
         <breakdowns>
            <model>f21aef69-9772-49bd-b6c1-4f3e55fc3887</model>
         </breakdowns>
      </vertex>
   </contains>
</model>

Required output

<tree>
    <node>
       <name>Supply Chain</name>
       <children>
          <child>34c1e701-5a70-4493-b877-38624348947c</child>
          <child>25a39e71-aa59-4f63-9c09-8cc4e36bae72</child>
          <child>58a77718-1e95-408b-a6ae-f185348ec310</child>
       </children>
    </node>
    <node>
       <name>Planning</name>
       <children>
          <child>45c0d6c3-a910-4050-b10e-f17eb7276c44</child>
          <child>87767baa-bab9-46dd-80d8-a0d0c3993429</child>
       </children>
    </node>
    <node>
       <name>Execution</name>
       <children>
          <child>f21aef69-9772-49bd-b6c1-4f3e55fc3887</child>
       </children>
    </node>
</tree>
3
  • Possible duplicate of How to merge multiple xml files using xsl? Commented Apr 19, 2017 at 11:06
  • You have tagged both [xslt-1.0] and [xslt-2.0]. Which are you actually using? Commented Apr 19, 2017 at 13:00
  • 1
    You have two options, as you use XInclude, you can simply enable XInclude processing in your parser/the parser the XSLT processor uses and then the input processed by XSLT will not contain the xi:include elements but rather the referenced contents and you can simply group it. As an alternative, you can use e.g. document(index/xi:include/@href) to pull in those referenced files and then use grouping. As for grouping, refer to w3.org/TR/xslt20/#grouping-examples. Commented Apr 19, 2017 at 13:46

1 Answer 1

1

First bind a variable $models to the set of model elements, which you can do in a number of ways, for example

<xsl:variable name="models" select="//@href/document(.)/*"/>

Then do the grouping:

<xsl:for-each-group select="$models/*/vertex" group-by="functionalarea">
    <node>
       <name><xsl:value-of select="current-grouping-key()"/></name>
       <children>
          <xsl:for-each select="current-group()">
            <child><xsl:value-of select=".//model"/></child>
          </xsl:for-each>
       </children>
    </node>
</xsl:for-each-group>
Sign up to request clarification or add additional context in comments.

4 Comments

Thanks your code helped a lot. If I have input xml <model> <id>123456</id> <contains> <vertex>.</vertex> </contains> </model> How can I get the following output?How can I get the parent <id> within the <vertex> group loop? <tree> <node> <id>123456</id> <name>Supply Chain</name> <children> <child>34c1e701-5a70-4493-b877-38624348947c</child> <child>25a39e71-aa59-4f63-9c09-8cc4e36bae72</child> <child>58a77718-1e95-408b-a6ae-f185348ec310</child> </children> </node> <node>..</node> </tree>
If this is a clarification of the original question, edit the question. If it's a new question, then start a new question. Please don't ask supplementary questions in comments - they aren't designed for that, and the format ends up being unreadable.
Thank you for the comment but the above code doesn't work as expected. What it does is it will combine all the <vertex> nodes from both files in to one file, but it will not group them according to the <functionalarea> I'm assuming this is because the include file content are read one at a time then if there is no common <functionalarea> it will just include the content.
Nothing is done "one at a time" in XSLT: it's a declarative language with no notion of time. If it's not working for you then I think you've done something wrong, or your data isn't as described here.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.