variablesgroovyfindallxmlslurpergpath

How to use GPath with variable?


Let's say I have the following XML at hand

<Envelope>
  <Body>
    <analyzeEffectOfReplaceOfferResponse>
      <productOfferings>
        <productOffering>
          <id>some value</id>
        </productOffering>
      </productOfferings>
    </analyzeEffectOfReplaceOfferResponse>
  </Body>
</Envelope>

I also have the input XML in form of GPathResult after retrieving the file and parsing it:

inputXML = new XmlSlurper().parse(inputFile)

when I try to find the node like this:

inputXML."Body"."analyzeEffectOfReplaceOfferResponse"."productOfferings"."productOffering".depthFirst().findAll {it.value}

I get the required child "id"

however if I use a string that holds this text:

"Body"."analyzeEffectOfReplaceOfferResponse"."productOfferings"."productOffering"

and use it like so:

inputXML."${xPath}".depthFirst().findAll {it.value}

It doesn't work... what am I doing wrong?


Solution

  • In your current attempt, Groovy is calling the getProperty method on the inputXML object with argument "Body"."analyzeEffectOfReplaceOfferResponse"."productOfferings"."productOffering".

    Since there is no XML child element with that specific name, nothing is found.

    Instead, your aim is to dynamically chain the calls along the lines of this:

    inputXML.getProperty('Body')
            .getProperty('analyzeEffectOfReplaceOfferResponse')
            .getProperty('productOfferings')
            .getProperty('productOffering')
            .depthFirst().findAll {it.value}
    

    You could do this by creating a method that recursively creates this chaining, e.g.

    def xPath = '"Body"."analyzeEffectOfReplaceOfferResponse"."productOfferings"."productOffering"'
    
    def getProperties(gpathResult, dotProp) {
        def props = dotProp?.split(/\./)
        props.length <= 1 ? gpathResult : getProperties(gpathResult[props.head() - '"' - '"'], (props.tail().join('.')))
    }
    
    getProperties(inputXML, xPath).depthFirst().findAll {it.value}
    

    Or you could use a full-fledged XPath library.