xslt динамический / условный apply-template в функции переменной? - PullRequest
0 голосов
/ 18 декабря 2011

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

Эта строка должна быть такой же, как и она

<xsl:template match="/data/peptides/peptide[generate-id()=generate-id(key('byAccSeq', concat(protein_accessions/accession, '|', sequence))[1])]">

или как оно

<xsl:template match="/data/peptides/peptide">

Моей первой идеей было создать два разных файла .xsl и применить их (javascript) в зависимости от значения переменной.

var xsltProcessor = new XSLTProcessor();
xsltProcessor.importStylesheet(xslDoc);
xhtml = xsltProcessor.transformToFragment(xmlDoc,document);

Однако это всего лишь строка, и я хотел бы сохранить только один файл. Я хотел бы сделать что-то вроде этого

<xsl:param name="variable"/>
<xsl:choose>
<xsl:when test="$variable = 0">
<xsl:template match="/data/peptides/peptide[generate-id()=generate-id(key('byAccSeq', concat(protein_accessions/accession, '|', sequence))[1])]">
...
</xsl:template>
</xsl:when>
<xsl:otherwise>
<xsl:template match="/data/peptides/peptide">
...
</xsl:template>
</xsl:otherwise>
</xsl:choose>

Но это не работает.

пробуя использовать функцию "mode" в xsl: apply-templates, этот код также не работает

<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:param name="analysis" select="1"/>

<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:apply-templates select="/data/peptides/peptide[accession=current()/accession]"/>
</xsl:template>

<xsl:choose>
<xsl:when test="$analysis=1">
<xsl:apply-templates select="/data/peptides/peptide" mode="one"/>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="/data/peptides/peptide[accession=current()/accession]" mode="two"/>
</xsl:otherwise>
</xsl:choose>

<xsl:template match="/data/peptides/peptide" mode="one">
<xsl:copy-of select="."/>
</xsl:template>

<xsl:template match="/data/peptides/peptide[generate-id()=
           generate-id(key('byAccSeq', concat(accession, '|', sequence))[1])]" mode="two">
<xsl:copy-of select="."/>
</xsl:template>

</xsl:stylesheet>

-> http://www.xsltcake.com/slices/sgWUFu/2

  • этот код неверен, так как xsl: choose не может быть дочерним по отношению к 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:param name="analysis" select="1"/>
    <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="/data/peptides/peptide[accession=current()/accession]" mode="one"/>
            </xsl:when>
            <xsl:otherwise>
                <xsl:apply-templates select="/data/peptides/peptide[accession=current()/accession]" mode="two"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
    <xsl:template match="/data/peptides/peptide" mode="one">
        <xsl:copy-of select="."/>
    </xsl:template>

    <xsl:template match="/data/peptides/peptide" mode="two"/>

    <xsl:template match="/data/peptides/peptide[generate-id()=
    generate-id(key('byAccSeq', concat(accession, '|', sequence)))]" mode="two">
    <xsl:copy-of select="."/>
</xsl:template>
</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: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:when>
            <xsl:otherwise>
                <xsl:apply-templates select="key('byAcc',accession)[
                generate-id()
                =
                generate-id(key('byAccSeq', concat(accession, '|', sequence)))]" />
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
    <xsl:template match="/data/peptides/peptide">
        <xsl:copy-of select="."/>
    </xsl:template>
</xsl:stylesheet>

Я сохраняю вызовы apply-template, потому что они мне нужны, но без них (как в исходном коде, см. Комментарии) еще проще.

Еще раз спасибо, не только за ответ, но и за обучение XSLT:)

Ответы [ 2 ]

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

Изменение с <xsl:template> на <xsl:apply-templates>

<xsl:apply-templates select="/data/peptides/peptide[generate-id()=generate-id(key('byAccSeq', concat(protein_accessions/accession, '|', sequence))[1])]" mode="type1" />

<xsl:apply-templates select="/data/peptides/peptide[generate-id()=generate-id(key('byAccSeq', concat(protein_accessions/accession, '|', sequence)))]" mode="type2" />

После этого напишите <xsl:template> для обоих или для одного соответственно.

Измените ваше решение в более короткие сроки:

<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:param name="analysis" select="2"/>
    <xsl:template match="/">
        <root>
            <name>
                <xsl:value-of select="$analysis"/>
            </name>
            <xsl:apply-templates select="data[peptides/peptide/accession=proteins/protein/accession]/peptides" />
        </root>
    </xsl:template>
    <xsl:template match="peptides">
        <xsl:choose>
            <xsl:when test="$analysis=1">
                <xsl:copy-of select="peptide"/>
            </xsl:when>
            <xsl:otherwise>
                <xsl:for-each select="peptide[generate-id()=generate-id(key('byAccSeq', concat(accession, '|', sequence)))]">
                    <xsl:copy-of select="."/>
                </xsl:for-each>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
</xsl:stylesheet>

Я проверил мой код в соответствии с вашим входным XML и выводом. Теперь я могу повторить то же самое.

В моем коде все еще я могу сократить еще несколько строк кода

Заменить <xsl:for-each> на следующую строку: -

<xsl:copy-of select="peptide[generate-id()=generate-id(key('byAccSeq', concat(accession, '|', sequence)))]"/>

Проверьте это ..

1 голос
/ 18 декабря 2011
/data/peptides/peptide[
  generate-id()
  =
  generate-id(
    key('byAccSeq', concat(protein_accessions/accession, '|', sequence))[1]
  )
]

и

/data/peptides/peptide[
  generate-id()
  =
  generate-id(
    key('byAccSeq', concat(protein_accessions/accession, '|', sequence))
  )
]

эквивалентны.generate-id() всегда возвращает идентификатор первого узла в наборе узлов, который был ему передан.

Поэтому не имеет значения, используете ли вы generate-id(some-node-set) или generate-id(some-node-set[1]).Вы можете использовать любой из файлов XSLT.

...