2012-01-11 6 views
0

私は自動番号付けしたいマルチレベル節を含むXML(XHTML、実際には)ドキュメントを多数持っています。問題は、文書が、テキスト属性で示されたレベルを持つ構造化されていないフラットリストであることです。はい、私は知っていますが、私は現実的にそれらを変更することはできません。あまりにも多く、大きすぎる。XSLTマルチレベルではあるが構造化されていないドキュメント

構造と、私は希望のラベルを示す簡略化された場合は、次のとおりです。

<root> 
    <p label="1" class="clause_L1">A</p> 
    <p label="1.1" class="clause_L2">B</p> 
    <p label="1.2" class="clause_L2">C</p> 
    <p label="1.3" class="clause_L2">D</p> 
    <p label="2" class="clause_L1">E</p> 
    <p label="3" class="clause_L1">F</p> 
    <p label="4" class="clause_L1">G</p> 
    <p label="4.1" class="clause_L2">H</p> 
    <p label="4.1.1" class="clause_L3">I</p> 
    <p label="4.1.2" class="clause_L3">J</p> 
    <p label="4.2" class="clause_L2">K</p> 
    <p label="4.3" class="clause_L2">L</p> 
</root> 

ずっと周りのハッキングの後、私は次のスタイルシートを持っている:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
> 
<xsl:output method="xml" indent="yes" /> 

<xsl:template match="/"> 
<xsl:apply-templates /> 
</xsl:template> 

<xsl:template match="p[substring(@class, 1, 6) = 'clause']"> 
    <xsl:variable name="class" select="@class"/> 
    <xsl:variable name="level" select="substring(@class, 9, 1)"/> 
    <xsl:variable name="parent" select="preceding-sibling::p[@class = concat('clause_L', $level - 1)][1]"/> 
    <xsl:variable name="parentPos" select="count($parent/preceding-sibling::p[substring(@class, 1, 6) = 'clause']) + 1"/> 

    <clause> 
    <xsl:attribute name="parent"> 
     <xsl:value-of select="$parent/@label"/> 
    </xsl:attribute> 
    <xsl:attribute name="parentPos"> 
     <xsl:value-of select="$parentPos"/> 
    </xsl:attribute> 
    <xsl:attribute name="origLabel"> 
     <xsl:value-of select="@label"/> 
    </xsl:attribute> 
    <xsl:attribute name="label"> 
     <xsl:number count="p[string($parent) = '' or position() &gt; $parentPos][@class = $class]" /> 
    </xsl:attribute> 
    <xsl:value-of select="."/> 
    </clause> 
</xsl:template> 

。 ..私に最も低い電流レベルの正しい番号付けを与える:

<clause parent="" parentPos="1" origLabel="1" label="1">A</clause> 
<clause parent="1" parentPos="1" origLabel="1.1" label="1">B</clause> 
<clause parent="1" parentPos="1" origLabel="1.2" label="2">C</clause> 
<clause parent="1" parentPos="1" origLabel="1.3" label="3">D</clause> 
<clause parent="" parentPos="1" origLabel="2" label="2">E</clause> 
<clause parent="" parentPos="1" origLabel="3" label="3">F</clause> 
<clause parent="" parentPos="1" origLabel="4" label="4">G</clause> 
<clause parent="4" parentPos="7" origLabel="4.1" label="1">H</clause> 
<clause parent="4.1" parentPos="8" origLabel="4.1.1" label="1">I</clause> 
<clause parent="4.1" parentPos="8" origLabel="4.1.2" label="2">J</clause> 
<clause parent="4" parentPos="7" origLabel="4.2" label="2">K</clause> 
<clause parent="4" parentPos="7" origLabel="4.3" label="3">L</clause> 

まず、現在のコンテキストでのみxsl:numberが動作するように、このテンプレート内のラベルの上位レベルの数値を生成することは可能ですか?現在の次のレベルを取得する方法はわかりませんアップカウンタ。

第2に、この完全停止を行うためのよりよい方法はありますか?私はソースデータ形式に悩まされています。

答えて

0

