Search code examples
xmlxsltdtd

Include xml from another file with contents from parent file


Is it possible to insert contents of another xml file (child xml) to a parent xml with updated attributes -- strictly using xml or xslt? Or do I have to use python to generate the xml.

So for example lets say I have a parent xml with contents:

<root>
    <parent1 value="parent1">
        # get contents of child.xml
    </parent1>
    <parent2 value="parent2">
        # get contents of child.xml
    </parent2>
</root>

child.xml has contents:

<root>
    <child1 value="child1"/>
    <child2 value="child2"/>
</root>

which I could do with include, but I also want to update the value. So the final xml I want is:

<root>
    <parent1 value="parent1">
        <child1 value="parent1_child1"/>
        <child2 value="parent1_child2"/>
    </parent1>
    <parent2 value="parent2">
        <child1 value="parent2_child1"/>
        <child2 value="parent2_child2"/>
    </parent2>
</root>

Where the value of the child is update based on the parent value.


Solution

  • You can use the document() function to refer to another XML file. You could implement it like this.

    <?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"/>
      
      <xsl:variable name="childDoc" select="document('child.xml')"/>
    
      <xsl:template match="@*|node()">
        <xsl:copy>
          <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
      </xsl:template>
      
      <xsl:template match="parent">
        <xsl:variable name="currentParent" select="."/>
        <xsl:copy>
          <xsl:for-each select="$childDoc/root/child">
            <xsl:copy>
              <xsl:attribute name="value" select="concat($currentParent/@value,'_',@value)"/>
            </xsl:copy>
          </xsl:for-each>
        </xsl:copy>
      </xsl:template>
      
    </xsl:stylesheet>
    

    See it working here: https://xsltfiddle.liberty-development.net/pNvtBGr (I have put the document in a variable for testing purposes.)