XSLT-1.0, как устранить избыточность, но выбрать один конкретный узел вместо первого - PullRequest
2 голосов
/ 19 декабря 2011

У меня есть этот 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>

С помощью следующего XSLT я могу получить пептиды с «присоединением» «111», исключая избыточность последовательностей.Так что я получаю этот XML

<root>
    <peptide>
        <accession>111</accession>
        <sequence>AAA</sequence>
        <score>4000</score>
    </peptide>
    <peptide>
        <accession>111</accession>
        <sequence>BBB</sequence>
        <score>5000</score>
    </peptide>
</root>

Вот это 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: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="key('byAcc','111')
            [
            generate-id()
            =
            generate-id(key('byAccSeq', concat(accession, '|', sequence))[1])
            ]">
            <xsl:sort select="sequence" data-type="text"/>
            <xsl:sort select="score" data-type="number"/>
        </xsl:apply-templates>
    </root>
</xsl:template>
<xsl:template match="/data/peptides/peptide">
    <xsl:copy-of select="."/>
</xsl:template>
</xsl:stylesheet>

И живой пример здесь

Тогда проблемазаключается в том, что из всей избыточности «выбранный» узел является только первым, который появляется в исходном XML.

Мне нужно выбрать из всех избыточных пептидов (то есть тех, которые имеют одинаковое присоединение и последовательность), тот, который набрал максимальное количество баллов.

Желаемый XML был бы таким, тогда

<root>
    <peptide>
        <accession>111</accession>
        <sequence>AAA</sequence>
        <score>6000</score>
    </peptide>
    <peptide>
        <accession>111</accession>
        <sequence>BBB</sequence>
        <score>8000</score>
    </peptide>
</root>

Если неясно, пожалуйста, дайте мне знать, и я заново отредактирую вопрос.Большое спасибо.

Джерард

1 Ответ

1 голос
/ 19 декабря 2011

Это преобразование :

<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:strip-space elements="*"/>

 <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=
    "key('byAcc','111')
            [
            generate-id()
            =
            generate-id(key('byAccSeq', concat(accession, '|', sequence))[1])
            ]">
    <xsl:sort select="sequence" data-type="text"/>
    <xsl:sort select="score" data-type="number"/>
   </xsl:apply-templates>
  </root>
 </xsl:template>

 <xsl:template match="/data/peptides/peptide">
    <xsl:for-each select=
    "key('byAccSeq', concat(accession, '|', sequence))">
      <xsl:sort select="score" data-type="number" order="descending"/>

      <xsl:if test="position() = 1">
        <xsl:copy-of select="."/>
      </xsl:if>
    </xsl:for-each>
 </xsl:template>
</xsl:stylesheet>

при применении к предоставленному документу 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>

дает желаемый, правильный результат :

<root>
   <peptide>
      <accession>111</accession>
      <sequence>AAA</sequence>
      <score>6000</score>
   </peptide>
   <peptide>
      <accession>111</accession>
      <sequence>BBB</sequence>
      <score>8000</score>
   </peptide>
</root>

Объяснение

  1. Шаблон, который обрабатывает каждый первый элемент из группы, получает все элементы в текущей группе (используя функцию key()).

  2. Затем он использует фрагмент кода, чтобы найти те из них, которые имеют максимум score. Выводится только первый такой элемент.

...