开发者

Convert short form days of the week to day names in xslt

开发者 https://www.devze.com 2023-02-08 12:45 出处:网络
I have some short form day names like so: M -> Monday T -> Tuesday W -> Wednesday R -> Thursday

I have some short form day names like so:

M -> Monday
T -> Tuesday
W -> Wednesday
R -> Thursday
F -> Friday
S -> Saturday
U -> Sunday

How can I convert an xml element like <days>MRF</days> into the long version <long-days>Monday,Thursday,Friday</long-days> using xslt?

Update from comments

Days will not be repeated

开发者_如何学Python


This stylesheet

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:d="day"
 exclude-result-prefixes="d">
    <d:d l="M" n="Monday"/>
    <d:d l="T" n="Tuesday"/>
    <d:d l="W" n="Wednesday"/>
    <d:d l="R" n="Thursday"/>
    <d:d l="F" n="Friday"/>
    <d:d l="S" n="Saturday"/>
    <d:d l="U" n="Sunday"/>
    <xsl:variable name="vDays" select="document('')/*/d:d"/>
    <xsl:template match="days">
        <long-days>
            <xsl:apply-templates
                 select="$vDays[contains(current(),@l)]"/>
        </long-days>
    </xsl:template>
    <xsl:template match="d:d">
        <xsl:value-of select="@n"/>
        <xsl:if test="position()!=last()">,</xsl:if>
    </xsl:template>
</xsl:stylesheet>

With this input:

<days>MRF</days>

Output:

<long-days>Monday,Thursday,Friday</long-days>

Edit: For those who wander, retaining the sequence order:

<xsl:variable name="vCurrent" select="current()"/>
<xsl:apply-templates
         select="$vDays[contains($vCurrent,@l)]">
    <xsl:sort select="substring-before($vCurrent,@l)"/>
</xsl:apply-templates>

Note: Because days wouldn't be repeated, this is the same as looking up for item existence in sequence with empty string separator.


That should do it... (There might be more elegant solutions though... ;-)

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="/days">
    <long-days>
        <xsl:if test="contains(.,'M')">Monday<xsl:if test="string-length(substring-before(.,'M'))=string-length(.)-1">,</xsl:if></xsl:if>
        <xsl:if test="contains(.,'T')">Tuesday<xsl:if test="string-length(substring-before(.,'T'))=string-length(.)-1">,</xsl:if></xsl:if>
        <xsl:if test="contains(.,'W')">Wednesday<xsl:if test="string-length(substring-before(.,'W'))=string-length(.)-1">,</xsl:if></xsl:if>
        <xsl:if test="contains(.,'R')">Thursday<xsl:if test="string-length(substring-before(.,'R'))=string-length(.)-1">,</xsl:if></xsl:if>
        <xsl:if test="contains(.,'F')">Friday<xsl:if test="string-length(substring-before(.,'F'))=string-length(.)-1">,</xsl:if></xsl:if>
        <xsl:if test="contains(.,'S')">Saturday<xsl:if test="string-length(substring-before(.,'S'))=string-length(.)-1">,</xsl:if></xsl:if>
        <xsl:if test="contains(.,'U')">Sunday<xsl:if test="string-length(substring-before(.,'U'))=string-length(.)-1">,</xsl:if></xsl:if>
    </long-days>
</xsl:template>


The currently accepted solution always displays the long days names in chronological order and in addition, it doesn't display repeating (with same code) days.

Suppose we have the following XML document:

<days>STMSU</days>

I. This XSLT 1.0 transformation:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:my="my:my" exclude-result-prefixes="my" >
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <my:days>
  <M>Monday</M>
  <T>Tuesday</T>
  <W>Wednesday</W>
  <R>Thursday</R>
  <F>Friday</F>
  <S>Saturday</S>
  <U>Sunday</U>
 </my:days>

 <xsl:key name="kLongByShort" match="my:days/*"
  use="name()"/>

  <xsl:variable name="vstylesheet"
   select="document('')"/>

 <xsl:template match="days">
  <long-days>
   <xsl:call-template name="expand"/>
  </long-days>
 </xsl:template>

 <xsl:template name="expand">
  <xsl:param name="pcodeString" select="."/>

  <xsl:if test="$pcodeString">
    <xsl:variable name="vchar" select=
    "substring($pcodeString,1,1)"/>
    <xsl:for-each select="$vstylesheet">
     <xsl:value-of select=
     "concat(key('kLongByShort',$vchar),
             substring(',',1,string-length($pcodeString)-1)
            )
     "/>
    </xsl:for-each>

    <xsl:call-template name="expand">
     <xsl:with-param name="pcodeString" select=
      "substring($pcodeString,2)"/>
    </xsl:call-template>
  </xsl:if>
 </xsl:template>
</xsl:stylesheet>

when applied on the above document, produces the wanted, correct result:

<long-days>Saturday,Tuesday,Monday,Saturday,Sunday</long-days>

II. This XSLT 2.0 transformation:

<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:xs="http://www.w3.org/2001/XMLSchema"
 exclude-result-prefixes="xs">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:variable name="vshortCodes" as="xs:integer+"
 select="string-to-codepoints('MTWRFSU')"/>

 <xsl:variable name="vlongDays" as="xs:string+"
 select="'Monday','Tuesday','Wenesday','Thursday',
         'Friday','Saturday','Sunday'
 "/>

 <xsl:template match="days">
  <long-days>
    <xsl:for-each select="string-to-codepoints(.)">
      <xsl:value-of separator="" select=
      "for $pos in position() ne last()
        return
         ($vlongDays[index-of($vshortCodes,current())],
          ','[$pos])
      "/>
    </xsl:for-each>
  </long-days>
 </xsl:template>
</xsl:stylesheet>

when applied on the same XML document:

<days>STMSU</days>

produce the wanted, correct result:

<long-days>Saturday,Tuesday,Monday,Saturday,Sunday</long-days>
0

精彩评论

暂无评论...
验证码 换一张
取 消