Jerome Dobosz
Jerome Dobosz

Reputation: 1

How to merge xml files using xslt and remove empty elements

I have several files that I want to merge, ignoring empty elements.

For example : File 1:

    <ds>
    <sk>
    <f1>1</f1>
    <f2>2</f2>
    </sk>
    <sk>
    <f1>3</f1>
    <f2>4</f2>
    </sk>
    </ds>    

file 2 :

    <ds>
    <ac>
    <g1>9</f1>
    <g2>10</f2>
    </ac>
    <ac>
    <g1>11</f1>
    <g2>12</f2>
    </ac>
    </ds>    

and File 3:

    <ds>
    <rs>
    <k1>A</f1>
    <k2>B</f2>
    <k3></k3>
    </rs>
    <rs>
    <k1>C</f1>
    <k2>B</f2>
    <k3/>
    </rs>
    </ds>    

I want as outpout:

    <ds>
    <sk>
    <f1>1</f1>
    <f2>2</f2>
    </sk>
    <sk>
    <f1>3</f1>
    <f2>4</f2>
    </sk>
    <ac>
    <g1>9</f1>
    <g2>10</f2>
    </ac>
    <ac>
    <g1>11</f1>
    <g2>12</f2>
    </ac>
    <rs>
    <k1>A</f1>
    <k2>B</f2>
    </rs>
    <rs>
    <k1>C</f1>
    <k2>B</f2>
    </rs>
    </ds>    

I have tried this as xslt :

    <?xml version="1.0" ?>
    <xsl:transform
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xml:space="preserve"
        version="1.0">
        <xsl:output indent="yes"/>

     <xsl:template match="/ds">
         <xsl:copy-of select="document('File1')/ds/sk"/>
         <xsl:copy-of select="document('File2')/ds/ac"/>
         <xsl:copy-of select="document('File3')/ds/rs"/>
     </xsl:template>

    </xsl:transform>

Input is File1. Files are merge but I cannot figure how to remove empty elements like or in File3. Any idea ?

Upvotes: 0

Views: 284

Answers (2)

Jerome Dobosz
Jerome Dobosz

Reputation: 1

I cannot figure why but the problem is solved using this xslt

 <xsl:template match="/">
     <xsl:copy>
     <xsl:apply-templates select="document('File1')/ds/sk" />
     <xsl:apply-templates select="document('File2')/ds/ac" />
     <xsl:apply-templates select="document('File3')/ds/rs" />
     </xls:copy>
 </xsl:template>

<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="*[not(*)][not(normalize-space())]" />

Note : yours was performing well using Altova (with msxml as parser). In my code (powerbuilder), i need to use this one ...

Upvotes: 0

Tim C
Tim C

Reputation: 70618

Assuming all your XML file were actually well-formed, you should start off by using the XSLT identity transform

<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>

Then, instead of doing xsl:for-each, do xsl:apply-templates instead.

<xsl:apply-templates select="document('File1')/ds/sk" />
<xsl:apply-templates select="document('File2')/ds/ac" />
<xsl:apply-templates select="document('File3')/ds/rs" />

Note, you may not necessarily need to use the document function on File1 if that happens to be the input file of the XSLT itself.

Then to remove empty elements, just add a template like this:

<xsl:template match="*[not(*)][not(normalize-space())]" />

Try this XSLT

<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output method="xml" encoding="UTF-8" indent="yes" />

     <xsl:template match="/">
         <xsl:apply-templates select="document('File1')/ds/sk" />
         <xsl:apply-templates select="document('File2')/ds/ac" />
         <xsl:apply-templates select="document('File3')/ds/rs" />
     </xsl:template>

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="*[not(*)][not(normalize-space())]" />
</xsl:transform>

Upvotes: 2

Related Questions