如何将translate()应用于XSLT中的属性值?

时间:2015-11-13 13:21:39

标签: xml xslt msxml

我有一个返回XML数据的函数,并希望为它编写测试以检查它是否返回预期的结果。 XML数据如下所示:

<Session Id="OF1qxev4OSZcIbsS">
  <User Id="10001">
    <LoginName>SelfTest</LoginName>
    <RealName>SelfTest User</RealName>
  </User>
  <StartTime>2015-11-13T13:01:59Z</StartTime>
  <EndTime>2015-11-13T15:01:59Z</EndTime>
</Session>

XML包含每个请求不同的数据,因此在与预期结果进行比较之前,我使用XSLT将某些固定模式替换为可变数据(会话ID属性和StartTime / EndTime节点的内容)。 XSL文件如下所示:

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
  <xsl:output method="xml" encoding="utf-8" omit-xml-declaration="yes" indent="no"/>

  <xsl:variable name="uid-chars">ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789</xsl:variable>
  <xsl:variable name="uid-mask" >IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII</xsl:variable>

  <xsl:variable name="timestamp-nums">0123456789</xsl:variable>
  <xsl:variable name="timestamp-mask">DDDDDDDDDD</xsl:variable>

  <xsl:template match="*">
    <xsl:copy>
      <!-- copy attributes -->
      <xsl:apply-templates select="@*"/>
      <!-- copy child elements -->
      <xsl:apply-templates select="*|text()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="text()">
    <!-- trim whitespace -->
    <xsl:value-of select="normalize-space(.)"/>
  </xsl:template>

  <!-- normalize uids -->
  <xsl:template match="@Id">
    <xsl:copy>
      <xsl:attribute name="Id">
        <xsl:value-of select="translate(., $uid-chars, $uid-mask)"/>
      </xsl:attribute>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="StartTime|EndTime">
    <xsl:copy>
      <xsl:apply-templates mode="timestamp"/>
    </xsl:copy>
  </xsl:template>

  <!-- normalize timestamps -->
  <xsl:template mode="timestamp" match="text()">
    <xsl:value-of select="translate(., $timestamp-nums, $timestamp-mask)"/>
  </xsl:template>

</xsl:stylesheet>

预期的输出看起来像这样:

<Session Id="IIIIIIIIIIIIIIII">
  <User Id="10001">
    <LoginName>SelfTest</LoginName>
    <RealName>SelfTest User</RealName>
  </User>
  <StartTime>DDDD-DD-DDTDD:DD:DDZ</StartTime>
  <EndTime>DDDD-DD-DDTDD:DD:DDZ</EndTime>
</Session>

不幸的是,当前XSL高于规范化仅适用于StartTime / EndTime值,但不适用于会话ID:

<Session Id="OF1qxev4OSZcIbsS">
  <User Id="10001">
    <LoginName>SelfTest</LoginName>
    <RealName>SelfTest User</RealName>
  </User>
  <StartTime>DDDD-DD-DDTDD:DD:DDZ</StartTime>
  <EndTime>DDDD-DD-DDTDD:DD:DDZ</EndTime>
</Session>

将translate()函数应用于属性值的正确方法是什么?

注意:我在测试中使用了MSXML6中的XSLT引擎。

1 个答案:

答案 0 :(得分:2)

您不应在模板中使用xsl:copyId属性匹配,因为它只是按原样复制属性。您的现有xsl:attribute只是被忽略,因为您无法在此复制的属性中添加属性。

只需从模板中删除xsl:copy,然后只需创建一个全新属性

即可
<xsl:template match="@Id">
   <xsl:attribute name="Id">
     <xsl:value-of select="translate(., $uid-chars, $uid-mask)"/>
   </xsl:attribute>
</xsl:template>

请注意,这会更新Id元素的User以及Session元素。如果您确实希望将其限制为Session属性,则可以改为使用这两个模板:

<xsl:template match="Session/@Id">
   <xsl:attribute name="Id">
      <xsl:value-of select="translate(., $uid-chars, $uid-mask)"/>
   </xsl:attribute>
</xsl:template>

<xsl:template match="@Id">
    <xsl:copy />
</xsl:template>