0

Given the following XML document:

<root>
  <Person>
    <Name>JOHN DOE</Name>
  </Person>
</root>

With a Groovy script I parse the document like this:

def xmlFile = new File("mydocument.xml")
def root = new XmlSlurper().parse(xmlFile)
println(root.Person.Name)

Is it possible to make the GPath expression variable so that it would like something like this?

def xmlFile = new File("mydocument.xml")
def root = new XmlSlurper().parse(xmlFile)
def gpathExpr = "root.Person.Name"
println(gpathExpr) // <-- Evaluate this during runtime
Robert Strauch
  • 12,055
  • 24
  • 120
  • 192
  • I also saw that post and referenced it but there is another solution that uses `Eval` to actually evaluate the GPath expression. – Andy Feb 25 '17 at 04:04

1 Answers1

1

Here are two working solutions (in the form of JUnit Groovy tests). The former was derived from this answer; the latter I experimented with and found on my own. I think the latter is more closely aligned with what you were looking for, but the former is probably more robust.

Side note: I don't know how you intend to read in the "variable path" expression, but you should be very careful to sanitize it completely because you do not want to run Eval.me() on arbitrary, unsanitized, user-provided input.

@Test
void testShouldUseVariableGPathExpression() {
    // Arrange
    def xmlContent = """<root>
  <Person>
    <Name>JOHN DOE</Name>
  </Person>
</root>"""

    def getNodes = { doc, path ->
        def nodes = doc
        path.split("\\.").each { nodes = nodes."${it}" }
        return nodes
    }

    def root = new XmlSlurper().parseText(xmlContent)

    // Don't reference 'root' here
    def path = "Person.Name"

    // Act
    def personName = getNodes(root, path)
    logger.info("Parsed ${path}: ${personName}")

    // Assert
    assert personName == "JOHN DOE"
}

@Test
void testShouldUseVariableGPathExpressionAndEval() {
    // Arrange
    def xmlContent = """<root>
  <Person>
    <Name>JOHN DOE</Name>
  </Person>
</root>"""

    def root = new XmlSlurper().parseText(xmlContent)
    def path = "root.Person.Name"
    def expression = "evaluatedPath = ${path}"
    logger.info("Generated expression: ${expression}")

    // Act
    def evaluatedPath = Eval.me('root', root, path)
    logger.info("Evaluated result: ${evaluatedPath}")

    def personName = evaluatedPath
    logger.info("Parsed ${path}: ${personName}")

    // Assert
    assert personName == "JOHN DOE"
}
Community
  • 1
  • 1
Andy
  • 13,916
  • 1
  • 36
  • 78