bos*_*sam 6 sorting xslt timestamp xslt-1.0
关于使用XSL 1.0进行排序,我有一个非常特殊的问题(只有1.0 - 我正在使用.Net Parser).
这是我的xml:
<Root>
....
<PatientsPN>
<Patient>
<ID>1</ID>
<TimeStamp>20111208165819</TimeStamp>
<NomPatient>Dudule</NomPatient>
<PrenomPatient>Fanny</PrenomPatient>
<Sexe>F</Sexe>
</Patient>
<Patient>
<ID>4</ID>
<TimeStamp>20111208165910</TimeStamp>
<NomPatient>Dudule</NomPatient>
<PrenomPatient>Fanny4</PrenomPatient>
<Sexe>F</Sexe>
</Patient>
<Patient>
<ID>4</ID>
<TimeStamp>20111208165902</TimeStamp>
<NomPatient>Dudule</NomPatient>
<PrenomPatient>FannyMOI</PrenomPatient>
<Sexe>M</Sexe>
</Patient>
<Patient>
<ID>2</ID>
<TimeStamp>20111208170000</TimeStamp>
<NomPatient>Dudule</NomPatient>
<PrenomPatient>FannyMOI</PrenomPatient>
<Sexe>F</Sexe>
</Patient>
<Patient>
<ID>2</ID>
<TimeStamp>20111208165819</TimeStamp>
<NomPatient>Dudule</NomPatient>
<PrenomPatient>Fanny</PrenomPatient>
<Sexe>F</Sexe>
</Patient>
<Patient>
<ID>2</ID>
<TimeStamp>20111208170050</TimeStamp>
<NomPatient>Dudule</NomPatient>
<PrenomPatient>Cmoi2</PrenomPatient>
<Sexe>F</Sexe>
</Patient>
<Patient>
<ID>3</ID>
<TimeStamp>20111208165829</TimeStamp>
<NomPatient>Dudule</NomPatient>
<PrenomPatient>Jesuis3</PrenomPatient>
<Sexe>F</Sexe>
</Patient>
</PatientsPN>
...
</Root>
Run Code Online (Sandbox Code Playgroud)
我想首先通过ID对我的PatientsNP进行排序,然后获取每个ID的更高的TimeStamp.我的输出:
<Root>
<PatientsPN>
<Patient>
<ID>1</ID>
<TimeStamp>20111208165819</TimeStamp>
<NomPatient>Dudule</NomPatient>
<PrenomPatient>Fanny</PrenomPatient>
<Sexe>F</Sexe>
</Patient>
<Patient>
<ID>2</ID>
<TimeStamp>20111208170050</TimeStamp>
<NomPatient>Dudule</NomPatient>
<PrenomPatient>Cmoi2</PrenomPatient>
<Sexe>F</Sexe>
</Patient>
<Patient>
<ID>3</ID>
<TimeStamp>20111208165829</TimeStamp>
<NomPatient>Dudule</NomPatient>
<PrenomPatient>Jesuis3</PrenomPatient>
<Sexe>F</Sexe>
</Patient>
<Patient>
<ID>4</ID>
<TimeStamp>20111208165910</TimeStamp>
<NomPatient>Dudule</NomPatient>
<PrenomPatient>Fanny4</PrenomPatient>
<Sexe>F</Sexe>
</Patient>
</PatientsPN>
</Root>
Run Code Online (Sandbox Code Playgroud)
首先,我尝试按ID对列表进行排序,然后解析每个节点并使用Xpath提取更高的时间戳,但这不起作用.它不断重复其他节点.
还尝试了Muench排序方法,但我无法使其更通用的东西正常工作.
我的XSL是:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name="mark">PN</xsl:param>
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
<Root>
<xsl:apply-templates/>
</Root>
</xsl:template>
<xsl:template match="/Root/*">
<xsl:for-each select=".">
<xsl:choose>
<xsl:when test="substring(name(), (string-length(name()) - string-length($mark)) + 1) = $mark">
<!-- Search for an ID tag -->
<xsl:copy>
<xsl:if test="node()/ID">
<xsl:for-each select="node()">
<xsl:sort select="ID" order="ascending" />
<!-- So far everything I've done here failed -->
<xsl:for-each select=".[ID = '1']">
<xsl:copy>
<xsl:copy-of select="node()[not(number(TimeStamp) < (preceding-sibling::node()/TimeStamp | following-sibling::node()/TimeStamp))]"/>
</xsl:copy>
</xsl:for-each>
<!-- This is just an example, I don't want to have ID = 1 and ID = 2 -->
</xsl:for-each>
</xsl:if>
<xsl:if test="not(node()/ID)">
<xsl:copy-of select="node()[not(number(TimeStamp) < (preceding-sibling::node()/TimeStamp | following-sibling::node()/TimeStamp))]"/>
</xsl:if>
</xsl:copy>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="."/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Run Code Online (Sandbox Code Playgroud)
我希望我清楚自己.提前感谢您带来的所有帮助!
编辑:
我真的很抱歉我应该提到我想让它尽可能通用.在我的例子中,我在谈论PatientsPN,但我真正想做的是匹配以PN结尾的每个PARENT节点(因此结束了 - 与XSL 1.0的copycat版本).
无论如何你真的很棒,我不能期待更多来自你.谢谢 !
解决方案 在重新构建Dimitre给出的解决方案之后,我想出了这个XSL:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="kPatById" match="*['PN' = substring(name(), string-length(name()) -1)]/*"
use="concat(generate-id(..), '|', ID)"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*['PN' = substring(name(), string-length(name()) -1)]">
<xsl:copy>
<xsl:apply-templates select="node()">
<xsl:sort select="ID" data-type="number"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="*['PN' = substring(name(), string-length(name()) -1)]/node()[TimeStamp < key('kPatById', concat(generate-id(..), '|', ID))/TimeStamp]"/>
</xsl:stylesheet>
Run Code Online (Sandbox Code Playgroud)
它完美地完成了这项工作,它允许我有多个将被处理和排序的父节点.
可以这么简单:
一、XSLT 1.0解决方案:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="kPatById" match=
"*['PN' = substring(name(), string-length(name()) -1)]/Patient"
use="concat(generate-id(..), '|', ID)"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match=
"*['PN' = substring(name(), string-length(name()) -1)]">
<xsl:apply-templates select="Patient">
<xsl:sort select="ID" data-type="number"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match=
"*['PN' = substring(name(), string-length(name()) -1)]
/Patient
[TimeStamp < key('kPatById', concat(generate-id(..), '|', ID))/TimeStamp]
"/>
</xsl:stylesheet>
Run Code Online (Sandbox Code Playgroud)
当应用于提供的 XML 文档时:
<Root>
....
<PatientsPN>
<Patient>
<ID>1</ID>
<TimeStamp>20111208165819</TimeStamp>
<NomPatient>Dudule</NomPatient>
<PrenomPatient>Fanny</PrenomPatient>
<Sexe>F</Sexe>
</Patient>
<Patient>
<ID>4</ID>
<TimeStamp>20111208165910</TimeStamp>
<NomPatient>Dudule</NomPatient>
<PrenomPatient>Fanny4</PrenomPatient>
<Sexe>F</Sexe>
</Patient>
<Patient>
<ID>4</ID>
<TimeStamp>20111208165902</TimeStamp>
<NomPatient>Dudule</NomPatient>
<PrenomPatient>FannyMOI</PrenomPatient>
<Sexe>M</Sexe>
</Patient>
<Patient>
<ID>2</ID>
<TimeStamp>20111208170000</TimeStamp>
<NomPatient>Dudule</NomPatient>
<PrenomPatient>FannyMOI</PrenomPatient>
<Sexe>F</Sexe>
</Patient>
<Patient>
<ID>2</ID>
<TimeStamp>20111208165819</TimeStamp>
<NomPatient>Dudule</NomPatient>
<PrenomPatient>Fanny</PrenomPatient>
<Sexe>F</Sexe>
</Patient>
<Patient>
<ID>2</ID>
<TimeStamp>20111208170050</TimeStamp>
<NomPatient>Dudule</NomPatient>
<PrenomPatient>Cmoi2</PrenomPatient>
<Sexe>F</Sexe>
</Patient>
<Patient>
<ID>3</ID>
<TimeStamp>20111208165829</TimeStamp>
<NomPatient>Dudule</NomPatient>
<PrenomPatient>Jesuis3</PrenomPatient>
<Sexe>F</Sexe>
</Patient>
</PatientsPN>
...
</Root>
Run Code Online (Sandbox Code Playgroud)
产生了想要的正确结果:
<Root>
....
<Patient>
<ID>1</ID>
<TimeStamp>20111208165819</TimeStamp>
<NomPatient>Dudule</NomPatient>
<PrenomPatient>Fanny</PrenomPatient>
<Sexe>F</Sexe>
</Patient>
<Patient>
<ID>2</ID>
<TimeStamp>20111208170050</TimeStamp>
<NomPatient>Dudule</NomPatient>
<PrenomPatient>Cmoi2</PrenomPatient>
<Sexe>F</Sexe>
</Patient>
<Patient>
<ID>3</ID>
<TimeStamp>20111208165829</TimeStamp>
<NomPatient>Dudule</NomPatient>
<PrenomPatient>Jesuis3</PrenomPatient>
<Sexe>F</Sexe>
</Patient>
<Patient>
<ID>4</ID>
<TimeStamp>20111208165910</TimeStamp>
<NomPatient>Dudule</NomPatient>
<PrenomPatient>Fanny4</PrenomPatient>
<Sexe>F</Sexe>
</Patient>
...
</Root>
Run Code Online (Sandbox Code Playgroud)
解释:
使用和"PN"的组合来匹配名称以 -- 结尾的任何元素。substring()string-length()
超越身份规则。
排序,但不使用任何 Muenchian 分组。
使用密钥获取同一xxxPN父项下同一患者的所有记录。
“简单”最大值(不排序)。
正确的模式匹配可以排除任何不需要的记录。
二. XSLT 2.0 解决方案:
我发现最好的 XSLT 2.0 解决方案与上面的 XSLT 1.0 解决方案几乎相同,但可能更有效:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="kPatById" match="*[ends-with(name(),'PN')]/Patient"
use="concat(generate-id(..), '|', ID)"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[ends-with(name(),'PN')]">
<xsl:apply-templates select="Patient">
<xsl:sort select="ID" data-type="number"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match=
"*[ends-with(name(),'PN')]
/Patient
[number(TimeStamp)
lt
max((key('kPatById', concat(generate-id(..), '|', ID))
/TimeStamp/xs:double(.)))
]"/>
</xsl:stylesheet>
Run Code Online (Sandbox Code Playgroud)