XSLT copy elements from second XML if an attribute is set in the first XML

137 views Asked by At

I have the following input XMLs:
car.xml:

<car ref-id="parts.xml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <color>red</color>
  <tire>michelin</tire>
  <engines override="false">
    <engine>
      <model>Z</model>
    </engine>
  </engines>
  <hifi>pioneer</hifi>
</car>

parts.xml:

<?xml version="1.0" encoding="UTF-8"?>
<parts xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <engines>
    <engine>
      <model>X</model>
    </engine>
    <engine>
      <model>Y</model>
    </engine>
  </engines>
  <tire>goodyear</tire>
  <color>black</color>
  <airbag>true</airbag>
</parts>

I'd like to merge parts.xml with car.xml, but want to copy only those nodes from parts.xml (regardless of their value) which:

  • A, doesn't exist in car.xml
  • B, exists in car xml, but the element's "override" attribute is set to false.

Michael-hor257k provided a solution to A, but I'm stuck implementing B.

Then XSLT looks like this:

<xsl:variable name="loc">
    <xsl:value-of select="car/@ref-id" />
</xsl:variable>

<xsl:template match="/car">
    <xsl:variable name="local-names">
        <xsl:for-each select="*">
            <name>
                <xsl:value-of select="name()" />
            </name>
            <attr>
                <xsl:value-of select="@override" />
            </attr>
        </xsl:for-each>
    </xsl:variable>

    <xsl:copy>
        <xsl:copy-of select="*" />
        <xsl:copy-of
            select="document($loc)/parts/*[not(name()=exsl:node-set($local-names)/name)] or 
                exsl:node-set($local-names)/attr='false'"/> 
    </xsl:copy>
</xsl:template>

I tried to add

<attr>
  <xsl:value-of select="@override" />
</attr>

and or exsl:node-set($local-names)/attr='false' to the XSLT but no success.

2

There are 2 answers

1
michael.hor257k On BEST ANSWER

You could change line #10 from:

<xsl:for-each select="*">

to:

<xsl:for-each select="*[not(@override='false')]">

You didn't post the expected result, so I am not sure it will be to your liking. This could prove much more complicated than it seems, if you need to merge nodes at different levels.

0
AudioBubble On

Change:

        <attr>
            <xsl:value-of select="@override" />
        </attr>

To:

        <attr>
            <xsl:value-of select="engines/@override" />
        </attr>