2

此时我已经获得了一个 XSLT(从现在开始命名为 myLookupTable.xslt),它可以包含到其他 XSLT 文件中以便能够进行一些代码转换。这个 myLookupTable.xslt 是一个命名模板,每个人都可以使用它来编写 XSLT 文件并希望使用它。xsl:call-template所以我真的需要像现在一样坚持这一点。

XSLT 目前工作正常,但是对于包含转换的非常大的 XML 文件需要更多时间,我正在研究如何优化。

例如:

  • 是不是更好用xsl:key?如果是这样,我将如何在xsl:call-template?
  • 任何其他结构变化,所以我仍然能够坚持xsl:call-template
  • 如果最好摆脱 ,xsl:call-template我为什么要这样做,我怎样才能让其他人尽可能容易地实现它?

我读过一篇关于Muenchian Method的文章,我明白了,但不太确定如何在这个xsl:call-template例子中实现它。

任何帮助和建议表示赞赏。

输入 XML 示例

<?xml version="1.0" encoding="UTF-8"?>
<pref:data xmlns:pref="http://example.org/uri/data">
    <pref:PackageGroup>
        <pref:sendPackage>BX</pref:sendPackage>
        <pref:sendRelation>66778899</pref:sendRelation>
    </pref:PackageGroup>
    <pref:TypeGroup>
        <pref:sendType>80</pref:sendType>
        <pref:sendRelation>88996677</pref:sendRelation>
    </pref:TypeGroup>
</pref:data>

XSLT 用于在输入 XML 上进行转换

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

    <!-- Include lookup table XSLT and add variable to the lookup table xml -->
    <xsl:include href="myLookupTable.xslt"/>
    <xsl:variable name="myLookupTableFile">myLookupTable.xml</xsl:variable>

    <!-- Identity template -->
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()" />
        </xsl:copy>
    </xsl:template>

    <!-- Translate packageCode -->
    <xsl:template match="pref:sendPackage">
        <xsl:copy>
            <xsl:call-template name="myLookup">
                <xsl:with-param name="file"><xsl:value-of select="$myLookupTableFile" /></xsl:with-param>
                <xsl:with-param name="direction">in</xsl:with-param>
                <xsl:with-param name="function">filter</xsl:with-param>
                <xsl:with-param name="table">packageCode</xsl:with-param>
                <xsl:with-param name="relation"><xsl:value-of select="following-sibling::pref:sendRelation"/></xsl:with-param>
                <xsl:with-param name="value"><xsl:value-of select="."/></xsl:with-param>
            </xsl:call-template>
        </xsl:copy>
    </xsl:template>

    <!-- Translate type -->
    <xsl:template match="pref:sendType">
        <xsl:copy>
            <xsl:call-template name="myLookup">
                <xsl:with-param name="file"><xsl:value-of select="$myLookupTableFile" /></xsl:with-param>
                <xsl:with-param name="direction">in</xsl:with-param>
                <xsl:with-param name="function">filter</xsl:with-param>
                <xsl:with-param name="table">type</xsl:with-param>
                <xsl:with-param name="relation"><xsl:value-of select="following-sibling::pref:sendRelation"/></xsl:with-param>
                <xsl:with-param name="value"><xsl:value-of select="."/></xsl:with-param>
            </xsl:call-template>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

包含 xsl:call-template 的 XSLT

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:conv="http://example.org/uri/lookuptable">
    <xsl:template name="myLookup">
        <xsl:param name="file"/><!-- Name of the conversion XML file -->
        <xsl:param name="direction"/><!-- 'in' ('directionIncoming' element is used) or 'out' ('directionOutgoing' element is used) -->
        <xsl:param name="function"/><!-- 'copy', 'copy+', 'filter', 'filter+' -->
        <xsl:param name="table"/><!-- Name of the lookup table to use for conversion (see 'name' attribute of 'translateCode' element) -->
        <xsl:param name="relation"/><!-- Relation number to use for conversion (see 'relation' attribute of 'translateValue' element) -->
        <xsl:param name="value"/><!-- Value to convert -->
        <xsl:variable name="fallbackRelation">0</xsl:variable>

        <!-- Step 1: convert input value -->
        <xsl:variable name="result1">
            <xsl:call-template name="convert">
                <xsl:with-param name="file" select="$file"/>
                <xsl:with-param name="direction" select="$direction"/>
                <xsl:with-param name="function" select="$function"/>
                <xsl:with-param name="table" select="$table"/>
                <xsl:with-param name="relation" select="$relation"/>
                <xsl:with-param name="value" select="$value"/>
            </xsl:call-template>
        </xsl:variable>

        <!-- Step 2: if result is empty and function name ends with '+' convert again using fallback relation number -->
        <xsl:variable name="result2">
            <xsl:choose>
                <xsl:when test="string-length($result1)=0 and ends-with($function,'+') and $relation!='0'">
                    <xsl:call-template name="convert">
                        <xsl:with-param name="file" select="$file"/>
                        <xsl:with-param name="direction" select="$direction"/>
                        <xsl:with-param name="function" select="$function"/>
                        <xsl:with-param name="table" select="$table"/>
                        <xsl:with-param name="relation" select="$fallbackRelation"/>
                        <xsl:with-param name="value" select="$value"/>
                    </xsl:call-template>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:value-of select="$result1"/>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:variable>

        <!-- Step 3: if result is still empty and function name starts with 'copy' use original input value as output result -->
        <xsl:variable name="result3">
            <xsl:choose>
                <xsl:when test="string-length($result2)=0 and starts-with($function,'copy')">
                    <xsl:value-of select="$value"/>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:value-of select="$result2"/>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:variable>

        <!-- Step 4: final conversion result -->
        <xsl:value-of select="$result3"/>
    </xsl:template>

    <!-- Template for actual conversion using external conversion XML file. -->
    <xsl:template name="convert">
        <xsl:param name="file"/>
        <xsl:param name="direction"/>
        <xsl:param name="function"/>
        <xsl:param name="table"/>
        <xsl:param name="relation"/>
        <xsl:param name="value"/>
        <xsl:variable name="result">
            <xsl:choose>
                <xsl:when test="$direction='in'">
                    <xsl:value-of select="document($file)/conv:myLookupTable/conv:table[@name=$table]/conv:directionIncoming/conv:translateCode[@name=$value]/conv:translateValue[@relation=$relation]/text()"/>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:value-of select="document($file)/conv:myLookupTable/conv:table[@name=$table]/conv:directionOutgoing/conv:translateCode[@name=$value]/conv:translateValue[@relation=$relation]/text()"/>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:variable>
        <xsl:value-of select="$result"/>
    </xsl:template>
