Why does xmlstarlet say there's no 'ends-with' function?

xmlstarlet, xpath

Solution

`xmlstarlet` only supports XPath 1.0, which does not offer an `ends-with($string, $token)` function. You need to use `substring`, `string-length` and and string comparison to construct your own using this pattern:

substring($string, string-length($string) - string-length($token) + 1) = $token]

Applied to your query, it should look like this (I "precomputed" the string length):

/x:databaseChangeLog/x:changeSet[x:createView[
  substring(@viewName, string-length(@viewName)) = 'v']
]

Alternatively, you might want to look for a more powerful XPath 2.0/XQuery engine.

Problem

I'm using xmlstarlet to extract `changeSet` nodes from a liquibase XML changelog where the `viewName` ends with "v". However, xmlstarlet is complaining that the `ends-with` XPATH function does not exist: ``` $ xmlstarlet sel -N x="http://www.liquibase.org/xml/ns/dbchangelog" -t -m \ "/x:databaseChangeLog/x:changeSet[x:createView[ends-with(@viewName, 'v')]]" \ -c . public.db.changelog.xml xmlXPathCompOpEval: function ends-with not found Unregistered function Stack usage errror xmlXPathCompiledEval: 3 objects left on the stack. runtime error: element for-each Failed to evaluate the 'select' expression. None of the XPaths matched; to match a node in the default namespace use '_' as the prefix (see section 5.1 in the manual). For instance, use /_:node instead of /node ``` The XML looks a bit like this: ``` <databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd"> <changeSet id="1391529990457-3"> <createView viewName="myviewnamev"><!-- view definition here --></createView> </changeSet> <changeSet id="1391529990457-4"> <createView viewName="anotherviewname"><!-- view definition here --></createView> </changeSet> </databaseChangeLog> ``` I do know that the XPATH expression is otherwise correct, because if I change the selection criteria to `x:createView[@viewName="myviewnamev"]` then it correctly selects only that `changeLog` entry. How do I get xmlstarlet to correctly use `ends-with`? Or, is there an alternative way to accomplish what I want to do?

Original source