Index > XSLTで子要素(テキスト)を属性にする記述、およびその逆変換
Sun, December 27, 2009

XSLTで子要素(テキスト)を属性にする記述、およびその逆変換

このXSLのイディオムはあまりによく使うのでメモ。

やりたいこと その1 子要素を属性値にする

title要素の子要素(テキスト)を value の属性値に設定する。

FrameMakerでは、章タイトルをボディページではなく、マスターページに記述する場合があり、 そのときによく使うテクニックです。

変換前

<?xml version="1.0" encoding="UTF-8"?>
<book>
  <title>設置と接続</title>
</book>

変換後

<?xml version="1.0" encoding="UTF-8"?>
<book>
  <title value="設置と接続" />
</book>

変換前から変換後を作り出す conv.xsl

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

    <!-- すべての内容をコピーするお約束指定 -->
    <xsl:template match="@*|node()" >
        <xsl:copy>
            <xsl:apply-templates select="@*|node()" />
        </xsl:copy>
    </xsl:template>


    <!-- title要素の内容を value属性に入れる -->
    <xsl:template match="title" >
        <xsl:element name="{name()}" >
            <xsl:copy-of select="@*" />
            <xsl:attribute name="value">
                <xsl:value-of select="." />
            </xsl:attribute>
        </xsl:element>
    </xsl:template>

</xsl:stylesheet>

変換を実行

$ xsltproc conv.xsl sample.xml

結果が標準出力されます。

やりたいこと その2 属性値を子要素にする

要は先ほどの逆。 結果として元に戻る。

逆の変換は、 XML RoundTripをする上では必須テックニック。

変換後から変換前に戻す reconv.xsl

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

    <!-- すべての内容をコピーするお約束指定 -->
    <xsl:template match="@*|node()" >
        <xsl:copy>
            <xsl:apply-templates select="@*|node()" />
        </xsl:copy>
    </xsl:template>


    <!-- title要素の内容を value属性に入れる -->
    <xsl:template match="title" >
        <xsl:element name="{name()}" >
            <xsl:for-each select="@*" >
                <xsl:if test=" not(name()='value') " >
                    <xsl:attribute name="{name()}">
                        <xsl:value-of select="."/>
                    </xsl:attribute>
                </xsl:if>
            </xsl:for-each>

            <xsl:value-of select="@value"/>
        </xsl:element>
    </xsl:template>

</xsl:stylesheet>

ポイント

xsl:for-each を使って、属性を一つずつ取り出し、value 属性だけを除外する部分。

<xsl:for-each select="@*" >
    <xsl:if test=" not(name()='value') " >
 Twitter
follow me on Twitter
 Categories