3

私はこれを行うことができるかどうか疑問に思っている XSLT を開始しています:

この例http://www.w3schools.com/xsl/tryxslt.asp?xmlfile=cdcatalog&xsltfile=cdcatalogを使用して、少し変更しています。

以下を XSLT エリアに貼り付けます。

<?xml version="1.0" encoding="ISO-8859-1"?>
<!-- Edited by XMLSpy® -->
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="/">


  <html>
  <body>
  <h2>My CD Collection</h2>
    <table border="1">
      <tr bgcolor="#9acd32">
        <th>Title</th>
        <th>Artist</th>
      </tr>
      <xsl:for-each select="catalog/cd">
      <xsl:choose>
<xsl:when test="country = 'USA'"> 
    <tr>
        <td>Title:</td> <td><xsl:value-of select="title"/></td>
        <td>Artist</td> <td><xsl:value-of select="artist"/></td>
        <td>Year:</td>  <td><xsl:value-of select="year"/></td>
    </tr>
</xsl:when>

<xsl:otherwise>
    <tr>
        <td>Price:</td>     <td><xsl:value-of select="price"/></td>
        <td>Company:</td>   <td><xsl:value-of select="company"/></td>
    </tr>
</xsl:otherwise>
</xsl:choose>

      </xsl:for-each>
    </table>
  </body>
  </html>
</xsl:template>
</xsl:stylesheet>

ここにあるのは一般的な XML ソースですが、XML 要素の 1 つのノード (この場合は国) に応じて、データを異なる方法で表示したいと考えています。

ここまでは順調ですね。

次に、XML 構造を使用して、国に応じて表示されるラベルとノードのペアをそれぞれ指定します。次に、for-each ループを使用してすべてのペアを反復処理し、それらを表示します。

これの合理的な理由は、フォーマットが単純な LabelValue よりも少し複雑になる可能性があり、後でそれらすべてを手動で変更する必要がないからです。

これは私が試したものです。

<?xml version="1.0" encoding="ISO-8859-1"?>
<!-- Edited by XMLSpy® -->
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="/">
<xsl:variable name="Details">
    <Details>
        <USA>
            <Pair><Node>title</Node><Label>Title:</Label></Pair>
            <Pair><Node>artist</Node><Label>Artist:</Label></Pair>
            <Pair><Node>year</Node><Label>Year:</Label></Pair>
    </USA>
    <Others>
            <Pair><Node>price</Node><Label>Price:</Label></Pair>
            <Pair><Node>company</Node><Label>Company:</Label></Pair>
    </Others>
</Details>
</xsl:variable>


  <html>
  <body>
  <h2>My CD Collection</h2>
    <table border="1">
      <tr bgcolor="#9acd32">
        <th>Title</th>
        <th>Artist</th>
      </tr>
      <xsl:for-each select="catalog/cd">
      <xsl:choose>
<xsl:when test="country = 'USA'"> 

    <xsl:for-each select = "$Details/Details/USA/Pair">
        <xsl:variable name="Node">
            <xsl:value-of select ="Node"/>
        </xsl:variable> 
        <tr><td><xsl:value-of select = "Label"/></td><td> <xsl:value-of select ="Node"/></td></tr>
    </xsl:for-each>

</xsl:when>
<xsl:otherwise>
    <xsl:for-each select = "$Details/Details/Others/Pair">
        <xsl:variable name="Node">
            <xsl:value-of select ="Node"/>
        </xsl:variable> 
        <tr><td><xsl:value-of select = "Label"/></td><td> <xsl:value-of select ="Node"/></td></tr>
    </xsl:for-each>
</xsl:otherwise>
</xsl:choose>

      </xsl:for-each>
    </table>
  </body>
  </html>
</xsl:template>
</xsl:stylesheet>

しかし、これはうまくいきません。

誰かが私がこれを行う方法について正しい方向に向けることができますか?

4

1 に答える 1

4

