0

XSLT1.0でのみ動作するperlモジュールで使用しているスタイルシートがあります。JSONディクショナリ内にJSON配列を作成したいので、要素に適切なコンマ区切りが必要です。2番目のセルに1つ以上のスパンがあるXHTMLテーブルを解析しています。つまり、for-each select = "./ tr"、次にfor-each select = "./ td [1]/span"などです。

少し変更すると、Ianが言ったように動作します。

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" version="1.0" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" doctype-public="-//W3C//DTD HTML 4.01//EN"  encoding="UTF-8" />
    <xsl:template match="text()">
    </xsl:template>
    <xsl:template match="table/tbody">
        <xsl:text>[</xsl:text>
        <xsl:for-each select="./tr[not(@class='no-results')]">
            <xsl:text>{"</xsl:text>
            <xsl:value-of select="normalize-space(.//strong)" />
            <xsl:text>":{"ingredients":{</xsl:text>
            <xsl:for-each select=".//div[@class='reagent-list']//a[@class='item-link reagent']">
                <xsl:value-of select="substring(./@href, 14)" />:<xsl:value-of select="normalize-space(./span[1])" />
                <xsl:if test="position() != last()">
                    <xsl:text>,</xsl:text>
                </xsl:if>
            </xsl:for-each>
            <xsl:text>}</xsl:text>
            <xsl:if test="position() != last()">
                <xsl:text>,</xsl:text>
            </xsl:if>
            <xsl:text>&#10;</xsl:text>
        </xsl:for-each>
        <xsl:text>]</xsl:text>
    </xsl:template>
</xsl:stylesheet>

スタイルシートが以下のxmlと一致しないことに気付きました。実際のドキュメントは巨大です。しかし、私が何を意味するのか理解していただければ幸いです。私はこれを作りました:

<table>
  <thead>
    <tr>
      <th>a</th>
      <th>b</th>
      <th>c</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>foo</td>
      <td><span>an element</span></td>
      <td>bar</td>
    </tr>
    <tr>
      <td>foo</td>
      <td><span>an element</span><span>an element</span></td>
      <td>bar</td>
    </tr>
    <tr>
      <td>foo</td>
      <td><span>an element</span><span>an element</span><span>an element</span><span>an element</span></td>
      <td>bar</td>
    </tr>
  </tbody>
</table>

=>

{
  "Row one":["an element"],
  "Row two":["an element", "an element"],
  "Row three":["an element", "an element", "an element", "an element"]
}

代わりに私はこれを取得します:

{
  "Row one":["an element",],
  "Row two":["an element", "an element",],
  "Row three":["an element" "an element" "an element" "an element"]
}

position()テストタグでコンマを印刷するために使用してきましたがlast()、外側のループでは正しく機能しているようですが、配列を区切るコンマを印刷するときに、内側のfor-eachスコープを使用するようにテストタグに指示するにはどうすればよいですか?

4

1 に答える 1

2

@IanRobertsが述べたように、既存のXSLTがどのように見えるかを確認せずに、的を絞った支援を提供することは困難です。

とは言うものの、これはプッシュ指向(つまり、no <xsl:for-each>)であり、を必要としないソリューションですlast()

このXSLTの場合:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:my="my"
  exclude-result-prefixes="my"
  version="1.0">
  <xsl:output omit-xml-declaration="no" indent="yes" method="text" />
  <xsl:strip-space elements="*" />

  <my:ones>
    <num>one</num>
    <num>two</num>
    <num>three</num>
    <num>four</num>
    <num>five</num>
    <num>six</num>
    <num>seven</num>
    <num>eight</num>
    <num>nine</num>
  </my:ones>

  <xsl:template match="/*">
    <xsl:text>{&#10;</xsl:text>
    <xsl:apply-templates select="tbody/tr" />
    <xsl:text>&#10;}</xsl:text>
  </xsl:template>

  <xsl:template match="tr">
    <xsl:variable name="vPos" select="position()" />
    <xsl:if test="$vPos &gt; 1">,&#10;</xsl:if>
    <xsl:text>&#09;"Row </xsl:text>
    <xsl:value-of select="document('')/*/my:ones/*[$vPos]" />
    <xsl:text>":[</xsl:text>
    <xsl:apply-templates select="td[2]/span" />
    <xsl:text>]</xsl:text>
  </xsl:template>

  <xsl:template match="span">
    <xsl:if test="position() &gt; 1">, </xsl:if>
    <xsl:value-of select="concat('&quot;', ., '&quot;')" />
  </xsl:template>

</xsl:stylesheet>

...提供されたXMLに対して実行されます:

<table>
  <thead>
    <tr>
      <th>a</th>
      <th>b</th>
      <th>c</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>foo</td>
      <td>
        <span>an element</span></td>
      <td>bar</td>
    </tr>
    <tr>
      <td>foo</td>
      <td>
        <span>an element</span><span>an element</span></td>
      <td>bar</td>
    </tr>
    <tr>
      <td>foo</td>
      <td>
        <span>an element</span><span>an element</span><span>an element</span><span>an element</span></td>
      <td>bar</td>
    </tr>
  </tbody>
</table>

...必要な結果が生成されます:

{
  "Row one":["an element"],
  "Row two":["an element", "an element"],
  "Row three":["an element", "an element", "an element", "an element"]
}

説明:

  • 最初のテンプレートはルート要素と一致します。その目的は、その要素の<tr>孫にテンプレートを適用し、それらの結果をとの間に挟む{こと}です(必要に応じて改行を追加します)。

  • 2番目のテンプレートは<tr>要素と一致します。<span>行情報を出力し、2番目の要素のすべての子にテンプレートを適用するように指示されます<td>(ここでも、必要に応じて、結果を中括弧と他のテキストで挟みます)。

    • 注:現在のコンテキストでのこの位置が1より大きい場合、を使用する代わりにlast()、最初の要素がコンマを出力し、その後に改行が続くことがわかります。これは、コンマを正しく適用するのと同じ効果があります。<tr>これは、同じ問題を見る別の方法にすぎません(そして、私にとってはより効率的であると思われるため、私が使用している方法です;))。

    • 注:このソリューションをより拡張可能にするために、各行の単語、、などを"one"静的に出力していないことがわかります。"two"代わりに、XSLTの上部で、<my:ones>各「1」の数値のテキスト値を保持する要素を定義しました。それぞれを処理するとき、現在のコンテキストで<tr>のその位置を使用して<tr>、正しい<num>要素の値を取得します。読者の練習問題として残しましたが、このソリューションを潜在的に多数の行にスケールアップするため<my:tens>に、などを定義することは確かに可能です。<my:hundreds>

  • 最終的なテンプレートは<span>要素と一致します。ここでも、要素を使用して、現在のコンテキストでのこの位置が1より大きい<xsl:if>かどうかをテストします。<span>その場合、コンマ(後にスペースが続く)が出力されます。その後、2つの"シンボルを間に挟まれたスパンの値と連結するだけです。

于 2012-11-21T16:37:55.273 に答える