3

私は、XML 文書を別の XML 文書に変換する XSLT 2.0 を作成する任務を負っています。私は XSLT に比較的慣れていませんが、これを行っている間に多くのことを学びました。この間、単純な値、つまり 002 -> TH などをマッピングする必要がありました。値が 10 個未満の小さなリストではこれで問題ありませんでした。xsl:choose を使用しました。ただし、あるリストから別のリストに、またはその逆に 300 を超える値をマップする必要があります。各リストには、値とテキストによる説明があります。2 つのリスト値は常に直接対応するとは限らないため、テキストの説明を比較し、必要に応じてデフォルト値を使用する必要がある場合があります。

この問題には 2 つの解決策があります。

  1. Use xsl:choose: リストのいずれかが変更された場合、これは遅くなり、更新が難しくなる可能性があると思います。

  2. 各リスト項目間の関係を含む XML ドキュメントを用意します。XPath 式を使用して関連付けられた値を取得します。これは、より保守しやすく、更新しやすいと考えているため、私の推奨するソリューションです。効率的かどうかはわかりませんが。

私の提案の1つであるどのソリューションを使用する必要がありますか、またはこれらの値をマップするより良い方法はありますか?

4

2 に答える 2

4

XSLT 2.0 ソリューションは次のとおりです。

ソース XML ファイル:

<input>
  <data>001</data>
  <data>002</data>
  <data>005</data>
</input>

「マッピング」xml ファイル:

<map>
  <default>?-?-?</default>
    <input value="001">RZ</input>
    <input value="002">TH</input>
    <input value="003">SC</input>
</map>

XSLT 変換:

<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output omit-xml-declaration="yes" indent="yes"/>

  <xsl:param name="pmapFile" 
       select="'C:/temp/deleteMap.xml'" />

  <xsl:variable name="vMap" 
       select="document($pmapFile)" />

  <xsl:variable name="vDefault" 
       select="$vMap/*/default/text()" />

  <xsl:key name="kInputByVal" match="input" 
   use="@value" />

  <xsl:template match="/*">
    <output>
      <xsl:apply-templates/>
    </output>
  </xsl:template>

  <xsl:template match="data">
    <data>
        <xsl:sequence select= 
         "(key('kInputByVal', ., $vMap)[1]/text(),
           $vDefault
           )[1]
         "/>
    </data> 
  </xsl:template>
</xsl:stylesheet>

出力:

<output>
  <data>RZ</data>
  <data>TH</data>
  <data>?-?-?</data>
</output>

次の点に注意してください

  1. document()関数を使用して、別の XML ファイルに保存されている「マッピング」xml ドキュメントにアクセスします。

  2. <xsl:key/>および XSLT 2.0key()関数を使用して、対応する各出力値を決定してアクセスします。3 番目の引数は、アクセスしてインデックスを作成する必要がある xml ドキュメントを指定します。

于 2009-01-20T14:48:02.960 に答える
2

<xsl:key>を使用して、または方法2に従って、意図したことを行う方法を次に示します。

サンプル入力ファイル (data.xml):

<?xml version="1.0" encoding="utf-8"?>
<input>
  <data>001</data>
  <data>002</data>
  <data>005</data>
</input>

サンプル マップ ファイル (map.xml):

<?xml version="1.0" encoding="utf-8"?>
<map default="??">
  <entry key="001">RZ</entry>
  <entry key="002">TH</entry>
  <entry key="003">SC</entry>
</map>

サンプル XSL スタイルシート、説明は次のとおりです。

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" 
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" encoding="utf-8" indent="yes"/>

  <xsl:param name="map-file" select="string('map.xml')" />
  <xsl:variable name="map-doc" select="document($map-file)" />
  <xsl:variable name="default-value" select="$map-doc/map/@default" />
  <xsl:key name="map" match="/map/entry" use="@key" />

  <xsl:template match="/input">
    <output>
      <xsl:apply-templates select="data" />
    </output>
  </xsl:template>

  <xsl:template match="data">
    <xsl:variable name="raw-value" select="." />
    <xsl:variable name="mapped-value">
      <xsl:for-each select="$map-doc">
        <xsl:value-of select="key('map', $raw-value)" />
      </xsl:for-each>
    </xsl:variable>
    <data>
      <xsl:choose>
        <xsl:when test="$mapped-value = ''">
          <xsl:value-of select="$default-value" />
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="$mapped-value" />
        </xsl:otherwise>
      </xsl:choose>
    </data>
  </xsl:template>
</xsl:stylesheet>

これが行うことは次のとおりです。

  • を使用document()して開きmap.xml、結果のノードセットを変数に保存します
  • 今後の参考のためにデフォルト値を保存します
  • <xsl:key>「マップ」ノード セットに対して動作するように準備します
  • <xsl:for-each>ループとしてではなく、key()関数を呼び出す前に実行コンテキストを切り替える手段として使用します。そうしないkey()と、「データ」ドキュメントに対して機能し、何も返されません
  • 関数で対応するノードを見つけ、key()変数に保存します
  • 出力の変数値を確認します - 空の場合はデフォルト値を使用します
  • 繰り返す(~<xsl:apply-templates>

<xsl:for-each>この巧妙なトリックの功績は、XSL メーリング リストでこのテクニックを説明したJeni Tennisonの功績によるものです。スレッドを必ずお読みください。

data.xml に対してスタイルシートを実行した場合の出力:

<?xml version="1.0" encoding="utf-8"?>
<output>
  <data>RZ</data>
  <data>TH</data>
  <data>??</data>
</output>

これらはすべて XSLT 1.0 です。XSLT 2.0 が提供する利点を利用した、より優れた、より洗練されたバージョンが存在すると確信していますが、残念ながら、私は XSLT 2.0 にあまり詳しくありません。他の誰かがより良い解決策を投稿しているかもしれません。


編集

コメントの Dimitre Novatchev のヒントにより、かなり短く、より好ましいスタイルシートを作成することができました。

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" 
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" encoding="utf-8" indent="yes"/>

  <xsl:param name="map-file" select="string('map.xml')" />
  <xsl:variable name="map-doc" select="document($map-file)" />
  <xsl:variable name="default" select="$map-doc/map/default[1]" />
  <xsl:key name="map" match="/map/entry" use="@key" />

  <xsl:template match="/input">
    <output>
      <xsl:apply-templates select="data" />
    </output>
  </xsl:template>

  <xsl:template match="data">
    <xsl:variable name="raw-value" select="." />
    <data>
      <xsl:for-each select="$map-doc">
        <xsl:value-of select="(key('map', $raw-value)|$default)[1]" />
      </xsl:for-each>
    </data>
  </xsl:template>
</xsl:stylesheet>

ただし、これを XSLT 1.0 で動作させるには、わずかに異なるマップ ファイルが必要です。

<?xml version="1.0" encoding="utf-8"?>
<map>
  <entry key="001">RZ</entry>
  <entry key="002">TH</entry>
  <entry key="003">SC</entry>
  <!-- default entry must be last in document -->
  <default>??</default>
</map>
于 2009-01-20T00:43:35.427 に答える