XSLT Сопоставление шаблона для однократного изменения атрибута

У меня есть документ с определенным атрибутом (myId), значение которого необходимо обновлять всякий раз, когда его значение равно нулю. Документ выглядит так

<?xml version="1.0" encoding="UTF-8"?><Summary>
 <Section myId="0">
  <Section myId="0">
   <Para>...</Para>
  </Section>
  <Section myId="5">
   <Para>...</Para>
  </Section>
 </Section>
</Summary>

Я использую шаблон для сопоставления атрибута myId, чтобы установить для него уникальный идентификатор, переданный из вызывающей программы, но я хочу сопоставить только один из атрибутов в документе. Любые дополнительные атрибуты со значением 0 будут обновлены путем передачи другого идентификатора. Мой шаблон, который я использую, выглядит так:

 <xsl:template        match  = '@myId[.="0"]'>
  <xsl:attribute name = "{name()}">
   <xsl:value-of select = "$addValue"/>
  </xsl:attribute>
 </xsl:template>

Значение addValue является глобальным параметром, передаваемым из вызывающей программы. Я искал ответ большую часть дня, но не могу применить этот шаблон только один раз. В выходных данных оба значения myId заменяются содержимым addValue. Я пытался сопоставить с '@myId[."0"][1]' и пытался использовать функцию position() для сопоставления, но мой шаблон всегда применяется ко всем атрибутам myId, которые равны нулю.

Можно ли применить соответствующий шаблон только один раз?


person VEnglisch    schedule 05.05.2012    source источник
comment
Попробуйте использовать ось preceding, где count равен 0.   -  person    schedule 05.05.2012


Ответы (1)


Можно ли применить соответствующий шаблон только один раз?

Да:

  1. Применяется ли шаблон или нет, зависит от xsl:apply-templates, который вызывает выбор шаблона для выполнения.

  2. Кроме того, шаблон соответствия может быть указан таким образом, чтобы гарантировать соответствие шаблона только одному конкретному узлу в документе.

Вот что вы можете сделать:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:param name="pNewIdValue" select="9999"/>


 <xsl:template match="node()|@*">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match=
 "Section
   [@myId = 0
  and
    not((preceding::Section | ancestor::Section)
                 [@myId = 0]
       )
   ]/@myId">
  <xsl:attribute name="myId"><xsl:value-of select="$pNewIdValue"/></xsl:attribute>
 </xsl:template>
</xsl:stylesheet>

Когда это преобразование применяется к предоставленному XML-документу:

<Summary>
    <Section myId="0">
        <Section myId="0">
            <Para>...</Para>
        </Section>
        <Section myId="5">
            <Para>...</Para>
        </Section>
    </Section>
</Summary>

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

<Summary>
   <Section myId="9999">
      <Section myId="0">
         <Para>...</Para>
      </Section>
      <Section myId="5">
         <Para>...</Para>
      </Section>
   </Section>
</Summary>
person Dimitre Novatchev    schedule 05.05.2012
comment
preceding не включает ancestor, или я что-то упустил? - person ; 05.05.2012
comment
@torazaburo: Нет, предыдущие/последующие оси и оси предков/потомков не перекрываются. См. это в спецификации W3C XPath w3.org/TR/xpath/#axes. пули 7 и 8. - person Dimitre Novatchev; 05.05.2012
comment
@dimitre: я не мог понять, как использовать ось предыдущий/предок с моим шаблоном, соответствующим атрибуту. Возможно, это даже невозможно, но ваше решение делает именно то, что мне нужно. Большое спасибо за твою помощь! Здесь я изучил опрятную технику сопоставления. - person VEnglisch; 07.05.2012