Quero adicionar um prefixo de namespace às tags do namespace padrão de um documento XML do shell

Quero adicionar um prefixo de namespace às tags do namespace padrão de um documento XML do shell

Eu tenho um arquivo SVG, que é um documento 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>

Quero adicionar o prefixo svg: a todas as tags correspondentes ao namespace padrão para obter a próxima saída:

<?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>

Tenho certeza de que isso é possível em uma ou algumas linhas de comando do shell usandoxmllinte/ouxmlstarletmas não consigo lidar com isso.

Responder1

Já faz um tempo desde que você perguntou. No entanto ...

xmlstarlet editA ação -r/ --renamerequer um valor literal para o novo nome, portanto as funções XPath estão fora. No entanto, xmlstarlet select pode ser usado como gerador de código para produzir o comando de edição:

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 

onde

  • a //_:*expressão corresponde a todos os nós de elemento no namespace padrão (o _atalho está noxmlstarlet Guia do usuário)
  • a função EXSLTset:distinct elimina duplicatas
  • -ogera uma string literal, -numa nova linha, -fo nome do caminho/URL de entrada (mas -para stdin)
  • -btermina o contêiner atual ( -m, --varsem =, ao)
  • adicionar uma -Copção antes -tde listar o código XSLT gerado

Saída:

xmlstarlet edit --pf \
  -r '//_:svg'  -v 'svg:svg' \
  -r '//_:defs'  -v 'svg:defs' \
file.xml

onde

  • -P/ --pfpreserva a formatação original
  • adicionar uma opção -L/ depois de suportar edição no local (não no guia do usuário, mas em --inplaceeditxmlstarlet.txt)

Para executar a saída como um script de shell:

xmlstarlet-select-command | sh -s > result.xml

Caso você queira evitar EXSLT, em vez disso -m '//_:*' --sort 'A:T:-' . , canalize a saída através de uniq, ou simplesmente -m '//_:*'com possíveis duplicatas.

Responder2

Usando xmlstarletde uma forma particularmente brutal (aguardo o xpath adequado)

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

Como você já declarou o namespace svg, é necessário invocá-lo para xpathalterar o valor literal dos nomes dos nós.

informação relacionada