Pankaj
Pankaj

Reputation: 177

pulling content from one xml to another xml

I have two different xmls (unique reference is @id). Need to copy all child nodes of B.xml's "transunit/target" to A.xml's nodes when @id matches. Please have a look at A.xml and B.xml.

note: all the target content in B.xml is suffix by "Translated"

XSLT version 2.0 and processor Saxon EE/HE 9.X.X.X

A.xml

<concept id="001" xml:lang="en-us">
    <title id="002">Notice</title>
    <shortdesc id="003">This information U.S.A.</shortdesc>
    <conbody id="004">
        <p id="005">This product blah blah <companyname id="006">blah bla</companyname> No other warranty expressed or implied. </p>
        <p id="007">This supersedes all previous notices.</p>
        <section id="008">
            <title id="009">COPYRIGHT LICENSE:</title>
            <p id="010">This information contains <b id="011">in source language</b> , blah blah</p>
        </section>
    </conbody>
</concept>

B.xml

<root>
    <transunit id="002">
        <source>Notice</source>
        <target>Translated:Notice</target>
    </transunit>
    <transunit id="003">
        <source>This information U.S.A.</source>
        <target>Translated:This information U.S.A.</target>
    </transunit>
    <transunit id="005">
        <source>This product blah blah <companyname id="006" local-name="companyname">blah bla</companyname> No other warranty expressed or implied. </source>
        <target>Translated:This product blah blah <companyname id="006" local-name="companyname">blah bla</companyname> No other warranty expressed or implied. </target>
    </transunit>
    <transunit id="007">
        <source>This supersedes all previous notices.</source>
        <target>Translated:This supersedes all previous notices.</target>
    </transunit>
    <transunit id="009">
        <source>COPYRIGHT LICENSE:</source>
        <target>Translated:COPYRIGHT LICENSE:</target>
    </transunit>
    <transunit id="010">
        <source>This information contains <b id="011" local-name="b">in source language</b> , blah blah</source>
        <target>Translated:This information contains <b id="011" local-name="b">in source language</b> , blah blah</target>
    </transunit>
</root>

Expected result:

<concept id="001" xml:lang="en-us">
    <title id="002">Translated:Notice</title>
    <shortdesc id="003">Translated:This information U.S.A.</shortdesc>
    <conbody id="004">
        <p id="005">Translated:This product blah blah <companyname id="006">blah bla</companyname> No other warranty expressed or implied. </p>
        <p id="007">Translated:This supersedes all previous notices.</p>
        <section id="008">
            <title id="009">Translated:COPYRIGHT LICENSE:</title>
            <p id="010">Translated:This information contains <b id="011">in source language</b> , blah blah</p>
        </section>
    </conbody>
</concept>

I am trying something like:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" version="2.0">
<xsl:template match="node()">
    <xsl:copy>
        <xsl:copy-of select="@*"/>
        <xsl:apply-templates/>
    </xsl:copy>
</xsl:template>
<xsl:template match="*[count(ancestor::*) != 0]" priority="2">
    <xsl:copy>
        <xsl:copy-of select="@*"/>
        <xsl:variable name="id">
            <xsl:value-of select="@id"/>
        </xsl:variable>
        <xsl:choose>
            <xsl:when test="document('B.xml')//*[$id=@id]">
            <xsl:for-each select="document('B.xml')//*[$id=@id]/target">
            <xsl:message>i m hre</xsl:message>
            <xsl:apply-templates/>
        </xsl:for-each>
    </xsl:when>
    <xsl:otherwise>
        <xsl:apply-templates/>
    </xsl:otherwise>
</xsl:choose>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>

Upvotes: 0

Views: 99

Answers (1)

Sean B. Durkin
Sean B. Durkin

Reputation: 12729

This XSLT 2.0 stylesheet ...

<xsl:stylesheet version="2.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:output encoding="UTF-8" indent="yes" omit-xml-declaration="yes" />
<xsl:strip-space elements="*" />
<xsl:param name="translations" select="''" />

<xsl:variable name="valid-ids" as="xs:string*">
 <xsl:if test="$translations ne ''">
  <xsl:sequence select="document($translations)//*[target]/@id" />
 </xsl:if>
</xsl:variable>

<xsl:key name="trans" match="*[@id][target]" use="@id" />

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

<xsl:template match="*[@id = $valid-ids]">
 <xsl:variable name="id" select="@id" />
 <xsl:copy>
  <xsl:apply-templates select="@*" />
  <xsl:for-each select="document($translations)">
   <xsl:apply-templates select="key('trans',$id)/target/node()" />
  </xsl:for-each>
 </xsl:copy> 
</xsl:template>

</xsl:stylesheet>

... applied using a command line like (for Saxon processor) ...

"C:\Program Files\Saxonica\SaxonHE9.5N\bin\transform" "-s:A.xml" "-xsl:sheet.xsl" "-o:outp.xml" "translations=B.xml"

... with the two given input files (A.xml being the main input document and B.xml referenced as a stylesheet parameter, yields ...

<concept id="001" xml:lang="en-us">
   <title id="002">Translated:Notice</title>
   <shortdesc id="003">Translated:This information U.S.A.</shortdesc>
   <conbody id="004">
      <p id="005">Translated:This product blah blah <companyname id="006" local-name="companyname">blah bla</companyname> No other warranty expressed or implied. </p>
      <p id="007">Translated:This supersedes all previous notices.</p>
      <section id="008">
         <title id="009">Translated:COPYRIGHT LICENSE:</title>
         <p id="010">Translated:This information contains <b id="011" local-name="b">in source language</b> , blah blah</p>
      </section>
   </conbody>
</concept>

Note

You could enhance the functionality of this stylesheet, by including the doc-avail() function . Choose how to handle the translation document being specified but not available. A number of reasonable options would be possible to implement.


Thanks to Martin, here is an improved version of second template.

<xsl:template match="*[@id = $valid-ids]">
 <xsl:copy>
  <xsl:apply-templates select="@*,key('trans',@id, document($translations))/target/node()" />
 </xsl:copy> 
</xsl:template>

Upvotes: 1

Related Questions