ノードは順不同
はじめに
ノードを入替えるxsltを考えてみよう.例えば,
<first>first</first>
<second>second</second>
でも
<second>second</second>
<first>first</first>
でも変換結果が
<first>first</first>
<second>second</second>
となるようなxsltである.つまり,firstとsecondが順不同にできるxsltを考えてみる.
環境は以下の通り.
兄弟ノード
サンプルとして以下のようなxmlを考える.
<?xml version="1.0" encoding="utf-8"?>
<root>
<first>first</first>
<second>second</second>
<third>third</third>
<second>2nd</second>
<first>1st</first>
<third>3rd</third>
</root>
必要なのはこれを以下のように出力するxsltである.
<?xml version="1.0" encoding="utf-8"?>
<root>
<first>first</first>
<second>second</second>
<third>third</third>
<first>1st</first>
<second>2nd</second>
<third>3rd</third>
</root>
考え方としては,
- まずfirst要素を出力
- 前または後にあるsecond要素を出力
- thirdを出力
と順番に対象とすれば良い.ということで作ってみた.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output
method="xml"
encoding="UTF-8"
indent="yes"/>
<xsl:template match="/root">
<xsl:copy>
<xsl:apply-templates select="first"/>
</xsl:copy>
</xsl:template>
<xsl:template match="first">
<xsl:copy-of select="."/>
<xsl:apply-templates select="following::second[1]|preceding::second[1]"/> <!-- 前方or後方直近のsecond要素にマッチ -->
<xsl:apply-templates select="following::third[1]"/>
</xsl:template>
<xsl:template match="second|third">
<xsl:copy-of select="."/>
</xsl:template>
</xsl:stylesheet>
followingまたはprecedingで軸を指定して述語で直近の(1番目の)secondまたはthird要素を指定している.1番目の要素を指定しないと,前方または後方にある全要素が対象になるので注意が必要である.
親子ノード
兄弟だけでなく,親子ノードでも順不同にするxsltを考えてみよう.以下のようなxmlを考える.
<?xml version="1.0" encoding="utf-8"?>
<root>
<first>
first
<second>
second
<third>
third
</third>
</second>
</first>
<second>
2nd
<first>
1st
<third>
3rd
</third>
</first>
</second>
</root>
firstとsecondを入替えて,以下のような結果を出力するxsltを考えよう.
<?xml version="1.0" encoding="utf-8"?>
<root>
<first>
first
<second>
second
<third>
third
</third>
</second>
</first>
<first>
1st
<second>
2nd
<third>
3rd
</third>
</second>
</first>
</root>
考え方としては,
- まずfirst要素を出力.rootの子要素であるfirstと孫要素であるfirstがあるので注意.
- 親または子にあるsecond要素を出力
- thirdを出力.secondの子要素であるthirdと孫要素であるthirdがあるので注意.
と順番に対象とすれば良い.ということで作ってみた.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output
method="xml"
encoding="UTF-8"
indent="yes"/>
<xsl:template match="/root">
<xsl:copy>
<xsl:apply-templates select="descendant::first"/> <!-- 子孫のfirst要素が対象 -->
</xsl:copy>
</xsl:template>
<xsl:template match="first">
<xsl:copy>
<xsl:value-of select="text()"/>
<xsl:apply-templates select="child::second|parent::second"/> <!-- 親または子のsecond -->
</xsl:copy>
</xsl:template>
<xsl:template match="second">
<xsl:copy>
<xsl:value-of select="text()"/>
<xsl:apply-templates select="descendant::third"/> <!-- 子孫のthird -->
</xsl:copy>
</xsl:template>
<xsl:template match="third">
<xsl:copy>
<xsl:apply-templates select="*|text()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>