- ベストアンサー
xmlstarletを使って他のファイルからエレメントをコピーする方法
- Linux上でxmlstarletを使用して、2つのxmlファイルを合成する方法を紹介します。
- xmlstarletコマンドの使用例を示し、目的の合成ファイルを生成する方法について説明します。
- また、エレガントな解決策についても考えてみましたが、簡潔な方法は見つかりませんでした。
- みんなの回答 (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-Elements-with-xsl:element 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>
お礼
回答頂きありがとうございます。 特にXSLTコードの添付、どのような環境でも実行できる汎用性が高い方法 のように見受けられます。これを、とっかかりに調べてみます。
補足
その後、色々と試してみて以下のような方法も見付けました。 $ 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 で成形する力技的解決方法です。