来自 Filemaker 导出数据的日期的 XSL 模板问题

Issue with XSL Template for Dates from Filemake Exported Data

好的,所以我之前问过这个问题,但现在我正在努力实现目标,所以可以(希望)更好地解释。
我正在支持一个 FileMaker 应用程序,该应用程序已更新为允许用户以特定格式导出数据,总共有五个报告,每个报告生成的数据都是正确的。为了让最终用户更容易理解输出,我们已经从使用字段名称的简单导出切换到使用 XSL 模板,以允许我们自定义结果的外观。除了日期字段外,一切都完美无缺。在 FileMaker 论坛上进行讨论并获得后续帮助后,我已经到了需要特定帮助的地步,我希望这里有人可以帮助我。
我将包括 XSL 的相关片段(因为样式 sheet 详细信息和标题行工作正常),但为了解释我的代码,我定义了几个样式:

  <Styles>
    <Style ss:ID="Heading">
      <Font ss:Size="10" ss:Bold="1" />
    </Style>
    <Style ss:ID="DateDisplay">
      <NumberFormat ss:Format="Short Date"/>
    </Style>
    <Style ss:ID="Other"/>
  </Styles>

我编写了一个模板来管理日期格式从空白或从 YYYY/MM/DD(FileMaker 导出的格式)到 YYYY-MM-DDTHH:MM:SS.000(格式适合Excel理解)。

  <xsl:template name="format-date">
    <xsl:param name="dateParam" />
    <!--store default time to append to date-->
    <xsl:variable name="timeFormat" select="concat('T', '00:00:00.000')"/>
    <!--define default for blank dates-->
    <xsl:choose>
      <xsl:when test="$dateParam=''">
        <xsl:value-of select="concat('1900-01-01', timeFormat)" />
      </xsl:when>
      <!--reformat non blank dates-->
      <xsl:when test="$dateParam!=''">
        <!--store the month and day elements of the date-->
        <xsl:choose>
          <xsl:when test="contains($dateParam, '/')">
            <xsl:variable name="yearPart" select="substring-before($dateParam, '/')" />
            <xsl:variable name="monthPart" select="format-number(number(substring-before(substring-after($dateParam, '/'), '/')), '00')" />
            <xsl:variable name="dayPart" select="format-number(number(substring-after(substring-after($dateParam, '/'), '/')), '00')" />
            <!--concatenate all the parts to make a date in the correct format-->
            <xsl:value-of select="concat($yearPart, '-', $monthPart, '-', $dayPart, $timeFormat)" />
          </xsl:when>
          <xsl:when test="contains($dateParam, '.')">
            <xsl:variable name="yearPart" select="substring-before($dateParam, '.')" />
            <xsl:variable name="monthPart" select="format-number(number(substring-before(substring-after($dateParam, '.'), '.')), '00')" />
            <xsl:variable name="dayPart" select="format-number(number(substring-after(substring-after($dateParam, '.'), '.')), '00')" />
            <!--concatenate all the parts to make a date in the correct format-->
            <xsl:value-of select="concat($yearPart, '-', $monthPart, '-', $dayPart, $timeFormat)" />
          </xsl:when>
        </xsl:choose>
      </xsl:when>
    </xsl:choose>
  </xsl:template>

我遇到的问题是任何包含 non-blank 或日期不是 1900/01/01 的记录都设置为 1900-1-01T00:00:00.000,因此值不正确由 XSL 模板分配。我有 运行 我的导出使用 XML(无 XSL)来确认数据,这里是生成的示例:

<ROW MODID="4" RECORDID="19">
<COL><DATA>Company A Limited</DATA></COL>
<COL><DATA>617642</DATA></COL>
<COL><DATA>Company</DATA></COL>
<COL><DATA>Walker, K</DATA></COL>
<COL><DATA>Yes</DATA></COL>
<COL><DATA /></COL>
<COL><DATA>Active</DATA></COL>
<COL><DATA /></COL>
<COL><DATA /></COL>
<COL><DATA>01/01/1900</DATA></COL>
<COL><DATA>Low risk</DATA></COL>
<COL><DATA /></COL>
<COL><DATA>N</DATA></COL>
<COL><DATA /></COL>
<COL><DATA>0</DATA></COL>
<COL><DATA /></COL>
<COL><DATA>4715</DATA></COL>
<COL><DATA /></COL>
<COL><DATA>1460</DATA></COL>
</ROW>
<ROW MODID="3" RECORDID="34">
<COL><DATA>Company B Limited</DATA></COL>
<COL><DATA>662922</DATA></COL>
<COL><DATA>Company</DATA></COL>
<COL><DATA>Jones, A</DATA></COL>
<COL><DATA /></COL>
<COL><DATA /></COL>
<COL><DATA>Active</DATA></COL>
<COL><DATA /></COL>
<COL><DATA /></COL>
<COL><DATA /></COL>
<COL><DATA /></COL>
<COL><DATA /></COL>
<COL><DATA>N</DATA></COL>
<COL><DATA /></COL>
<COL><DATA>0</DATA></COL>
<COL><DATA /></COL>
<COL><DATA>0</DATA></COL>
<COL><DATA /></COL>
<COL><DATA>7973.75</DATA></COL>
</ROW>
<ROW MODID="3" RECORDID="89">
<COL><DATA>Company C Limited</DATA></COL>
<COL><DATA>602611</DATA></COL>
<COL><DATA>Trustee</DATA></COL>
<COL><DATA>Smith, R</DATA></COL>
<COL><DATA>Yes</DATA></COL>
<COL><DATA>FTSE 100</DATA></COL>
<COL><DATA>Active</DATA></COL>
<COL><DATA /></COL>
<COL><DATA /></COL>
<COL><DATA>23/06/2004</DATA></COL>
<COL><DATA /></COL>
<COL><DATA /></COL>
<COL><DATA>N</DATA></COL>
<COL><DATA /></COL>
<COL><DATA>1816.25</DATA></COL>
<COL><DATA /></COL>
<COL><DATA>0</DATA></COL>
<COL><DATA /></COL>
<COL><DATA>0</DATA></COL>
</ROW>

我的结果应该是一个 Excel 工作簿,其中只有一个 sheet,第一行包含粗体标题,第二行以后是数据,日期格式正确,并且删除了所有其他字符 - 这里是代码的最后一部分:

  <!--called for every "COL" node in a "ROW"-->
  <xsl:template match="fmp:COL">
    <!--get the current field position-->
    <xsl:variable name="i" select="position()" />
    <!--store the current field type-->
    <xsl:variable name="fmType" select="/fmp:FMPXMLRESULT/fmp:METADATA/fmp:FIELD[$i]/@TYPE" />
    <!--create and set field type variable-->
    <xsl:variable name="ssType">
      <xsl:choose>
        <xsl:when test="$fmType='NUMBER'">Number</xsl:when>
        <xsl:when test="$fmType='DATE'">DateTime</xsl:when>
        <xsl:otherwise>String</xsl:otherwise>
      </xsl:choose>
    </xsl:variable>
    <!--create and set cell style variable-->
    <xsl:variable name="ssStyle">
      <xsl:choose>
        <xsl:when test="$fmType='DATE'">DateDisplay</xsl:when>
        <xsl:otherwise>Other</xsl:otherwise>
      </xsl:choose>
    </xsl:variable>
    <!--define cell and associated number format-->
    <Cell ss:StyleID="{$ssStyle}">
      <!--define data and associated type-->
      <Data ss:Type="{$ssType}">
        <xsl:variable name="d" select="fmp:DATA" />
        <xsl:choose>
          <!--clean up number fields-->
          <xsl:when test="$fmType='NUMBER'">
            <xsl:value-of select="translate($d, translate($d, '0123456789.', ''), '')" />
          </xsl:when>
          <!--reformat date fields-->
          <xsl:when test="$fmType='DATE'">
            <xsl:call-template name="format-date">
              <xsl:with-param name="dateParam" select="$d" />
            </xsl:call-template>
          </xsl:when>
          <!--pass other types unchanged-->
          <xsl:otherwise>
            <xsl:value-of select="$d" />
          </xsl:otherwise>
        </xsl:choose>
      </Data>
    </Cell>    
  </xsl:template>

对于相同的三个记录(在 运行通过 XSL 之后)我实际得到的是:

