0


XML 入力のような入力 xml があります。

    <parent>
        <child>
            <child2 name="Action">Change</child2>
            <child1 name="Change">

                <child2 name="Dest_Author">Author1</child2>

                <child2 name="Book1">BookID1</child2>
                <child2 name="Type1">General</child2>
                <child2 name="Pages1">100</child2>

                <child2 name="Book2">BookID2</child2>
                <child2 name="Type2">Cooking</child2>
                <child2 name="Pages2">200</child2>

                <child2 name="Orig_Author">Author2</child2>

                <child2 name="Book1">BookID3</child2>
                <child2 name="Type1">General</child2>
                <child2 name="Pages1">150</child2>

                <child2 name="Book2">BookID4</child2>
                <child2 name="Type2">Cooking</child2>
                <child2 name="Pages2">120</child2>

            </child1>
        </child>
    </parent>

xslt 変換を使用して次の xml に変換したい
予想される XML 出力:

    <list>
        <author id="Author1">
            <book>
                <id>BookID1</id>
                <type>General</type>
                <pages>100</pages>
            </book>
            <book>
                <id>BookID1</id>
                <type>Cooking</type>
                <pages>200</pages>
            </book>
        </author>    
        <author id="Author2">
            <book>
                <id>BookID1</id>
                <type>General</type>
                <pages>150</pages>
            </book>
            <book>
                <id>BookID1</id>
                <type>Cooking</type>
                <pages>120</pages>
            </book>
        </author>
    </list>

xslt を使用して変換しようとしましたが、変換できませんでした。私のxsltは以下のようになります

<?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" omit-xml-declaration="yes" />
    <xsl:strip-space elements="*" />
    <xsl:template match="/">
        <xsl:apply-templates />
    </xsl:template>
    <xsl:template match="parent">
        <list>
            <xsl:apply-templates />
        </list>
    </xsl:template>
    <xsl:template match="child">
        <xsl:apply-templates />
    </xsl:template>
    <xsl:template match="child1">
        <xsl:choose>
            <xsl:when test="./@name='Change'">
                <author>
                    <xsl:attribute name="id"><xsl:value-of
                        select="./child2[@name='Dest_Author']" /></xsl:attribute>
                    <xsl:apply-templates />
                </author>
            </xsl:when>
        </xsl:choose>
    </xsl:template>
    <xsl:template match="child2">
        <xsl:choose>
            <xsl:when test="contains(@name,'Orig_Author')">
                <!-- I thought of changing the below code(line no 36-38) as
                </author>
                <author>
                    <xsl:attribute name="id"><xsl:value-of select="text()"/></xsl:attribute>
                but if do this it throws error "The element type "xsl:when" must be terminated by the matching end-tag "</xsl:when>"."
            -->
                <author>
                    <xsl:attribute name="id"><xsl:value-of select="text()"/></xsl:attribute>
                </author>
            </xsl:when>

            <xsl:when test="contains(@name,'Book')">
                <book>
                    <id>
                        <xsl:value-of select="text()" />
                    </id>
                    <xsl:variable name="next"
                        select="./following-sibling::node()[@name!=''][1]"></xsl:variable>
                    <xsl:choose>
                        <xsl:when test="contains($next/@name,'Type')">
                            <type>
                                <xsl:value-of select="$next" />
                            </type>
                            <pages>
                                <xsl:value-of select="$next/following-sibling::node()[@name!=''][1]" />
                            </pages>
                        </xsl:when>
                        <xsl:when test="contains($next/@name,'Pages')">
                            <pages>
                                <xsl:value-of select="$next" />
                            </pages>
                        </xsl:when>
                    </xsl:choose>
                </book>
            </xsl:when>
            <xsl:otherwise>    
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
</xsl:stylesheet>

XSLT 出力:

<list>
    <author id="Author1">
        <book>
            <id>BookID1</id>
            <type>General</type>
            <pages>100</pages>
        </book>
        <book>
            <id>BookID2</id>
            <type>Cooking</type>
            <pages>200</pages>
        </book>
        <author id="Author2"/>
        <book>
            <id>BookID3</id>
            <type>General</type>
            <pages>150</pages>
        </book>
        <book>
            <id>BookID4</id>
            <type>Cooking</type>
            <pages>120</pages>
        </book>
    </author>
</list>

誰かが私を助けて、正しい出力を得るためにxsltコードに必要な変更を教えてもらえますか

4

1 に答える 1

0

これをグループ化の問題として扱います。名前に が含まれていないそれぞれchild2を、名前に が含まれている最も近い先行する兄弟に関連付け、グループごとに 1 つの要素を生成ます。次に、グループ内で、各非要素を最も近い前の要素に接続し、グループごとに1 つの要素を生成します。_Author_AuthorauthorBookBookbook

XSLT には、要素をグループ化するために使用できるキーの概念があります。最初に 2 つのキーを定義します。

<xsl:key name="booksByAuthor" match="child2[starts-with(@name, 'Book')]"
   use="generate-id(preceding-sibling::child2[contains(@name, '_Author')][1])" />

これは、それぞれBook(つまり) を取得し、最も近い前の著者のchild2[@name = 'Book1' or @name='Book2' or ....]ID ( ) に基づいてグループ化キーを割り当てます。generate-id2 番目のキー

<xsl:key name="bookDetails"
   match="child2[not(contains(@name, '_Author') or starts-with(@name, 'Book'))]"
   use="generate-id(preceding-sibling::child2[starts-with(@name, 'Book')][1])" />

すべての「詳細」要素 (Something_Authorまたはのいずれでもない要素BookN) を、最も近い先行する Book でグループ化します。これらのキーによって階層構造が得られ、テンプレート マッチングの通常のシステムとしてスタイルシートの残りの部分をコーディングできます。

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"  version="1.0">
    <xsl:output method="xml" omit-xml-declaration="yes" />
    <xsl:strip-space elements="*" />

    <xsl:key name="booksByAuthor" match="child2[starts-with(@name, 'Book')]"
       use="generate-id(preceding-sibling::child2[contains(@name, '_Author')][1])" />

    <xsl:key name="bookDetails"
       match="child2[not(contains(@name, '_Author') or starts-with(@name, 'Book'))]"
       use="generate-id(preceding-sibling::child2[starts-with(@name, 'Book')][1])" />

    <xsl:template match="/parent">
        <list>
            <!-- process all the authors -->
            <xsl:apply-templates select=".//child2[contains(@name, '_Author')]" />
        </list>
    </xsl:template>

    <xsl:template match="child2[contains(@name, '_Author')]">
        <!-- for each author, create an author element -->
        <author id="{.}">
            <!-- and process this author's books -->
            <xsl:apply-templates select="key('booksByAuthor', generate-id())" />
        </author>
    </xsl:template>

    <xsl:template match="child2[starts-with(@name, 'Book')]">
        <!-- for each book, create a book element -->
        <book>
            <id><xsl:value-of select="." /></id>
            <!-- and process this book's details -->
            <xsl:apply-templates select="key('bookDetails', generate-id())" />
        </book>
    </xsl:template>

    <xsl:template match="child2[starts-with(@name, 'Type')]">
        <type><xsl:value-of select="." /></type>
    </xsl:template>

    <xsl:template match="child2[starts-with(@name, 'Pages')]">
        <pages><xsl:value-of select="." /></pages>
    </xsl:template>
</xsl:stylesheet>

Publisher1、 、 ...などの他の子タイプがある場合は、および とPublisher2同じ行に沿って追加のテンプレートを追加するだけです。TypePages

于 2013-09-26T10:14:56.747 に答える