1

Web サービスは、以下の xml 形式で人のリストを返しています。値はセミコロンで区切られます。値を 2 列または 3 列に表示する必要があります (変数である必要があります)。

望ましい結果:

<table border="1">
 <tr>
  <td>Smith, John</td>
  <td>Jackson, Samuel</td>
  <td>Wayne, Bruce</td>
 </tr>
 <tr>
  <td>Cosby, Bill</td>
  <td>Kent, Clarke</td>
  <td>Leno, Jay</td>
 </tr>
 <tr>
  <td>OBrian, Conan</td>
  <td> </td>
  <td> </td>
 </tr>
</table>

XML サンプル

 <?xml version="1.0" encoding="UTF-8"?> <PI>Smith, John; Jackson,
 Samuel; Wayne, Bruce; Cosby, Bill; Kent, Clarke; Leno, Jay; OBrian,
 Conan; </PI>
4

2 に答える 2

0

ホルマンの解決策を受け入れてください。彼のテクニックは的を射ている。

XSLT 2.0 ソリューション

サンプル入力データは、セミコロンで区切られたリストではなく、セミコロンで終了するリストを示唆しています。

この XSLT 2.0 スタイルシートは、セミコロンで終了するリストまたはセミコロンで区切られたリストのいずれでも正しく機能します。1 つの入力パラメーターを取りcol-count、デフォルトは 3 です。

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="html" doctype-system="about:legacy-compat" encoding="UTF-8" indent="yes" />
<xsl:strip-space elements="*" />
<xsl:param name="col-count" select="3" />

<xsl:template match="/*">
 <table border="1">
  <xsl:variable name="names" select="tokenize(.,';')[normalize-space(.)]" />
  <xsl:for-each-group select="$names , for $x in 1 to
    ($col-count - (count($names) mod $col-count)) mod $col-count return ''"
                      group-by="(position() - 1) idiv $col-count"> 
   <tr>
    <xsl:for-each select="current-group()">
     <td><xsl:value-of select="normalize-space(.)" /></td>
    </xsl:for-each>
   </tr>
  </xsl:for-each-group>
 </table>
</xsl:template>

</xsl:stylesheet>

ノート:

(1) 解決策が簡潔であり、ぎこちないxsl:ifステートメントがないことに注意してください。計算されたシーケンスの使用 (入力ドキュメント ノードの選択とは対照的に) は、group-by 属性に限定されるだけでなく、 にも適用できますselect。計算されたシーケンスの使用は、手続き的なビューではなく、より機能的なビューを示唆しています。

(2) 古いブラウザでも安全に出力したい場合は、... を置き換えてください。

  <xsl:for-each-group select="$names , for $x in 1 to
    ($col-count - (count($names) mod $col-count)) mod $col-count return ''"
                      group-by="(position() - 1) idiv $col-count"> 

... と ...

  <xsl:for-each-group select="$names , for $x in 1 to
    ($col-count - (count($names) mod $col-count)) mod $col-count return '&#160;'"
                      group-by="(position() - 1) idiv $col-count"> 

XSLT 1.0 ソリューション

XSLT 1.0 に行き詰まっている場合は、この同等のスタイルシートを使用できますが、効率は劣ります ...

<xsl:stylesheet
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:esl="http://exslt.org/common"
  xmlns:so="http://stackoverflow.com/questions/18066463"
  version="1.0"
  exclude-result-prefixes="xsl so esl">
<xsl:output method="html" doctype-system="about:legacy-compat" encoding="UTF-8" indent="yes" />
<xsl:strip-space elements="*" />
<xsl:variable name="col-count" select="3" /><!-- Must be 2 or 3. -->

<xsl:variable name="empty-rtf">
  <so:name>&#160;</so:name>
</xsl:variable>
<xsl:variable name="empty" select="esl:node-set($empty-rtf)/*" />


