プロが教えるわが家の防犯対策術!

xml→xmlを行うxsltの記述方法で質問があります。
元のxmlの例を下に示します。

<?xml version="1.0" encoding="Shift_JIS" ?>
<root>
<A1>
<B1>
<DATA1>aaa</DATA1>
<DATA2>bbb</DATA2>
</B1>
</A1>
<A2>
<DATA3>ccc</DATA3>
<DATA4>ddd</DATA4>
<B2>
<DATA5>eee</DATA5>
<C1>
<DATA6>fff</DATA6>
</C1>
<DATA7>ggg</DATA7>
</B2>
</A2>
<DATA8>hhh</DATA8>
</root>

(実際はDATA1,DATA2のような規則的な要素名ではありません)
変換後のxmlとしては

<root>
<DATA1>aaa</DATA1>
<DATA2>bbb</DATA2>
      ・
      ・
      ・
<DATA8>hhh</DATA8>
</root>

のように、値を持っている要素だけを、ルートノードの下に記述したものが欲しいのです。

作った物としては、
 <xsl:template match="DATA1" >
  <xsl:copy>
   <xsl:value-of select="." />
 </xsl:copy>
 </xsl:template>
このようなtemplateをDATA1-8まで記述するものです。
何か簡潔な記述方法はないでしょうか?
よろしくお願いいたします。

A 回答 (3件)

=================================Q4519133-1.xml(入力)======================


<?xml version="1.0" encoding="UTF-8" ?>
<root>
<A1>
<B1>
<DATA1>aaa</DATA1>
<DATA2>bbb</DATA2>
</B1>
</A1>
<!-- このA2要素自体は取得されない-->
<A2>xxx <DATA3>ccc</DATA3>
<DATA4>ddd</DATA4>
<B2>
<DATA5>eee</DATA5>
<C1>
<DATA6>fff</DATA6>
</C1>
<DATA7>gg<!-- ppp -->g</DATA7> <!--DATA7は取得される-->
</B2>
</A2>
<DATA8>hhh</DATA8>
</root>

=================================Q4519133-1.xsl(変換)======================
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output indent="yes"/>

<xsl:template match="/*">
<xsl:element name="{local-name(.)}" namespace="{namespace-uri(.)}">
<xsl:apply-templates />
</xsl:element>
</xsl:template>

<xsl:template match="text()">
<xsl:choose>
<!--
質問文中に指示が無かったので、
1.最下層にある「空要素」は取得しません。(空の要素自体出力されない。)
2.コメントノード・処理命令・CDATAマーク区間は階層としない
3.コードが示すとおり,混在内容に含まれる,テキストノードのある要素は取得しません。
4.ただし,テキストノード以外の内容がコメント・処理命令・CDATAマーク区間のみである
要素については取得した。嫌ならpreceding-sibling::node()とでもすれば良い。
5.取得した要素についてはコピーを行なった。テキストノードだけが欲しいなどの場合は
xsl:elementやxsl:value-of selectで地道に書く必要がある。
-->

<!-- 後半の条件がないとDATA7が二つ取得されるハメになる-->
<xsl:when test="count(preceding-sibling::*|following-sibling::*) = 0 and count(preceding-sibling::text()) = 0">
<xsl:copy-of select="parent::*" />
</xsl:when>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>

=================================Q4519133-2.xml(結果)======================
<?xml version="1.0" encoding="utf-8"?>
<root>
<DATA1>aaa</DATA1>
<DATA2>bbb</DATA2>
<DATA3>ccc</DATA3>
<DATA4>ddd</DATA4>
<DATA5>eee</DATA5>
<DATA6>fff</DATA6>
<DATA7>gg<!-- ppp -->g</DATA7>
<DATA8>hhh</DATA8>
</root>
==========================
あんまりエレガントじゃないな
テキストノードからやった方が楽かと思ったら混在内容考えるとそうでもなかったorz
    • good
    • 0
この回答へのお礼

書き込みありがとうございます!
明日早速教えていただいた2通りのやり方を試して、勉強させていただきます。

お礼日時:2008/12/01 23:43

テキストノードから考えてたの,やっぱり考え直すかも。

(コメントノードと処理命令ノードのみからなるノードのこと忘れてる)
    • good
    • 0

<?xml version="1.0" encoding="UTF-8"?>


<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output indent="yes"/>

<xsl:template match="/*">
<xsl:element name="{local-name(.)}" namespace="{namespace-uri(.)}">
<xsl:apply-templates />
</xsl:element>
</xsl:template>

<xsl:template match="*">
<xsl:choose>
<xsl:when test="count(*) = 0">
<xsl:copy-of select="." />
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="*" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>

このほうが圧倒的に簡単だね。(ただし,空要素はとってくる方針に変更)

この回答への補足

himajin100000様

適用したところ、希望通りの出力結果となりました。
このスタイルシートの内容について確認させてください。

1.
<xsl:template match="/*">
<xsl:element name="{local-name(.)}" namespace="{namespace-uri(.)}">
<xsl:apply-templates />
</xsl:element>
</xsl:template>

上記の部分で、xmlのルートノード以下全要素に対して、出力要素を作成しに行くのは分かるのですが、nameとnamespaceに何をしているのかがイマイチ掴めません。
nameに要素名をコピー、namespaceには要素の名前空間URI(?)をコピー?しているのでしょうか。
そもそもこのnamespaceは何故必要になるのでしょうか。

2.<xsl:template match="*">
<xsl:choose>
<xsl:when test="count(*) = 0">
<xsl:copy-of select="." />
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="*" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>

子の要素を持たない要素を判定するのが
<xsl:when test="count(*) = 0">
この部分。この条件を通ればコピーして、要素を出力。
<xsl:otherwise>
<xsl:apply-templates select="*" />
</xsl:otherwise>
の所は繰り返し処理を短くするために、selectで指定していると考えてよいのでしょうか。

以上2点の追加質問申し訳ございません。
またよろしくお願いいたします。

補足日時:2008/12/03 03:33
    • good
    • 0

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