16

わかりました、この質問にはさまざまなバリエーションがありますが、私が解決しようとしていることに正確に答えている人はいません。おそらく、私がやろうとしていることに他の答えの1つを適用する方法がわかりません.

次のような XML があります。

<?xml version="1.0" encoding="utf-8"?>
<message>
  <cmd id="api_info">
    <api-version>1.0</api-version>
    <api-build>1.0.0.0</api-build>
  </cmd>
</message>

これで、この XML に適用する XSLT 変換ができました。XSLT は次のようになります。

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:fo="http://www.w3.org/1999/XSL/Format"
                xmlns:xs="http://www.w3.org/2001/XMLSchema"
                xmlns:fn="http://www.w3.org/2005/xpath-functions"
                version="2.0">

    <xsl:output method="xml" version="1.0" indent="yes"/>

    <xsl:template match="/">
        <xsl:apply-templates select="message"/>
    </xsl:template>

    <xsl:template match="message">
        <xsl:element name="message" xmlns="http://www.companyname.com/schemas/product/Version001">
            <xsl:apply-templates select="/message/cmd/@id"/>
        </xsl:element>
    </xsl:template>

    <xsl:template match="/message/cmd/@id">
        <xsl:variable name="_commandType" select="/message/cmd/@id"/>
        <xsl:element name="messageHeader">
            <xsl:element name="cmdType">
                <xsl:value-of select="$_commandType"/>
            </xsl:element>
        </xsl:element>

        <xsl:element name="messageBody">
            <xsl:choose>
                <xsl:when test="$_commandType = 'api_info'">
                    <xsl:element name="apiInfoBody">
                        <xsl:element name="apiVersion">
                            <xsl:value-of select="/message/cmd/api-version"/>
                        </xsl:element>
                        <xsl:element name="apiBuild">
                            <xsl:value-of select="/message/cmd/api-build"/>
                        </xsl:element>
                    </xsl:element>
                </xsl:when>
                <xsl:when test="$_commandType = 'communicationError'">
                    <xsl:element name="communicationErrorBody">
                        <xsl:element name="errorCode">
                            <xsl:value-of select="error-code"/>
                        </xsl:element>
                        <xsl:element name="badCmd">
                            <xsl:value-of select="bad-cmd"/>
                        </xsl:element>
                    </xsl:element>
                </xsl:when>
            </xsl:choose>
        </xsl:element>
    </xsl:template>
</xsl:stylesheet>

私が得る出力は、基本的に私が望むものであり、次のようになります。

<?xml version="1.0" encoding="UTF-8"?>
<message xmlns="http://www.companyname.com/schemas/product/Version001">
    <messageHeader xmlns="">
        <cmdType>api_info</cmdType>
    </messageHeader>
    <messageBody xmlns="">
        <apiInfoBody>
            <apiVersion>1.0</apiVersion>
            <apiBuild>1.0.0.0</apiBuild>
        </apiInfoBody>
    </messageBody>
</message>

しかし、私が望んでいないのは、<messageHeader> 要素と <messageBody> 要素のxmlns = " "属性です。

これらの要素の XSLT で名前空間を明示的に指定すると、不要な属性がそれらの属性の子に 1 レベル下にプッシュされることがわかりました。

XSLT 全体を調べて、xmlns="" http://www.companyname.com/schemas/product/Version001 "属性を各xsl:element定義に明示的に追加することもできますが、より洗練された方法. 私たちプログラマーは怠惰すぎて, この種のナンセンスのショートカットを持たない. 私のXSLTが短縮された例のように単純なもので構成されていない場合, 私はそのようにしたくなる. しかし、私はそこを知っている.より良い方法でなければなりません。

ここで何が欠けているか知っている人はいますか?

ありがとう、

アラームトリッパー

4

3 に答える 3

0

わかりました、私はそれを理解しました。

