
У меня есть файл SVG, который представляет собой XML-документ:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape">
<defs
id="defs2">
<!-- a lot of stuff> </defs>
<!-- more stuff-->
</svg>
Я хочу добавить префикс svg: ко всем тегам, соответствующим пространству имен по умолчанию, чтобы получить следующий вывод:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg:svg
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape">
<svg:defs
id="defs2">
<!-- a lot of stuff> </svg:defs>
<!-- more stuff-->
</svg:svg>
Я уверен, что это возможно сделать одной или несколькими командными строками из оболочки, используяxmllintи/илиxmlstarletно я не могу этого сделать.
решение1
Прошло много времени с тех пор, как вы спрашивали. Тем не менее...
xmlstarlet edit
's -r
/ --rename
действие требует буквального значения для нового имени, поэтому функции XPath отсутствуют. Однако, xmlstarlet select
может использоваться как генератор кода для создания команды редактирования:
xmlstarlet select -t \
--var sq -o "'" -b \
-o 'xmlstarlet edit --pf \' -n \
-m 'set:distinct(//_:*)' \
-o ' -r ' -v 'concat($sq,"//_:",local-name(),$sq)' \
-o ' -v ' -v 'concat($sq,"svg:",local-name(),$sq)' -o ' \' -n \
-b \
-f -n \
file.xml
где
- выражение
//_:*
соответствует всем узлам элементов в пространстве имен по умолчанию (_
сокращение находится вxmlstarlet
руководство пользователя) - функция EXSLT
set:distinct
устраняет дубликаты -o
выводит строковый литерал,-n
новую строку,-f
входной путь/URL (но-
для stdin)-b
завершает текущий контейнер (-m
,--var
без=
, ао)- добавление
-C
опции перед-t
списком сгенерированного кода XSLT
Выход:
xmlstarlet edit --pf \
-r '//_:svg' -v 'svg:svg' \
-r '//_:defs' -v 'svg:defs' \
file.xml
где
-P
/--pf
сохраняет исходное форматирование- добавление параметра
-L
/--inplace
послеedit
поддерживает редактирование на месте (не в руководстве пользователя, а в xmlstarlet.txt)
Чтобы выполнить вывод как скрипт оболочки:
xmlstarlet-select-command | sh -s > result.xml
Если вы хотите избежать EXSLT, вместо этого -m '//_:*' --sort 'A:T:-' .
передайте вывод через uniq
, или просто -m '//_:*'
с возможными дубликатами.
решение2
Использование xmlstarlet
в особенно жестокой манере (жду правильный xpath)
for x in $(xmlstarlet sel -t -m "//*" -n -v "name()" file1.xml | sort | uniq); do
xmlstarlet ed -r "//svg:$x" -v "svg:$x" file1.xml > tmp.xml;
mv tmp.xml file1.xml;
done
Поскольку вы уже объявили пространство имен svg
, вам необходимо вызвать его, чтобы xpath
изменить буквальное значение имен узлов.