【问题标题】:XSLT sorting groups of nodes previously selected with keyXSLT 对先前使用键选择的节点组进行排序
【发布时间】:2011-12-19 18:39:12
【问题描述】:

我有一个包含一组 protein 节点的 XML 文件,每个节点都有一个 accession 编号。还有一组peptides,每个都带有accessionsequenceRTscore参数。

我有一个 XSLT 文件,它为每种蛋白质调用具有相同accession 蛋白质编号的所有肽节点。

然后,根据变量的值,此处为<xsl:param name="analysis" select="0"/>,XSLT 文件调用所有共享相同accession 编号的肽段,或所有共享相同accession 编号但丢弃所有这些肽段的肽段具有重合的sequence 值。

这是我所说的代码(将变量的值从0更改为1,可以看到我描述的2种情况)

link

我也把代码贴在文末

现在,我需要做的是排序和选择得分最高的肽节点。

因此,在 XSLT 文件调用共享相同accession 编号的所有肽段的情况下,我需要根据其分值对它们进行排序。

并且,如果代码调用所有共享相同accession 编号的肽,但只选择那些也共享相同序列的肽中的一个肽,我需要这个肽是得分最高的肽,不仅仅是 XML 文件中的第一个。

我曾尝试在此代码link 中使用“排序”功能,但如果您查看一下,您会看到 XML 输出对所有肽段进行排序,丢失了之前使用key 声明。

XML 代码

<data>
    <proteins>
        <protein>
            <accession>111</accession>
        </protein>
    </proteins>
    <peptides>
        <peptide>
            <accession>111</accession>
            <sequence>AAA</sequence>
            <RT>13</RT>
            <score>4000</score>
        </peptide>
        <peptide>
            <accession>111</accession>
            <sequence>AAA</sequence>
            <RT>14</RT>
            <score>6000</score>
        </peptide>
        <peptide>
            <accession>111</accession>
            <sequence>AAA</sequence>
            <RT>15</RT>
            <score>5000</score>
        </peptide>
        <peptide>
            <accession>111</accession>
            <sequence>BBB</sequence>
            <RT>23</RT>
            <score>5000</score>
        </peptide>
        <peptide>
            <accession>111</accession>
            <sequence>BBB</sequence>
            <RT>24</RT>
            <score>1000</score>
        </peptide>
        <peptide>
            <accession>111</accession>
            <sequence>BBB</sequence>
            <RT>25</RT>
            <score>8000</score>
        </peptide>
        <peptide>
            <accession>111</accession>
            <sequence>BBB</sequence>
            <RT>26</RT>
            <score>5000</score>
        </peptide>
    </peptides>
</data>

XSLT 代码

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
    <xsl:param name="analysis" select="0"/>
    <xsl:key name="byAcc"    match="/data/peptides/peptide" use="accession" />
    <xsl:key name="byAccSeq" match="/data/peptides/peptide" use="concat(accession, '|', sequence)"/>
    <xsl:template match="/">
        <root>
            <name>
                <xsl:value-of select="$analysis"/>
            </name>
            <xsl:apply-templates select="/data/proteins/protein" />
        </root>
    </xsl:template>
    <xsl:template match="/data/proteins/protein">
        <xsl:choose>
            <xsl:when test="$analysis=1">
                <xsl:apply-templates select="key('byAcc',accession)">
                </xsl:apply-templates>
            </xsl:when>
            <xsl:otherwise>
                <xsl:apply-templates select="key('byAcc',accession)[
                generate-id()
                =
                generate-id(key('byAccSeq', concat(accession, '|', sequence)))]">
            </xsl:apply-templates>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>
<xsl:template match="/data/peptides/peptide">
    <xsl:copy-of select="."/>
</xsl:template>
</xsl:stylesheet>

以及我需要的 XML 输出,为简单起见,仅选择了一种肽 &lt;xsl:param name="analysis" select="0"/&gt;

<root>
    <name>0</name>
    <peptide>
        <accession>111</accession>
        <sequence>AAA</sequence>
        <RT>14</RT>
        <score>6000</score>
    </peptide>
    <peptide>
        <accession>111</accession>
        <sequence>BBB</sequence>
        <RT>25</RT>
        <score>8000</score>
    </peptide>
</root>

这是来自共享 accessionsequence 值的 2 个肽节点,具有最大 score 值的那些

谢谢

----------------------------------------------- ----------------------------------------

编辑:试图让问题更清楚

我能想到的最简化的代码是:

我有这个 XML 代码

