所以我的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) = '
' or substring($text, 1, 1) = ' '">
<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> </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, '
')">
<xsl:call-template name="replace-spaces">
<xsl:with-param name="text" select="substring-before($text, '
')" />
</xsl:call-template>
<br />
<xsl:call-template name="replace-spaces">
<xsl:with-param name="text" select="substring-after($text, '
')" />
</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>
内的子项,即将替换标记嵌套在彼此内部(例如<replace ...><replace ...>...</replace></replace>
)是没有意义的,因为XSLT不会递归迭代兄弟姐妹。
无论如何我可以让这个XSLT迭代兄弟姐妹并根据需要执行替换吗?
答案 0 :(得分: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() > 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>
它对第一个替换进行单独检查,然后对后续的(如果有的话)检查它是否根据当前 @start 属性之间的差异来执行子字符串和之前的 @end 属性。最后它将最后一个替换元素分开。