XSLT добавляет атрибут к узлу, только если атрибут источника существует - PullRequest
3 голосов
/ 08 мая 2011

Я имею в виду добавить элемент атрибута в узел тогда и только тогда, когда существует источник данных этого атрибута.

Другими словами, я не хочу заканчиваться пустыми атрибутами, если источник не соответствует моему правилу.

<tok id="t1" fooID=""/> //not accepted
<tok id="t1" /> //instead of ^
<tok id="t1" fooID="bar"/> //accepted


Более того, я хотел бы проверить, имеет ли источник более 1 узла, соответствующего моему текущему атрибуту, и если да, добавьте еще один атрибут foo с «source2». Вот что я сейчас использую:
<xsl:template match="tokens/token">
<tok id="{@ID}" 
     ctag="{/root/myStuff/fooSources[1and2 how?]/fooSource[@fooID=current()/@ID]}" 
>
</tok>

Исходный XML выглядит следующим образом:

<root>
   <myStuff>
      <tokens>
         <token ID="bar"/>
         <token ID="anotherBar"/>
         <token ID="noFoo"/>
      </tokens>

      <fooSources>
         <fooSource fooID="bar"> kitten </fooSource>
         <fooSource fooID="anotherBar"> shovel </fooSource>
      </fooSources>

      <fooSources>
         <fooSource fooID="bar"> kitty </fooSource>
         <fooSource fooID="notAnotherBar"> fridge </fooSource>
      </fooSources>
   </myStuff>
</root>

Желаемый результат будет следующим:

<tok id="bar" fooID="kitten" fooID_2="kitty"/>
<tok id="anotherBar" fooID="shovel"/> 
<tok id="noFoo" /> 

Заранее спасибо за любую помощь!

PS: я бы хотел сделать это в xpath 1.0

Ответы [ 2 ]

5 голосов
/ 08 мая 2011
<foo>
   <xsl:if test="@bar">
      <xsl:attribute name="id">
         <xsl:value-of select="@bar"/>
      </xsl:attribute>
   </xsl:if>
</foo>
3 голосов
/ 08 мая 2011

PS: я бы хотел сделать это в xpath 1.0

XPath является языком запросов для документов XML и поэтому не может изменять никакие узлы документа.

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

Это преобразование XSLT 1.0 :

<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:key name="kFooIdByVal" match="fooSource/@fooID"
  use="."/>

 <xsl:template match="token">
  <tok>
   <xsl:copy-of select="@*"/>
   <xsl:apply-templates
        select="key('kFooIdByVal',@ID)"/>
  </tok>
 </xsl:template>

 <xsl:template match="@fooID">
  <xsl:variable name="vattrName"
   select="concat('fooID',
                  substring(concat('_',position()),
                            1 div (position() >1)
                           )
                  )
   "/>

  <xsl:attribute name="{$vattrName}">
   <xsl:value-of select="normalize-space(..)"/>
  </xsl:attribute>
 </xsl:template>
 <xsl:template match="fooSources"/>
</xsl:stylesheet>

при применении к предоставленному документу XML :

<root>
    <myStuff>
        <tokens>
            <token ID="bar"/>
            <token ID="anotherBar"/>
            <token ID="noFoo"/>
        </tokens>
        <fooSources>
            <fooSource fooID="bar"> kitten </fooSource>
            <fooSource fooID="anotherBar"> shovel </fooSource>
        </fooSources>
        <fooSources>
            <fooSource fooID="bar"> kitty </fooSource>
            <fooSource fooID="notAnotherBar"> fridge </fooSource>
        </fooSources>
    </myStuff>
</root>

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

<tok ID="bar" fooID="kitten" fooID_2="kitty"/>
<tok ID="anotherBar" fooID="shovel"/>
<tok ID="noFoo"/>

Объяснение

  1. Шаблон, соответствующий любому token элементу , создает tok element that has all the existing attributes (if any) of the matched токен element. It also applies templates on any fooID attribute, whose value is the same as the value of the ID attribute of the current (matched) node. If there isn't any such fooID`, дальнейшая обработка не выполняется и никаких дополнительных атрибутов созданы.

  2. Шаблон, соответствующий атрибуту fooID , должен сгенерировать новый атрибут формы "fooID_{N}", где N - позиция текущего узла (атрибут fooID, соответствующий ему) ) в списке узлов (создан инструкцией <xsl:apply-templates>, которая выбрала этот текущий шаблон для применения к этому атрибуту fooID). Если N равно 1, мы не добавляем в начало имени ("fooID") строку "_"{N}.

  3. Чтобы избежать побочных эффектов обработки XSLT по умолчанию , мы добавляем третий шаблон, который соответствует любому элементу fooSources, и (шаблон) имеет пустое тело.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...