我正在使用xmlstarlet从liquibase XML更改日志中提取changeSet
个节点,其中viewName
以“v”结尾。
然而,xmlstarlet抱怨ends-with
XPATH函数不存在:
$ 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
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>
我知道XPATH表达式是正确的,因为如果我将选择条件更改为x:createView[@viewName="myviewnamev"]
,那么它只能正确选择changeLog
条目。
如何让xmlstarlet正确使用ends-with
?或者,有没有其他方法可以完成我想要做的事情?
答案 0 :(得分:4)
xmlstarlet
仅支持XPath 1.0,它不提供ends-with($string, $token)
功能。您需要使用substring
,string-length
和字符串比较来构建您自己的模式:
substring($string, string-length($string) - string-length($token) + 1) = $token]
应用于您的查询,它应该如下所示(我“预先计算”字符串长度):
/x:databaseChangeLog/x:changeSet[x:createView[
substring(@viewName, string-length(@viewName)) = 'v']
]
或者,您可能希望寻找更强大的XPath 2.0 / XQuery引擎。