以月-名称日-编号年-编号格式按日期对 XSL 进行排序 [英] Sorting XSL by date in Month-Name Day-Number Year-Number format

查看:29
本文介绍了以月-名称日-编号年-编号格式按日期对 XSL 进行排序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 Joomla SobiPro 事件数据库,每个数据库都包含一个名为start_date"的日期字段,看起来像2015 年 10 月 10 日"和2016 年 1 月 3 日".我需要搜索不同的字段(距给定邮政编码的距离,以英里为单位),然后输出按这些日期按升序排序的结果.

我对 XSL/SobiPro/Joomla 完全陌生,所以我很挣扎,但经过大量谷歌搜索后,我发现我需要在下面由 <!- 指示的位置插入 XSL 排序命令- **** 在此处插入排序命令 **** --> 在 SobiPro 模板文件 common/entries.xsl 中:

<xsl:output method="xml" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" encoding="UTF-8"/><xsl:include href="vcard.xsl"/><xsl:include href="manage.xsl"/><xsl:template name="entriesLoop"><xsl:variable name="entriesInLine"><xsl:value-of select="entries_in_line"/></xsl:变量><xsl:variable name="cellClass"><xsl:value-of select="floor( 12 div $entriesInLine )"/></xsl:变量><xsl:variable name="entriesCount"><xsl:value-of select="count(entries/entry)"/></xsl:变量><xsl:comment>条目循环 - 开始</xsl:comment><div class="entry-container"><xsl:for-each select="entries/entry"><!-- **** 在此处插入排序命令 **** --><xsl:if test="($entriesInLine > 1 and (position() = 1 or (position() mod $entriesInLine) = 1 )) or $entriesInLine = 1"><!-- 打开表格"行--><xsl:text disable-output-escaping="yes">&lt;div class="row-fluid" &gt;</xsl:text></xsl:if><div class="span{$cellClass}"><xsl:call-template name="vcard"/>

<xsl:if test="($entriesInLine > 1 and ((position() mod $entriesInLine) = 0 or position() = $entriesCount)) 或 $entriesInLine = 1"><!-- 关闭表格"行--><xsl:text disable-output-escaping="yes">&lt;/div&gt;</xsl:text></xsl:if></xsl:for-each>

<xsl:comment>条目循环 - 结束</xsl:comment></xsl:模板></xsl:stylesheet>

我根本不熟悉 XSL 但我确实发现如果日期格式是 2015 10 09 而不是 Oct 09 2015 那么我可以替换注释行上面这一行:

并且排序会成功,因为它似乎是按字母顺序排序的.我无法更改日期格式,也无法添加与该可排序格式相同日期的第二个字段.

我还发现,如果我按原样保留日期格式,我可以按年份排序,然后按月份名称排序:

但这不会产生所需的升序输出顺序,因为二月按字母顺序排在一月之前,等等.

我知道从日期的末尾开始计算字符以找到每个数据组件(年、日和月)的开始看起来很奇怪,但我尝试从 0 和 1 向前计数但无法做到工作.似乎月份名称从字符位置 9 开始(idk 为什么 - 关于 start_date 是一个带有字符串 + 时区 + 其他信息的复合字段我期望的东西)但是日数并不像你期望的那样从位置 13 开始我放弃了通过反复试验找到它.

鉴于上述情况,我仍然需要弄清楚如何将月份名称缩写映射到数字(Jan->01、Feb->02 等),并且我找到了各种方法示例,例如https://stackoverflow.com/a/555536/1745001 作者@DimitreNovatchev,但经过一天的研究和试验-and-error 我只是不知道如何重新排列该代码或任何其他类似的代码以适应我现有的 XSL 文件并在我的情况下工作.

谁能帮我解决这个问题?

<小时>

上下文:

如果您访问了我的网站,http://tournamart.com/,请在地图下方向下滚动,并在给定字段中输入这些值:

距离:[Oswego, Illinois, USA] [(Drop Down:) 100 英里]开始日期来自:[10/01/2015]至: [03/01/2015]

然后单击绿色的开始搜索"按钮,该网站将打印出 2015 年 10 月 1 日至 2016 年 3 月 1 日期间在奥斯威戈 100 英里范围内举行的 9 场比赛的列表.我正在尝试按日期对输出进行排序,以便最早的锦标赛排在第一位.在没有修改代码的情况下,我能说的最好的输出是按照它在数据库中输入的顺序排序.

