Как имитировать вызов шаблона-сопоставления со значением параметра?

Я ищу обходной путь для передачи параметров в соответствие с шаблоном. Я знаю, что это не разрешено в XPath, и поэтому я ищу решение «плана Б».

Это то, что я хотел бы работать:

Часть 1 xslt (2.0):

<xsl:template match="/">
    <xsl:for-each select="//Main/PageList/Page">
    <xsl:result-document href="{@ID}.xml">
        <Page ID="{@ID}">
            <xsl:apply-templates select="node()">
                <xsl:with-param name="theID" select="@ID"/>
            </xsl:apply-templates>
        </Page>
    </xsl:result-document>
    </xsl:for-each> 
</xsl:template>

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

Итак, ниже то, что я хотел бы видеть работающим:

<!-- identity template -->
    <xsl:template match="node()|@*">
    <xsl:param name="theID"/>
    <xsl:copy>
        <xsl:apply-templates select="node()|@*">
            <xsl:with-param name="theID" select="$theID"/>
        </xsl:apply-templates>
    </xsl:copy>
</xsl:template>

<!-- lots of templates here doing what I want them to do -->

<!-- one template creating an issue -->

<xsl:template match="@src">
<!-- would be nice to know the current ID, but unfortunately this one stays empty... -->
<xsl:param name="theID"/>

<!-- clean current attribute a bit -->
<xsl:variable name="S1" select="replace(.,'\.\.\/','')"/>

<xsl:attribute name="src">
<xsl:choose>
<xsl:when test="contains($S1,'common')">
<!-- just use current value, don't bother about current ID -->
    <xsl:value-of select="$S1"/>
</xsl:when>
<xsl:otherwise>
    <!-- use ID parameter -->
    <xsl:value-of select="concat($theID,'_',$S1)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
</xsl:template>

Не смотрите на код как таковой, это просто меньшая часть всего файла, но суть в том, что я хочу использовать параметр ID из моей первой части (match="/") внутри другого шаблона (match= "@src"), но это кажется довольно сложным.

Я что-то упускаю ? Если мне просто не повезло, и это действительно невозможно, может ли кто-нибудь посоветовать, как мне действовать?

Заранее спасибо !


person Wokoman    schedule 08.08.2011    source источник
comment
Таким образом вы можете передать параметры для соответствия шаблону. Возможно, применение шаблонов к node() является слишком общим и будет соответствовать шаблону без параметра.   -  person Emiliano Poggi    schedule 08.08.2011
comment
@empo: я пытался удалить часть node(), но никакой реальной разницы (хотя, возможно, неправильно понял вашу точку зрения, поэтому не уверен, что это то, к чему вы стремились). Параметр в части «match» остается пустым, поэтому, если он должен работать, я действительно теряю его где-то в процессе. Я поиграюсь с более простой версией (мой текущий XSLT немного сложнее, чем предоставленное упрощение)   -  person Wokoman    schedule 08.08.2011
comment
Я имел в виду, что вам, вероятно, понадобится xsl:apply-templates select="//@src", где @src вместо node().   -  person Emiliano Poggi    schedule 08.08.2011
comment
Хороший вопрос, @Wokoman, +1: см. мой ответ для подробного объяснения и полного решения.   -  person Dimitre Novatchev    schedule 08.08.2011


Ответы (2)


Ваша проблема здесь:

<xsl:apply-templates select="node()">
  <xsl:with-param name="theID" select="@ID"/>
</xsl:apply-templates>

атрибут select указывает, что обработка должна продолжаться на любых дочерних узлах текущего узла.

Однако node() выбирает только дочерние узлы (элементы, текстовые узлы, инструкции по обработке и комментарии), а не атрибуты.

Решение:

  1. Чтобы напрямую вызвать обработку (всех) атрибутов текущего узла, используйте:

--

<xsl:apply-templates select="@*">
  <xsl:with-param name="theID" select="@ID"/>
</xsl:apply-templates>

.2. Чтобы вызвать обработку только атрибута src текущего узла, используйте:

--

<xsl:apply-templates select="@src">
  <xsl:with-param name="theID" select="@ID"/>
</xsl:apply-templates>

.3. Чтобы косвенно обрабатывать атрибуты потомков текущего узла, выполните:

