web-dev-qa-db-ja.com

xmlstarletを使用して別の要素の下に新しい要素を挿入するにはどうすればよいですか?

$ vim test.xml

<?xml version="1.0" encoding="UTF-8" ?>
<config>
</config>
$ xmlstarlet ed -i "/config" -t elem -n "sub" -v "" test.xml
<?xml version="1.0" encoding="UTF-8"?>
<sub></sub>
<config>
</config>

しかし、私はsubをconfigの子にしたかったのです。 -iのxpathパラメーター をどのように変更する必要がありますか?

ボーナス:子を属性で直接挿入し、値に設定することもできますか?何かのようなもの:

$ xmlstarlet ed -i "/config" -t elem -n "sub" -v ""  -a attr -n "class" -v "com.foo" test.xml
26
simpatico

使用する -s(または--subnode) の代わりに -i。ボーナスに関しては、属性を持つ要素を直接挿入することはできませんが、すべての編集操作は順番に実行されるため、要素を挿入してから属性を追加するには、次のようにします。

> 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>
20
npostavs

同様の問題がありました。Tomcat構成ファイル(server.xml)があり、事前定義された属性を持つ<Resource>タグを<GlobalNamingResources>セクションに挿入する必要がありました。

以前は次のようになりました。

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

これが私が達成したかったことです:

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

これが私がそれをした方法です(シェルスクリプトからの抜粋):

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

秘訣は、新しい要素に一時的に一意の名前を付けて、後でXPATH式で見つけられるようにすることです。すべての属性が追加された後、名前はResourceに戻されます(-rを使用)。

他のxmlstarletオプションの意味:

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

XMLStarletのバージョン1.4.0(2012- 08-26日付)から、$prev(または$xstar:prev)を-i-a、および-sの引数として使用して、最後に挿入されたノードセットを参照できます。ファイルdoc/xmlstarlet.txtexamples/ed-backref1examples/ed-backref2、およびexamples/ed-backref-deleteのXMLStarletソースコードの例を参照してください。一時的な要素名で要素を挿入し、最後に名前を変更するというトリックを使用する必要がなくなりました。例examples/ed-backref2は、以前に作成されたメモを参照するために使用する変数を定義する方法を示すのに特に役立ちます。これにより、ノードから「ナビゲート」するために$prev/..などのトリックを実行する必要がなくなります。

6
Richard Walker

この例は、<GlobalNamingResources><Server>要素にラップするまで機能しませんでした。

1
George Smith

上記のcelluxからトリックを試しました。ありがとう!しかし、フォーマットは永続化されませんでした。試してみると、オプション-Pと-Sを削除し、フォーマットの問題はなくなりました。 CentOSを使用しています。これは誰かを助けることができるかもしれません。

0
dev