<Row>
<Cell ss:StyleID="Other"><Data ss:Type="String">Company A Limited</Data></Cell>
<Cell ss:StyleID="Other"><Data ss:Type="Number">617642</Data></Cell>
<Cell ss:StyleID="Other"><Data ss:Type="String">Company</Data></Cell>
<Cell ss:StyleID="Other"><Data ss:Type="String">Walker, K</Data></Cell>
<Cell ss:StyleID="Other"><Data ss:Type="String">Yes</Data></Cell>
<Cell ss:StyleID="Other"><Data ss:Type="String"/></Cell>
<Cell ss:StyleID="Other"><Data ss:Type="String">Active</Data></Cell>
<Cell ss:StyleID="Other"><Data ss:Type="String"/></Cell>
<Cell ss:StyleID="Other"><Data ss:Type="String"/></Cell>
<Cell ss:StyleID="DateDisplay"><Data ss:Type="DateTime">01-1-1900T00:00:00.000</Data></Cell>
<Cell ss:StyleID="Other"><Data ss:Type="String">Low risk</Data></Cell>
<Cell ss:StyleID="Other"><Data ss:Type="String"/></Cell>
<Cell ss:StyleID="Other"><Data ss:Type="String">N</Data></Cell>
<Cell ss:StyleID="Other"><Data ss:Type="Number"/></Cell>
<Cell ss:StyleID="Other"><Data ss:Type="Number">0</Data></Cell>
<Cell ss:StyleID="Other"><Data ss:Type="Number"/></Cell>
<Cell ss:StyleID="Other"><Data ss:Type="Number">4715</Data></Cell>
<Cell ss:StyleID="Other"><Data ss:Type="Number"/></Cell>
<Cell ss:StyleID="Other"><Data ss:Type="Number">1460</Data></Cell>
</Row>
<Row>
<Cell ss:StyleID="Other"><Data ss:Type="String">Company B Limited</Data></Cell>
<Cell ss:StyleID="Other"><Data ss:Type="Number">662922</Data></Cell>
<Cell ss:StyleID="Other"><Data ss:Type="String">Company</Data></Cell>
<Cell ss:StyleID="Other"><Data ss:Type="String">Jones, A</Data></Cell>
<Cell ss:StyleID="Other"><Data ss:Type="String"/></Cell>
<Cell ss:StyleID="Other"><Data ss:Type="String"/></Cell>
<Cell ss:StyleID="Other"><Data ss:Type="String">Active</Data></Cell>
<Cell ss:StyleID="Other"><Data ss:Type="String"/></Cell>
<Cell ss:StyleID="Other"><Data ss:Type="String"/></Cell>
<Cell ss:StyleID="DateDisplay"><Data ss:Type="DateTime">1900-01-01</Data></Cell>
<Cell ss:StyleID="Other"><Data ss:Type="String"/></Cell>
<Cell ss:StyleID="Other"><Data ss:Type="String"/></Cell>
<Cell ss:StyleID="Other"><Data ss:Type="String">N</Data></Cell>
<Cell ss:StyleID="Other"><Data ss:Type="Number"/></Cell>
<Cell ss:StyleID="Other"><Data ss:Type="Number">0</Data></Cell>
<Cell ss:StyleID="Other"><Data ss:Type="Number"/></Cell>
<Cell ss:StyleID="Other"><Data ss:Type="Number">0</Data></Cell>
<Cell ss:StyleID="Other"><Data ss:Type="Number"/></Cell>
<Cell ss:StyleID="Other"><Data ss:Type="Number">7973.75</Data></Cell>
</Row>
<Row>
<Cell ss:StyleID="Other"><Data ss:Type="String">Company C Limited</Data></Cell>
<Cell ss:StyleID="Other"><Data ss:Type="Number">602611</Data></Cell>
<Cell ss:StyleID="Other"><Data ss:Type="String">Trustee</Data></Cell>
<Cell ss:StyleID="Other"><Data ss:Type="String">Smith, R</Data></Cell>
<Cell ss:StyleID="Other"><Data ss:Type="String">Yes</Data></Cell>
<Cell ss:StyleID="Other"><Data ss:Type="String">FTSE 100</Data></Cell>
<Cell ss:StyleID="Other"><Data ss:Type="String">Active</Data></Cell>
<Cell ss:StyleID="Other"><Data ss:Type="String"/></Cell>
<Cell ss:StyleID="Other"><Data ss:Type="String"/></Cell>
<Cell ss:StyleID="DateDisplay"><Data ss:Type="DateTime">23-6-2004T00:00:00.000</Data></Cell>
<Cell ss:StyleID="Other"><Data ss:Type="String"/></Cell>
<Cell ss:StyleID="Other"><Data ss:Type="String"/></Cell>
<Cell ss:StyleID="Other"><Data ss:Type="String">N</Data></Cell>
<Cell ss:StyleID="Other"><Data ss:Type="Number"/></Cell>
<Cell ss:StyleID="Other"><Data ss:Type="Number">1816.25</Data></Cell>
<Cell ss:StyleID="Other"><Data ss:Type="Number"/></Cell>
<Cell ss:StyleID="Other"><Data ss:Type="Number">0</Data></Cell>
<Cell ss:StyleID="Other"><Data ss:Type="Number"/></Cell>
<Cell ss:StyleID="Other"><Data ss:Type="Number">0</Data></Cell>
</Row>