--

<xsl:apply-templates select="node()|@*">
  <xsl:with-param name="theID" select="@ID"/>
</xsl:apply-templates>

Вы также должны убедиться, что любой шаблон, который обрабатывает node(), должен иметь xsl:param с именем theID и что он должен передавать этот параметр в любой инструкции xsl:apply-templates.

На практике это означает, что вы должны переопределить все встроенные шаблоны XSLT, поскольку они не знают о вашем xsl:param.

person Dimitre Novatchev    schedule 08.08.2011
comment
Я должен был быть более ясным, но на самом деле есть много шаблонов, поэтому вызов src напрямую не поможет (на самом деле src является частью элемента img, который, в свою очередь, делает что-то...) Я понял, прочитав ваш обратная связь о том, что мой параметр просто теряется после первого прохода, поэтому я решил быть умным и вместо этого добавить его в шаблон удостоверения (я немного изменил свой вопрос), но это тоже не помогает. Итак, какую очевидную часть я здесь упускаю из виду? (изменение на node()|attr* в моем основном шаблоне не имело значения, на самом деле я намеренно игнорирую атрибуты при запуске) - person Wokoman; 08.08.2011
comment
@Wokoman: xsl:param должен быть добавлен ко всем шаблонам, и все они должны передавать его с xsl:with-param в шаблоны, которые они применяют (с xsl:apply-templates). Недостаточно только объявить xsl:param — его также следует передавать в применяемые шаблоны. - person Dimitre Novatchev; 08.08.2011
comment
Хорошо, я боялся этого :-) Просто для моего интереса (и для утоления моей жажды обучения ...), почему этого недостаточно, чтобы применить его к шаблону идентификации? Я всегда думал, что это будет каскадом. Если это слишком сложно, объясните, не беспокойтесь, как было сказано, это будет просто для лучшего понимания, чтобы я мог избежать подобных вопросов в будущем. - person Wokoman; 08.08.2011
comment
@Wokoman: Как я сказал в своем ответе, всякий раз, когда в результате xsl:apply-templates для выполнения выбирается соответствующий шаблон, и этот шаблон не имеет объявления xsl:param для вашего конкретного параметра, это разрывает цепочку. В частности, это делает любой встроенный шаблон XSLT, поэтому было бы безопасно переопределить все встроенные шаблоны XSLT своими собственными, и все ваши шаблоны должны объявлять необходимые xsl:param и передавать их в любые другие шаблоны, используя xsl:with-param в детстве xsl:apply-templates. - person Dimitre Novatchev; 08.08.2011
comment
@Wokoman: Если вы можете использовать XSLT 2.0, для этого есть специальная функция, называемая tunnel parameters - это может быть очень удобно в таких случаях, как ваш. - person Dimitre Novatchev; 09.08.2011

я думаю вместо

        <xsl:apply-templates select="node()">
            <xsl:with-param name="theID" select="@ID"/>
        </xsl:apply-templates>

ты скорее хочешь

        <xsl:apply-templates select="node()">
            <xsl:with-param name="theID" select="parent::Page/@ID"/>
        </xsl:apply-templates>

предполагая, что вы хотите передать атрибут ID родительского элемента Page.

С другой стороны, select="node()" выбирает любые дочерние узлы, такие как дочерние элементы, дочерние узлы комментариев, дочерние текстовые узлы, дочерние узлы инструкций по обработке, поэтому я не понимаю, почему вы позже показываете шаблон, соответствующий узлу атрибута.

person Martin Honnen    schedule 08.08.2011
comment
Я показал только один шаблон, но на самом деле их несколько десятков, и все они выполняют некоторую реконструкцию основных данных (постранично). Проблема, с которой я столкнулся с упомянутым здесь конкретным, заключается в том, что мне нужно восстановить путь к изображению, а есть два типа путей. Для одного я могу просто сохранить значение, но для других мне нужно иметь текущую страницу (ID), чтобы можно было восстановить фактический путь. Я знаю, что это звучит ужасно сложно, но это легче увидеть, чем описать (то, что я не являюсь носителем языка, тоже не помогает...). К сожалению, использование вашего изменения ничего не изменило. - person Wokoman; 08.08.2011