<data>
    <peptides>
        <peptide>
            <accession>111</accession>
            <sequence>AAA</sequence>
            <score>4000</score>
        </peptide>
        <peptide>
            <accession>111</accession>
            <sequence>AAA</sequence>
            <score>6000</score>
        </peptide>
        <peptide>
            <accession>111</accession>
            <sequence>AAA</sequence>
            <score>5000</score>
        </peptide>
        <peptide>
            <accession>111</accession>
            <sequence>BBB</sequence>
            <score>5000</score>
        </peptide>
        <peptide>
            <accession>111</accession>
            <sequence>BBB</sequence>
            <score>1000</score>
        </peptide>
        <peptide>
            <accession>111</accession>
            <sequence>BBB</sequence>
            <score>8000</score>
        </peptide>
        <peptide>
            <accession>111</accession>
            <sequence>BBB</sequence>
            <score>5000</score>
        </peptide>
        <peptide>
            <accession>222</accession>
            <sequence>CCC</sequence>
            <score>5000</score>
        </peptide>
        <peptide>
            <accession>222</accession>
            <sequence>CCC</sequence>
            <score>9000</score>
        </peptide>
        <peptide>
            <accession>222</accession>
            <sequence>CCC</sequence>
            <score>2000</score>
        </peptide>
  </peptides>
</data>

不假设它的排序方式是一致的,所以这个 XML 可以有任何位置的节点。

然后,我想要的是首先按加入对节点进行分组,然后在这些节点中按顺序对它们进行分组,然后在这些节点中按分数对它们进行排序。

所以输出的 XML 会是这样的

<data>
    <peptides>
        <peptide>
            <accession>111</accession>
            <sequence>AAA</sequence>
            <score>6000</score>
        </peptide>
        <peptide>
            <accession>111</accession>
            <sequence>AAA</sequence>
            <score>5000</score>
        </peptide>
        <peptide>
            <accession>111</accession>
            <sequence>AAA</sequence>
            <score>4000</score>
        </peptide>
        <peptide>
            <accession>111</accession>
            <sequence>BBB</sequence>
            <score>8000</score>
        </peptide>
        <peptide>
            <accession>111</accession>
            <sequence>BBB</sequence>
            <score>5000</score>
        </peptide>
        <peptide>
            <accession>111</accession>
            <sequence>BBB</sequence>
            <score>5000</score>
        </peptide>
        <peptide>
            <accession>111</accession>
            <sequence>BBB</sequence>
            <score>1000</score>
        </peptide>
        <peptide>
            <accession>222</accession>
            <sequence>CCC</sequence>
            <score>9000</score>
        </peptide>
        <peptide>
            <accession>222</accession>
            <sequence>CCC</sequence>
            <score>5000</score>
        </peptide>
        <peptide>
            <accession>222</accession>
            <sequence>CCC</sequence>
            <score>2000</score>
        </peptide>
  </peptides>
</data>

最后一个代码的解决方案,来自提供的答案:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
    <xsl:key name="byAcc"    match="/data/peptides/peptide" use="accession" />
    <xsl:key name="byAccSeq" match="/data/peptides/peptide" use="concat(accession, '|', sequence)"/>
    <xsl:template match="/">
        <root>
            <xsl:apply-templates select="/data/proteins/protein">
            </xsl:apply-templates>
        </root>
    </xsl:template>
    <xsl:template match="/data/proteins/protein">
        <xsl:apply-templates select="key('byAcc',accession)">
            <xsl:sort select="sequence" data-type="text"/>
            <xsl:sort select="score" data-type="number"/>
        </xsl:apply-templates>
    </xsl:template>
    <xsl:template match="/data/peptides/peptide">
        <xsl:copy-of select="."/>
    </xsl:template>
</xsl:stylesheet>

查看here

【问题讨论】:

  • 通过升序对 XML 文档进行初始排序然后应用转换是否可以解决问题?请您解释一下您希望转换做什么?目前的措辞相当混乱。也许,如果你能提供一个完全简化的小例子,它会更容易理解。然后,当发布此简化示例的解决方案时,您可以将其应用于您的特定问题。
  • 对不起,这是试图提供一个简单的例子。我将编辑问题。
  • @_Gerard:感谢您的编辑。似乎如果您对 XML 文档进行预排序(按score 递增)——我的回答中的两个解决方案中的第一个。

标签: xslt sorting key


【解决方案1】:

不清楚究竟需要什么处理,但这里我提供了两种不同的分组和排序组合(我还假设需要 XSLT 1.0):

让我们拥有以下非常简单的 XML 文档:

<nums>
 <num>5</num>
 <num>1</num>
 <num>2</num>
 <num>2</num>
 <num>9</num>
 <num>1</num>
 <num>5</num>
 <num>2</num>
 <num>9</num>
 <num>8</num>
</nums>

