Относительные или абсолютные пути XSLT, неожиданное поведение - PullRequest
2 голосов
/ 13 декабря 2011

У меня есть этот XML-код

<data>

<proteins>
<protein>
<accession>111</accession>
</protein>
</proteins>

<peptides>
<peptide>
<accession>111</accession>
<sequence>AAA</sequence>
</peptide>
<peptide>
<accession>111</accession>
<sequence>AAA</sequence>
</peptide>
<peptide>
<accession>111</accession>
<sequence>AAA</sequence>
</peptide>
<peptide>
<accession>111</accession>
<sequence>BBB</sequence>
</peptide>
<peptide>
<accession>111</accession>
<sequence>BBB</sequence>
</peptide>
<peptide>
<accession>111</accession>
<sequence>BBB</sequence>
</peptide>
<peptide>
<accession>111</accession>
<sequence>BBB</sequence>
</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:key name="byAccSeq" match="peptide" 
                             use="concat(accession, '|', sequence)"/>
    <xsl:template match="/">
        <root><xsl:apply-templates select="/*/proteins/protein"/></root>
    </xsl:template>
    <xsl:template match="protein">
        <xsl:apply-templates
            select="../../peptides/peptide[accession=current()/accession]"/>
    </xsl:template>
    <xsl:template match="peptide[generate-id()=
             generate-id(key('byAccSeq', concat(accession, '|', sequence))[1])]">
        <xsl:copy-of select="."/>
    </xsl:template>
    <xsl:template match="peptide"/>
</xsl:stylesheet>

Это вывод

<root>
    <peptide>
        <accession>111</accession>
        <sequence>AAA</sequence>
    </peptide>
    <peptide>
        <accession>111</accession>
        <sequence>BBB</sequence>
    </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="byAccSeq" match="/data/peptides/peptide" 
                             use="concat(accession, '|', sequence)"/>
    <xsl:template match="/">
      <root><xsl:apply-templates select="/data/proteins/protein"/></root>
    </xsl:template>
  <xsl:template match="/data/proteins/protein">
        <xsl:apply-templates
    select="/data/peptides/peptide[accession=current()/accession]"/>
    </xsl:template>
  <xsl:template match="/data/peptides/peptide[generate-id()=
             generate-id(key('byAccSeq', concat(accession, '|', sequence))[1])]">
        <xsl:copy-of select="."/>
    </xsl:template>
    <xsl:template match="peptide"/>
</xsl:stylesheet>

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

<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="byAccSeq" match="/data/peptides/peptide" 
                             use="concat(accession, '|', sequence)"/>
    <xsl:template match="/">
      <root><xsl:apply-templates select="/data/proteins/protein"/></root>
    </xsl:template>
  <xsl:template match="/data/proteins/protein">
        <xsl:apply-templates
    select="/data/peptides/peptide[accession=current()/accession]"/>
    </xsl:template>
  <xsl:template match="/data/peptides/peptide[generate-id()=
             generate-id(key('byAccSeq', concat(accession, '|', sequence))[1])]">
        <xsl:copy-of select="."/>
    </xsl:template>
    <xsl:template match="/data/peptides/peptide"/>
</xsl:stylesheet>

тогда вывод просто

<root></root>

Я этого не ожидал.

И, также неожиданно (для меня), если я напишу совпадение с шаблоном раньше, результат снова будет желаемым

<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="byAccSeq" match="/data/peptides/peptide" 
                             use="concat(accession, '|', sequence)"/>
    <xsl:template match="/">
      <root><xsl:apply-templates select="/data/proteins/protein"/></root>
    </xsl:template>
  <xsl:template match="/data/proteins/protein">
        <xsl:apply-templates
    select="/data/peptides/peptide[accession=current()/accession]"/>
    </xsl:template>
    <xsl:template match="/data/peptides/peptide"/>
  <xsl:template match="/data/peptides/peptide[generate-id()=
             generate-id(key('byAccSeq', concat(accession, '|', sequence))[1])]">
        <xsl:copy-of select="."/>
    </xsl:template>
</xsl:stylesheet>

Последние файлы: http://www.xsltcake.com/slices/sgWUFu

Я бы хотел понять логику этого.

Ответы [ 2 ]

4 голосов
/ 14 декабря 2011

Если каждый узел, который соответствует match = "x", также соответствует match = "/ a / b / c / x", то единственный эффект изменения первого на второй - изменение приоритета правила; правило считается более конкретным, поэтому имеет более высокий приоритет, что может привести к его срабатыванию, когда узел соответствует более чем одному правилу.

3 голосов
/ 14 декабря 2011

Как уже упоминал @Michael, проблема заключается в разрешении конфликтов шаблонов . Изменение шаблона сопоставления с peptide на /data/peptides/peptide повышает приоритет шаблона до того же уровня, что и шаблон для обработки /data/peptides/peptide[generate-id()= generate-id(key('byAccSeq', concat(accession, '|', sequence))[1])]. В документе есть узлы, которые могут быть выбраны одним или обоими шаблонами сопоставления, что приводит к конфликту шаблонов.

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

Как Майкл хорошо знал, Саксон выдает следующее предупреждение:

Recoverable error 
  XTRE0540: Ambiguous rule match for /data/peptides[1]/peptide[1]
Matches both "/data/peptides/peptide" on line 16 of file:///C:/sandbox/so.xsl
and "/data/peptides/peptide[generate-id()= generate-id(key('byAccSeq', concat(accession,
  '|', sequence))[1])]" on line 13 of file:///C:/sandbox/so.xsl
Recoverable error 
  XTRE0540: Ambiguous rule match for /data/peptides[1]/peptide[4]
Matches both "/data/peptides/peptide" on line 16 of file:///C:/sandbox/so.xsl
and "/data/peptides/peptide[generate-id()= generate-id(key('byAccSeq', concat(accession,
  '|', sequence))[1])]" on line 13 of file:///C:/sandbox/so.xsl
...