XSL 中的递归替换

Posted

技术标签:

【中文标题】XSL 中的递归替换【英文标题】:Recursive replace in XSL 【发布时间】:2018-12-29 11:16:30 【问题描述】:

我有以下 XML:

<?xml version="1.0" encoding="utf-8"?>
<routes>
    <route name="/path/id/name">
        <location>~ ^/path/id/name$</location>
        <methods>
            <method>GET</method>
        </methods>
        <parameters>
            <parameter name="id">[a-zA-Z0-9]+</parameter>
            <parameter name="name">[a-z]+</parameter>
        </parameters>
    </route>
</routes>

我想得到以下输出: ~ ^/path/(?&lt;id&gt;[a-zA-Z0-9]+)/(?&lt;name&gt;[a-z]+)$

但目前我有像 ~ ^/path/(?&lt;id&gt;[a-zA-Z0-9]+)/name$~ ^/path/id/(?&lt;name&gt;[a-z]+)$ 这样使用 XSL 的输出:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:php="http://php.net/xsl"
        version="1.0"
>

    <xsl:output method="text" encoding="utf-8"/>

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

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

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

    <xsl:template match="parameter">
        <xsl:value-of select="php:function('str_replace', concat('', @name, ''), concat('(?&lt;', @name, '&gt;', text(), ')'), string(./../../location))"/>
    </xsl:template>

</xsl:stylesheet>

我如何使用重用结果并将其传递给下一次运行?

【问题讨论】:

【参考方案1】:

您需要首先选择第一个参数,然后使用它进行替换。如果有以下参数,则递归选择它,将转换后的文本作为参数传递。否则输出当前文本。

试试这个 XSLT

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

    <xsl:output method="text" encoding="utf-8"/>

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

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

    <xsl:template match="parameters">
        <xsl:apply-templates select="parameter[1]"/>
    </xsl:template>

    <xsl:template match="parameter">
        <xsl:param name="text" select="string(./../../location)" />
        <xsl:variable name="newText" select="php:function('str_replace', concat('', @name, ''), concat('(?&lt;', @name, '&gt;', text(), ')'), $text)"/>
        <xsl:choose>
            <xsl:when test="following-sibling::parameter">
                <xsl:apply-templates select="following-sibling::parameter[1]">
                    <xsl:with-param name="text" select="$newText" />
                </xsl:apply-templates>
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="$newText" />
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
</xsl:stylesheet>

注意,如果您可以使用 XSLT 2.0,您可以直接在 location 节点上使用 xsl:analyze-string

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
    <xsl:output method="text" encoding="utf-8"/>

    <xsl:key name="parameters" match="parameter" use="@name" />

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

    <xsl:template match="route">
        <xsl:variable name="root" select="/" />
        <xsl:analyze-string select="location" regex="\([a-z]+)\">
            <xsl:matching-substring>
                <xsl:value-of select="key('parameters', regex-group(1), $root)" />
            </xsl:matching-substring>
            <xsl:non-matching-substring>
                <xsl:value-of select="." />
            </xsl:non-matching-substring>
        </xsl:analyze-string>
    </xsl:template>
</xsl:stylesheet>

【讨论】:

以上是关于XSL 中的递归替换的主要内容,如果未能解决你的问题,请参考以下文章

XSLT/XSL 递归嵌套元素

在 Saxon 中处理无限递归 XSL

递归地在不同的 xsl 文件中添加一行行

递归删除并替换clojure中的项目

递归替换字典中的字符

linux递归替换文件中的字符串