3

XSLTのグループ化のと、高性能XSLTのためのfor-each-groupの使用について説明しました。for-each-groupに問題があります。

私のXML

<?xml version="1.0" encoding="UTF-8"?>
<body>
   <p name="h-title" other="main">Introduction</p>
   <p name="h1-title " other="other-h1">XSLT and XQuery</p>
   <p name="h2-title" other=" other-h2">XSLT</p>
   <p name="">
      <p1 name="bold"> XSLT is used to write stylesheets.</p1>
   </p>
   <p name="h2-title " name="other-h2">XQuery</p>
   <p name="">
      <p1 name="bold"> XQuery is used to query XML databases.</p1>
   </p>
   <p name="h3-title" name="other-h3">XQuery and stylesheets</p>
   <p name="">
      <p1 name="bold"> XQuery is used to query XML databases.</p1>
   </p>
   <p name="h1-title " other="other-h1">XSLT and XQuery</p>
   <p name="h2-title " other=" other-h2">XSLT</p>
</body>

 </ p>

私の欲しい出力

<?xml version="1.0" encoding="UTF-8"?>
<body>
   <p name="h-title " other="main">Introduction</p>
   <h1>
      <p name="h1-title " other="other-h1"> XSLT and XQuery </p>
      <h2>
         <p name="h2-title " other="other-h2">XSLT</p>
         <p name="">
            <p1 name="bold">XSLT is used to write stylesheets.
            </p1>
         </p>
      </h2>
      <h2>
         <p name="h2-title " other="other-h2"> XQuery is used to query XML databases    
         </p>
         <p name="">
            <p name="bold"> XQuery is used to query XML databases.</p>
         </p>
         <h3>
            <p name="h3-title " name="other-h3">XQuery and stylesheets</p>
            <p name="">
         <p1 name="bold"> XQuery is used to query XML databases.</p1>
           </p>
        </h3>
      </h2>
</h1>

<h1>
            <p name="h1-title " other="other-h1">XSLT and XQuery</p>
       <h2>   
            <p name="h2"-title other=" other-h2">XSLT</p>
       </h2>
</h1>
</body>

これでやってみました。(動作していません)

<xsl:template match="body">


        <body>
            <xsl:for-each-group select="*" group-starting-with="@h1-title"      >
                <h1>
                    <xsl:for-each select="current-group()[self:: h1-title]">
                        <xsl:value-of select="."/> 
                        </xsl:for-each> 
                </h1>
            </xsl:for-each-group>

            <xsl:for-each-group select="*" group-starting-with="@h2-title"      >
                <h2>
                    <xsl:for-each select="current-group()[self::h2-title/@h2-title]">
                        <xsl:value-of select="."/>
                    </xsl:for-each> 
                </h2>
            </xsl:for-each-group>

            <xsl:for-each-group select="*" group-starting-with="@h3-title"      >
                <h3>
                    <xsl:for-each select="current-group()[self::h2-title/@h3-title]">
                        <xsl:value-of select="."/>
                    </xsl:for-each> 
                </h3>
            </xsl:for-each-group>

        </body>

  </xsl:template>

誰かが私の望みの結果を得るための正しい方法を教えてくれますか?

4

3 に答える 3

5

for-each-groupこれは、再帰関数で使用するXSLT 2.0スタイルシートです(XSLT 2.0の名前付きテンプレートよりも優先します)。

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  xmlns:mf="http://example.com/mf"
  exclude-result-prefixes="xs mf">

<xsl:param name="prefix" as="xs:string" select="'h'"/>
<xsl:param name="suffix" as="xs:string" select="'-title'"/>

<xsl:output method="html" version="4.0" indent="yes"/>

<xsl:function name="mf:group" as="node()*">
  <xsl:param name="items" as="node()*"/>
  <xsl:param name="level" as="xs:integer"/>
  <xsl:for-each-group select="$items" group-starting-with="p[@name = concat($prefix, $level, $suffix)]">
    <xsl:choose>
      <xsl:when test="not(self::p[@name = concat($prefix, $level, $suffix)])">
        <xsl:apply-templates select="current-group()"/>
      </xsl:when>
      <xsl:otherwise>
        <xsl:element name="h{$level}">
          <xsl:apply-templates select="."/>
          <xsl:sequence select="mf:group(current-group() except ., $level + 1)"/>
        </xsl:element>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:for-each-group>
