Как разделить вывод xmlstarlet с помощью nul?

Я пытаюсь использовать nul (U + 0) для разграничения значений xml в выводе xmlstarlet. xmlstarlet игнорирует -o '', -o $'\0' и -o '\0'.

Я знаю, что могу использовать другие символы, такие как различные разделители полей, для разграничения вывода. Проблема с этим подходом заключается в том, что эти символы также могут существовать как данные. Я не хочу никакой двусмысленности.

Я хочу использовать nul специально, потому что это единственное значение, которое не может быть представлено в необработанном XML.

Итак, повторю мой вопрос: Как разделить вывод xmlstarlet с помощью nul?

Дополнительная информация

Я включил следующую информацию по просьбе людей, которые просили ее. Хотя я ценю ваше желание помочь, пожалуйста, не предлагайте решения XY. Я только ищу ответ на свой вопрос, как представлено.

Данные, с которыми я работаю, выглядят так:

<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 $'\0' -v ./@attribute-1 -o $'\0' 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.|

person Tenders McChiken    schedule 05.12.2020    source источник
comment
Каков именно ваш ожидаемый результат с учетом выборки данных в вопросе?   -  person Jack Fleeting    schedule 05.12.2020
comment
Посмотрите en.wikipedia.org/wiki/Valid_characters_in_XML и выберите символ, разрешенный в Версия XML, которую вы используете.   -  person Shawn    schedule 05.12.2020
comment
@JackFleeting Я обновил свой вопрос, указав шестнадцатеричный дамп желаемого результата.   -  person Tenders McChiken    schedule 06.12.2020
comment
@Shawn К сожалению, это полная противоположность тому, что я хочу. Весь смысл использования nul заключается в том, что он не может быть представлен в xml. Я обновил свой вопрос, чтобы сделать это требование более ясным.   -  person Tenders McChiken    schedule 06.12.2020
comment
Вам повезет больше, если вы напишете файл perl/python/etc. script, чтобы проанализировать xml и распечатать его по желанию.   -  person Shawn    schedule 06.12.2020
comment
@Shawn Конкретный проект, с которым я работаю, написан на bash, поэтому переключение не вариант. Мне нужно, чтобы эти значения были разделены в bash. К счастью, я нашел решение :)   -  person Tenders McChiken    schedule 06.12.2020


Ответы (3)


К сожалению, 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", "\0"))'
person Tenders McChiken    schedule 06.12.2020

Вы можете использовать $'\1', который в большинстве ситуаций должен быть таким же хорошим, как null:

mapfile -d $'\1' -t ARRAY < <( xmlstarlet sel -t -m "XPATH" -v "XPATH" -o $'\1' -v 'XPATH' "FILE" )
person Philippe    schedule 05.12.2020
comment
Только с XML 1.1. en.wikipedia.org/wiki/Valid_characters_in_XML - person Shawn; 05.12.2020
comment
@Shawn, спасибо, что указали на различия в версиях XML. Знаете ли вы, как узнать версию XML, поддерживаемую xmlstarlet? - person Philippe; 05.12.2020
comment
Тот, что у меня есть (1.6.1), поддерживает только 1.0, хотя я подозреваю, что это больше зависит от базовой версии libxml2. - person Shawn; 06.12.2020
comment
@Шон, у меня тоже (1.6.1). где вы видели, что он поддерживает только XML 1.0? Кстати, приведенная выше команда mapfile работает с (1.6.1). - person Philippe; 06.12.2020
comment
Передайте ему файл XML, начинающийся с <?xml version="1.1"?>. Найдите предупреждающее сообщение. - person Shawn; 06.12.2020
comment
Это не сработает, поскольку U+1 можно представить в XML, что может привести к двусмысленности. Кроме того, этот вопрос специально запрашивает nul в выводе. - person Tenders McChiken; 06.12.2020
comment
xmlstarlet поддерживает только XML 1.0, где U+1 не может быть представлено. - person Philippe; 06.12.2020
comment
@Филипп Очень справедливое замечание. я все же хотел бы избежать этого подхода на случай, если xmlstarlet примет поддержку XML 1.1 в будущем. - person Tenders McChiken; 06.12.2020
comment
Разумно ли ожидать, что xmlstarlet примет поддержку XML 1.1, если она не делала этого последние 14 лет? - person Philippe; 06.12.2020

Вот вариант ответа @TendersMcChiken с заменой python на perl:

xmlstarlet sel -t -m /data/datapoint \
  -o 'datapoint' -o $'\uffff' -v ./@attribute-1 -o $'\uffff' data.xml \ 
  | perl -C -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. [источник]

person Robin A. Meade    schedule 08.07.2021