XSLT 1.0:通过日期字符串的连接部分进行排序
我正在尝试获取 XML 数据并按元素的数据属性对元素进行排序。不幸的是,日期以 mm/dd/yyyy 格式显示,并且不是静态长度。 (Jan = 1 而不是 01)所以我相信该字符串必须解析为三个组成部分并填充月份。新连接的值 (yyyymmdd) 然后按降序排序。
问题是我不知道该怎么做。这是一个数据示例
<content date="1/13/2011 1:21:00 PM">
<collection vo="promotion">
<data vo="promotion" promotionid="64526" code="101P031" startdate="1/7/2011 12:00:00 AM" type="base"/>
<data vo="promotion" promotionid="64646" code="101P026" startdate="2/19/2011 12:00:00 AM" type=""/>
<data vo="promotion" promotionid="64636" code="101P046" startdate="1/9/2011 12:00:00 AM" type="base"/>
</collection>
</content>
另外谁能推荐一本关于学习 XSLT 的好书吗?
谢谢!
更新1
我真的希望我能更好地理解这个哈哈无论如何,我使用了您提供的代码并添加了在您在另一个问题中提供的相关代码中工作的“值”代码,并且我没有看到任何结果。理想情况下,一旦排序完毕,我就需要引用最新数据元素中的多个其他属性。
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ext="http://exslt.org/common">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<xsl:variable name="vrtfPass1">
<xsl:apply-templates/>
</xsl:variable>
<xsl:apply-templates mode="pass2" select=
"ext:node-set($vrtfPass1)/*"/>
</xsl:template>
<xsl:template match="@startdate">
<xsl:variable name="vDate" select="substring-before(.,' ')"/>
<xsl:variable name="vYear" select=
"substring($vDate, string-length($vDate) -3)"/>
<xsl:variable name="vDayMonth" select=
"substring-before($vDate, concat('/',$vYear))"/>
<xsl:variable name="vMonth"
select="format-number(substring-before($vDayMonth, '/'), '00')"/>
<xsl:variable name="vDay"
select="format-number(substring-after($vDayMonth, '/'), '00')"/>
<xsl:attribute name="startdate">
<xsl:value-of select="concat($vYear,$vMonth,$vDay)"/>
</xsl:attribute>
</xsl:template>
<xsl:template match="node()|@*" mode="pass2">
<xsl:copy>
<xsl:apply-templates mode="pass2" select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template mode="pass2" match="collection">
<xsl:copy>
<xsl:apply-templates mode="pass2" select="@*"/>
<xsl:apply-templates mode="pass2">
<xsl:sort select="@startdate"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="content/collection/data">
<xsl:if test="position()=1">
<xsl:value-of select="@promotionid"/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
更新 2
嗯,我尝试像你说的那样更新它
...
</xsl:template>
<xsl:template mode="pass2" match="content/collection/data">
<xsl:value-of select="@promotionid"/>
</xsl:template>
</xsl:stylesheet>
,但我仍然没有得到任何输出。我用谷歌搜索了一下,也尝试弄乱这个声明 xmlns:ext="http://exslt.org/common"
并根据我看过的一篇文章尝试了不同的值。我尝试了
- http://exslt.org/common
- urn:schemas-microsoft-com:xslt
- http://xml.apache.org/xalan (已更改 节点集到节点集)
并且没有提供任何输出。所以我想知道我是否有问题或者我的 xslt 处理器是否不支持它。
更新 3
好吧,显然我们已经多次收到错误的信息。我已经使用另一个属性更新了示例 XML,该属性更改了需要完成的操作。
需要做的是像我们已经完成的那样按日期对数据进行排序,然后提取最新且类型为“base”的数据节点的promotionid。如果没有数据节点具有 type='base' ,那么我们只需引用最新的数据节点,就像我们已经在工作的那样。
希望这是有道理的。再次非常感谢。
I'm trying to take XML data and sort elements by their data attribute. Unfortunately the dates come over in mm/dd/yyyy format and are not static lengths. (Jan = 1 instead of 01) So I believe the string will have to be parsed into three components and the month padded. The newly concated value (yyyymmdd) then sorted descending.
Problem is I have no idea how to do this. Here is an example of the data
<content date="1/13/2011 1:21:00 PM">
<collection vo="promotion">
<data vo="promotion" promotionid="64526" code="101P031" startdate="1/7/2011 12:00:00 AM" type="base"/>
<data vo="promotion" promotionid="64646" code="101P026" startdate="2/19/2011 12:00:00 AM" type=""/>
<data vo="promotion" promotionid="64636" code="101P046" startdate="1/9/2011 12:00:00 AM" type="base"/>
</collection>
</content>
Also can anyone please recommend a good book on learning XSLT?
Thanks!
Update 1
I really wish I had a better understanding of this LOL Anyways, I used the code you provided and added the 'value-of' code that worked in the related code you provide in another question and am seeing no results. Ideally once this has been sorted I would then need to reference multiple other attributes from the most recent data element.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ext="http://exslt.org/common">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<xsl:variable name="vrtfPass1">
<xsl:apply-templates/>
</xsl:variable>
<xsl:apply-templates mode="pass2" select=
"ext:node-set($vrtfPass1)/*"/>
</xsl:template>
<xsl:template match="@startdate">
<xsl:variable name="vDate" select="substring-before(.,' ')"/>
<xsl:variable name="vYear" select=
"substring($vDate, string-length($vDate) -3)"/>
<xsl:variable name="vDayMonth" select=
"substring-before($vDate, concat('/',$vYear))"/>
<xsl:variable name="vMonth"
select="format-number(substring-before($vDayMonth, '/'), '00')"/>
<xsl:variable name="vDay"
select="format-number(substring-after($vDayMonth, '/'), '00')"/>
<xsl:attribute name="startdate">
<xsl:value-of select="concat($vYear,$vMonth,$vDay)"/>
</xsl:attribute>
</xsl:template>
<xsl:template match="node()|@*" mode="pass2">
<xsl:copy>
<xsl:apply-templates mode="pass2" select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template mode="pass2" match="collection">
<xsl:copy>
<xsl:apply-templates mode="pass2" select="@*"/>
<xsl:apply-templates mode="pass2">
<xsl:sort select="@startdate"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="content/collection/data">
<xsl:if test="position()=1">
<xsl:value-of select="@promotionid"/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
Update 2
Hmm, well I tried updating it like you said
...
</xsl:template>
<xsl:template mode="pass2" match="content/collection/data">
<xsl:value-of select="@promotionid"/>
</xsl:template>
</xsl:stylesheet>
And I still don't get any output. I googled around a bit and also tried messing with this declaration xmlns:ext="http://exslt.org/common"
and tried different values based on an article I looked at. I tried
- http://exslt.org/common
- urn:schemas-microsoft-com:xslt
- http://xml.apache.org/xalan (changed
the node-set to nodeset)
And nothing provided output. So I wonder if I have something wrong or if my xslt processor doesn't support it.
Update 3
Okay apparently we've been given, repeatedly, bad information. I've update the sample XML with another attribute which changes what needs to be done.
What needs to happen is the data be sorted by date like we've already done and then pull the promotionid of the data node that is the most recent AND has the type='base'. If no data node has type='base' than we just reference the most recent data node like we've already have working.
Hope that makes sense. And once again thanks so much.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您可以使用多个
xsl:sort
指令,如以下样式表所示:输出:
从注释更新
更新3:现在有了新的选择数据条件,
使用“标准”最大惯用语。该样式表:
输出:
You can use multiple
xsl:sort
instructions like in this stylesheet:Output:
Update from comments
Update 3: Now with new selecting data conditions
Use the "standard" maximum idiom. This stylesheet:
Output:
这是使用两遍转换进行排序的一种方法(可以在单遍转换中执行此操作,但代码会太复杂):
当转换应用于提供的 XML 文档:
生成所需的正确结果:
请注意:
XSLT 1.0 中的多通道转换需要使用特定于供应商的
xxx:node-set()
函数将传递结果从 RTF(结果转换片段)类型转换为常规树(文档)。本解决方案中使用的
xxx:node-set()
函数是EXSLT的ext:node-set()
函数,它在大多数 XSLT 处理器上实现。Here is one way to do this sorting using a 2-pass transformation (it is possible to do this in a one-pass transformation, but the code would be too-complicated):
when this transformation is applied on the provided XML document:
the wanted, correct result is produced:
Do note:
Multipass transformations in XSLT 1.0 require the use of the vendor-specific
xxx:node-set()
function to convert the result of a pass from its RTF (Result Transformation Fragment) type to a regular tree (document).The
xxx:node-set()
function used in this solution is theext:node-set()
function of EXSLT, which is implemented on most XSLT processors.