Cyprus

XML Concatenation

I have three xml files

<step> <Products> <Product UserTypeID="Country"> <Name>Cyprus</Name> <Product UserTypeID="Resort"> <Name>Argaka</Name> <Product UserTypeID="Property"> <Name>Villa Tester</Name> </Product> </Product> <Product UserTypeID="Resort"> <Name>Coral Bay</Name> <Product UserTypeID="Property"> <Name>1</Name> </Product> <Product UserTypeID="Property"> <Name>2</Name> </Product> </Product> </Product> <Product UserTypeID="Country"> <Name>Greece</Name> <Product UserTypeID="Region"> <Name>Corfu</Name> <Product UserTypeID="Resort"> <Name>Aghios Stefanos</Name> <Product UserTypeID="Property"> <Name>Villa Joanna</Name> </Product> <Product UserTypeID="Property"> <Name>Villa Eleonas</Name> </Product> </Product> <Product UserTypeID="Resort"> <Name>Kassiopi</Name> <Product UserTypeID="Property"> <Name>Villa 2</Name> </Product> </Product> </Product> </Product> </Products> 

 <step> <Products> <Product UserTypeID="Country"> <Name>Cyprus</Name> <Product UserTypeID="Resort"> <Name>Argaka</Name> <Product UserTypeID="Property"> <Name>Villa Jaime</Name> </Product> </Product> </Product> <Product UserTypeID="Country"> <Name>Greece</Name> <Product UserTypeID="Region"> <Name>Corfu</Name> <Product UserTypeID="Resort"> <Name>Acharavi</Name> <Product UserTypeID="Property"> <Name>Villa 1</Name> </Product> <Product UserTypeID="Property"> <Name>Villa 2</Name> </Product> </Product> <Product UserTypeID="Resort"> <Name>Gouvia</Name> <Product UserTypeID="Property"> <Name>Villa De Bono</Name> </Product> </Product> <Product UserTypeID="Resort"> <Name>Kassiopi</Name> <Product UserTypeID="Property"> <Name>Villa 1</Name> </Product> </Product> </Product> </Product> </Products> 

 <step> <Products> <Product UserTypeID="Country"> <Name>Cyprus</Name> <Product UserTypeID="Resort"> <Name>Aghia Marina</Name> <Product UserTypeID="Property"> <Name>Villa Aghia Marina</Name> </Product> </Product> <Product UserTypeID="Resort"> <Name>Coral Bay</Name> <Product UserTypeID="Property"> <Name>Ascos Coral Villas</Name> </Product> <Product UserTypeID="Property"> <Name>Coral Villa</Name> </Product> <Product UserTypeID="Property"> <Name>Lella Villas</Name> </Product> </Product> </Product> <Product UserTypeID="Country"> <Name>Greece</Name> <Product UserTypeID="Region"> <Name>Corfu</Name> <Product UserTypeID="Resort"> <Name>Acharavi</Name> <Product UserTypeID="Property"> <Name>Villa Angelos</Name> </Product> <Product UserTypeID="Property"> <Name>Villa Eleonas</Name> </Product> </Product> <Product UserTypeID="Resort"> <Name>Aghios Stefanos</Name> <Product UserTypeID="Property"> <Name>Villa Joanna</Name> </Product> <Product UserTypeID="Property"> <Name>Villa Eleonas</Name> </Product> </Product> <Product UserTypeID="Resort"> <Name>Kassiopi</Name> <Product UserTypeID="Property"> <Name>Villa Imerolia</Name> </Product> <Product UserTypeID="Property"> <Name>Test Property</Name> </Product> </Product> </Product> </Product> </Products> 

Each file has the same products (by. / Name), but with different offal (by. / Name), and I need to combine them in one tree with one product per product / name, containing all the subitems on the same one I could output one structure.

I have found an xslt method that will create a node as shown below

  <xsl:variable name="step-output"> <xsl:for-each select="/index/file"> <xsl:copy-of select="document(.)" /> </xsl:for-each> </xsl:variable> <xsl:variable name="step-products" select="exsl:node-set($step-output)//Products" /> 

But this, when I create other templates, will create three products by product / name, i.e. cyprus will appear three times.

