0

I have two input files: file1.xml and file2.xml, with same structure but different contents (of source and target nodes).

file1.xml (simplified version)

<?xml version="1.0" encoding="UTF-8"?>
<xliff>
    <file>
        <body>
            <trans-unit id="MDSD_0">
                <source>Gestioni els seus favorits</source>
                <target>Gestioni els seus favorits</target>
            </trans-unit>
            <trans-unit id="MDSD_1">
                <source>Favorits</source>
                <target>Favorits</target>
            </trans-unit>
        </body>
    </file>
</xliff>

file2.xml (simplified version)

<?xml version="1.0" encoding="UTF-8"?>
<xliff>
    <file>
        <body>
            <trans-unit id="MDSD_0">
                <source>Manage your bookmarks</source>
                <target>Manage your bookmarks</target>
            </trans-unit>
            <trans-unit id="MDSD_1">
                <source>Bookmarks</source>
                <target>Bookmarks</target>
            </trans-unit>
        </body>
    </file>
</xliff>

I would like to take all content from file1.xml except the source node, that I want from file2.xml. In other words, I want to replace source in file1.xml with source in file2.xml.

I am tempted to do it in Perl or PHP, but I think in XSLT it would be more efficient. However, I'm a bit stuck.

My stylesheet:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" />
    <xsl:strip-space elements="*"/>

    <xsl:template match="source">
        <source>
            <xsl:value-of select="document('file2.xlf')//source" />
        </source>
    </xsl:template>

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

</xsl:stylesheet>

This produces the following output:

<?xml version="1.0" encoding="UTF-8"?>
<xliff>
    <file>
        <body>
            <trans-unit id="MDSD_0">
                <source>Manage your bookmarks</source>
                <target>Gestioni els seus favorits</target>
            </trans-unit>
            <trans-unit id="MDSD_1">
                <source>Manage your bookmarks</source> <!-- this one is wrong -->
                <target>Favorits</target>
            </trans-unit>
        </body>
    </file>
</xliff>

As you can see, it's using the content from only the first source node in file2.xml to replace all source nodes in file1.xml.

I suppose I would need to make my selection somehow based on the position or where the id of the parent trans-unit is the same. I have tried with

<xsl:value-of select="document('file2.xlf')//source/parent::trans-unit[@id= current()]" />

but that gives me <source/>.

I'd be thankful for any tips.

My stylesheet is XSLT version 1 but I suppose I could use XLST 2.0 if necessary (I am using Oxygen and free versions of Saxon).

msoutopico
  • 357
  • 3
  • 15

2 Answers2

1

Assuming you want to lookup the source value by matching the id of the parent trans-unit, you could do:

<xsl:value-of select="document('file2.xml')/xliff/file/body/trans-unit[@id=current()/../@id]/source" />

In XSLT 2.0, you can make this easier (and more efficient) by defining a key as:

<xsl:key name="src" match="source" use="../@id" />

and then use it as:

<xsl:value-of select="key('src', ../@id, document('file2.xml'))" />
michael.hor257k
  • 113,275
  • 6
  • 33
  • 51
  • The first solution for XSLT 1.0 didn't work. It produces ``. The second solution I haven't tried, but it seems the same as the one provided by Martin, so it should work. Thanks! – msoutopico Jun 18 '17 at 11:41
  • It works for me - but then my file is named `file2.xml` (as stated in your question), not `file2.xlf`as used in your example code. – michael.hor257k Jun 18 '17 at 11:44
  • You are right, my fault. I chose your answer for being more complete (solutions for both v.1 and v.2) and being the first one posted. Thanks. – msoutopico Jun 18 '17 at 12:20
1

Change

<xsl:template match="source">
        <source>
            <xsl:value-of select="document('file2.xlf')//source" />
        </source>
</xsl:template>

to

<xsl:template match="source">
        <xsl:copy-of select="key('ref', ../@id, document('file2.xlf'))/source" />
</xsl:template>

with <xsl:key name="ref" match="trans-unit" use="@id"/> added to the stylesheet (and make sure in oXygen you use Saxon 9 to have XSLT 2.0 support).

Martin Honnen
  • 160,499
  • 6
  • 90
  • 110