Saltar al contenido

¿Cómo insertar un nuevo elemento debajo de otro con xmlstarlet?

Solución:

Tuve un problema similar: tenía un archivo de configuración de Tomcat (server.xml) y tuve que insertar un <Resource> etiqueta con atributos predefinidos en el <GlobalNamingResources> sección.

Así es como se veía antes:

<GlobalNamingResources>
    <!-- Editable user database that can also be used
         by UserDatabaseRealm to authenticate users
    -->
    <Resource name="UserDatabase"
              auth="Container"
              type="org.apache.catalina.UserDatabase"
              description="User database that can be updated and saved"
              factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
              pathname="conf/tomcat-users.xml" />
</GlobalNamingResources>

Esto es lo que quería lograr:

<GlobalNamingResources>
    <!-- Editable user database that can also be used
         by UserDatabaseRealm to authenticate users
    -->
    <Resource name="UserDatabase"
              auth="Container"
              type="org.apache.catalina.UserDatabase"
              description="User database that can be updated and saved"
              factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
              pathname="conf/tomcat-users.xml" />
    <Resource name="jdbc/templateassets"
              auth="Container"
              type="javax.sql.DataSource"
              driverClassName="com.mysql.jdbc.Driver"
              url="jdbc:mysql://DBHOST:DBPORT/DBNAME?createDatabaseIfNotExist=false&amp;useUnicode=true&amp;characterEncoding=utf-8"
              username="DBUSER"
              password="DBPASS"
              maxActive="150"
              maxIdle="10"
              initialSize="10"
              validationQuery="SELECT 1"
              testOnBorrow="true" />
</GlobalNamingResources>

Así es como lo hice (fragmento de un script de shell):

if [ -n "$(xmlstarlet sel -T -t -v "/Server/GlobalNamingResources/Resource[@name="jdbc/templateassets"]/@name" server.xml)" ]; then
  echo "Resource jdbc/templateassets already defined in server.xml"
else
  echo "Adding resource jdbc/templateassets to <GlobalNamingResources> in server.xml"
  xmlstarlet ed -P -S -L -s /Server/GlobalNamingResources -t elem -n ResourceTMP -v "" 
    -i //ResourceTMP -t attr -n "name" -v "jdbc/templateassets" 
    -i //ResourceTMP -t attr -n "auth" -v "Container" 
    -i //ResourceTMP -t attr -n "type" -v "javax.sql.DataSource" 
    -i //ResourceTMP -t attr -n "driverClassName" -v "com.mysql.jdbc.Driver" 
    -i //ResourceTMP -t attr -n "url" -v "jdbc:mysql://DBHOST:DBPORT/DBNAME?createDatabaseIfNotExist=false&useUnicode=true&characterEncoding=utf-8" 
    -i //ResourceTMP -t attr -n "username" -v "DBUSER" 
    -i //ResourceTMP -t attr -n "password" -v "DBPASS" 
    -i //ResourceTMP -t attr -n "maxActive" -v "150" 
    -i //ResourceTMP -t attr -n "maxIdle" -v "10" 
    -i //ResourceTMP -t attr -n "initialSize" -v "10" 
    -i //ResourceTMP -t attr -n "validationQuery" -v "SELECT 1" 
    -i //ResourceTMP -t attr -n "testOnBorrow" -v "true" 
    -r //ResourceTMP -v Resource 
    server.xml
fi

El truco consiste en dar temporalmente un nombre único al nuevo elemento, de modo que se pueda encontrar más tarde con una expresión XPATH. Una vez que se han agregado todos los atributos, el nombre se cambia de nuevo a Recurso (con -r).

El significado de las otras opciones de xmlstarlet:

-P (or --pf)        - preserve original formatting
-S (or --ps)        - preserve non-significant spaces
-L (or --inplace)   - edit file inplace

Usar -s (o --subnode) en lugar de -i. Con respecto a la bonificación, no puede insertar un elemento con un atributo directamente, pero dado que cada operación de edición se realiza en secuencia, para insertar un elemento y luego agregar un atributo:

> xml ed -s /config -t elem -n sub -v "" -i /config/sub -t attr -n class -v com.foo test.xml
<?xml version="1.0" encoding="UTF-8"?>
<config>
<sub class="com.foo"></sub></config>

A partir de la versión 1.4.0 de XMLStarlet (con fecha del 26 de agosto de 2012), puede utilizar $prev (o $xstar:prev) como argumento para -i, -a, y -s para hacer referencia al último conjunto de nodos insertado. Vea los ejemplos en el código fuente de XMLStarlet en los archivos doc/xmlstarlet.txt, examples/ed-backref1, examples/ed-backref2, y examples/ed-backref-delete. Ya no necesita usar el truco de insertar el elemento con un nombre de elemento temporal y luego renombrarlo al final. El ejemplo examples/ed-backref2 es particularmente útil para mostrar cómo definir una variable para usar para referirse a una (la) nota creada previamente para que no necesite hacer trucos como $prev/.. para “navegar” fuera de un nodo.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *