XSLT从时间戳中删除毫秒

时间:2016-07-28 19:07:37

标签: xslt-2.0

我正在尝试编写一个XSLT样式表,它从XML表单中的任何时间戳中删除毫秒。下面的示例XML只是一个示例,可以想象信封中包含任意数量的时间戳。所以我想我需要模式匹配时间戳然后转换它。我可以使用XSLT 2.0原始消息如下:

<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <soap:Header xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> 
    </soap:Header>
      <soap:Body>
        <Staging_Submit_Service xmlns="com.xxx"> 
            <u_From_Partner__c>Our Partner</u_From_Partner__c>
            <u_To_Partner__c>Us</u_To_Partner__c>
            <u_Partner_CI__c/>
            <u_Partner_ID__c>10051</u_Partner_ID__c>
            <u_Partner_Name__c>ROSEVILLE</u_Partner_Name__c>
            <u_Partner_Reported_Date__c>2016-07-26T17:38:28.746134Z</u_Partner_Reported_Date__c>
            <u_Partner_Status_Reason__c>Failure in System</u_Partner_Status_Reason__c>
            <u_Partner_Submit_Date__c>2016-07-25T18:11:23.5443Z</u_Partner_Submit_Date__c>
            <u_Partner_Priority__c>Low</u_Partner_Priority__c>
            <u_Partner_Service_Type>Event</u_Partner_Service_Type>
        </Staging_Submit_Service>
    </soap:Body>
</soap:Envelope>

我生成的xml需要看起来像:

<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <soap:Header xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">    
    </soap:Header><soap:Body>
        <Staging_Submit_Service xmlns="com.xxx"> 
            <u_From_Partner__c>Our Partner</u_From_Partner__c>
            <u_To_Partner__c>Us</u_To_Partner__c>
            <u_Partner_CI__c/>
            <u_Partner_ID__c>10051</u_Partner_ID__c>
            <u_Partner_Name__c>ROSEVILLE</u_Partner_Name__c>
            <u_Partner_Reported_Date__c>2016-07-26T17:38:28Z</u_Partner_Reported_Date__c>
            <u_Partner_Status_Reason__c>Failure in System</u_Partner_Status_Reason__c>
            <u_Partner_Submit_Date__c>2016-07-25T18:11:23Z</u_Partner_Submit_Date__c>
            <u_Partner_Priority__c>Low</u_Partner_Priority__c>
            <u_Partner_Service_Type>Event</u_Partner_Service_Type>
        </Staging_Submit_Service>
    </soap:Body>
</soap:Envelope>

注意时间戳。我开始走这条路,但它似乎没有让我到达我需要的地方。

<xsl:stylesheet version="2.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:ns1="java:com.verizon.webservices.adapter.clecclient">
<xsl:output method="xml" indent="no" version="1.0" encoding="UTF-8" omit-xml-declaration="yes"/>
<xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"  />
    </xsl:copy>
</xsl:template>
<xsl:template match="@*|node()"
  <xsl:copy>
    <xsl:value-of select="." />
      <xsl:value-of select='matches(.,".*[0-9]\{4\}-[0-9]\{2\}.*:[0-9]\{2\}*")'/>
    <xsl:value-of select='replace(., "s/.*[0-9]\{4\}-[0-9]\{2\}.*:[0-9]\{2\}\(\.[0-9]*\).*/\1","")'/>
  </xsl:copy>
</xsl:template>
</xsl:stylesheet>

我真的只是模糊地熟悉XSLT,这个特殊问题需要我使用它。

2 个答案:

答案 0 :(得分:1)

从评论看来,您似乎只能使用XSLT 1.0解决方案。

这是一个:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:df="com.xxx">
 <xsl:output omit-xml-declaration="yes"/>

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

  <xsl:template match="df:u_Partner_Reported_Date__c/text()
                      |df:u_Partner_Submit_Date__c/text()">
    <xsl:value-of select="concat(substring-before(.,'.'), 'Z')"/>
  </xsl:template>
</xsl:stylesheet>

