Home > Software engineering >  Merge two xml with substring as key
Merge two xml with substring as key

Time:12-09

I have two XML file.

First XML

<annunci>
    <annuncio>
        <any_info>222</any_info>
        <reference>333</reference>
                .
                .
                <lot_of_info> </lot_of_info>
                .
                .
        <some_info>1</some_info>
     <images>
    
    </images>
</annuncio>

Second XML

<images>
    <img>       
        <url>http://example.com/xml/img/333/somefile</url>
        <type>0</type>
        <public>1</public>
        <share>1</share>
    </img>

      <img>     
        <url>http://example.com/xml-feed/img/333/somefile</url>
        <type>0</type>
        <public>1</public>
        <share>1</share>
    </img>

</images>

Merging two XML using first file <reference> (example: 333) and <url> on second file with substring (folder) with same number (example: https://example.com/xml-feed/img/333/file1 and https://example.com/xml-feed/img/333/file2) to get a final XML like this one:

<annunci>
    <annuncio>
            <any_info>222</any_info>
        <reference>333</reference>
                .
                .
                <lot_of_info> </lot_of_info>
                .
                .
        <some_info>1</some_info>
     <images>
<img>       
        <url>http://example.com/xml/img/333/file1</url>
        <type>0</type>
        <public>1</public>
        <share>1</share>
    </img>

      <img>     
        <url>http://example.com/xml-feed/img/333/file2</url>
        <type>0</type>
        <public>1</public>
        <share>1</share>
    </img>
     </images>
</annuncio>

I try this but with no luck:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes"/>
    
    <!-- identity template: copies all nodes and attributes as-is -->
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    
    <!-- template to add the <img> elements from the second XML file -->
    <xsl:template match="/annunci/annuncio/images">
        <xsl:copy>
  
            <!-- add the <img> elements from the second XML file that have a matching <url> -->
            <xsl:for-each select="document('second.xml')/images/img[contains(url, /annunci/annuncio/reference)]">
                <xsl:copy-of select="."/>
            </xsl:for-each>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

Because I need to copy just ... with matching URL inside annuncio/annunci/images

CodePudding user response:

I would use a key <xsl:key name="ref" match="images/img" use="tokenize(url, '/')[last() - 1]"/> and then e.g.

<xsl:template match="/annunci/annuncio/images">
    <xsl:copy>
       <xsl:copy-of select="key('ref', ../reference, doc('second.xml'))"/>
    </xsl:copy>
</xsl:template>

CodePudding user response:

You could modify your second template to this :

<!-- template to add the <img> elements from the second XML file -->
    <xsl:template match="images">
        <xsl:variable name="ref" select="../reference"/>
        <xsl:copy>
            <!-- add the <img> elements from the second XML file that have a matching <url> -->
            <xsl:for-each select="document('second.xml')/images/img[contains(url, $ref)]">
                <xsl:copy-of select="."/>
            </xsl:for-each>
        </xsl:copy>
    </xsl:template>

(Although as pointed out in the other answer, using a key for lookups is the best practice.)

To make sure that you don't match sub-patterns of your reference id in the URL you could do something like this :

<xsl:for-each select="document('second.xml')/images/img[contains(url, concat('/',$ref,'/'))]">
  • Related