問題は XSLT 1.0 にあり、$Details変数は「ノード セット」ではなく「結果ツリー フラグメント」を保持します。XSLT は、必要な方法でアクセスするためにノード セットである必要があります。XSLT 1.0 でこれを回避するには、拡張関数を使用して結果ツリー フラグメントをノード セットに変換する必要があります。どの拡張機能を使用するかは、現在のプラットフォームによって異なります。この例では Micorsoft を使用していますが、Microsoft 以外で最も一般的なのは EXSLT です。( http://www.xml.com/pub/a/2003/07/16/nodeset.htmlを参照)

拡張関数を定義することで、これを行うことができます

<xsl:for-each select="msxsl:node-set($Details)/Details/USA/Pair">

ただし、目的を達成するには、まだいくつかの調整が必要です。このループ内でPair要素に配置されますが、外側のループで元のcdを参照する必要があります。これを行うには、最初にcdへの参照を保持する変数を定義する必要があります(これは内側のループの前に行う必要があります)。

 <xsl:variable name="cd" select="." />

次に、内側のループで、これを実行して関連するフィールドを取得できます

<xsl:value-of select ="$cd/*[local-name() = current()/Node]"/>

新しいコードを使用すると、コードの重複を減らすことができます。xsl:chooseを捨てて、内部xsl:for-eachを1つだけ持つことができます

<xsl:for-each 
     select="$Details/*[local-name()=current()/country or local-name()='Others'][1]/Pair">

これは、一致する国が存在する場合はそれを選択し、存在しない場合は「その他」を使用します

ここに完全な XSLT があります

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">

<xsl:template match="/">
<xsl:variable name="Details">
    <Details>
        <USA>
            <Pair><Node>title</Node><Label>Title:</Label></Pair>
            <Pair><Node>artist</Node><Label>Artist:</Label></Pair>
            <Pair><Node>year</Node><Label>Year:</Label></Pair>
    </USA>
    <Others>
            <Pair><Node>price</Node><Label>Price:</Label></Pair>
            <Pair><Node>company</Node><Label>Company:</Label></Pair>
    </Others>
</Details>
</xsl:variable>

<html>
    <body>
    <h2>My CD Collection</h2>
      <table border="1">
        <tr bgcolor="#9acd32">
          <th>Title</th>
          <th>Artist</th>
        </tr>
        <xsl:for-each select="catalog/cd">
          <xsl:variable name="cd" select="." />
          <xsl:for-each select="msxsl:node-set($Details)/Details/*[local-name()=current()/country or local-name()='Others'][1]/Pair">
            <tr>
              <td>
                <xsl:value-of select = "Label"/>
              </td>
              <td>
                <xsl:value-of select ="$cd/*[local-name() = current()/Node]"/>
              </td>
            </tr>
          </xsl:for-each>
        </xsl:for-each>
      </table>
    </body>
  </html>
</xsl:template>
</xsl:stylesheet>

XSLT 2.0 では事情が異なり、$Detailsは「シーケンス」を保持し、拡張機能を使用する必要はありません。

拡張関数を使用せずにこれを実現する別の方法があります。それは、document()関数を使用して XSTL がそれ自体を参照するようにすることです。変数を持つだけでなく、XML フラグメントを含めるだけです

  <my:Details>
    <Details>
     ...
    </Details>
  </my:Details>

次に、変数を宣言して、そのように参照できます。入力ドキュメントを直接参照しているため、これはノード セットとして扱われます。

 <xsl:variable name="Details" select="document('')/*/my:Details" />

このXSLTも試してみてください

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:my="my" exclude-result-prefixes="my">
  <my:Details>
    <Details>
    <USA>
      <Pair>
        <Node>title</Node>
        <Label>Title:</Label>
      </Pair>
      <Pair>
        <Node>artist</Node>
        <Label>Artist:</Label>
      </Pair>
      <Pair>
        <Node>year</Node>
        <Label>Year:</Label>
      </Pair>
    </USA>
    <Others>
      <Pair>
        <Node>price</Node>
        <Label>Price:</Label>
      </Pair>
      <Pair>
        <Node>company</Node>
        <Label>Company:</Label>
      </Pair>
    </Others>
    </Details>
  </my:Details>

  <xsl:template match="/">
    <xsl:variable name="Details" select="document('')/*/my:Details" />
    <html>
      <body>
        <h2>My CD Collection</h2>
        <table border="1">
          <tr bgcolor="#9acd32">
            <th>Title</th>
            <th>Artist</th>
          </tr>
          <xsl:for-each select="catalog/cd">
            <xsl:variable name="cd" select="." />
            <xsl:for-each select = "$Details/Details/*[local-name()=current()/country or local-name()='Others'][1]/Pair">
              <tr>
                <td>
                  <xsl:value-of select = "Label"/>
                </td>
                <td>
                  <xsl:value-of select ="$cd/*[local-name() = current()/Node]"/>
                </td>
              </tr>
            </xsl:for-each>
          </xsl:for-each>
        </table>
      </body>
    </html>
  </xsl:template>
</xsl:stylesheet>
于 2013-09-24T08:09:16.297 に答える