如果我们想消除重复,我们可以从这个转换开始

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:key name="kNumByVal" match="num" use="."/>

 <xsl:template match="/*">
  <nums>
    <xsl:copy-of select=
    "num
      [generate-id(key('kNumByVal', .)[1])
      =
       generate-id()
      ]"/>
  </nums>
 </xsl:template>
</xsl:stylesheet>

结果是

<nums>
   <num>5</num>
   <num>1</num>
   <num>2</num>
   <num>9</num>
   <num>8</num>
</nums>

现在,如果我们希望结果中的 num 元素按值排序,有两种不同的解决方案:

  1. 对原始XML文档进行排序,然后进行分组:

...

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:ext="http://exslt.org/common" exclude-result-prefixes="ext">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:key name="kNumByVal" match="num" use="."/>

 <xsl:template match="/*">

  <xsl:variable name="vrtfSorted">
   <xsl:for-each select="num">
    <xsl:sort data-type="number"/>
    <xsl:copy-of select="."/>
   </xsl:for-each>
  </xsl:variable>

  <xsl:variable name="vSorted" select=
       "ext:node-set($vrtfSorted)/*"/>

  <nums>
   <xsl:for-each select=
    "$vSorted
      [generate-id(key('kNumByVal', .)[1])
      =
       generate-id()
      ]
     ">
    <xsl:sort data-type="number"/>
    <xsl:copy-of select="."/>
   </xsl:for-each>
  </nums>
 </xsl:template>
</xsl:stylesheet>

产生正确的结果

<nums>
   <num>1</num>
   <num>2</num>
   <num>5</num>
   <num>8</num>
   <num>9</num>
</nums>

.2。进行分组,然后对结果进行排序:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:key name="kNumByVal" match="num" use="."/>

 <xsl:template match="/*">

    <xsl:variable name="vDistinct" select=
    "num
      [generate-id(key('kNumByVal', .)[1])
      =
       generate-id()
      ]"/>

  <nums>
   <xsl:for-each select="$vDistinct">
    <xsl:sort data-type="number"/>
    <xsl:copy-of select="."/>
   </xsl:for-each>
  </nums>
 </xsl:template>
</xsl:stylesheet>

再次产生正确的结果

<nums>
   <num>1</num>
   <num>2</num>
   <num>5</num>
   <num>8</num>
   <num>9</num>
</nums>

更新:在 OP 的评论中澄清后,这是一个新的例子:

<nums>
  <num seq="1">01</num>
  <num seq="2">01</num>
  <num seq="1">01</num>
  <num seq="3">01</num>
  <num seq="2">01</num>
  <num seq="4">01</num>
  <num seq="1">02</num>
  <num seq="2">3</num>
  <num seq="3">04</num>
  <num seq="3">01</num>
  <num seq="4">02</num>
  <num seq="1">01</num>
</nums>

要求@seq和元素的字符串值分组,同时按@seq和字符串值排序:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:key name="kBySeqVal" match="num"
  use="concat(@seq, '+', .)"/>

 <xsl:key name="kByValSeq" match="num"
  use="concat(., '+', @seq.)"/>

 <xsl:template match="/">
  <xsl:apply-templates select=
   "/*/*
     [generate-id()
     =
      generate-id(key('kBySeqVal',
                      concat(@seq, '+', .)
                      )
                       [1]
                  )
     ]
   ">
    <xsl:sort select="@seq" data-type="number"/>
    <xsl:sort select="." data-type="number"/>
   </xsl:apply-templates>
 </xsl:template>

 <xsl:template match="num">
  <xsl:copy-of select="."/>
 </xsl:template>
</xsl:stylesheet>

结果完全按照需要进行分组和排序

<num seq="1">01</num>
<num seq="1">02</num>
<num seq="2">01</num>
<num seq="2">3</num>
<num seq="3">01</num>
<num seq="3">04</num>
<num seq="4">01</num>
<num seq="4">02</num>

【讨论】:

  • 您的解决方案在只有一组数据时有效,在您的示例 中。在我的示例中,就像您有 AAA1。然后我需要按 对数据进行排序,因此首先按 进行分组,然后按 对该组进行排序,或者相反,按 进行分组,然后按 . 对组进行排序
  • @Gerard:我用这个请求案例的解决方案更新了我的答案(看最后)。
  • 就是这样,我不知道可以连续编写两种类型:) 我用应用于 XML 代码的解决方案更新了问题,让我们看看是否可以将它应用于我的真实代码。但我会说我能:) 非常感谢:D
  • @Gerard:不客气。现在您也知道我所说的“简单示例”是什么意思,并希望在您以后的问题中给我们这样的回答:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-05-04
  • 1970-01-01
  • 1970-01-01
  • 2011-07-16
  • 2021-11-02
相关资源
最近更新 更多