dポイントプレゼントキャンペーン実施中!

Linux上で、
xmlstarletを使って、2つのxmlファイルを合成しようとしています。

一つ目のファイル、"list.xml"の内容は以下です。
---
<?xml version="1.0"?>
<x>
<e a="1">value1</e>
<e a="2">value2</e>
</x>
---
エレメントのリストです。

二つ目のファイル、"elem.xml"の内容は以下です。
---
<?xml version="1.0"?>
<x>
<e a="3">value3</e>
</x>
---
このファイルのエレメントを、list.xmlに付け加えようとしています。

最終的に、以下の内容のファイルを合成しようとしています。
---
<?xml version="1.0"?>
<x>
<e a="1">value1</e>
<e a="2">value2</e>
<e a="3">value3</e>
</x>
---

xmlstarletを使って、
$ xml ed -s "/x" -t elem -n e -v value3 -s "/x/e[last()]" -t attr -n a -v 3 list.xml
とすれば、目的の合成された内容が得られるんですが、あくまで、他のファイルからエレメントを
コピーしたいんです。

例えば、↓のコマンドは間違ってるんですが、イメージに一番近いものです。
$ xml ed -m "document('elem.xml')/x/e" "/x" list.xml

現状は、sedでlist.xmlの行末を削り、elem.xmlの内容をリダイレクトで追記し(>> list.xml)、
その後、削ったlist.xmlの行末を再び追記してますが、エレガントに解決できないでしょうか。

A 回答 (1件)

WinXPで実験してみた


・・・・が,エレガントじゃ全然ない。
ファイル名が気に入らなかったというか考えながら打つのが面倒くさいので
list.xml → hoge.xml
elem.xml → fuga.xml
となっている。

Editだとどうしても厳密に指定しなきゃいけなさそうな気がするので
諦めて新たにXSLTモドキを書いて別ファイル作ってしまえ!という策に出ることにした。こんなコマンド書くなら素直にXSLTファイルを別に用意してXSLTプロセッサに流したほうが楽だろうなあとは思う。

C:\xmlstarlet-1.0.1>xml sel -t -m "/x" -e "x" -m "@*" -c "." -b -m "e" -c "." -b -c "document('./fuga.xml')/x/e" -b
./hoge.xml

出力結果は以下の通り。
<x><e a="1">value1</e><e a="2">value2</e><e a="3">value3</e></x>

●ルート要素が共に各ファイルは/x/eという構造をしているものとしてのみ想定し,/x/aとか/x/text()があることは考慮されてない。

なお,一応XSLTの規格によれば
http://www.w3.org/TR/xslt#section-Creating-Eleme …
xsl:elementのname属性はattribute value templateらしいので
「ルート要素の要素名」という指定も可能だ。解説はしないので自分で読んどくれ。

●hoge.xmlのルートのx要素に属性が存在していた場合には一応コピーするようにしたが,fuga.xmlのルートのx要素と属性が異なっていた場合は保証しない。

最後にこのコードをXSLTに直しておく。
面倒くさいのでxsl:output要素のencoding属性等コマンドラインでも
以下のシートでも指定してないのでUTF-16になる可能性大ですが。その辺はヘルプ見て。

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/x">
<xsl:call-template name="t1"/>
</xsl:template>
<xsl:template name="t1">
<xsl:element name="x">
<xsl:for-each select="@*">
<xsl:copy-of select="." />
</xsl:for-each>
<xsl:for-each select="e">
<xsl:copy-of select="." />
</xsl:for-each>
<xsl:copy-of select="document('./fuga.xml')/x/e" />
</xsl:element>
</xsl:template>
</xsl:stylesheet>

この回答への補足

その後、色々と試してみて以下のような方法も見付けました。

$ cat <<EOF |xml ed -m "//e" "/x" |xml ed -d "/x/x" >list-new.xml
> <x>
> $(xml fo -o list.xml)
> $(xml fo -o elem.xml)
> </x>
> EOF

xml fo で余分な部分をstrip、catのヒアドキュメントを使い合成した
xmlファイルを xml ed で成形する力技的解決方法です。

補足日時:2008/04/25 17:42
    • good
    • 0
この回答へのお礼

回答頂きありがとうございます。
特にXSLTコードの添付、どのような環境でも実行できる汎用性が高い方法
のように見受けられます。これを、とっかかりに調べてみます。

お礼日時:2008/04/25 17:42

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!