Включить узлы HTML в <xsl: attribute>

Я хочу включить HTML в атрибут элемента (для атрибута очистки данных, используемого здесь: http://foundation.zurb.com/docs/components/clearing.html). мой <caption> Данные доступны двумя способами:

<caption mode="formatted">
    <p>A fairly long looking <a href="http://www.stackru.com">caption with a link</a> that goes to an external site.</p>
</caption>
<caption mode="unformatted">
    <![CDATA[A fairly long looking <a href="http://www.stackru.com">caption with a link</a> that goes to an external site.]]>
</caption>

Вот мой шаблон:

<xsl:template match="images/entry">
    <!-- process contents of caption node-->
    <xsl:variable name="cap">
        <xsl:text disable-output-escaping="yes">&lt;![CDATA[</xsl:text>
        <xsl:apply-templates select="caption/*" mode="html" />
        <xsl:text disable-output-escaping="yes">]]&gt;</xsl:text>
    </xsl:variable>

    <li>
        <xsl:copy-of select="$cap"/> //outside of attribute it works
        <img>
            <xsl:attribute name="src">/image/2/150/112/5<xsl:value-of select="@path"/>/<xsl:value-of select="filename"/></xsl:attribute>
            <xsl:attribute name="data-caption">
                <xsl:copy-of select="$cap"/> //inside of attribute it removes the <a> tag
            </xsl:attribute>
        </img>
    </li>
</xsl:template>

mode=html соответствует <a> тег в <caption> узел с этим шаблоном:

<!-- mark external links -->
<xsl:template match="a" mode="html">
<a href="{@href}" title="{@title}">
    <xsl:if test="number(substring(@href,1,4)='http')">
        <xsl:attribute name="class">external</xsl:attribute>
        <xsl:attribute name="target">_blank</xsl:attribute>
    </xsl:if>
    <xsl:apply-templates select="* | @* | text()" mode="html"/>
</a>
</xsl:template>

Если я использую "неотформатированную" подпись, она сохраняет <a> тег (желаемое поведение). Однако, когда я использую эту подпись, я не могу использовать шаблон "пометить внешние ссылки", чтобы исправить <a> тег. Используя "отформатированный" заголовок, я могу обработать <a> тег, как я хочу, но он теряется, когда я использую xsl:copy-of внутри <img><xsl:attribute>, Он будет отображаться нормально вне атрибута, например так:

<![CDATA[<p>A fairly long looking <a href="http://www.stackru.com" title="" class="external" target="_blank">caption with a link</a> that goes to an external site.</p>]]>

Есть ли способ, чтобы мой конечный результат выглядел так:

<img src="/image/2/150/112/5/images/my-image.jpg" 
    data-caption="<![CDATA[A fairly long looking <a class="external" target="_blank" href="http://www.stackru.com">caption with a link</a> that goes to an external site.]]>;" />

Спасибо за прочтение.

1 ответ

Решение

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

Чтобы получить этот результат, есть две проблемы. Во-первых, вам нужно создать строку, содержащую лексический XML, а затем передать эту строку в качестве значения атрибута. Во-вторых, вам нужно предотвратить экранирование специальных символов в этой строке.

Для первой проблемы есть два подхода: вы можете вызвать внешнюю функцию serialize(), которая преобразует дерево в лексический XML в виде строки, например, saxon:serialize(), если вы используете Saxon, или вы можете написать свой собственный (что не сложно для простых случаев, и это уже было сделано - Дэвид Карлайл (David Carlisle) написал полный сериализатор XML на XSLT).

Вторая проблема сложна. Спецификация сериализации XSLT (все версии) непреклонна, что метод сериализации HTML не должен экранировать "<", появляющийся в значениях атрибутов, но он почти или ничего не говорит о ">". Саксонский избегает ">" как "&gt;"Якобы потому, что это требуется в старых браузерах (возможно, уже очень старых), но я не думаю, что это требуется спецификацией, и другие процессоры могут отличаться. Disable-output-escaping не работает для значений атрибутов, поэтому вам, возможно, придется прибегнуть к созданию всей сериализации элемента вручную, используя disable-output-escaping. Кроме того, в XSLT 2.0 вы можете использовать карты символов для принудительного вывода ">" в ​​значении атрибута.

В вашем примере кода вы используете disable-output-escaping при записи значения переменной. В спецификации есть история йойо. В сообщении об ошибке XSLT 1.0 (так называемое исправление "липкая точка") сказано, что это разрешено, но в XSLT 2.0 это было отменено, поскольку это было несовместимо с разрешением полного навигационного доступа к фрагментам результирующего дерева, содержащимся в переменных. Таким образом, суть в том, что он может или не может работать в зависимости от процессора, который вы используете - но, конечно, это верно для отключения-вывода-выхода в целом.

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

Другие вопросы по тегам