bash+xmlstarlet:如何将索引编入列表或填充数组?
bash+xmlstarlet: How can one index into a list, or populate an array?
我正在尝试 select 使用来自以下示例的 xmlstarlet 的单个节点 XML:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?xml-stylesheet type="text/xsl" href="key.xsl" ?>
<tables>
<tableset>
<table name="table1">
<row>
<fld name="fileName">
<strval><![CDATA[/my/XYZ/file1]]></strval>
</fld>
<fld name="fileName">
<strval><![CDATA[/my/XYZ/file2]]></strval>
</fld>
<fld name="fileName">
<strval><![CDATA[/my/other/XYZ/file3]]></strval>
</fld>
<fld name="worksBecauseUnique">
<strval><![CDATA[/XYZ/unique]]></strval>
</fld>
</row>
</table>
</tableset>
</tables>
我正在尝试在 bash 中构建一个关联数组...我怎样才能 select 单个节点,或者使用 xmlstarlet 遍历多个节点?
到目前为止,我正在尝试类似以下的方法,但没有用:
xmlstarlet sel -t -v "//tables/tableset/table/row/fld[@name=\"fileName\"]/strval[0]" xmlfile.xml
希望得到“/my/XYZ/file1”但是这不起作用。
回答你问题的第一部分,你犯了一个简单的错误:
strval[0]
需要
strval[1]
...到 select 第一个实例,因为 XPath 数组是 1 索引的,而不是 0 索引的。
现在,如果您想要 select 整个文档中的第二个匹配项,而不是父文档中的 fld
,这看起来有点不同:
(//tables/tableset/table/row/fld[@name="fileName"]/strval)[2]
现在开始填充 shell 数组。由于您此处的内容不包含换行符:
query='//tables/tableset/table/row/fld[@name="fileName"]/strval'
fileNames=( )
while IFS= read -r entry; do
fileNames+=( "$entry" )
done < <(xmlstarlet sel -t -v "$query" -n xmlfile.xml)
# print results
printf 'Extracted filename: %q\n' "${fileNames[@]}"
你没有提供足够的细节来设置关联数组(你想如何建立键?),所以我将其作为一个简单的索引数组来做。
另一方面,如果我们做出一些假设——您想要设置关联数组以匹配从 @name
键到 strval
值,并且您想在为同一个键给出时使用换行符分隔多个值——那么它可能看起来像这样:
match='//tables/tableset/table/row/fld[@name][strval]'
key_query='./@name'
value_query='./strval'
declare -A content=( )
while IFS= read -r key && IFS= read -r value; do
if [[ $content[$key] ]]; then
# appending to existing value
content[$key]+=$'\n'"$value"
else
# first value for this key
content[$key]="$value"
fi
fileNames+=( "$entry" )
done < <(xmlstarlet sel \
-t -m "$query" \
-v "$key_query" -n \
-v "$value_query" -n xmlfile.xml)
我正在尝试 select 使用来自以下示例的 xmlstarlet 的单个节点 XML:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?xml-stylesheet type="text/xsl" href="key.xsl" ?>
<tables>
<tableset>
<table name="table1">
<row>
<fld name="fileName">
<strval><![CDATA[/my/XYZ/file1]]></strval>
</fld>
<fld name="fileName">
<strval><![CDATA[/my/XYZ/file2]]></strval>
</fld>
<fld name="fileName">
<strval><![CDATA[/my/other/XYZ/file3]]></strval>
</fld>
<fld name="worksBecauseUnique">
<strval><![CDATA[/XYZ/unique]]></strval>
</fld>
</row>
</table>
</tableset>
</tables>
我正在尝试在 bash 中构建一个关联数组...我怎样才能 select 单个节点,或者使用 xmlstarlet 遍历多个节点?
到目前为止,我正在尝试类似以下的方法,但没有用:
xmlstarlet sel -t -v "//tables/tableset/table/row/fld[@name=\"fileName\"]/strval[0]" xmlfile.xml
希望得到“/my/XYZ/file1”但是这不起作用。
回答你问题的第一部分,你犯了一个简单的错误:
strval[0]
需要
strval[1]
...到 select 第一个实例,因为 XPath 数组是 1 索引的,而不是 0 索引的。
现在,如果您想要 select 整个文档中的第二个匹配项,而不是父文档中的 fld
,这看起来有点不同:
(//tables/tableset/table/row/fld[@name="fileName"]/strval)[2]
现在开始填充 shell 数组。由于您此处的内容不包含换行符:
query='//tables/tableset/table/row/fld[@name="fileName"]/strval'
fileNames=( )
while IFS= read -r entry; do
fileNames+=( "$entry" )
done < <(xmlstarlet sel -t -v "$query" -n xmlfile.xml)
# print results
printf 'Extracted filename: %q\n' "${fileNames[@]}"
你没有提供足够的细节来设置关联数组(你想如何建立键?),所以我将其作为一个简单的索引数组来做。
另一方面,如果我们做出一些假设——您想要设置关联数组以匹配从 @name
键到 strval
值,并且您想在为同一个键给出时使用换行符分隔多个值——那么它可能看起来像这样:
match='//tables/tableset/table/row/fld[@name][strval]'
key_query='./@name'
value_query='./strval'
declare -A content=( )
while IFS= read -r key && IFS= read -r value; do
if [[ $content[$key] ]]; then
# appending to existing value
content[$key]+=$'\n'"$value"
else
# first value for this key
content[$key]="$value"
fi
fileNames+=( "$entry" )
done < <(xmlstarlet sel \
-t -m "$query" \
-v "$key_query" -n \
-v "$value_query" -n xmlfile.xml)