0

XSLT を使い始めるのは楽しいです。慣れるまで少し時間がかかりますが、私はプリンシパルが好きです。今...私はすでに疑問に思っている問題に遭遇しました。おそらく誰かがそれについて教えてくれるかもしれません。

プライオリティのあるボックスのセットがあります。優先度の低いボックスが最初に表示されます。これはうまくいきます。ただし、ボックスを行に配置し、行 1 と 3 を奇数としてマークし、行 2 を偶数としてマークしたいと思います (実際のプロジェクトでは、さらに多くの行があると予想されます)。

したがって、 fn:position() 関数を使用できるはずだと思いました。残念ながら、返される位置は元のノードの 1 つであり、結果の並べ替えられたノードではありません。その問題を解決する方法はありますか?

問題を明らかにするサンプル XSLT があります。

<?xml version="1.0"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="body">
    <xsl:apply-templates>
      <xsl:sort select="@priority" data-type="number"/>
    </xsl:apply-templates>
  </xsl:template>
  <xsl:template match="body/box">
<div class="box">
Box[<xsl:value-of select="count(preceding-sibling::box) + 1" />,<xsl:value-of select="position()"/>] = (<xsl:value-of select="@priority"/>)
  <xsl:copy-of select="title"/></div>
  </xsl:template>
</xsl:stylesheet>

入力例もあります。TWO が最初に表示され、次に THREE、最後に ONE が表示されます。

<?xml version="1.0"?>
<body>
  <box priority="103">
    <title>This is box ONE</title>
  </box>
  <box priority="1">
    <title>This is box TWO</title>
  </box>
  <box priority="12">
    <title>This is box THREE</title>
  </box>
</body>

それでも、position() は 1、2、および 3 であると予想しますが、これが出力です。

<div class="box">
Box[2,4] = (1)
  <title>This is box TWO</title>
</div>
<div class="box">
Box[3,6] = (12)
  <title>This is box THREE</title>
</div>
<div class="box">
Box[1,2] = (103)
  <title>This is box ONE</title>
</div>

ボックス角括弧内の 2 番目の数字は position() です。私は 1、2、3 と予想されていました。 xsl:for-each タグではなく、2、3、および 1 でした。)

xmlpatterns (Qt 4.7) と xsltproc (libxml2、これはバージョン 1.0 を使用する必要があり、コードは 1.0 と互換性があります) でテストしたところ、どちらも同じ数値を返しました。

それで...それは XSLT の制限ですか、それともこれら 2 つの XSLT 実装のバグですか?!

2012 年 5 月 27 日更新

その特定のケースでは、QXmlQuery (xmlpatterns) が破損したパーサーであることが判明しました。count(preceding-sibling::box) + 1position()は、実行中の for-each またはテンプレート シーケンスの正しいインデックスではなく、 に似たものを使用して計算する必要があります。

4

2 に答える 2

2

そうですね

<xsl:apply-templates>
  <xsl:sort select="@priority" data-type="number"/>
</xsl:apply-templates>

これはdoingの略です

<xsl:apply-templates select="node()">
  <xsl:sort select="@priority" data-type="number"/>
</xsl:apply-templates>

これは、すべての種類の子ノード、関心があると思われる要素ノードと、要素間の空白テキスト ノードの両方を処理します。だから使う

<xsl:apply-templates select="box">
  <xsl:sort select="@priority" data-type="number"/>
</xsl:apply-templates>

必要に応じて、少なくとも position() を 1,2,3 にする必要があります。

価値があるので、スタイルシートを使用してWindowsでxsltprocをテストしました

<?xml version="1.0"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="body">
    <xsl:apply-templates select="box">
      <xsl:sort select="@priority" data-type="number"/>
    </xsl:apply-templates>
  </xsl:template>
  <xsl:template match="body/box">
<div class="box">
Box[<xsl:value-of select="count(preceding-sibling::box) + 1" />,<xsl:value-of select="position()"/>] = (<xsl:value-of select="@priority"/>)
  <xsl:copy-of select="title"/></div>
  </xsl:template>
</xsl:stylesheet>

あなたが投稿した入力に対して、結果は

compilation error: file test2012052702.xsl line 2 element stylesheet
xsl:version: only 1.0 features are supported
<?xml version="1.0"?>
<div class="box">
Box[2,1] = (1)
  <title>This is box TWO</title></div><div class="box">
Box[3,2] = (12)
  <title>This is box THREE</title></div><div class="box">
Box[1,3] = (103)
  <title>This is box ONE</title></div>

だから位置は正しいと思います。

于 2012-05-27T11:45:05.390 に答える
1

これを再現できません

Saxon 9.1.07 で変換を実行すると、結果は次のようになります。

<div class="box">
      Box[2,5] = (1)
      <title>This is box TWO</title></div><div class="box">
      Box[3,6] = (12)
      <title>This is box THREE</title></div><div class="box">
      Box[1,7] = (103)
      <title>This is box ONE</title></div>

ご覧のとおり、位置は正しいです(まだ 1、2、3 ではありません。空白のみのノードも存在するためです)。

同じ結果が XQSharp (XmlPrime) によって生成されます。

AltovaXML2009 (XML-SPY) は、これさえも生成します:

<?xml version="1.0" encoding="UTF-8"?><div class="box">
    Box[2,1] = (1)
      <title>This is box TWO</title></div><div class="box">
    Box[3,2] = (12)
      <title>This is box THREE</title></div><div class="box">
    Box[1,3] = (103)
      <title>This is box ONE</title></div>

これは、空白のみのテキスト ノードを取り除く XML パーサーを使用することを意味します。

この変換の改良版では、空白のみのノードが除外されます。

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

 <xsl:template match="body">
        <xsl:apply-templates>
          <xsl:sort select="@priority" data-type="number"/>
        </xsl:apply-templates>
 </xsl:template>

 <xsl:template match="box">
    <div class="box">
      Box[<xsl:value-of select="count(preceding-sibling::box) + 1" />
      <xsl:text>,</xsl:text>
      <xsl:value-of select="position()"/>
      <xsl:text>] = (</xsl:text>
      <xsl:value-of select="@priority"/>)
      <xsl:copy-of select="title"/></div>
 </xsl:template>
</xsl:stylesheet>

提供された XML ドキュメントに対してこの変換が適用されると、次のようになります。

<body>
    <box priority="103">
        <title>This is box ONE</title>
    </box>
    <box priority="1">
        <title>This is box TWO</title>
    </box>
    <box priority="12">
        <title>This is box THREE</title>
    </box>
</body>

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

<div class="box">
      Box[2,1] = (1)
      <title>This is box TWO</title>
</div>
<div class="box">
      Box[3,2] = (12)
      <title>This is box THREE</title>
</div>
<div class="box">
      Box[1,3] = (103)
      <title>This is box ONE</title>
</div>

:xsl:strip-spaceは、解析対象からも空白のみのノードを除外するために使用されます。

結論: 報告された結果は、バグのある XSLT プロセッサを使用しているか、提供されたものとは異なる変換を実行したことが原因です。

于 2012-05-27T13:39:14.417 に答える