2013-04-13 142 views
0
遞歸替換XSLT文本

所以我有XML,看起來像:使用兄弟節點

<?xml version="1.0" encoding="UTF-8" ?> 
<?xml-stylesheet type="text/xsl" href="reports.xsl"?> 
<analysis> 
    <layers> 
     <layer name="Initial Bool" id="l0"> 
      <code><![CDATA[some 
multiline text 
goes here]]></code> 
     </layer> 
    </layers> 
    <report name="Some Node"> 
     <issues> 
      <issue> 
       <layer id="l0" /> 
       <name>Replace expression</name> 
       <description> 
        Test description. 
       </description> 
       <locations> 
        <replace start="20" end="30">hello</replace> 
       </locations> 
      </issue> 
     </issues> 
    </report> 
</analysis> 

和我目前的XSLT是:

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

    <xsl:template match="/analysis"> 
     <html> 
      <head> 
       <title>Tychaia Analysis Reports</title> 
       <script src="https://google-code-prettify.googlecode.com/svn/loader/run_prettify.js"> 
       </script> 
      </head> 
      <body> 
       <xsl:apply-templates /> 
      </body> 
     </html> 
    </xsl:template> 

    <xsl:template match="/analysis/layers"> 
     <!-- Do nothing with layers as we reference them from the reports --> 
    </xsl:template> 

    <xsl:template match="/analysis/report"> 
     <h2> 
      <xsl:value-of select="@name" /> 
     </h2> 
     <xsl:apply-templates /> 
    </xsl:template> 

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

    <xsl:template match="/analysis/report/issues/issue"> 
     <h3> 
      <xsl:value-of select="name" /> 
     </h3> 
     <p> 
      <xsl:value-of select="description" /> 
     </p> 
     <code style="border: none;" class="prettyprint"> 
      <!-- This is the bit that I can't work out how to do (ideally the 
      replaced content would also then get passed into 
      remove-leading-whitespace as the text data): 
      <xsl:call-template name="format-locations"> 
       <xsl:with-param name="text" select="/analysis/layers/layer[@id=current()/layer/@id]" /> 
       <xsl:with-param name="locations" select="locations" /> 
      </xsl:call-template> 
      --> 
      <xsl:call-template name="remove-leading-whitespace"> 
       <xsl:with-param name="text" select="/analysis/layers/layer[@id=current()/layer/@id]" /> 
      </xsl:call-template> 
     </code> 
    </xsl:template> 

    <!-- THIS DOESN'T WORK --> 
    <xsl:template name="format-locations"> 
     <xsl:param name="text" /> 
     <xsl:param name="locations" /> 
     <xsl:variable name="result" select="$text" /> 
     <xsl:for-each select="$locations/replace"> 
      <xsl:variable name="result"> 
       <xsl:value-of select="substring($result, 1, current()/@start)" /> 
       <xsl:text>yo replaced</xsl:text> 
       <xsl:value-of select="substring($result, current()/@end)" /> 
      </xsl:variable> 
     </xsl:for-each> 
     <xsl:copy-of select="$result" /> 
    </xsl:template> 

    <!-- Removes leading whitespaces for code rendering --> 
    <xsl:template name="remove-leading-whitespace"> 
     <xsl:param name="text" /> 
     <xsl:choose> 
      <xsl:when test="substring($text, 1, 1) = ' ' or substring($text, 1, 1) = '&#xA;' or substring($text, 1, 1) = '&#xA0;'"> 
       <xsl:call-template name="remove-leading-whitespace"> 
        <xsl:with-param name="text" select="substring($text, 2)" /> 
       </xsl:call-template> 
      </xsl:when> 
      <xsl:otherwise> 
       <xsl:call-template name="replace-spaces"> 
        <xsl:with-param name="text" select="$text" /> 
       </xsl:call-template> 
      </xsl:otherwise> 
     </xsl:choose> 
    </xsl:template> 

    <!-- Replaces spaces and newlines in code with nbsp and <br/> --> 
    <xsl:template name="replace-spaces"> 
     <xsl:param name="text" /> 
     <xsl:choose> 
      <xsl:when test="contains($text, ' ')"> 
       <xsl:call-template name="replace-spaces"> 
        <xsl:with-param name="text" select="substring-before($text, ' ')" /> 
       </xsl:call-template> 
       <xsl:text>&#xA0;</xsl:text> 
       <xsl:call-template name="replace-spaces"> 
        <xsl:with-param name="text" select="substring-after($text, ' ')" /> 
       </xsl:call-template> 
      </xsl:when> 
      <xsl:when test="contains($text, '&#xA;')"> 
       <xsl:call-template name="replace-spaces"> 
        <xsl:with-param name="text" select="substring-before($text, '&#xA;')" /> 
       </xsl:call-template> 
       <br /> 
       <xsl:call-template name="replace-spaces"> 
        <xsl:with-param name="text" select="substring-after($text, '&#xA;')" /> 
       </xsl:call-template> 
      </xsl:when> 
      <xsl:otherwise> 
       <xsl:value-of select="$text" /> 
      </xsl:otherwise> 
     </xsl:choose> 
    </xsl:template> 

</xsl:stylesheet> 

我希望能夠更換裏面的內容<code>標籤基於<locations>中定義的替換。這是爲了使報告可以突出顯示代碼的一部分以及與每個代碼一起發送的消息。

但是,我對format-locations目前的策略不工作,因爲你不能設置一個變量在XSLT第二次,但我需要遍歷所有的孩子裏面<location>非遞歸,也就是說,它沒有任何意義只需要簡單地因爲XSLT不會遞歸地迭代兄弟就可以將替換標籤嵌套在對方內部,如<replace ...><replace ...>...</replace></replace>

是否有無論如何我可以得到這個XSLT迭代兄弟姐妹並根據需要執行替換?

回答

0

試試這個模板。

<xsl:template name="format-locations"> 
    <xsl:param name="text"/> 
    <xsl:param name="locations"/> 

    <xsl:variable name="result"> 
    <xsl:value-of select="substring($text, 1, $locations/replace[1]/@start)"/> 
    <xsl:text>yo replaced</xsl:text> 
    <xsl:for-each select="$locations/replace[position() &gt; 1]"> 
     <xsl:value-of select="substring($text, preceding-sibling::replace[1]/@end + 1, @start - preceding-sibling::replace[1]/@end)"/> 
     <xsl:text>yo replaced</xsl:text> 
    </xsl:for-each> 
    <xsl:value-of select="substring($text, $locations/replace[last()]/@end + 1)"/> 
    </xsl:variable> 
    <xsl:copy-of select="$result"/> 
</xsl:template> 

它具有用於第一一個單獨檢查更換,然後用於隨後的人(如果有的話)它基於當前@啓動屬性與先前@end之間的差異的子屬性。最後它將最後的替換爲元素。