在提供的XML文档上应用此转换时:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" 
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <soap:Header xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> 
    </soap:Header>
      <soap:Body>
        <Staging_Submit_Service xmlns="com.xxx"> 
            <u_From_Partner__c>Our Partner</u_From_Partner__c>
            <u_To_Partner__c>Us</u_To_Partner__c>
            <u_Partner_CI__c/>
            <u_Partner_ID__c>10051</u_Partner_ID__c>
            <u_Partner_Name__c>ROSEVILLE</u_Partner_Name__c>
            <u_Partner_Reported_Date__c>2016-07-26T17:38:28.746134Z</u_Partner_Reported_Date__c>
            <u_Partner_Status_Reason__c>Failure in System</u_Partner_Status_Reason__c>
            <u_Partner_Submit_Date__c>2016-07-25T18:11:23.5443Z</u_Partner_Submit_Date__c>
            <u_Partner_Priority__c>Low</u_Partner_Priority__c>
            <u_Partner_Service_Type>Event</u_Partner_Service_Type>
        </Staging_Submit_Service>
    </soap:Body>
</soap:Envelope>

产生了想要的正确结果

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" 
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
 xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <soap:Header> 
    </soap:Header>
      <soap:Body>
        <Staging_Submit_Service xmlns="com.xxx"> 
            <u_From_Partner__c>Our Partner</u_From_Partner__c>
            <u_To_Partner__c>Us</u_To_Partner__c>
            <u_Partner_CI__c/>
            <u_Partner_ID__c>10051</u_Partner_ID__c>
            <u_Partner_Name__c>ROSEVILLE</u_Partner_Name__c>
            <u_Partner_Reported_Date__c>2016-07-26T17:38:28Z</u_Partner_Reported_Date__c>
            <u_Partner_Status_Reason__c>Failure in System</u_Partner_Status_Reason__c>
            <u_Partner_Submit_Date__c>2016-07-25T18:11:23Z</u_Partner_Submit_Date__c>
            <u_Partner_Priority__c>Low</u_Partner_Priority__c>
            <u_Partner_Service_Type>Event</u_Partner_Service_Type>
        </Staging_Submit_Service>
    </soap:Body>
</soap:Envelope>

答案 1 :(得分:0)

尝试

<xsl:template match="*[not(*) and . castable as xs:dateTime]">
  <xsl:copy>
    <xsl:value-of select="format-dateTime(., '[Y0001]-[M01]-[D01]T[H01]:[m01]:[s01]')"/>
  </xsl:copy>
</xsl:template>

加上你的第一个模板。

所以完整的样式表是

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" version="2.0">

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

    <xsl:template match="*[not(*) and . castable as xs:dateTime]">
        <xsl:copy>
            <xsl:value-of select="format-dateTime(., '[Y0001]-[M01]-[D01]T[H01]:[m01]:[s01]')"/>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

实际上上面似乎没有保留任何时区后缀并确保它输出为Z如果是UTC有点棘手,但我想如果你做value-of

        <xsl:value-of select="if (timezone-from-dateTime(.) eq xs:dayTimeDuration('PT0H')) then format-dateTime(., '[Y0001]-[M01]-[D01]T[H01]:[m01]:[s01]Z') else format-dateTime(., '[Y0001]-[M01]-[D01]T[H01]:[m01]:[s01][Z]')"/>

然后它运作正常。

有关时区Z的问题似乎已在https://www.w3.org/TR/xpath-functions-31/#rules-for-datetime-formatting中解决以允许

        <xsl:value-of select="format-dateTime(., '[Y0001]-[M01]-[D01]T[H01]:[m01]:[s01][Z00:00t]')"/>

但我没有测试它是否适用于XmlPrime或Saxon以外的处理器。

以下对我来说,在Oxygen中使用Xalan,只需在输入样本中使用dateTimes识别两个元素,然后重新格式化它们以删除秒的小数:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:date="http://exslt.org/dates-and-times"
    exclude-result-prefixes="xs date" version="1.0">

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

    <xsl:template match="*[not(*) and string-length() > 19 and date:date() != '']">
        <xsl:copy>
            <xsl:value-of select="date:format-date(date:date(.), &quot;yyyy-MM-dd'T'HH:mm:ssZ&quot;)"/>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

但是,创建的输出日期不同,输入<u_Partner_Reported_Date__c>2016-07-26T17:38:28.746134Z</u_Partner_Reported_Date__c>显示为<u_Partner_Reported_Date__c>2016-07-25T22:00:00+0000</u_Partner_Reported_Date__c>,因此日期解析或格式设置已损坏。