鉴于以下建议的解决方案 (https://stackoverflow.com/a/32904143/1745001):>

<xsl:sort select="substring(fields/field_start_date, 8 , 4)" data-type="number"/><xsl:sort select="string-length(substring-before('JanFebMarAprMayJunJulAugSepOctNovDec', substring(fields/field_start_date, 1 , 3)))" data-type="number"/><xsl:sort select="substring(fields/field_start_date, 5, 2)" data-type="number"/>

输出仍未按日期排序:

PUMA 2016 总统日室内杯城市:斯图尔蒂文特州:威斯康星州开始日期:2016 年 2 月 13 日彪马 2016 马丁路德金室内杯城市:斯图尔蒂文特州:威斯康星州开始日期:2016 年 1 月 15 日冬季冻结城市:皇冠点州:印第安纳州开始日期:2015 年 12 月 4 日2015 年 Eclipse 选择 AT&T 慕尼黑啤酒节枪战城市: 沃基根州:伊利诺伊州开始日期:2015 年 10 月 10 日拉辛灯塔经典 - 2015城市: 弗兰克斯维尔州:威斯康星州开始日期:2015 年 10 月 10 日2015 年秋季耐克经典杯足球鞋城市:芝加哥州:伊利诺伊州开始日期:2015 年 10 月 9 日Quaker Oats 呈献的 2015 年十月节经典城市: 利伯蒂维尔州:伊利诺伊州开始日期:2015 年 10 月 9 日WSA哥伦布日经典赛城市:惠灵州:伊利诺伊州开始日期:2015 年 10 月 9 日格伦埃林湖人队 2015 秋季经典赛城市:格伦埃林州:伊利诺伊州开始日期:2015 年 10 月 2 日

但是当我修改代码以从日期字符串的末尾开始计算字符时:

<xsl:sort select="substring(fields/field_start_date, string-length(fields/field_start_date)-3, 4)" data-type="number"/><xsl:sort select="string-length(substring-before('JanFebMarAprMayJunJulAugSepOctNovDec', substring(fields/field_start_date, string-length(fields/field_start_date)-10, 3)))" data-type="number"/><xsl:sort select="substring(fields/field_start_date, string-length(fields/field_start_date)-6, 2)" data-type="number"/>

它似乎成功了,因为它现在生成:

Glen Ellyn Lakers FC 2015 秋季经典赛城市:格伦埃林州:伊利诺伊州开始日期:2015 年 10 月 2 日2015 年秋季耐克经典杯足球鞋城市:芝加哥州:伊利诺伊州开始日期:2015 年 10 月 9 日Quaker Oats 呈献的 2015 年十月节经典城市: 利伯蒂维尔州:伊利诺伊州开始日期:2015 年 10 月 9 日WSA哥伦布日经典赛城市:惠灵州:伊利诺伊州开始日期:2015 年 10 月 9 日2015 年 Eclipse 选择 AT&T 慕尼黑啤酒节枪战城市: 沃基根州:伊利诺伊州开始日期:2015 年 10 月 10 日拉辛灯塔经典 - 2015城市: 弗兰克斯维尔州:威斯康星州开始日期:2015 年 10 月 10 日冬季冻结城市:皇冠点州:印第安纳州开始日期:2015 年 12 月 4 日彪马 2016 马丁路德金室内杯城市:斯图尔蒂文特州:威斯康星州开始日期:2016 年 1 月 15 日彪马 2016 总统日室内杯城市:斯图尔蒂文特州:威斯康星州开始日期:2016 年 2 月 13 日

所以,这非常有帮助,谢谢,剩下的问题是:

  1. 为什么我必须从末尾开始计算字符位置?
  2. 是否有更有效(或稳健或更好")的方法来做到这一点?

解决方案

我仍然需要弄清楚如何将月份名称缩写映射到数字(Jan->01、Feb->02 等)

你可以这样做:

string-length(substring-before('JanFebMarAprMayJunJulAugSepOctNovDec', substring($f, 1 , 3)))

这将缩写映射为 Jan->0、Feb->3、Mar->6 等,这对于 数字 排序来说已经足够了.

与其尝试制造单个文本字符串,我建议您只需使用三个数字排序指令:

<xsl:sort select="substring(fields/field_start_date, 8 , 4)" data-type="number"/><xsl:sort select="string-length(substring-before('JanFebMarAprMayJunJulAugSepOctNovDec', substring(fields/field_start_date, 1 , 3)))" data-type="number"/><xsl:sort select="substring(fields/field_start_date, 5, 2)" data-type="number"/>

<小时><块引用>

我知道从末尾开始计算字符看起来很奇怪date 查找每个数据组件的开始(年、日和月)但我尝试从 0 和 1 向前数但无法它起作用了.

如果它仍然不适合您,请发布一个失败的输入示例.

I have a Joomla SobiPro database of events that each contain a date field named "start_date" that looks like "Oct 10 2015" and "Jan 03 2016". I need to search on a different field (distance from a given zip code in miles) and then output the results sorted by those dates in ascending order.

I'm completely new to XSL/SobiPro/Joomla so I'm struggling but after a lot of googling I have found that I need to insert an XSL sort command at the location indicated below by <!-- **** Insert Sort Command Here **** --> in the SobiPro template file common/entries.xsl:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:output method="xml" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" encoding="UTF-8" />
        <xsl:include href="vcard.xsl" />
        <xsl:include href="manage.xsl" />

        <xsl:template name="entriesLoop">
                <xsl:variable name="entriesInLine">
                        <xsl:value-of select="entries_in_line" />
                </xsl:variable>

                <xsl:variable name="cellClass">
                        <xsl:value-of select="floor( 12 div $entriesInLine )" />
                </xsl:variable>

                <xsl:variable name="entriesCount">
                        <xsl:value-of select="count(entries/entry)" />
                </xsl:variable>

                <xsl:comment>entries loop - start</xsl:comment>
        <div class="entry-container">
                <xsl:for-each select="entries/entry">

<!-- **** Insert Sort Command Here **** -->

                    <xsl:if test="($entriesInLine > 1 and (position() = 1 or (position() mod $entriesInLine) = 1 )) or $entriesInLine = 1">
                        <!-- opening the "table" row -->
                        <xsl:text disable-output-escaping="yes">&lt;div class="row-fluid" &gt;</xsl:text>
                    </xsl:if>
                    <div class="span{$cellClass}">
                        <xsl:call-template name="vcard" />
                    </div>
                    <xsl:if test="($entriesInLine > 1 and ((position() mod $entriesInLine) = 0 or position() = $entriesCount)) or $entriesInLine = 1">
                        <!-- closing the "table" row -->
                        <xsl:text disable-output-escaping="yes">&lt;/div&gt;</xsl:text>
                    </xsl:if>
                </xsl:for-each>
        </div>
                <xsl:comment>entries loop - end</xsl:comment>

        </xsl:template>
</xsl:stylesheet>

I am not familiar with XSL at all but I did find that if the date format was 2015 10 09 instead of Oct 09 2015 then I could replace the commented line above with this line:

<xsl:sort select="fields/field_start_date" order="ascending" />

and the sort would succeed since it appears to be sorting alphabetically. I cannot change the date format, nor can I add a second field that is the same date in that sortable format.

I also found that if I left the date format as-is I could get the sort by year and then by month name if I did:

<xsl:sort select="concat(
        substring(fields/field_start_date,string-length(fields/field_start_date)-3,4),
        substring(fields/field_start_date,string-length(fields/field_start_date)-10,3),
        substring(fields/field_start_date,string-length(fields/field_start_date)-6,2)
                         )" order="ascending" />

but that wont produce the desired ascending-dates output order because Feb comes before Jan alphabetically, etc.

I know it looks weird to be counting chars back from the end of the date to find the start of each data component (year, day, and month) but I tried counting forward from both zero and 1 and could not make it work. It seems like the month name starts at character position 9 (idk why - something about start_date being a compound field with a string+timezone+other info I expect) but then the day number doesn't start at position 13 as you'd expect and I gave up trying to find it by trial and error.

Given the above though I still need to figure out how to map the month name abbreviation to the number (Jan->01, Feb->02, etc.) and I've found various examples of ways to do that, e.g. https://stackoverflow.com/a/555536/1745001 by @DimitreNovatchev, but after a day of research and trial-and-error I just can't figure out how to rearrange that or any other similar code to fit into my existing XSL file and work in my case.

Can anyone help me figure this out?


Context:

If you got to my site, http://tournamart.com/, scroll down below the map, and enter these values in the given fields:

Distance From: [Oswego, Illinois, USA]  [(Drop Down:) 100 miles]
Start Date
    From: [10/01/2015]
    To:   [03/01/2015]

and then click on the green "Start Search" button, the site will print a list of the 9 tournaments coming up between Oct 1 2015 and Mar 1 2016 within 100 miles of Oswego. I'm trying to get the output sorted by date so the earliest tournament comes first. With not modification to the code the output, best I can tell, is instead ordered by the order it was entered in the database.

Given the proposed solution below (https://stackoverflow.com/a/32904143/1745001):

<xsl:sort select="substring(fields/field_start_date, 8 , 4)" data-type="number" />
<xsl:sort select="string-length(substring-before('JanFebMarAprMayJunJulAugSepOctNovDec', substring(fields/field_start_date, 1 , 3)))" data-type="number" />
<xsl:sort select="substring(fields/field_start_date, 5 , 2)" data-type="number" />

the output is still not sorted by date:

PUMA 2016 PRESIDENTS DAY INDOOR CUP
City: Sturtevant
State: Wisconsin
Start Date: Feb 13 2016

PUMA 2016 MARTIN LUTHER KING INDOOR CUP
City: Sturtevant
State: Wisconsin
Start Date: Jan 15 2016

Winter Freeze
City: Crown Point
State: Indiana
Start Date: Dec 04 2015

2015 Eclipse Select AT&T Oktoberfest Shootout
City: Waukegan
State: Illinois
Start Date: Oct 10 2015

Racine Lighthouse Classic - 2015
City: Franksville
State: Wisconsin
Start Date: Oct 10 2015

Sockers Nike Classic Cup Fall 2015
City: Chicago
State: Illinois
Start Date: Oct 09 2015

2015 Octoberfest Classic Presented by Quaker Oats
City: Libertyville
State: Illinois
Start Date: Oct 09 2015

WSA Columbus Day Classic
City: Wheeling
State: Illinois
Start Date: Oct 09 2015

Glen Ellyn Lakers FC 2015 Fall Classic
City: Glen Ellyn
State: Illinois
Start Date: Oct 02 2015

but when I modify the code to count characters back from the end of the date string:

<xsl:sort select="substring(fields/field_start_date, string-length(fields/field_start_date)-3 , 4)" data-type="number" />
<xsl:sort select="string-length(substring-before('JanFebMarAprMayJunJulAugSepOctNovDec', substring(fields/field_start_date, string-length(fields/field_start_date)-10 , 3)))" data-type="number" />
<xsl:sort select="substring(fields/field_start_date, string-length(fields/field_start_date)-6 , 2)" data-type="number" />

it seems like it succeeds as it now generates:

Glen Ellyn Lakers FC 2015 Fall Classic
City: Glen Ellyn
State: Illinois
Start Date: Oct 02 2015

Sockers Nike Classic Cup Fall 2015
City: Chicago
State: Illinois
Start Date: Oct 09 2015

2015 Octoberfest Classic Presented by Quaker Oats
City: Libertyville
State: Illinois
Start Date: Oct 09 2015

WSA Columbus Day Classic
City: Wheeling
State: Illinois
Start Date: Oct 09 2015

2015 Eclipse Select AT&T Oktoberfest Shootout
City: Waukegan
State: Illinois
Start Date: Oct 10 2015

Racine Lighthouse Classic - 2015
City: Franksville
State: Wisconsin
Start Date: Oct 10 2015

Winter Freeze
City: Crown Point
State: Indiana
Start Date: Dec 04 2015

PUMA 2016 MARTIN LUTHER KING INDOOR CUP
City: Sturtevant
State: Wisconsin
Start Date: Jan 15 2016

PUMA 2016 PRESIDENTS DAY INDOOR CUP
City: Sturtevant
State: Wisconsin
Start Date: Feb 13 2016

So, that is immensely helpful, thank you, and the remaining questions are:

  1. Why do I have to count char positions back from the end?
  2. Is there a more efficient (or robust or otherwise "better") way to do it?

解决方案

I still need to figure out how to map the month name abbreviation to the number (Jan->01, Feb->02, etc.)

You can do:

string-length(substring-before('JanFebMarAprMayJunJulAugSepOctNovDec', substring($f, 1 , 3)))

This maps the abbreviations as Jan->0, Feb->3, Mar->6, etc. which is quite sufficient for a numerical sort.

Instead of trying to manufacture a single text string, I suggest you simply use three numerical sort instructions:

<xsl:sort select="substring(fields/field_start_date, 8 , 4)" data-type="number" />
<xsl:sort select="string-length(substring-before('JanFebMarAprMayJunJulAugSepOctNovDec', substring(fields/field_start_date, 1 , 3)))" data-type="number" />
<xsl:sort select="substring(fields/field_start_date, 5 , 2)" data-type="number" />


I know it looks weird to be counting chars back from the end of the date to find the start of each data component (year, day, and month) but I tried counting forward from both zero and 1 and could not make it work.

If it still doesn't work for you, post an example of an input where it fails.

这篇关于以月-名称日-编号年-编号格式按日期对 XSL 进行排序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
其他开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