XSL中的递归替换

时间:2018-07-21 08:57:02

标签: php xml xslt dom

我有以下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/(?<id>[a-zA-Z0-9]+)/(?<name>[a-z]+)$

但是目前我使用XSL这样的输出~ ^/path/(?<id>[a-zA-Z0-9]+)/{name}$~ ^/path/{id}/(?<name>[a-z]+)$是这样的:

<?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 个答案:

答案 0 :(得分:2)

您只需要选择第一个参数,然后使用该参数进行替换即可开始。如果存在以下参数,则可以递归选择它,并将转换后的文本作为参数传递。否则,输出当前文本。

尝试使用此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,则可以直接在xsl:analyze-string节点上使用location

<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>