Search code examples
xmlxsltxpathxslt-1.0xslt-2.0

How to add an element specified in a variable at a xpath location specified in param in XSLT?


I want to add an xml element to a specified location within xml document. The problem is, that element will be in a param and also location (which is xpath) is also specified in param of xslt stylesheet.

XML looks like this:

<?xml version="1.0"?>

<soap:Envelope
xmlns:soap="http://www.w3.org/2003/05/soap-envelope/"
soap:encodingStyle="http://www.w3.org/2003/05/soap-encoding">

<soap:Body>
  <m:GetPriceResponse xmlns:m="https://www.w3schools.com/prices">
    <m:Price>1.90</m:Price>
  </m:GetPriceResponse>
</soap:Body>

</soap:Envelope>

XPATH =/soap:Envelop/soap:Body

variable having xml element to add = <customer>foo</customer> (this xml element to be added is getting added from external configuration to a parameter and I am using saxon:parse(param_name) to store it in a variable.)


Solution

  • If you are using Saxon then you could leverage the saxon:eval() function to evaluate the XPath from the $path parameter.

    Below is an example that evaluates the XPath with the result in a variable, and uses it in a template match pattern to test whether generate-id() of the $eval is equal to that of the matched element. If it matches, then it will add the $add parameter as XML using parse-xml(), as a child of that element.

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="3.1"
        xmlns:saxon="http://saxon.sf.net/"
        xmlns:soap="http://www.w3.org/2003/05/soap-envelope/">
       
      <xsl:param name="path" select="'/soap:Envelope/soap:Body'"/>
      <xsl:param name="add" select="'&lt;customer>foo&lt;/customer>'"/>
        
      <xsl:variable name="eval" select="saxon:eval(saxon:expression($path))" as="item()*"/>
           
      <xsl:mode on-no-match="shallow-copy" />
        
      <xsl:template match="*[. is $eval]">
        <xsl:copy>
            <xsl:sequence select="@*, parse-xml($add), node()"/>
        </xsl:copy>      
      </xsl:template>
        
    </xsl:stylesheet>