为什么 xmlstarlet 说没有“ends-with”函数?

Jon*_*han 3 xpath xmlstarlet

我正在使用xmlstarletchangeSetliquibase XML 变更日志中提取viewName以“v”结尾的节点。

然而,xmlstarlet 抱怨ends-withXPATH 函数不存在:

$ 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
Run Code Online (Sandbox Code Playgroud)

XML 看起来有点像这样:

<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>
Run Code Online (Sandbox Code Playgroud)

我确实知道 XPATH 表达式在其他方面是正确的,因为如果我将选择标准更改为 那么x:createView[@viewName="myviewnamev"]它只会正确选择该changeLog条目。

如何正确使用 xmlstarlet ends-with?或者,有其他方法可以完成我想做的事情吗?

Jen*_*rat 6

xmlstarlet仅支持XPath 1.0,不提供任何ends-with($string, $token)功能。您需要使用substring, string-lengthand 和字符串比较来使用以下模式构建您自己的比较:

substring($string, string-length($string) - string-length($token) + 1) = $token]
Run Code Online (Sandbox Code Playgroud)

应用于您的查询,它应该如下所示(我“预先计算”了字符串长度):

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

或者,您可能想要寻找更强大的 XPath 2.0/XQuery 引擎。