因此,任何现有日期(01/01/1900 或实际日期)都会被颠倒过来,并且月份不会以零为前缀,但空白日期似乎已正确添加。 我确定是我的模板导致了这些问题,但我看不出哪里出错了!
任何help/advice感激地收到
非常感谢
马丁

来个简单的怎么样:

<xsl:template name="format-date">
    <xsl:param name="dateParam"/>
    <xsl:param name="time" select="'T00:00:00.000'"/>
    <xsl:choose>
        <xsl:when test="not(string($dateParam))">place your default result for blank dates here</xsl:when>
        <xsl:otherwise>
            <!-- normalize separators to "/" -->
            <xsl:variable name="date" select="translate($dateParam, '.-', '//')"/>
            <!-- extract date elements -->          
            <xsl:variable name="d" select="substring-before($date, '/')"/>
            <xsl:variable name="m" select="substring-before(substring-after($date, '/'), '/')"/>
            <xsl:variable name="y" select="substring-after(substring-after($date, '/'), '/')"/>
            <!-- construct date from elements -->           
            <xsl:value-of select="concat($y, '-', $m, '-', $d, 'T00:00:00.000')" />
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

注意

  1. 这假设输入日期为 DD/MM/YYYY 或 DD.MM.YYYY 或 DD-MM-YYYY 格式(不是您问题中所述的 YYYY/MM/DD),并且 Day 和 Month 值被零填充为两位数;

  2. 如果您使用的是 Filemaker 的内置 XSLT 引擎,则不能使用 format-number() 函数。如果确实需要填充值,则必须使用其他设备,例如EXSLT str:align() 扩展函数。

我到达那里,并编写了一个通用模板来处理这两者(虽然想了解如何控制 Filemaker 的输出格式,但这是另一个问题!)。所以这是我的工作代码:

  <!--set default and reformat dates-->
  <xsl:template name="format-date">
    <xsl:param name="dateParam"/>
    <!--store default time to append to date-->
    <xsl:param name="time" select="'T00:00:00.000'"/>
    <xsl:choose>
      <!--set default value for blank entries-->
      <xsl:when test="not(string($dateParam))">
        <xsl:value-of select="concat('1900-01-01', $time)" />
      </xsl:when>
      <!--reformat non blank dates-->
      <xsl:otherwise>
        <xsl:choose>
          <!--deal with dates in the format 'dd mmm yyyy'-->
          <xsl:when test="contains($dateParam, ' ')">
            <xsl:variable name="d" select="substring-before($dateParam, ' ')"/>
            <xsl:variable name="m" select="substring-before(substring-after($dateParam, ' '), ' ')"/>
            <xsl:variable name="y" select="substring-after(substring-after($dateParam, ' '), ' ')"/>
            <!--convert the month name to a number-->
            <xsl:variable name="mNum" select="
                          string-length(substring-before(
                            'JanFebMarAprMayJunJulAugSepOctNovDec', 
                            substring($m, 1, 3))) div 3 + 1"
                />
            <xsl:choose>
              <xsl:when test="number($mNum) &lt; 10">
                <!-- construct date from elements -->
                <xsl:value-of select="concat($y, '-0', $mNum, '-', $d, $time)" />
              </xsl:when>
              <xsl:otherwise>
                <xsl:value-of select="concat($y, '-', $mNum, '-', $d, $time)" />
              </xsl:otherwise>
            </xsl:choose>
          </xsl:when>
          <xsl:otherwise>
            <!-- normalize separators to "/" -->
            <xsl:variable name="date" select="translate($dateParam, '.-', '//')"/>
            <!-- extract date elements -->
            <xsl:variable name="d" select="substring-before($date, '/')"/>
            <xsl:variable name="m" select="substring-before(substring-after($date, '/'), '/')"/>
            <xsl:variable name="y" select="substring-after(substring-after($date, '/'), '/')"/>
            <!-- construct date from elements -->
            <xsl:value-of select="concat($y, '-', $m, '-', $d, $time)" />
          </xsl:otherwise>
        </xsl:choose>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

谢谢你help/advice
马丁