Собственно XSLT Lookup (хранить переменные во время цикла и использовать в нем другой шаблон) - PullRequest
0 голосов
/ 02 мая 2010

Этот вопрос на самом деле задает нечто совершенно иное . Посмотрите комментарии к ответу @ Tomalak, чтобы понять, чего действительно хотел ОП. (

Есть ли способ сохранить переменную / параметр во время цикла for-each в виде массива и использовать его в другом шаблоне, а именно <xsl:template match="Foundation.Core.Classifier.feature">. Все значения classname, которые появляются во время for-each, должны быть сохранены. Как бы вы реализовали это в XSLT? Вот мой текущий код.

<xsl:for-each select="Foundation.Core.Class">       
 <xsl:for-each select="Foundation.Core.ModelElement.name">
  <xsl:param name="classname">
   <xsl:value-of select="Foundation.Core.ModelElement.name"/>
  </xsl:param>
 </xsl:for-each>
 <xsl:apply-templates select="Foundation.Core.Classifier.feature" /> 
</xsl:for-each>

Вот шаблон, в котором должны использоваться параметры classname.

<xsl:template match="Foundation.Core.Classifier.feature">
 <xsl:for-each select="Foundation.Core.Attribute">
  <owl:DatatypeProperty rdf:ID="{Foundation.Core.ModelElement.name}">
   <rdfs:domain rdf:resource="$classname" />
  </owl:DatatypeProperty>
 </xsl:for-each>
</xsl:template>

Входной файл находится по адресу http://krisvandenbergh.be/uml_pricing.xml

Ответы [ 2 ]

5 голосов
/ 02 мая 2010

Нет, невозможно сохранить переменную в цикле for-each и использовать ее позже.

Это потому, что переменные имеют однократную запись в XSLT (после установки они неизменяемы) и строго ограничены родительским элементом. Как только обработка выходит из цикла for-each, переменная исчезает.

XSLT не работает как императивный язык программирования, но вы, похоже, пытаетесь здесь это сделать. Вам не нужно <xsl:for-each> в 98% всех случаев, и вы не должны его использовать, потому что это забивает ваше представление о том, как работает XSLT. Чтобы улучшить свой код XSLT, избавьтесь от всех имеющихся у вас циклов <xsl:for-each> (я имею в виду все они) и используйте вместо них шаблоны:

<xsl:template match="Foundation.Core.Class">
  <xsl:apply-templates select="
    Foundation.Core.Classifier.feature/Foundation.Core.Attribute
  " />
</xsl:template>

<xsl:template match="Foundation.Core.Attribute">
  <owl:DatatypeProperty rdf:ID="{Foundation.Core.ModelElement.name}">
    <rdfs:domain rdf:resource="{
      ancestor::Foundation.Core.Class[1]/Foundation.Core.ModelElement.name[1]
    }" />
  </owl:DatatypeProperty>
</xsl:template>

(Я не уверен, что вышесказанное - то, что вы на самом деле хотите, ваш вопрос довольно двусмысленный.)

Обратите внимание на использование оси XPath ancestor для ссылки на элемент выше в иерархии (кажется, вы хотите <Foundation.Core.ModelElement.name> родительского класса).

PS: Ваш XML невероятно раздут и сильно избыточен из-за структурированных имен элементов. Структура должна быть из ... ну ... структура , а не из таких элементов, как <Foundation.Core.Classifier.feature>. Я не уверен, что вы можете что-нибудь с этим сделать.


Дополнительно:

Для решения проблемы xmi.id / xmi.idref лучше всего использовать ключ XSL:

<!-- this indexes all elements by their @xmi.id attribute -->
<xsl:key name="kElementByIdref" match="*[@xmi.id]" use="@xmi.id" />

<!-- now you can do this -->
<xsl:template match="Foundation.Core.DataType">
  <dataTypeName>
   <!-- pull out the corresponding element from the key, output its value -->
   <xsl:value-of select="key('kElementByIdref', @xmi.idref)" />
  </dataTypeName>
</xsl:template>

Чтобы лучше понять, как ключи работают внутри, вы можете прочитать этот ответ, который я дал ранее . Не беспокойтесь слишком сильно вопросом, просто прочитайте нижнюю часть моего ответа, я объяснил ключи в терминах JavaScript.

0 голосов
/ 02 мая 2010

Хорошо, теперь я понимаю, почему for-each не всегда нужен. Рассмотрим код ниже.

<Foundation.Core.DataType xmi.id="UID71848B1D-2741-447E-BD3F-BD606B7FD29E">
<Foundation.Core.ModelElement.name>int</Foundation.Core.ModelElement.name>
</Foundation.Core.DataType>

У него есть идентификатор UID71848B1D-2741-447E-BD3F-BD606B7FD29E

В другом месте у меня есть следующее.

    <Foundation.Core.StructuralFeature.type>
<Foundation.Core.DataType xmi.idref="UID71848B1D-2741-447E-BD3F-BD606B7FD29E"/>
</Foundation.Core.StructuralFeature.type>

Как видите, оба кода имеют одинаковый идентификатор. Теперь я хочу вывести «int», каждый раз, когда этот идентификатор появляется где-то в документе. Поэтому в основном idref="UID71848B1D-2741-447E-BD3F-BD606B7FD29" следует заменить на int, который может быть легко получен из элемента Foundation.Core.ModelElement.name.

Выше приведена основная причина, по которой я хотел бы сохранить ее в переменной. Я не понимаю, как это можно сделать с помощью XSLT. Если кто-то мог бы уточнить это, я надеюсь, что существует какая-то модель для решения такой проблемы, так как она мне нужна довольно часто. Что было бы хорошим подходом?

Я понимаю, что это, возможно, немного не по теме, но я все равно хочу спросить об этом в этой теме, так как эта проблема очень близка к ней.

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