2014-03-04 32 views
2

我有以下Html文檔。如何根據其他元素的文本節點內的值更改HTML文檔的元素序列

<html> 
    <head><title>...</title></head> 
    <body> 

     <div class="figure-wrapper" id="figure1">...</div> 

     <p class="para">Lorem Ipsum (see Fig. 1). Lorem Ipsum (see Fig. 2).</p> 

     <div class="figure-wrapper" id="figure3">...</div> 

     <p class="para">Lorem Ipsum (see Fig. 3). Lorem Ipsum (see Fig. 1).</p> 

     <div class="figure-wrapper" id="figure2">...</div> 

    </body> 
</html> 

什麼我想實現

  • 將每一個數字元素(由<div class="figure-wrapper">元素包裹的)具有第一參考它的一個段落之後。
  • 如果第一段之後的元素本身就是一個數字元素,那麼應該把這個數字元素放在它後面。

實施例和理想輸出

<div class="figure-wrapper" id="figure1>元件應放置僅因爲它是引用該圖中的所有段落中的第一個的第一段之後。

<html> 
    <head><title>...</title></head> 
    <body> 

     <p class="para">Lorem Ipsum (see Fig. 1). Lorem Ipsum (see Fig. 2).</p> 

     <div class="figure-wrapper" id="figure1">...</div> 

     <div class="figure-wrapper" id="figure2">...</div> 

     <p class="para">Lorem Ipsum (see Fig. 3). Lorem Ipsum (see Fig. 1).</p> 

     <div class="figure-wrapper" id="figure3">...</div> 

    </body> 
</html> 

限制

沒有明確提及(在HTML元素計)與圖中的元素在輸入文檔中存在。因此,我必須分析段落內容(例如,出現某些值,如圖x等),以推斷段落內是否已經對圖形進行了引用。

我到目前爲止製作的是以下解決方案。

我嘗試了一個奇怪的混合使用身份轉換模式,密鑰和多通道方法,但是,我想不通。

<xsl:stylesheet 
    xmlns:xsl ="http://www.w3.org/1999/XSL/Transform" 
    xmlns:xd ="http://www.oxygenxml.com/ns/doc/xsl" 
    xmlns:fn ="http://www.w3.org/2005/xpath-functions" 
    xmlns:functx="http://www.functx.com" 
    exclude-result-prefixes="xd" 
    version="2.0"> 

    <!-- maximum number of figure references within one paragraph --> 

    <xsl:variable name="figThreshold" select="100" /> 

    <!-- index of all figure elements --> 

    <xsl:key name="figure-index" match="node()[@class='figure-wrapper']" use="@id" /> 

    <!-- transformation init --> 

    <xsl:template match="/"> 
     <xsl:variable name="pass1"> 
      <xsl:apply-templates mode="pass1" /> 
     </xsl:variable> 
     <xsl:variable name="pass2"> 
      <xsl:for-each select="$pass1"> 
       <xsl:apply-templates mode="pass2" /> 
      </xsl:for-each> 
     </xsl:variable> 
     <xsl:copy-of select="$pass2" /> 
    </xsl:template> 

    <!-- pass 1 start --> 

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

    <xsl:template match="node()[name()='p']" mode="pass1" priority="1"> 
     <xsl:copy> 
      <xsl:apply-templates select="@* | node()" mode="pass1" /> 
     </xsl:copy> 
     <xsl:call-template name="locate-and-move-figures" />   
    </xsl:template> 

    <!-- iterates x times (see value of figThreshold) over paragraph text and increment each time the figure number reference to look for --> 

    <xsl:template name="locate-and-move-figures"> 
     <xsl:param name="figCount" select="1" /> 
     <xsl:variable name="figureId" select="concat('figure',$figCount)" /> 
     <xsl:variable name="searchStringText" select="concat('Fig. ',$figCount)) /> 

     <!-- if figure reference is found within paragraph insert the appropriate after it --> 

     <xsl:if test="$searchStringText"> 
      <xsl:copy-of select="key('figure-index',$figureId)" />  
     </xsl:if> 

     <!-- recursive call of template unless threshold value is reached --> 

     <xsl:if test="$figCount &lt; $figThreshold"> 
      <xsl:call-template name="locate-and-move-figures"> 
       <xsl:with-param name="figCount" select="$figCount + 1" /> 
      </xsl:call-template> 
     </xsl:if> 
    </xsl:template> 

    <xsl:template match="node()[@class='figure-wrapper']" mode="pass1" /> 

    <!-- pass 1 end --> 

    <!-- pass 2 start - eliminations of all duplicates --> 

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

    <!-- pass 2 end --> 

