例子:-
<item href="cover.jpeg" id="cover" media-type="image/jpeg"/>
我想选择 @id="cover" 和 media-type="image/*" 并检索 @href。
我当前的“解决方案”似乎是:-
xmlstarlet sel -t -m "//_:item[@id='$opf_cover_name']" -v @href -o '|' -v @media-type -n file.xml
,然后是围绕“|”进行一些极其混乱的分割输出的字符。
Does xmlstarlet have a substring function?
Version = 1.6.1
compiled against libxml2 2.9.4, linked with 20904
compiled against libxslt 1.1.29, linked with 10132
答案1
the_id='cover'
the_mediatype_prefix='image/'
xmlstarlet sel -t \
--var queryid="'$the_id'" \
--var typeprefix="'$the_mediatype_prefix'" \
-v '//item[@id = $queryid and starts-with(@media-type, $typeprefix)]/@href' \
-nl file.xml
这使用两个 shell 变量查询 XML 文件。该the_id
变量包含id
我们要过滤的属性值,同时包含该属性必须开头的the_mediatype_prefix
字符串。media-type
我们创建两个内部变量来xmlstarlet
使用该工具的--var
选项。这些值需要是编码值,这就是为什么我在它们周围插入单引号(这有点麻烦,理想情况下它们应该是正确编码的 XPath 字符串,但它比直接将 shell 变量注入表达式要好一些)。
XPath 表达式选择具有匹配和的href
每个节点的属性。item
id
media-type
使用xq
(XML 解析器包装器 around jq
,JSON 解析器)改为:
the_id='cover'
the_mediatype_prefix='image/'
xq -r \
--arg queryid "$the_id" \
--arg typeprefix "$the_mediatype_prefix" '
.. | .item? |
select(
."@id" == $queryid and
(."@media-type" | startswith($typeprefix))
)."@href"' file.xml
xmlstarlet
除了使用jq
表达式而不是 XPath 查询之外,这与代码或多或少相同。在这里,该实用程序负责正确编码您的 shell 变量,即使它们包含引号等不稳定值(示例中的 shell 变量值xmlstarlet
如果包含非法字符序列,则需要手动编码)。
答案2
您可以添加多个条件:
xmlstarlet sel -t -m "//item[@id='cover'][starts-with(@media-type,'image/')]" -v '@href' -nl file.xml