关于使用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>
我想首先通过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>
首先,我尝试按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>
我希望自己清楚明白。 提前感谢您带来的所有帮助!
编辑:
我真的很抱歉我应该提到我想让它尽可能通用。在我的例子中,我说的是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>
它完美地完成了这项工作,并且它允许我拥有多个将被处理和排序的父节点。
答案 0 :(得分:2)
可以这么简单:
<强>予。 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>
应用于提供的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>
产生了想要的正确结果:
<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>
<强>解释强>:
使用"PN"
和substring()
的组合匹配名称以string-length()
结尾的任何元素。
覆盖 identity rule 。
排序,但不使用任何Muenchian分组。
使用密钥在同一xxxPN
父母下获取同一患者的所有记录。
“简单”最大值(不排序)。
正确的模式匹配,以排除任何不需要的记录。
<强> II。 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>
答案 1 :(得分:1)
第一个答案(没有检查)似乎是正确的,但我无法抗拒发布一个不使用'evil'for-each关键字的XSLT 1.0版本。
通过在排序之前合并ID和时间戳来完成排序。
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
>
<xsl:output method="xml" indent="yes"/>
<xsl:template match="PatientsPN">
<xsl:copy>
<xsl:apply-templates select="//Patient">
<xsl:sort select="concat(ID,TimeStamp)"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="Patient">
<xsl:if test="not(ID=following-sibling::Patient/ID)">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:if>
</xsl:template>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
希望这有帮助,