【问题标题】:JSON output using timing logic in XSLT 1.0在 XSLT 1.0 中使用计时逻辑的 JSON 输出
【发布时间】:2019-05-19 14:30:43
【问题描述】:

我正在尝试读取 XML 格式的消息并以 JSON 格式输出。每条消息还有一个定时逻辑来显示和隐藏消息。

下面是我的 XML,每条消息都有开始和结束日期/时间

<activeMessage>
<message>
<messageText>test message 1</messageText>
<displayScheduleContainer>
<startDate>17/05/2019</startDate>
<startTimeHrs>12</startTimeHrs>
<startTimeMins>00</startTimeMins>
<noEndDate/>
<endDate>17/05/2019</endDate>
<endTimeHrs>23</endTimeHrs>
<endTimeMins>59</endTimeMins>
</displayScheduleContainer>
</message>  

下面是我的 XSL

<xsl:for-each select="xalan:nodeset($messageData)/activeMessage/message">

                    <xsl:variable name="messageInDateTime">
                        <xsl:call-template name="dateLessThanTemplate">
                            <xsl:with-param name="startDateTime" select="concat(displayScheduleContainer/startDate, ' ', displayScheduleContainer/startTimeHrs, ':', displayScheduleContainer/startTimeMins)" />
                            <xsl:with-param name="endDateTime" select="concat(displayScheduleContainer/endDate, ' ', displayScheduleContainer/endTimeHrs, ':', displayScheduleContainer/endTimeMins)" />
                        </xsl:call-template>
                    </xsl:variable>

                    <xsl:if test="$messageInDateTime = 'true'">
                        <xsl:choose>
                            <xsl:when test="position()=1">
                                <xsl:call-template name="singleMessageJSON" />
                            </xsl:when>
                            <xsl:otherwise>
                                <xsl:call-template name="multiMessageJSON" />
                            </xsl:otherwise>
                        </xsl:choose>
                    </xsl:if>
        </xsl:for-each>

【问题讨论】:

  • 那么模板dateLessThanTemplate究竟做了什么?您是否有机会将其检查内联到select="select="xalan:nodeset($messageData)/activeMessage/message[predicate-goes-here]" 的谓词中?一般来说,整个任务似乎可以通过匹配message 的模板更好地解决,然后使用适当的apply-templates,然后您只需使用position() &gt; 签入匹配message 的模板即可输出逗号作为分隔符。
  • 当然,在 Xalan 的 Java 世界中,您可以轻松迁移到 Saxon 9 并拥有 XPath 3.1 的表现力和 JSON 支持。
  • 您需要展示该模板的代码,以便任何人提出建议。正如我所说,如果您可以在您的选择表达式的谓词中内联该检查,您可以简化代码。

标签: xml xslt xslt-1.0 xslt-2.0


【解决方案1】:

由于您为 XSLT 3 添加了标签,我认为您可以摆脱任何 Java 调用并简单地使用例如

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:mf="http://example.com/mf"
    exclude-result-prefixes="#all"
    version="3.0">

  <xsl:function name="mf:get-dateTime" as="xs:dateTime?">
      <xsl:param name="date" as="xs:string"/>
      <xsl:param name="hours" as="xs:string"/>
      <xsl:param name="minutes" as="xs:string"/>
      <xsl:try 
        select="xs:dateTime(replace($date, '([0-9]{2})/([0-9]{2})/([0-9]{4})', '$3-$2-$1') || 'T' || $hours || ':' || $minutes || ':00')">
          <xsl:catch select="()"/>
      </xsl:try>
  </xsl:function>

  <xsl:param name="now" select="current-dateTime()"/>
  <xsl:output method="json" indent="yes"/>

  <xsl:template match="activeMessage">
      <xsl:sequence
        select="map { 
          'message' : array { 
            message[mf:get-dateTime(displayScheduleContainer/startDate, displayScheduleContainer/startTimeHrs, displayScheduleContainer/startTimeMins) lt $now
                    and 
                    mf:get-dateTime(displayScheduleContainer/endDate, displayScheduleContainer/endTimeHrs, displayScheduleContainer/endTimeMins) gt $now]/messageText[normalize-space()]/string() 
            }
          }"/>
  </xsl:template>

</xsl:stylesheet>

在带有 Saxon 9.8 或更高版本的 XSLT 3 中。我不确定您想要的确切 JSON 输出格式,但 XSLT 3 的主要优点是您可以在 XSLT/XPath 中构造映射和数组,如果需要,它们会被序列化为 JSON,而不必担心在正确的位置输出逗号.

https://xsltfiddle.liberty-development.net/bnnZWx/1

将日期的两个比较移到另一个函数中可能会更好,因为该谓词变得更具可读性:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:mf="http://example.com/mf"
    exclude-result-prefixes="#all"
    version="3.0">

  <xsl:function name="mf:get-dateTime" as="xs:dateTime?">
      <xsl:param name="date" as="xs:string"/>
      <xsl:param name="hours" as="xs:string"/>
      <xsl:param name="minutes" as="xs:string"/>
      <xsl:try 
        select="xs:dateTime(replace($date, '([0-9]{2})/([0-9]{2})/([0-9]{4})', '$3-$2-$1') || 'T' || $hours || ':' || $minutes || ':00')">
          <xsl:catch select="()"/>
      </xsl:try>
  </xsl:function>

  <xsl:function name="mf:compare-dates" as="xs:boolean">
      <xsl:param name="schedule" as="element(displayScheduleContainer)"/>
      <xsl:sequence
        select="mf:get-dateTime($schedule/startDate, $schedule/startTimeHrs, $schedule/startTimeMins) lt $now
                and 
                mf:get-dateTime($schedule/endDate, $schedule/endTimeHrs, $schedule/endTimeMins) gt $now"/>
  </xsl:function>

  <xsl:param name="now" select="current-dateTime()"/>
  <xsl:output method="json" indent="yes"/>

  <xsl:template match="activeMessage">
      <xsl:sequence
        select="map { 
          'message' : array { 
            message[mf:compare-dates(displayScheduleContainer)]/messageText[normalize-space()]/string() 
            }
          }"/>
  </xsl:template>

</xsl:stylesheet>

https://xsltfiddle.liberty-development.net/bnnZWx/2

【讨论】:

  • Xalan 根据xalan.apache.org/xalan-j/extensionslib.html#exslt 支持exslt.org/func/elements/function/index.html。我确信他们不会进行 JSON 序列化,但是如果您将代码重新组织成一个函数,您可以在您的选择上使用谓词,然后任何位置使用都将起作用。或者将带有日期检查的代码运行到结果树片段中,然后使用第二步处理这些元素以具有正确的位置并根据需要获取逗号分隔符。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-16
  • 2010-11-09
  • 1970-01-01
  • 2013-09-13
  • 1970-01-01
相关资源
最近更新 更多