</xsl:stylesheet> 

輸出我得到的是這樣的:

<html> 
    <head><title>...</title></head> 
    <body> 
     <p class="para">Lorem Ipsum (see Fig. 1). Lorem Ipsum (see Fig. 2).</p> 

     <div class="figure-wrapper" id="figure1">...</div> 

     <div class="figure-wrapper" id="figure2">...</div> 

     <p class="para">Lorem Ipsum (see Fig. 3). Lorem Ipsum (see Fig. 1).</p> 

     <div class="figure-wrapper" id="figure1">...</div> 

     <div class="figure-wrapper" id="figure3">...</div> 
    </body> 
</html> 

的問題

  • 重複的<div class="figure-wrapper">元素。我試圖在第二回閤中擺脫他們,但我無法將重複刪除與身份轉換模式結合在一起。
  • 對於每個段落在圖形參考中獲得x次遞增搜索(在本例中爲100次)的事實,我並不感到滿意。我可以選擇一個較低的閾值(例如20次),但是恐怕我可能會錯過一些參考文獻,因爲一個段落內的參考文獻的自然最大值不存在。

任何與這些問題的幫助是高度讚賞。

回答

1

以下是您可以探索的不同方法。我在XSLT 1.0中這樣做了,但差異對於這種方法並不重要。

其基本思想是將父段的id附加到段所包含的每個引用。然後,使用Muenchian分組,我們只留下每個參考的第一個出現。而且由於每一個都保留了原始父代的id,所以我們知道它需要在最終輸出中出現的位置。

請注意,假設沒有獨立的參考元素(即在至少一個段中未引用的元素)。

<?xml version="1.0" encoding="utf-8"?> 
<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:exsl="http://exslt.org/common" 
extension-element-prefixes="exsl"> 

<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/> 
<xsl:strip-space elements="*"/> 

<xsl:key name="tokens" match="token" use="." /> 
<xsl:key name="ref" match="div[@class='figure-wrapper']" use="@id" /> 

<xsl:variable name="root" select="/"/> 

<!-- 1. collect all references, along with their parent id --> 
<xsl:variable name="references"> 
    <xsl:for-each select="//p[@class='para']"> 
     <xsl:call-template name="cat_ref"> 
      <xsl:with-param name="string" select="."/> 
      <xsl:with-param name="pid" select="generate-id()"/> 
     </xsl:call-template> 
    </xsl:for-each> 
</xsl:variable> 

<!-- 2. keep only unique references --> 
<xsl:variable name="unique-ref" select="exsl:node-set($references)/token[count(. | key('tokens', .)[1]) = 1]"/> 

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

<xsl:template match="p[@class='para']"> 
    <xsl:copy> 
     <xsl:apply-templates select="@*|node()"/> 
    </xsl:copy> 
    <!-- append my references --> 
    <xsl:for-each select="$unique-ref[@pid=generate-id(current())]"> 
    <xsl:variable name="ref-key" select="."/> 
     <!-- switch back to document in order to use key --> 
     <xsl:for-each select="$root"> 
      <xsl:copy-of select="key('ref', $ref-key)"/> 
     </xsl:for-each> 
    </xsl:for-each> 
</xsl:template> 

<!-- suppress references --> 
<xsl:template match="div [@class='figure-wrapper']"/> 