</xsl:stylesheet>

可用于查找代码转换的 XML

<?xml version="1.0" encoding="UTF-8"?>
<myLookupTable xmlns="http://example.org/uri/lookuptable">
    <table name="packageCode">
        <directionIncoming>
            <translateCode name="BX">
                <translateValue relation="99887766">GH</translateValue>
                <translateValue relation="66778899">LK</translateValue>
                <translateValue relation="88996677">LK</translateValue>
            </translateCode>
            <translateCode name="PL">
                <translateValue relation="99887766">BT</translateValue>
                <translateValue relation="66778899">LK</translateValue>
                <translateValue relation="88996677">LK</translateValue>
            </translateCode>
        </directionIncoming>
        <directionOutgoing>
            <translateCode name="LK">
                <translateValue relation="66778899">BX</translateValue>
                <translateValue relation="88996677">BX</translateValue>
            </translateCode>
            <translateCode name="BT">
                <translateValue relation="99887766">PL</translateValue>
            </translateCode>
            <translateCode name="GH">
                <translateValue relation="99887766">PL</translateValue>
            </translateCode>
        </directionOutgoing>
    </table>
    <table name="type">
        <directionIncoming>
            <translateCode name="10">
                <translateValue relation="99887766">20</translateValue>
                <translateValue relation="66778899">30</translateValue>
                <translateValue relation="88996677">30</translateValue>
            </translateCode>
            <translateCode name="80">
                <translateValue relation="99887766">90</translateValue>
                <translateValue relation="66778899">30</translateValue>
                <translateValue relation="88996677">30</translateValue>
            </translateCode>
        </directionIncoming>
        <directionOutgoing>
            <translateCode name="30">
                <translateValue relation="66778899">10</translateValue>
                <translateValue relation="88996677">10</translateValue>
            </translateCode>
            <translateCode name="90">
                <translateValue relation="99887766">80</translateValue>
            </translateCode>
            <translateCode name="20">
                <translateValue relation="99887766">80</translateValue>
            </translateCode>
        </directionOutgoing>
    </table>
</myLookupTable>

编辑

当我如下所述应用 Martin Honnen 他的解决方案并将输入 XML 从更改<pref:sendPackage>BX</pref:sendPackage><pref:sendPackage>XX</pref:sendPackage>(键查找将不返回任何内容)并在 Altova XML Spy 中执行转换时,我收到错误:

来自 Altova XMLSpy 的错误

代码如下所示:

<xsl:value-of select="key('relationKey', $relation, key('incomingKey', $value, key('tableKey', $table, document($file))))/text()" />

即使我xsl:if在它周围做了一个测试,测试也通过了(很奇怪),但xsl:value-of select仍然给出了同样的错误:

<xsl:if test="normalize-space(key('k3', $relation, key('k2', $value, key('k1', $table, document($file))))/text()) != ''">
    <xsl:value-of select="key('k3', $relation, key('k2', $value, key('k1', $table, document($file))))/text()" />
</xsl:if>
4

1 回答 1

2

您应该能够使用键来替换表达式,document($file)/conv:myLookupTable/conv:table[@name=$table]例如

<xsl:key name="k1" match="conv:myLookupTable/conv:table" use="@name"/>

允许你重写

document($file)/conv:myLookupTable/conv:table[@name=$table]

作为

key('k1', $table, document($file))

现在为conv:directionIncoming/conv:translateCode[@name=$value]你定义

<xsl:key name="k2" match="conv:directionIncoming/conv:translateCode" use="@name"/>

然后替换

document($file)/conv:myLookupTable/conv:table[@name=$table]/conv:directionIncoming/conv:translateCode[@name=$value]

  key('k2', $value, key('k1', $table, document($file)))

最后是

document($file)/conv:myLookupTable/conv:table[@name=$table]/conv:directionIncoming/conv:translateCode[@name=$value]/conv:translateValue[@relation=$relation]

你会用

<xsl:key name="k3" match="conv:translateCode/conv:translateValue" use="@relation"/>

key('k3', $relation, key('k2', $value, key('k1', $table, document($file))))

我还建议尽可能使用<xsl:with-param name="param-name" select="foo"/>代替,<xsl:with-param name="param-name"><xsl:value-of select="foo"/></xsl:with-param>并使用<xsl:variable name="var-name" select="foo"/>代替<xsl:variable name="var-name"><xsl:value-of select="foo"/></xsl:variable>。在大多数情况下,这应该更有效。

于 2013-11-13T11:08:33.290 回答