</xsl:function>

<xsl:template match="@* | node()">
  <xsl:copy>
    <xsl:apply-templates select="@* , node()"/>
  </xsl:copy>
</xsl:template>

<xsl:template match="body">
  <xsl:copy>
    <xsl:sequence select="mf:group(*, 1)"/>
  </xsl:copy>
</xsl:template>

</xsl:stylesheet>

Saxon9でそのスタイルシートを入力に適用すると

<body>
   <p name="h-title" other="main">Introduction</p>
   <p name="h1-title" other="other-h1">XSLT and XQuery</p>
   <p name="h2-title" other=" other-h2">XSLT</p>
   <p name="">
      <p1 name="bold"> XSLT is used to write stylesheets.</p1>
   </p>
   <p name="h2-title" other="other-h2">XQuery</p>
   <p name="">
      <p1 name="bold"> XQuery is used to query XML databases.</p1>
   </p>
   <p name="h3-title" other="other-h3">XQuery and stylesheets</p>
   <p name="">
      <p1 name="bold"> XQuery is used to query XML databases.</p1>
   </p>
   <p name="h1-title" other="other-h1">XSLT and XQuery</p>
   <p name="h2-title" other=" other-h2">XSLT</p>
</body>

結果が出ます

<body>
   <p name="h-title" other="main">Introduction</p>
   <h1>
      <p name="h1-title" other="other-h1">XSLT and XQuery</p>
      <h2>
         <p name="h2-title" other=" other-h2">XSLT</p>
         <p name="">

            <p1 name="bold"> XSLT is used to write stylesheets.</p1>

         </p>
      </h2>
      <h2>
         <p name="h2-title" other="other-h2">XQuery</p>
         <p name="">

            <p1 name="bold"> XQuery is used to query XML databases.</p1>

         </p>
         <h3>
            <p name="h3-title" other="other-h3">XQuery and stylesheets</p>
            <p name="">

               <p1 name="bold"> XQuery is used to query XML databases.</p1>

            </p>
         </h3>
      </h2>
   </h1>
   <h1>
      <p name="h1-title" other="other-h1">XSLT and XQuery</p>
      <h2>
         <p name="h2-title" other=" other-h2">XSLT</p>
      </h2>
   </h1>
</body>
于 2012-07-21T10:27:53.173 に答える
3

この変換では、キーとハンドルh1-titleを使用して次のことを行いますh6-title

<xsl:stylesheet version="1.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 select="p[@name='h1-title']" />
     </xsl:template>

     <xsl:key name="next-headings" match="p[@name='h6-title']"
       use="generate-id(preceding-sibling::p
                         [ @name='h1-title'
                        or @name='h2-title'
                        or @name='h3-title'
                        or @name='h4-title'
                        or @name='h5-title'
                        ][1])" />
     <xsl:key name="next-headings" match="p[@name='h5-title']"
       use="generate-id(preceding-sibling::p
                         [ @name='h1-title'
                        or @name='h2-title'
                        or @name='h3-title'
                        or @name='h4-title'
                        ][1])" />
     <xsl:key name="next-headings" match="p[@name='h4-title']"
       use="generate-id(preceding-sibling::p
                         [ @name='h1-title'
                        or @name='h2-title'
                        or @name='h3-title'
                        ][1])" />
     <xsl:key name="next-headings" match="p[@name='h3-title']"
       use="generate-id(preceding-sibling::p
                         [  @name='h1-title'
                        or @name='h2-title'
                        ][1])" />
     <xsl:key name="next-headings" match="p[@name='h2-title']"
       use="generate-id(preceding-sibling::p
                         [@name='h1-title'][1])" />

     <xsl:key name="immediate-nodes" match=
     "node()[not(self::p)
           or
            not(contains('|h1-title|h2-title|h3-title|h4-title|h5-title|h6-title|',
                         concat('|',@name,'|')
                        )
                )]"
       use="generate-id(preceding-sibling::p
             [contains('|h1-title|h2-title|h3-title|h4-title|h5-title|h6-title|',
                       concat('|',@name,'|')
                       )
             ][1])" />

     <xsl:template match=
      "p[contains('|h1-title|h2-title|h3-title|h4-title|h5-title|h6-title|',
                  concat('|',@name,'|')
                  )]">
       <xsl:variable name="vLevel" select="substring(@name,2,1)" />
       <xsl:element name="h{$vLevel}">
          <xsl:copy-of select="."/>
          <xsl:apply-templates select="key('immediate-nodes', generate-id())" />
          <xsl:apply-templates select="key('next-headings', generate-id())" />
       </xsl:element>
     </xsl:template>

     <xsl:template match="/*/node()" priority="-20">
       <xsl:copy-of select="." />
     </xsl:template>