<!-- proc template --> 
<xsl:template name="cat_ref"> 
    <xsl:param name="string"/> 
    <xsl:param name="pid"/> 
    <xsl:param name="prefix" select="'(see Fig. '" /> 
    <xsl:param name="suffix" select="')'" /> 
    <xsl:if test="contains($string, $prefix) and contains(substring-after($string, $prefix), $suffix)"> 
     <token pid="{$pid}"> 
      <xsl:text>figure</xsl:text> 
      <xsl:value-of select="substring-before(substring-after($string, $prefix), $suffix)" /> 
     </token> 
      <!-- recursive call --> 
      <xsl:call-template name="cat_ref"> 
       <xsl:with-param name="string" select="substring-after(substring-after($string, $prefix), $suffix)" /> 
       <xsl:with-param name="pid" select="$pid" /> 
      </xsl:call-template> 
    </xsl:if> 
</xsl:template> 

</xsl:stylesheet> 

應用到您的輸入時,獲得以下結果:

<?xml version="1.0" encoding="UTF-8"?> 
<html> 
    <head> 
     <title>...</title> 
    </head> 
    <body> 
     <p class="para">Lorem Ipsum (see Fig. 1). Lorem Ipsum (see Fig. 2).</p> 
     <div class="figure-wrapper" id="figure1">...</div> 
     <div class="figure-wrapper" id="figure2">...</div> 
     <p class="para">Lorem Ipsum (see Fig. 3). Lorem Ipsum (see Fig. 1).</p> 
     <div class="figure-wrapper" id="figure3">...</div> 
    </body> 
</html> 
1

這裏是我建議用於XSLT 2.0,其中在第一步驟使用analyze-string到例如變換(see Fig. 3)併入元素<ref name="figure" idref="3"/>,然後使用鍵識別p元素中的第一個參考以在第二步中輸出div[@class = 'figure-wrapper']。第二步也變換ref元素放回嵌入式文本:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 

<xsl:output method="html"/> 

<xsl:variable name="references"> 
    <xsl:apply-templates mode="references"/> 
</xsl:variable> 

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

<!-- might want to use match="p[@class = 'para']//text()" --> 
<xsl:template match="text()" mode="references" priority="5"> 
    <xsl:analyze-string select="." regex="\(see Fig\. ([0-9]+)\)"> 
    <xsl:matching-substring> 
     <ref name="figure" idref="{regex-group(1)}"/> 
    </xsl:matching-substring> 
    <xsl:non-matching-substring> 
     <xsl:value-of select="."/> 
    </xsl:non-matching-substring> 
    </xsl:analyze-string> 
</xsl:template> 

<xsl:key name="refs" match="div[@class = 'figure-wrapper']" use="@id"/> 
<xsl:key name="fig-refs" match="ref" use="concat(@name, @idref)"/> 

<xsl:template match="/"> 
    <xsl:apply-templates select="$references/node()"/> 
</xsl:template> 

<xsl:template match="div[@class = 'figure-wrapper']"/> 

<xsl:template match="p[@class = 'para'][.//ref[. is key('fig-refs', concat(@name, @idref))[1]]]"> 
    <xsl:next-match/> 
    <xsl:variable name="first-refs" select=".//ref[. is key('fig-refs', concat(@name, @idref))[1]]"/> 
    <xsl:copy-of select="key('refs', $first-refs/concat(@name, @idref))"/> 
</xsl:template> 

<xsl:template match="ref"> 
    <xsl:text>(see Fig. </xsl:text> 
    <xsl:value-of select="@idref"/> 
    <xsl:text>)</xsl:text> 
</xsl:template> 

</xsl:stylesheet> 

應用與撒克遜9.5是XSLT你輸入我得到

<html> 

    <head> 
     <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 
     <title>...</title> 
    </head> 

    <body> 




     <p class="para">Lorem Ipsum (see Fig. 1). Lorem Ipsum (see Fig. 2).</p> 
     <div class="figure-wrapper" id="figure1">...</div> 
     <div class="figure-wrapper" id="figure2">...</div> 




     <p class="para">Lorem Ipsum (see Fig. 3). Lorem Ipsum (see Fig. 1).</p> 
     <div class="figure-wrapper" id="figure3">...</div> 




    </body> 

</html> 

我認爲這是你想要的元素的順序。

相關問題