0

したがって、次のような 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 で変数を 2 回設定することはできないため、私の現在の戦略は機能しませんが<location>、非再帰的に内部の子をループする必要があります。単純に、XSLT が兄弟を再帰的<replace ...><replace ...>...</replace></replace>に反復しないためです。

とにかく、この XSLT で兄弟を反復処理し、必要に応じて置換を実行することはできますか?

4

1 に答える 1

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>

最初のreplaceに対して個別のチェックがあり、その後 (存在する場合) に対しては、現在の@start属性と前の@end属性の違いに基づいて部分文字列を実行します。そして最後に、最後の置換要素の末尾を分割します。

于 2013-04-13T18:21:27.363 に答える