3

私はXMLの初心者ですが、一部の要素の属性リストが不完全なXMLドキュメントが生成されているという問題があります。欠落している属性にデフォルト値を設定するために、マスタードキュメント(すべての属性のデフォルト値が含まれている)と相互参照するXSLTスタイルシートを実装しようとしています。

たとえば、次の不完全なXMLドキュメントを考えてみましょう。

<?xml version="1.0" encoding="utf-8"?>
<foo>
  <bar label="two" index="2"/>
</foo>

bar要素に属性'type'がありません。これは、'label'の値に従って、次のマスタードキュメントからのデフォルト値を入力したいと思います。

<?xml version="1.0" encoding="utf-8"?>
<foo>
  <bar label="one" index="1" type="type1"/>
  <bar label="two" index="2" type="type2"/>
  <bar label="three" index="3" type="type3"/>
</foo>

望ましい結果は次のようになります。

<?xml version="1.0" encoding="utf-8"?>
<foo>
  <bar label="two" index="2" type="type2"/>
</foo>

私のXSLTスタイルシートは、次のように'document()'とXPathの組み合わせを使用してこれを実行しようとします。

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

  <xsl:variable name="master" select="document('master.xml')"/>

  <!-- Template matching 'root' of XML document -->
  <xsl:template match="/">
    <xsl:apply-templates select="foo"/>
  </xsl:template>

  <!-- Template for generating 'foo' element -->
  <xsl:template match="foo">
    <foo>
      <xsl:apply-templates select="bar"/>
    </foo>
  </xsl:template>

  <!-- Template for generating 'bar' element -->
  <xsl:template match="bar">
    <bar label="{@label}" index="{@index}" type="{$master/foo/bar[@label=@label][1]/@type}"/>
  </xsl:template>

</xsl:stylesheet>

ただし、これは機能せず、「2」ではなく「1」の「ラベル」を持つ「bar」要素のデフォルトの「type」属性を取得します。

<?xml version="1.0" encoding="utf-8"?>
<foo>
  <bar label="two" index="2" type="type1"/>
</foo>

いくつかの調査により、XPathパターンが正しい要素だけでなく、すべての「バー」要素と一致していることが明らかになりましたが、その理由はわかりません。

私は何を間違っているのですか?これを行うためのより良い方法はありますか?

4

1 に答える 1

2

問題はこの行にあります:

<bar label="{@label}" index="{@index}" 
     type="{$master/foo/bar[@label=@label][1]/@type}"/> 

label基本的に、要素の属性がbarそれ自体と等しいかどうかをチェックしています。これは次と同等です。

<bar label="{@label}" index="{@index}" 
     type="{$master/foo/bar[true()][2]/@type}"/> 

これは次と同等です

<bar label="{@label}" index="{@index}" 
     type="{$master/foo/bar[1]/@type}"/> 

これが、観察した結果が生成される方法です。

解決策:XSLTcurrent()関数を使用します。

<bar label="{@label}" index="{@index}" 
     type="{$master/foo/bar[@label=current()/@label][4]/@type}"/> 

完全な変換は次のようになりmaster.xmlます(ローカルコンピューターで変換を実行できるようにURLを変更しました)。

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

      <xsl:variable name="master" select=
      "document('file:///c:/temp/delete/master.xml')"/>

      <!-- Template matching 'root' of XML document -->
      <xsl:template match="/">
        <xsl:apply-templates select="foo"/>
      </xsl:template>

      <!-- Template for generating 'foo' element -->
      <xsl:template match="foo">
        <foo>
          <xsl:apply-templates select="bar"/>
        </foo>
      </xsl:template>

      <!-- Template for generating 'bar' element -->
      <xsl:template match="bar">
        <bar label="{@label}" index="{@index}"
        type="{$master/foo/bar[@label=current()/@label][5]/@type}"/>
      </xsl:template>
</xsl:stylesheet>

そして、この変換が提供されたXMLドキュメントに適用される場合:

<foo>
    <bar label="two" index="2"/>
</foo>

必要な正しい結果が生成されます。

<foo><bar label="two" index="2" type="type2"/></foo>

II。キーを使用した、より効率的なソリューションの可能性

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

 <xsl:key name="kTypeByLabel" match="@type" use="../@label"/>

      <xsl:variable name="master" select=
      "document('file:///c:/temp/delete/master.xml')"/>

      <!-- Template matching 'root' of XML document -->
      <xsl:template match="/">
        <xsl:apply-templates select="foo"/>
      </xsl:template>

      <!-- Template for generating 'foo' element -->
      <xsl:template match="foo">
        <foo>
          <xsl:apply-templates select="bar"/>
        </foo>
      </xsl:template>

      <!-- Template for generating 'bar' element -->
      <xsl:template match="bar">
        <xsl:variable name="vCurrent" select="."/>
        <xsl:variable name="vDefault">
          <xsl:for-each select="$master">
            <xsl:value-of select=
                "key('kTypeByLabel', $vCurrent/@label)"/>
          </xsl:for-each>
        </xsl:variable>

        <bar label="{@label}" index="{@index}" type="{$vDefault}"/>
      </xsl:template>
</xsl:stylesheet>

この変換が(同じ)提供されたXMLドキュメント(上記)に適用されると、必要な正しい結果が生成されます。

<foo>
   <bar label="two" index="2" type="type2"/>
</foo>
于 2012-04-18T01:37:13.530 に答える