必要な XSLT は次のようになります。

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:fo="http://www.w3.org/1999/XSL/Format"
                xmlns:xs="http://www.w3.org/2001/XMLSchema"
                xmlns:fn="http://www.w3.org/2005/xpath-functions"
                exclude-result-prefixes="xsl fo xs fn">

    <xsl:output method="xml" version="1.0" indent="yes"/>

    <xsl:template match="/">
        <xsl:apply-templates select="message"/>
    </xsl:template>

    <xsl:template match="message">
        <message namespace="http://www.companyname.com/schemas/product/Version001">
            <xsl:apply-templates select="/message/cmd/@id"/>
        </message>
    </xsl:template>

    <xsl:template match="/message/cmd/@id">
        <xsl:variable name="_commandType" select="/message/cmd/@id"/>

        <xsl:element name="messageHeader">
            <xsl:element name="cmdType">
                <xsl:value-of select="$_commandType"/>
            </xsl:element>
        </xsl:element>

        <xsl:element name="messageBody">
            <xsl:choose>
                <xsl:when test="$_commandType = 'api_info'">
                    <xsl:element name="apiInfoBody">
                        <xsl:element name="apiVersion">
                            <xsl:value-of select="/message/cmd/api-version"/>
                        </xsl:element>
                        <xsl:element name="apiBuild">
                            <xsl:value-of select="/message/cmd/api-build"/>
                        </xsl:element>
                    </xsl:element>
                </xsl:when>
                <xsl:when test="$_commandType = 'communicationError'">
                    <xsl:element name="communicationErrorBody">
                        <xsl:element name="errorCode">
                            <xsl:value-of select="error-code"/>
                        </xsl:element>
                        <xsl:element name="badCmd">
                            <xsl:value-of select="bad-cmd"/>
                        </xsl:element>
                    </xsl:element>
                </xsl:when>
            </xsl:choose>
        </xsl:element>
    </xsl:template>
</xsl:stylesheet>

これを修正した変更は、exclude-result-prefixes属性を<xsl:stylesheet>要素に追加し、次のセクションを変更することでした。

    <xsl:template match="message">
        <xsl:element name="message" xmlns="http://www.companyname.com/schemas/product/Version001">
            <xsl:apply-templates select="/message/cmd/@id"/>
        </xsl:element>
    </xsl:template>

代わりに次のようになります。

    <xsl:template match="message">
        <message namespace="http://www.companyname.com/schemas/product/Version001">
            <xsl:apply-templates select="/message/cmd/@id"/>
        </message>
    </xsl:template>

そして今、私は再び幸せです。

おそらくもっと良い方法がありますが、これは私にとってはうまくいっています。今後の提案は引き続き歓迎します。

于 2009-12-04T04:38:40.047 に答える
0

Jim Garrison の (更新された) 回答だけで十分です。しかし、あなたが投稿した更新されたスタイルシートは、結果に「名前空間」属性を出力するので、それが何の役に立つのかわかりません。

理解しておくべき重要なことは、デフォルトの名前空間がどのように機能するかです。xmlns を結果に出力できる属性と考えないでください。代わりに、スタイルシートの字句的な詳細と考えてください。その目的は、その下にあるすべてのもの (要素自体と、オーバーライドされるまでのすべての子孫) のデフォルトの名前空間を設定することです。(同様に、結果の XML にも同じ機能があり、スタイルシート自体とは構造が大きく異なります。)

スタイルシートのリテラル結果要素 (例: <message>) と <xsl:element> 命令 (例: <xsl:element name="message">) は、指定された名前が使用されていない場合、両方ともデフォルトの名前空間を使用します。プレフィックス。それらすべてに同じ名前空間を持たせたい場合は、Jim Garrison が提案したように、スタイルシートの先頭にデフォルトの名前空間を配置する必要があります。

そうしないと、結果に xmlns="" (これらの要素の名前空間の設定を解除) が含まれる理由である、その名前空間にない要素がいくつか含まれることになります。

于 2009-12-07T21:46:24.240 に答える