Search code examples
xmlxsltxquerytransformationosb

XQuery XML insert


I have XML based target data:

<myTargetData>
    <myMap>
        <pairs>
            <key>KEY_1</key>
            <value>
                <myMap>
                    <pairs>
                        <key>INNER_KEY_1</key>
                        <value/>
                    </pairs>
                    <pairs>
                        <key>INNER_KEY_2</key>
                        <value/>
                    </pairs>
                    <pairs>
                        <key>INNER_KEY_3</key>
                        <value>
                            <myMap>
                                <pairs>
                                    <key>INNER_INNER_KEY_1</key>
                                    <value/>
                                </pairs>
                                <pairs>
                                    <key>INNER_INNER_KEY_2</key>
                                    <value/>
                                </pairs>
                            </myMap>
                        </value>
                    </pairs>
                </myMap>
            </value>
        </pairs>
        <pairs>
            <key>KEY_2</key>
            <value>
                <myString>test string 2</myString>
            </value>
        </pairs>
        <pairs>
            <key>KEY_3</key>
            <value>
                <myString>test string 3</myString>
            </value>
        </pairs>
        <pairs>
            <key>KEY_4</key>
            <value>
                <myString>test string 4</myString>
            </value>
        </pairs>
    </myMap>
</myTargetData>

There is configuration field list:

<myFieldData>
    <field>KEY_1</field>
    <field>INNER_KEY_2</field>
    <field>INNER_INNER_KEY_1</field>
    <field>KEY_3</field>
<myFieldData>

Configuration field value means that target XML should be appended by following two pairs:

<pairs>
    <key>{key name}_appendix1</key>
    <value><myString>smth text</myString></value>
</pairs>
<pairs>
    <key>{key name}_appendix2</key>
    <value><myString>smth text</myString></value>
</pairs>

The result after transformation should be:

<myTargetData>
    <myMap>
        <pairs>
            <key>KEY_1</key>
            <value>
                <myMap>
                    <pairs>
                        <key>INNER_KEY_1</key>
                        <value/>
                    </pairs>
                    <pairs>
                        <key>INNER_KEY_2</key>
                        <value/>
                    </pairs>
                    <pairs>
                        <key>INNER_KEY_2_appendix1</key>
                        <value><myString>smth text</myString></value>
                    </pairs>
                    <pairs>
                        <key>INNER_KEY_2_appendix2</key>
                        <value><myString>smth text</myString></value>
                    </pairs>
                    <pairs>
                        <key>INNER_KEY_3</key>
                        <value>
                            <myMap>
                                <pairs>
                                    <key>INNER_INNER_KEY_1</key>
                                    <value/>
                                </pairs>
                                <pairs>
                                    <key>INNER_INNER_KEY_1_appendix1</key>
                                    <value><myString>smth text</myString></value>
                                </pairs>
                                <pairs>
                                    <key>INNER_INNER_KEY_1_appendix2</key>
                                    <value><myString>smth text</myString></value>
                                </pairs>    
                                <pairs>
                                    <key>INNER_INNER_KEY_2</key>
                                    <value/>
                                </pairs>
                            </myMap>
                        </value>
                    </pairs>
                </myMap>
            </value>
        </pairs>
        <pairs>
            <key>KEY_1_appendix1</key>
            <value><myString>smth text</myString></value>
        </pairs>
        <pairs>
            <key>KEY_1_appendix2</key>
            <value><myString>smth text</myString></value>
        </pairs>
        <pairs>
            <key>KEY_2</key>
            <value>
                <myString>test string 2</myString>
            </value>
        </pairs>
        <pairs>
            <key>KEY_3</key>
            <value>
                <myString>test string 3</myString>
            </value>
        </pairs>
        <pairs>
            <key>KEY_3_appendix1</key>
            <value><myString>smth text</myString></value>
        </pairs>
        <pairs>
            <key>KEY_3_appendix2</key>
            <value><myString>smth text</myString></value>
        </pairs>
        <pairs>
            <key>KEY_4</key>
            <value>
                <myString>test string 4</myString>
            </value>
        </pairs>
    </myMap>
</myTargetData>

Is it possible to do that using XQuery? Or better to use XSLT? If it is possible - how to do that? Maybe recursive function? Transformation will be used in Oracle Service Bus.


Solution

  • You need to make a recursive copy (see the Identity Template pattern), and if the current node is a match (is a pairs element, with a matching key), then you also have to generate 2 elements after. This stylesheet does exactly that:

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    
       <xsl:variable name="keys" select="document('so-001-keys.xml')/myFieldData"/>
    
       <xsl:template match="node()">
          <xsl:copy>
             <xsl:copy-of select="@*"/>
             <xsl:apply-templates select="node()"/>
          </xsl:copy>
          <!-- if it's a match, add new elements -->
          <xsl:if test="self::pairs[key = $keys/field]">
             <pairs>
                <key>
                   <xsl:value-of select="key"/>
                   <xsl:text>_appendix1</xsl:text>
                </key>
                <value><myString>smth text</myString></value>
             </pairs>
             <pairs>
                <key>
                   <xsl:value-of select="key"/>
                   <xsl:text>_appendix2</xsl:text>
                </key>
                <value><myString>smth text</myString></value>
             </pairs>
          </xsl:if>
       </xsl:template>
    
    </xsl:stylesheet>