Сортировка по идентификатору, а затем по метке времени в одном узле

У меня очень специфическая проблема, связанная с сортировкой с помощью 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>

Я хотел бы сначала отсортировать мои PatientsNP по идентификатору, а затем взять более высокий 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>

Сначала я попытался отсортировать свой список по идентификатору, а затем проанализировать каждый узел и использовать Xpath для извлечения более высокой временной метки, но это не сработало. Он продолжал повторять другие узлы.

Также пробовал метод сортировки Мюнха, но мне не удалось заставить его работать должным образом с помощью чего-то более общего.

Мой 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) &lt; (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) &lt; (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, но на самом деле я пытаюсь сопоставить все узлы PARENT, оканчивающиеся на PN (отсюда и версия XSL 1.0 с подражателем, заканчивающаяся на конце).

В любом случае ты действительно потрясающий, я не мог ожидать большего от тебя. Спасибо !

РЕШЕНИЕ После переделки решения, данного Димитром, я придумал этот 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 &lt; key('kPatById', concat(generate-id(..), '|', ID))/TimeStamp]"/>
</xsl:stylesheet>

Он прекрасно выполняет свою работу и позволяет мне иметь несколько родительских узлов, которые будут обрабатываться и сортироваться.

6
задан bosam 15 December 2011 в 08:36
поделиться