4

私は変わる解決策を探しています

<p>
<hi rend="bold">aa</hi>
<hi rend="bold">bb</hi>
<hi rend="bold">cc</hi>
Perhaps some text.
<hi rend="italic">dd</hi>
<hi rend="italic">ee</hi>
Some more text.
<hi rend="italic">ff</hi>
<hi rend="italic">gg</hi>
Foo.
</p>

の中へ

<p>
<hi rend="bold">aabbcc</hi>
Perhaps some text.
<hi rend="italic">ddee</hi>
Perhaps some text.
<hi rend="italic">ffgg</hi>
Foo. 
</p>

しかし、私のソリューションでは、要素と属性値の名前(斜体、太字)をハードコードしないでください。XSLTは、同じ名前と同じ属性値を持つすべての兄弟要素を実際に連結する必要があります。他のすべては手つかずのままにしておく必要があります。

私はすでにそこに存在する解決策を見てきましたが、それらのどれも私の要件のすべてを満たしていないようでした。

誰かがこれのための便利なXSLTスタイルシートを持っているなら、私は大いに義務づけられるでしょう。

4

3 に答える 3

6

このXSLT2.0スタイルシートは、隣接する要素を共通のrend属性とマージします。

<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="@*|node()">
  <xsl:copy>
    <xsl:apply-templates select="@*|node()" />
  </xsl:copy>
</xsl:template>

<xsl:template match="*[*/@rend]">
  <xsl:copy>
    <xsl:apply-templates select="@*" />
    <xsl:for-each-group select="node()" group-adjacent="
       if (self::*/@rend) then
           concat( namespace-uri(), '|', local-name(), '|', @rend)
         else
           ''">
      <xsl:choose>
        <xsl:when test="current-grouping-key()" >
          <xsl:for-each select="current-group()[1]">
            <xsl:copy>
              <xsl:apply-templates select="@* | current-group()/node()" />
            </xsl:copy>
          </xsl:for-each>
        </xsl:when>
        <xsl:otherwise>
         <xsl:apply-templates select="current-group()" />
        </xsl:otherwise>
      </xsl:choose>
    </xsl:for-each-group>
  </xsl:copy>
</xsl:template>

</xsl:stylesheet>

Martinのソリューションに対するこのソリューションの利点は次のとおりです。

  • これは、p要素だけでなく、すべての親要素をマージします。
  • もっと早く。マージは、2つのネストされたxsl:for-eachではなく、単一のxsl:for-eachで実行されます。
  • ヘッドマージ可能要素の非rend属性が出力にコピーされます。

注:

  • 共通の名前とrend属性値を持つ「隣接する」要素を決定する目的で除外される純粋な空白ノードのテストは、xsl:strip-space命令によって完全に回避されます。したがって、xsl:for-each命令は、かなり単純で読みやすい場合に使用します。
  • group-adjacent属性値の代わりに、代わりに...を使用できます。

    <xsl:for-each-group select="node()" group-adjacent="
       string-join(for $x in self::*/@rend return
         concat( namespace-uri(), '|', local-name(), '|', @rend),'')">
    

    個人的に読みやすい形式を使用してください。

于 2012-10-01T12:46:04.983 に答える
1

その属性の名前(例rend)はわかっていますか?その場合、私はあなたが欲しいと思います

<xsl:template match="p">
  <xsl:copy>
    <xsl:for-each-group select="*" group-adjacent="concat(node-name(.), '|', @rend)">
      <xsl:element name="{name()}" namespace="{namespace-uri()}">
         <xsl:copy-of select="@rend"/>
         <xsl:apply-templates select="current-group()/node()"/>
      </xsl:element>
     </xsl:for-each-group>
  </xsl:copy>
</xsl:template>

[編集]入力の編集で示したように、要素間にコンテンツを含むテキストノードが存在する可能性がある場合は、サンプルのようにグループ化にネストする必要があります

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

<xsl:template match="p">
  <xsl:copy>
    <xsl:for-each-group select="node() except text()[not(normalize-space())]" group-adjacent="boolean(self::*)">
      <xsl:choose>
        <xsl:when test="current-grouping-key()">
          <xsl:for-each-group select="current-group()" group-by="concat(node-name(.), '|', @rend)">
            <xsl:element name="{name()}" namespace="{namespace-uri()}">
               <xsl:copy-of select="@rend"/>
               <xsl:apply-templates select="current-group()/node()"/>
            </xsl:element>
          </xsl:for-each-group>
        </xsl:when>
        <xsl:otherwise>
          <xsl:apply-templates select="current-group()"/>
        </xsl:otherwise>
      </xsl:choose>
     </xsl:for-each-group>
  </xsl:copy>
</xsl:template>

</xsl:stylesheet>
于 2012-09-30T16:30:09.007 に答える
1

カジュアルな訪問者が来て、この問題のXSLT 1.0ソリューションがあるかどうか疑問に思った場合に備えて、次のことを提供します。私はショーンとマーティンの正解を減らそうとしているのではないことに注意してください。私は単にいくつかの味を提供しています。

このXSLT1.0ソリューションの場合:

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

  <xsl:key
     name="kFollowing" 
     match="hi" 
     use="concat(@rend, '+', generate-id(following-sibling::text()[1]))" />

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

  <xsl:template match="/*">
    <p>
      <xsl:apply-templates 
        select="
          hi[generate-id() = 
             generate-id(
           key('kFollowing', 
             concat(@rend, '+', generate-id(following-sibling::text()[1])))[1])]" />
    </p>
  </xsl:template>

  <xsl:template match="hi">
    <xsl:copy>
      <xsl:apply-templates 
        select="@*|key('kFollowing', 
          concat(@rend, '+', generate-id(following-sibling::text()[1])))/text()" />
    </xsl:copy>
    <xsl:apply-templates select="following-sibling::text()[1]" />
  </xsl:template>

</xsl:stylesheet>

... OPの元のXMLに適用されます:

<p>
<hi rend="bold">aa</hi>
<hi rend="bold">bb</hi>
<hi rend="bold">cc</hi>
Perhaps some text.
<hi rend="italic">dd</hi>
<hi rend="italic">ee</hi>
Some more text.
<hi rend="italic">ff</hi>
<hi rend="italic">gg</hi>
Foo.
</p>

...目的の結果が生成されます:

<p>
<hi rend="bold">aabbcc</hi>
Perhaps some text.
<hi rend="italic">ddee</hi>
Perhaps some text.
<hi rend="italic">ffgg</hi>
Foo. 
</p>
于 2012-10-06T15:43:23.080 に答える