4

XML ドキュメントを変換しようとしています。私の XML 変換は、特定の要素の値に応じて、2 つの異なるタイプの基本要素になる可能性があります。

<xsl:template match="/">
  <xsl:choose>
    <xsl:when test="/databean/data[@id='pkhfeed']/value/text()='200'">
      <xsl:call-template name="StructureA">
        <xsl:with-param name="structure" select="//databean" />
      </xsl:call-template>
    </xsl:when>
    <xsl:otherwise>
      <xsl:call-template name="StructureB">
        <xsl:with-param name="structure" select="//databean" />
      </xsl:call-template>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

その後、独自の名前空間と schemaLocation を使用して StructureA または StructureB が作成されます。

<StructureA xmlns="http://...">

StructureA と B はいくつかの共通要素を共有しているため、これらは「xmlcommon.xslt」と呼ばれる別のファイルで定義されており、両方の構造にテンプレートが含まれています。この xmlcommon ファイルには、StructureA または StructureB で定義された名前空間から使用できるようにするため、デフォルトの名前空間が定義されていません。しかし、変換を実行すると、共通ファイルから引き出されたテンプレートの xmlns 属性が空白になります。

<StructureA xmlns="http://...">
  <SharedElement xmlns="">Something</SharedElement>
</StructureA>

検証時に、正しい親の名前空間の代わりに空白の名前空間が使用されます。 共通ファイルのテンプレートに空白の xmlns 属性が追加されないようにする方法を知っている人はいますか?

以下は、共通ファイルの抜粋です。

<xsl:stylesheet version="1.0" xmlns:fn="http://www.w3.org/2005/02/xpath-functions" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:template name="ControlledListStructure">
    <xsl:param name="xmlElem" />
    <xsl:param name="structure" />

    <xsl:element name="{$xmlElem}">
      <!-- Blah blah blah -->
    </xsl:element>
  </xsl:template>
</xsl:stylesheet>
4

1 に答える 1

9

理解しておくべき重要なことは、スタイルシートが結果ツリーに追加する各要素の名前を指示するということです。要素の名前には、ローカル名と名前空間URIの2つの部分があります。上記のコードでは、ローカル名(の値$xmlElem)を指定していますが、名前空間URIを指定していません。つまり、デフォルトで空の文字列になります。(実際には、そのスタイルシートモジュールのデフォルトの名前空間を使用します。存在しないため、空の文字列になります。)つまり、要素は名前空間に含まれません。ドキュメントをシリアル化する場合、XSLTプロセッサにはxmlns=""上部に表示されるデフォルトの名前空間を宣言解除するための宣言解除。そうしないと、要素はその名前空間を引き継ぎますが、これはスタイルシートで指定されたものではありません。これを修正する最も邪魔にならない方法は$namespaceURI、と同じように、別のパラメーター(たとえば)を追加することです$xmlElem。次に、次のように記述します。

<xsl:element name="{$xmlElem}" namespace="{$namespaceURI}">

これで、結果の要素は、指定した名前空間を引き継ぐようになります(これにより、デフォルトの名前空間の非宣言が削除されます)。

それはあなたの質問に答えるはずです。無料のボーナス素材として以下をご用意しております。;-)

text()値の比較でノードテストを削除する必要があります。テキストノードの値を直接比較する必要があることはめったにありません。代わりに、要素自体の文字列値を比較することができます(これは、すべての子孫テキストノードの文字列値の連結として定義されます)。これは次のようになります。

<xsl:when test="/databean/data[@id='pkhfeed']/value = '200'">

このようにすることの利点は、そこにコメントが隠れていてもコードが壊れないことです。

<value>2<!--test-->00</value>

この場合、2つのテキストノード(「2」と「00」)があります。元のテストは、それらのいずれかが「200」に等しいかどうかを確認するため、失敗します。この場合に発生する可能性はほとんどありませんが、いずれの場合でも、要素の文字列値をテストすることは(テキストノードの子ではなく)、それが意図されている場合は良い習慣です。

最後に、テンプレートルールとXPathコンテキストについて学ぶことをお勧めします。<xsl:choose>私は、、、<xsl:call-template>そして<xsl:with-param>可能な限り避ける傾向があります。一つには、テンプレートルールは、XSLTの醜い冗長な部分の多くを回避するのに役立ちます。

<xsl:template match="/databean[data[@id='pkhfeed']/value = '200']" priority="1">
  <StructureA xmlns="http://...">
    ...
  </StructureA>
</xsl:template>

<xsl:template match="/databean">
  <StructureB xmlns="http://...">
    ...
  </StructureB>
</xsl:template>

を使用し続ける場合でも、現在のノードは呼び出されたテンプレートで変更されないままになるため、<xsl:call-template>そのパラメーターを渡す必要はありません。現在のノードは引き続き「/」(ドキュメントノード)であるため、またはテンプレートのいずれかから同じように簡単に$structureアクセスできます//databean(または/databean、これが意味していると思います)。StructureAStructureB

XSLTのコア処理モデルとその最も強力な機能(テンプレートルール)について詳しく知りたい場合は、XSLT 1.0PocketReferenceの無料サンプルの章である「HowXSLTWorks」を確認することをお勧めます

たとえそれがあなたが交渉した以上のものであったとしても、これがあなたに役立つことを願っています!

于 2009-04-30T07:23:03.583 に答える