Search code examples
xpathxquery

replace strings in arbitrarily nested maps/arrays with XQuery/XPath 3.1


I have a map parsed from a JSON file, for example:

let $template := map{
  "name"    : "{{name}}",
  "aggregateRating": map{
    "ratingValue": "{{ratingValue}}"
  },
  "openingHoursSpecification": map{
    "workingHours" : "{{workingHours}}",
    "workingDays": array{
      "Friday",
      "Saturday",
      "Sunday",
      "{{workingDaysRemark}}"
    }
  }
}
return

And a map of values extracted from a HTML document:

let $values := map {
  "name": "My comedy Name",
  "ratingValue": 9.4,
  "workingHours": "7 PM to 3 AM",
  "workingDaysRemark": "Except for statutory holidays"
}
return

I would like to replace all the string values of $template that are of the form {{keyName}} with $values(keyName); the expected result would be:

map{
  "name"    : "My comedy Name",
  "aggregateRating": map{
    "ratingValue": 9.4
  },
  "openingHoursSpecification": map{
    "workingHours" : "7 PM to 3 AM",
    "workingDays": array{
      "Friday",
      "Saturday",
      "Sunday",
      "Except for statutory holidays"
    }
  }
}

What would be a sensible way to achieve that with XPath 3.1 / XQuery?


Solution

  • There is no direct way to do this in 3.1. We're working on proposals to offer this functionality in 4.0 - see my paper presented at XML Prague last week

    https://archive.xmlprague.cz/2024/files/xmlprague-2024-proceedings.pdf

    In an earlier 2016 paper I considered how to do this with the 3.0/3.1 language, and came to the conclusion that the easiest solution was to convert the JSON to XML, transform the XML, and then convert the result back to JSON:

    https://www.saxonica.com/papers/xmlprague-2016mhk.pdf

    A prototype deep update capability has been present in Saxon (commercial editions) for some years: see https://www.saxonica.com/documentation12/index.html#!extensions/instructions/deep-update -- but it's XSLT rather than XQuery.