msoutopico
msoutopico

Reputation: 356

Replace node value using value from same node in another file

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).

Upvotes: 0

Views: 322

Answers (2)

michael.hor257k
michael.hor257k

Reputation: 116959

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'))" />

Upvotes: 1

Martin Honnen
Martin Honnen

Reputation: 167401

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).

Upvotes: 1

Related Questions