<xsl:template match="/*">
  <table border="1">
    <xsl:variable name="names-rtf">
      <xsl:call-template name="split">
        <xsl:with-param name="list" select="." />
      </xsl:call-template>
    </xsl:variable>
    <xsl:variable name="names" select="esl:node-set($names-rtf)/*" />
    <xsl:for-each select="$names[(position() mod $col-count) = 1]">
      <xsl:variable name="row" select="position() - 1" />
      <tr>
        <xsl:apply-templates select="$names[floor((position() - 1) div $col-count) = $row]" />
        <xsl:if test="position()=last()">
         <xsl:for-each select="($names|$empty)[position() &lt;=
                               (($col-count - (count($names) mod $col-count)) mod $col-count)]">
           <xsl:apply-templates select="$empty" />
         </xsl:for-each>  
        </xsl:if>  
      </tr>
    </xsl:for-each>  
  </table>
</xsl:template>

<xsl:template name="split">
  <xsl:param name="list" />
  <xsl:choose>
    <xsl:when test="contains($list,';')">
      <xsl:call-template name="split">
        <xsl:with-param name="list" select="substring-before($list,';')" />
      </xsl:call-template>
      <xsl:call-template name="split">
        <xsl:with-param name="list" select="substring-after($list,';')" />
      </xsl:call-template>
    </xsl:when>  
    <xsl:when test="normalize-space($list)">
      <so:name><xsl:value-of select="normalize-space($list)" /></so:name>
    </xsl:when>  
    <xsl:otherwise />
  </xsl:choose>
</xsl:template>

<xsl:template match="so:*" priority="2">
  <td><xsl:value-of select="." /></td>
</xsl:template>  

</xsl:stylesheet>
于 2013-08-06T03:51:23.150 に答える
0

これは、要求に応じて列数を変数として使用する XSLT 2.0 ソリューションです。これは、私が教室で教えている手法を使用しており、グループ化は XML の値で行う必要はなく (多くの XSLT ユーザーが想定しているように)、任意の計算 (この場合は除算の結果) で行うことができることを強調しています。

[列数が異なる複数の呼び出しを表示するように編集]

t:\ftemp>type names.xml 
<?xml version="1.0" encoding="UTF-8"?> <PI>Smith, John; Jackson,
Samuel; Wayne, Bruce; Cosby, Bill; Kent, Clarke; Leno, Jay; OBrian,
Conan; </PI>
t:\ftemp>call xslt2 names.xml names.xsl names.out.xml "cols=3" 

t:\ftemp>type names.out.xml 
<?xml version="1.0" encoding="UTF-8"?>
<table border="1">
   <tr>
      <td>Smith, John</td>
      <td>Jackson, Samuel</td>
      <td>Wayne, Bruce</td>
   </tr>
   <tr>
      <td>Cosby, Bill</td>
      <td>Kent, Clarke</td>
      <td>Leno, Jay</td>
   </tr>
   <tr>
      <td>OBrian, Conan</td>
      <td/>
      <td/>
   </tr>
</table>

t:\ftemp>call xslt2 names.xml names.xsl names.out.xml "cols=2" 

t:\ftemp>type names.out.xml 
<?xml version="1.0" encoding="UTF-8"?>
<table border="1">
   <tr>
      <td>Smith, John</td>
      <td>Jackson, Samuel</td>
   </tr>
   <tr>
      <td>Wayne, Bruce</td>
      <td>Cosby, Bill</td>
   </tr>
   <tr>
      <td>Kent, Clarke</td>
      <td>Leno, Jay</td>
   </tr>
   <tr>
      <td>OBrian, Conan</td>
      <td/>
   </tr>
</table>

t:\ftemp>type names.xsl 
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="2.0">

<xsl:output indent="yes"/>

<xsl:param name="cols" required="yes"/>

<xsl:template match="PI">
  <table border="1">
    <!--determine population and group by number of columns-->
    <xsl:for-each-group select="tokenize(.,';\s+')"
                        group-by="(position()-1) idiv $cols">
      <tr>
        <!--put members into the row-->
        <xsl:for-each select="current-group()">
          <td>
            <xsl:value-of select="normalize-space(.)"/>
          </td>
        </xsl:for-each>
        <!--filler for the last row-->
        <xsl:if test="position()=last()">
          <xsl:for-each select="count(current-group())+1 to $cols">
            <td/>
          </xsl:for-each>
        </xsl:if>
      </tr>
    </xsl:for-each-group>
  </table>
</xsl:template>

</xsl:stylesheet>
t:\ftemp>rem
于 2013-08-05T20:26:30.197 に答える