</xsl:stylesheet>

このXMLドキュメントに適用した場合(提供されたものを修正し、name属性に統一された値を使用):

<body>
        <p name="h1-title" other="main">Introduction</p>
        <p name="h2-title" other="other-h2">XSLT and XQuery</p>
        <p name="h3-title" other=" other-h3">XSLT</p>
        <p name="">
                <p1 name="bold"> XSLT is used to write stylesheets.</p1>
        </p>
        <p name="h2-title" other="other-h2">XQuery</p>
        <p name="">
                <p1 name="bold"> XQuery is used to query XML databases.</p1>
        </p>
        <p name="h3-title" other="other-h3">XQuery and stylesheets</p>
        <p name="">
                <p1 name="bold"> XQuery is used to query XML databases.</p1>
        </p>
        <p name="h1-title" other="other-h1">XSLT and XQuery</p>
        <p name="h2-title" other=" other-h2">XSLT</p>
</body>

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

<h1>
   <p name="h1-title" other="main">Introduction</p>
   <h2>
      <p name="h2-title" other="other-h2">XSLT and XQuery</p>
      <h3>
         <p name="h3-title" other=" other-h3">XSLT</p>
         <p name="">
            <p1 name="bold"> XSLT is used to write stylesheets.</p1>
         </p>
      </h3>
   </h2>
   <h2>
      <p name="h2-title" other="other-h2">XQuery</p>
      <p name="">
         <p1 name="bold"> XQuery is used to query XML databases.</p1>
      </p>
      <h3>
         <p name="h3-title" other="other-h3">XQuery and stylesheets</p>
         <p name="">
            <p1 name="bold"> XQuery is used to query XML databases.</p1>
         </p>
      </h3>
   </h2>
</h1>
<h1>
   <p name="h1-title" other="other-h1">XSLT and XQuery</p>
   <h2>
      <p name="h2-title" other=" other-h2">XSLT</p>
   </h2>
</h1>

注意してください

この変換は、階層を生成するという主な問題を解決します。nameトップレベルの属性に値が必要な場合は、些細な変更のみが必要です"h-title"

より多くの階層レベルが必要な場合は、対応する句をキーの定義に機械的に追加し、すべての属性の値orのパイプ区切り文字列に対応する新しい文字列を追加するだけで済みます。name

ここでは、JeniTennisonが同様の問題に対して提供したソリューションを採用して再利用しました。

于 2012-07-21T03:35:09.427 に答える
2

各グループ化ステップでは、元の要素のセットを入力として使用しますが、前のグループ化ステップで作成されたグループで作業するには、各ステップが必要です。また、他にも多くのエラーがあります。たとえば、h1-titleは属性名ではありません。

次のようなものである必要があります。

<xsl:for-each-group select="*" group-starting-with="*[@name='h1-title']">
<h1>
  <xsl:choose>
    <xsl:when test="@name='h1-title'">
      <xsl:for-each-group select="current-group()" group-starting-with="*[name='h2-title']">
        <xsl:choose>
        <h2>
          ... similar logic for the next level ...
        </h2>
        </xsl:choose>
      </xsl:for-each-group>
    </xsl:when>
    <xsl:otherwise>
      <xsl:copy-of select="current-group()"/>
    </xsl:otherwise>
  </xsl:choose>
</h1>
</xsl:for-each-group>

処理するレベルの数に応じて、必要なだけ深くネストできます。または、不定の数を処理する場合は、名前付きテンプレートにコードを配置し、再帰呼び出しを行って次のレベルを処理できます。最も内側のレベルでは、を省略してxsl:choose実行しますxsl:copy-of select="current-group()

(「name」属性の末尾のスペースに気づきました。これらが実際に存在する場合は、比較テストに含めるか、削除する必要がありnormalize-space()ます。)

于 2012-07-20T19:56:50.780 に答える