Does anyone know how to do what I need? My result should be as follows.

 <step> <Products> <Product UserTypeID="Country"> <Name>Cyprus</Name> <Product UserTypeID="Resort"> <Name>Aghia Marina</Name> <Product UserTypeID="Property"> <Name>Villa Aghia Marina</Name> </Product> </Product> <Product UserTypeID="Resort"> <Name>Argaka</Name> <Product UserTypeID="Property"> <Name>Villa Jaime</Name> </Product> <Product UserTypeID="Property"> <Name>Villa Tester</Name> </Product> </Product> <Product UserTypeID="Resort"> <Name>Coral Bay</Name> <Product UserTypeID="Property"> <Name>Ascos Coral Villas</Name> </Product> <Product UserTypeID="Property"> <Name>Coral Villa</Name> </Product> <Product UserTypeID="Property"> <Name>Lella Villas</Name> </Product> <Product UserTypeID="Property"> <Name>1</Name> </Product> <Product UserTypeID="Property"> <Name>2</Name> </Product> </Product> </Product> <Product UserTypeID="Country"> <Name>Greece</Name> <Product UserTypeID="Region"> <Name>Corfu</Name> <Product UserTypeID="Resort"> <Name>Acharavi</Name> <Product UserTypeID="Property"> <Name>Villa Angelos</Name> </Product> <Product UserTypeID="Property"> <Name>Villa Eleonas</Name> </Product> <Product UserTypeID="Property"> <Name>Villa 1</Name> </Product> <Product UserTypeID="Property"> <Name>Villa 2</Name> </Product> </Product> <Product UserTypeID="Resort"> <Name>Aghios Stefanos</Name> <Product UserTypeID="Property"> <Name>Villa Joanna</Name> </Product> <Product UserTypeID="Property"> <Name>Villa Eleonas</Name> </Product> </Product> <Product UserTypeID="Resort"> <Name>Gouvia</Name> <Product UserTypeID="Property"> <Name>Villa De Bono</Name> </Product> </Product> <Product UserTypeID="Resort"> <Name>Kassiopi</Name> <Product UserTypeID="Property"> <Name>Villa Imerolia</Name> </Product> <Product UserTypeID="Property"> <Name>Test Property</Name> </Product> <Product UserTypeID="Property"> <Name>Villa 1</Name> </Product> <Product UserTypeID="Property"> <Name>Villa 2</Name> </Product> </Product> </Product> </Product> </Products> 

+4
source share
2 answers

Here is the XSLT 2.0 style sheet that should do the following:

 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"> <xsl:output indent="yes"/> <xsl:template match="/"> <step> <Products> <xsl:for-each-group select="document(index/file)/step/Products/Product" group-by="Name"> <Product UserTypeID="{@UserTypeID}"> <Name><xsl:value-of select="current-grouping-key()"/></Name> <xsl:for-each-group select="current-group()/Product" group-by="Name"> <xsl:sort select="current-grouping-key()"/> <Product UserTypeID="{@UserTypeID}"> <Name><xsl:value-of select="current-grouping-key()"/></Name> <xsl:for-each select="current-group()/Product"> <xsl:sort select="Name"/> <xsl:copy-of select="."/> </xsl:for-each> </Product> </xsl:for-each-group> </Product> </xsl:for-each-group> </Products> </step> </xsl:template> </xsl:stylesheet> 

You need to run it against an index XML document with a structure

 <index> <file>test2010020803.xml</file> <file>test2010020804.xml</file> <file>test2010020805.xml</file> </index> 

which lists the other files you want to process.

XSLT 2.0 style sheets can be run with Saxon 9 , which comes in .NET and the Java version, so it works wherever at least Java 1.5 or .NET 2.0 is available or can be installed. Other options are AltovaXML Tools (Windows only) and Gestalt .

If you are attached to XSLT 1.0, you can do it as follows if you have exsl: node -set or similar support:

 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exsl="http://exslt.org/common" exclude-result-prefixes="exsl" version="1.0"> <xsl:output indent="yes"/> <xsl:strip-space elements="*"/> <xsl:key name="k1" match="step/Products/Product" use="Name"/> <xsl:key name="k2" match="step/Products/Product/Product" use="concat(../Name, '|', Name)"/> <xsl:template match="/"> <xsl:variable name="rtf"> <xsl:copy-of select="document(index/file)/*"/> </xsl:variable> <step> <Products> <xsl:for-each select="exsl:node-set($rtf)/step/Products/Product[generate-id() = generate-id(key('k1', Name)[1])]"> <Product UserTypeID="{@UserTypeID}"> <xsl:copy-of select="Name"/> <xsl:for-each select="key('k1', Name)/Product[generate-id() = generate-id(key('k2', concat(../Name, '|', Name))[1])]"> <xsl:sort select="Name"/> <Product UserTypeID="{@UserTypeID}"> <xsl:copy-of select="Name"/> <xsl:for-each select="key('k2', concat(../Name, '|', Name))/Product"> <xsl:sort select="Name"/> <xsl:copy-of select="."/> </xsl:for-each> </Product> </xsl:for-each> </Product> </xsl:for-each> </Products> </step> </xsl:template> </xsl:stylesheet> 

The keys will look like this:

  <xsl:key name="k1" match="step/Products/Product" use="Name"/> <xsl:key name="k2" match="step/Products/Product/Product" use="concat(../Name, '|', Name)"/> <xsl:key name="k3" match="step/Products/Product/Product/Product" use="concat(../../Name, '|', ../Name, '|', Name)"/> <xsl:key name="k4" match="step/Products/Product/Product/Product/Product" use="concat(../../../Name, '|', ../../Name, '|', ../Name, '|', Name)"/> <xsl:key name="k5" match="step/Products/Product/Product/Product/Product/Product" use="concat(../../../../Name, '|', ../../../Name, '|', ../../Name, '|', ../Name, '|', Name)"/> <xsl:key name="k6" match="step/Products/Product/Product/Product/Product/Product/Product" use="concat(../../../../../Name, '|', ../../../../Name, '|', ../../../Name, '|', ../../Name, '|', ../Name, '|', Name)"/> 

This is all printed here directly in the forum editor, so there may be errors.

+4
source

Editing text to create your files will work, but it can be difficult to maintain.

The easiest way is to parse the XML of all three files as an object. Programmatically add the objects under one parent node, and then create a new XML file.

Is your environment an acceptable solution?

0
source

Source: https://habr.com/ru/post/1300639/


All Articles