如何将 xmlstarlet 输出与 nul 分开?

How do I separate xmlstarlet output with nul?

我正在尝试使用 nul (U+0) 来分隔 xmlstarlet 输出中的 xml 值。 xmlstarlet 忽略 -o ''-o $'[=15=]'-o '[=16=]'

我知道我可以使用其他字符(例如各种字段分隔符)来分隔输出。这种方法的问题是这些字符也可以作为数据存在。我不想有任何歧义。

我想特别使用 nul,因为它是唯一不能用原始值表示的值 XML。

所以,重复我的问题:如何将 xmlstarlet 输出与 nul 分开?

更多信息

应要求提供信息的人们的要求,我提供了以下信息。虽然我很感激你愿意提供帮助,但请避免建议 XY sulutions。我只是在寻找所提出问题的答案。

我正在处理的数据如下所示:

<data>
    <datapoint attribute-1="val-1" attribute-2="val-a" />
    <datapoint attribute-1="val-2" attribute-2="val-b"  />
    <datapoint attribute-1="val-3">
        <sub-datapoint />
    </datapoint>
</data>

我尝试使用的方式 xmlstarlet:

mapfile -tf ARRAY < <( xmlstarlet sel -t -m /data/datapoint -o 'datapoint' -o $'[=11=]' -v ./@attribute-1 -o $'[=11=]' data.xml )

我正在寻找的输出的十六进制转储:

64 61 74 61 70 6f 69 6e  74 00 76 61 6c 2d 31 00  |datapoint.val-1.|
64 61 74 61 70 6f 69 6e  74 00 76 61 6c 2d 32 00  |datapoint.val-2.|
64 61 74 61 70 6f 69 6e  74 00 76 61 6c 2d 33 00  |datapoint.val-3.|

您可以使用 $'',在大多数情况下它应该和 null 一样好:

mapfile -d $'' -t ARRAY < <( xmlstarlet sel -t -m "XPATH" -v "XPATH" -o $'' -v 'XPATH' "FILE" )

不幸的是,xmlstarlet 似乎无法在其输出中生成 nul。

然而,

xmlstarlet 能够产生 U+FFFF;在所有 XML 版本中无效的代码点。您可以使用此代码安全地分隔 XML 值,然后使用另一个程序将其替换为 nul:

xmlstarlet sel -t \
   -m /data/datapoint \
   -o 'datapoint' \
   -o $'\uffff' \
   -v ./@attribute-1 \
   -o $'\uffff' data.xml \
 | python3 -c 'import sys; 
               sys.stdout.write(sys.stdin.read().replace("\uffff", "[=10=]"))'

这是@TendersMcChiken 的答案的变体,用 perl 代替了 python:

xmlstarlet sel -t -m /data/datapoint \
  -o 'datapoint' -o $'\uFFFF' -v ./@attribute-1 -o $'\uFFFF' data.xml \
  | perl -CS -0xFFFF -l0 -pe '' \
  | hexdump -e '16/1 "%-3.2x"' -e '"|" 16/1 "%_p" "|\n"'

输出与问题中显示的 hexdump 完全匹配。

旁白: 因为目标是将结果捕获到 bash 数组中,所以我尝试了这个:

mapfile -d $'\uFFFF' -t arr < <(
  xmlstarlet sel -t -m /data/datapoint \
  -o 'datapoint' -o $'\uFFFF' -v ./@attribute-1 -o $'\uFFFF' data.xml
)

但是它没有用,因为 bash 不支持多字节字符作为其 mapfile 内置的分隔符。 [discussion]

您可以做的是让 xmlstarlet 输出 0xFFFF,使用 perl(或其他东西)将 0xFFFF 转换为 NUL,最后,使用带有 NUL 定界符的 mapfile:

mapfile -d '' -t arr < <(
  xmlstarlet sel -t -m /data/datapoint \
  -o 'datapoint' -o $'\uFFFF' -v ./@attribute-1 -o $'\uFFFF' data.xml \
  | perl -CS -0xFFFF -l0 -pe ''
)