これを解決し、再帰を使用して合理的にきちんとした一般的な方法で、任意のレベルに対応します。

これは、フラットなものから構造化文書を作成しようとする人にとっても便利に変更できます。

---パフォーマンスはおそらくひどいですが、これは、大量のアプリではありませんので、私は気にしない; O)

EDIT:パフォーマンスは、実際にgodawfulだったので、私は答えを更新しましたより最適化されたものパフォーマンスの問題を引き起こす実際のものはちょっと変わっていて、コードにコメントされています。私はそれが怠惰な評価の仕方と関係があると考えています。事前評価がなければ、完全な再帰的実行にはデータ(〜400句)を実行するのに1分30秒かかり、それには5秒かかります。私は.NET 4でXSLTエンジンを使用しています.5秒は聞こえますが、これはPDF最終ドキュメントの生成、ダウンロード、ブラウザレンダリングを含む完全なアプリケーションの実行であり、変換のみを測定していません。

<clause origLabel="1" label="1.">A</clause> 
<clause origLabel="1.1" label="1.1.">B</clause> 
<clause origLabel="1.2" label="1.2.">C</clause> 
<clause origLabel="1.3" label="1.3.">D</clause> 
<clause origLabel="2" label="2.">E</clause> 
<clause origLabel="3" label="3.">F</clause> 
<clause origLabel="4" label="4.">G</clause> 
<clause origLabel="4.1" label="4.1.">H</clause> 
<clause origLabel="4.1.1" label="4.1.1.">I</clause> 
<clause origLabel="4.1.2" label="4.1.2.">J</clause> 
<clause origLabel="4.2" label="4.2.">K</clause> 
<clause origLabel="4.3" label="4.3.">L</clause> 
:意図した結果を与える

<xsl:template match="p[substring(@class, 1, 6) = 'clause']"> 
    <clause> 
    <xsl:attribute name="origLabel"> 
     <xsl:value-of select="@label"/> 
     </xsl:attribute> 
    <xsl:attribute name="label"> 
     <xsl:call-template name="makeLabel"> 
      <xsl:with-param name="node" select="."/> 
     </xsl:call-template> 
    </xsl:attribute> 
    <xsl:value-of select="."/> 
    </clause> 
</xsl:template> 


<xsl:template name="makeLabel"> 
    <xsl:param name="node"/> 

    <xsl:variable name="class" select="$node/@class"/> 
    <xsl:variable name="level" select="substring($class, 9, 1)"/> 
    <xsl:variable name="parent" select="$node/preceding-sibling::p[@class = concat('clause_L', $level - 1)][1]"/> 
    <xsl:variable name="parentPos" select="count($parent/preceding-sibling::p[substring(@class, 1, 6) = 'clause']) + 1"/> 
    <xsl:variable name="myPos" select="count($node/preceding-sibling::p[substring(@class, 1, 6) = 'clause']) + 1"/> 
    <xsl:variable name="precPos" select="number($myPos - $parentPos)"/> 
    <xsl:variable name="topLevel" select="not($parent)"/> 

    <xsl:if test="string($parent) != ''"> 
     <xsl:call-template name="makeLabel"> 
      <xsl:with-param name="node" select="$parent"/> 
     </xsl:call-template> 
    </xsl:if> 

    <xsl:choose> 
    <xsl:when test="$topLevel"> 
     <xsl:value-of select="count($node/preceding-sibling::p[@class = $class]) + 1" /> 
    </xsl:when> 
    <xsl:otherwise> 
     <!-- 
     It is ABSOLUTELY REQUIRED to pre-evaluate $precPos before the count(); without this the request takes over a minute to run; 
     with it, it takes ~5 seconds. 
     --> 
     <xsl:comment><xsl:value-of select="$precPos"/></xsl:comment> 
     <!-- --> 
     <xsl:value-of select="count($node/preceding-sibling::p[position() &lt; $precPos][@class = $class]) + 1" /> 
    </xsl:otherwise> 
    </xsl:choose>  
    <xsl:text>.</xsl:text> 
</xsl:template> 

:XSLは、上記のようにソースXMLを使用して

関連する問題