XSLT: Как я могу создать вывод, используя исходный код и этот второй файл? - PullRequest
1 голос
/ 19 января 2011

У меня есть два XML, один для определения шаблонов для объектов моего приложения. и другой с реальными объектами. В основном в каждом объекте изменяются только несколько значений, поэтому я хотел предоставить какой-то механизм шаблонов и применить XSL для преобразования их в окончательный вариант.

Это образец объекта:

<config>
<objects>
    <object code="1000" name="object1">
        <template name="decoration" buyCoins="60" />
    </object>
</objects>

И это пример шаблона для этого объекта:

<config xmlns:template="object-template">
<templates>
  <template name="decoration">
<connection type="make" />
<placeable width="1" length="1" moveable="true" collision="D" />
<buyable>
  <requirement template:coins="buyCoins"/>
  <reward xp="1" />
</buyable>
<sellable>
  <reward coins="1"/>
</sellable></template></templates></config>

Это мой текущий XSL:

<xsl:variable name="templates" select="document('../templates.xml')/config/templates//template" />

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

<xsl:template match="//template">
    <xsl:variable name="itemTemplate" select="."/>
    <xsl:variable name="templateName" select="@name"/>
    <xsl:variable name="selectedTemplate" select="$templates[@name = $templateName]/*" />

    <xsl:for-each select="$selectedTemplate">

            <!-- This part is only a test to get the values that I need -->
        <xsl:for-each select=".//@*[namespace-uri() = 'object-template']">
            <xsl:variable name="attributeName" select="name()"/>
            <xsl:variable name="attributeValue" select="."/>
            <xsl:variable name="finalValue" select="$itemTemplate/@*[local-name() = $attributeValue]"/>

        </xsl:for-each> 
    </xsl:for-each>
</xsl:template>

<xsl:template match="comment()"/>

Мне просто нужно сделать следующее:

  1. Итерация каждого элемента, содержащего тег шаблона
  2. Для каждого из них получите соответствующий шаблон документа шаблона
  3. Скопируйте все внутри шаблона в объект (*)
  4. Заменить значения атрибутов внутри элемента (теперь с вставленным шаблоном) реальным значением в исходном шаблоне (**)

Пояснение:

(*) Применить

 <template name="test"><node></template> 

до

<object><template name="test"></object> 

становится

<object><node></object>

(**) В исходном примере выше значение buyCoins тега шаблона элемента должно заменить значение шаблона текста «buyCoins» перед отправкой его в вывод. Для удобства поиска и для того, чтобы избежать рег. эксп. Я использую пространства имен. Итак, что я делаю в XSL - это поиск всех атрибутов внутри шаблона с правильным пространством имен и поиск значений. Значение "60" должно быть помещено вместо "buyCoins" внутри атрибута coins.

Моя проблема в том, что я не понимаю, как копировать все (я думаю, это называется идентификационной копией), но заменяю нужное мне значение.

Любая помощь будет оценена, спасибо !!!

UPDATE:

Токовый выход:

<config xmlns:template="item-template">
<objects>   
    <object code="1000" name="object1" type="decorations">
    </object>
</object>

Если я поставлю:

<xsl:copy-of select="."/>

ниже:

<xsl:for-each select="$selectedTemplate">

Тогда я получаю:

<objects>
<object code="1000" name="object1">
    <connection type="make" /><placeable width="1" length="1" moveable="true" collision="D" />
<buyable>
    <requirement template:coins="buyCoins"/>
    <reward xp="1" />
</buyable>
<sellable>
    <reward coins="1"/>
</sellable>
</object></objects>

Это первая часть того, что мне нужно, чтобы поместить в каждый элемент вывода содержимое связанного с ним шаблона. У меня проблемы с заменой значений.

Эти строки дерева в XSL представляют данные, которые мне нужны:

        <xsl:variable name="attributeName" select="name()"/>
        <xsl:variable name="attributeValue" select="."/>
        <xsl:variable name="finalValue" select="$itemTemplate/@*[local-name() = $attributeValue]"/>

Для единственного элемента в этом примере это содержимое каждой переменной: attributeName будет содержать «template: coins» attributeValue будет содержать «buyCoins» finalValue будет содержать "60"

Мне нужно поместить finalValue вместо attributeValue в тег этого атрибута name.

В этот момент я застрял: (

Спасибо!

Обновление 2:

Чтобы избежать недоразумений, вот ТОЧНЫЙ вывод, который мне нужен:

    <objects>
<object code="1000" name="object1">
    <connection type="make" /><placeable width="1" length="1" moveable="true" collision="D" />
<buyable>
    <requirement coins="60"/>
    <reward xp="1" />
</buyable>
<sellable>
    <reward coins="1"/>
</sellable>
</object></objects>

Вместо «buyCoins» в атрибуте монеты мне нужно, чтобы оно было «60» (значение в файле входных объектов). Кроме того, наилучший возможный вывод должен также удалить шаблоны пространств имен атрибутов, потому что XSL-файл знает только, какие атрибуты нужно изменить.

Ответы [ 2 ]

0 голосов
/ 20 января 2011

Вот традиционное решение XSLT :

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

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

 <xsl:template match="template">
  <xsl:apply-templates select="
   /*/templates/template[@name = current()/@name]/node()">
    <xsl:with-param name="pParams" select="@*"/>
  </xsl:apply-templates>
 </xsl:template>

 <xsl:template match="@template:*">
   <xsl:param name="pParams"/>
   <xsl:attribute name="{local-name()}">
     <xsl:value-of select="$pParams[name()=current()]"/>
   </xsl:attribute>
 </xsl:template>
 <xsl:template match="templates"/>
</xsl:stylesheet>

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

<config xmlns:template="object-template">
    <objects>
        <object code="1000" name="object1">
            <template name="decoration"
                      buyCoins="60" />
        </object>
    </objects>
    <templates>
        <template name="decoration">
            <connection type="make" />
            <placeable width="1" length="1"
            moveable="true" collision="D" />
            <buyable>
                <requirement template:coins="buyCoins"/>
                <reward xp="1" />
            </buyable>
            <sellable>
                <reward coins="1"/>
            </sellable>
        </template>
    </templates>
</config>

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

<config xmlns:template="object-template">
   <objects>
      <object code="1000" name="object1">
         <connection type="make"/>
         <placeable width="1" length="1" moveable="true" collision="D"/>
         <buyable>
            <requirement coins="60"/>
            <reward xp="1"/>
         </buyable>
         <sellable>
            <reward coins="1"/>
         </sellable>
      </object>
   </objects>
</config>

Примечание :

  1. Идентификационные данныеПравило (шаблон) используется для копирования всех узлов "как есть".Использование и переопределение правила идентификации является наиболее фундаментальным шаблоном проектирования XSLT.

  2. Используемое нами правило идентификации модифицируется для принятия и прохождения через один параметр , названный pParams.Этот параметр представляет собой набор всех атрибутов элемента object/template, который ссылается на конкретный шаблон.

  3. Любой элемент object/template соответствует xsl: template таким образом, это отменяет правило идентичности.Он просто выдает <xsl:apply-templates> узлам соответствующего (соответствует элементу @name - templates\template.

  4. Все узлы ниже соответствующего элемента templates\template копируются по правилу идентификации, за исключением любого атрибута в пространстве имен "object-template".

  5. Шаблон соответствует любому атрибуту с именем в "object-template" namespace и, таким образом, переопределяет правило идентификации. Этот шаблон xsl: использует параметр pParams, чтобы найти в нем атрибут, имя которого совпадает со значением текущего сопоставленного атрибута. Значение атрибута-параметра«найденный таким образом» используется в качестве значения вновь созданного атрибута, который имеет тот же local-name(), что и текущий соответствующий атрибут, но не находится в пространстве имен.

  6. Пустойшаблон, соответствующий любому элементу templates, запрещает правило идентификации при копировании этого поддерева (во второй раз).

0 голосов
/ 20 января 2011

Просто для удовольствия, эта таблица стилей XSLT 1.0:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:template="object-template"
 exclude-result-prefixes="template">
    <xsl:key name="kTemplateByName" match="templates/template" use="@name"/>
    <xsl:template match="*">
        <xsl:param name="pContext"/>
        <xsl:element name="{name()}">
            <xsl:copy-of select="namespace::*[.!='object-template']"/>
            <xsl:apply-templates select="node()|@*">
                <xsl:with-param name="pContext" select="$pContext"/>
            </xsl:apply-templates>
        </xsl:element>
    </xsl:template>
    <xsl:template match="@*">
        <xsl:copy-of select="."/>
    </xsl:template>
    <xsl:template match="templates"/>
    <xsl:template match="config">
        <xsl:apply-templates/>
    </xsl:template>
    <xsl:template match="template">
        <xsl:apply-templates select="key('kTemplateByName',@name)/node()">
            <xsl:with-param name="pContext" select="."/>
        </xsl:apply-templates>
    </xsl:template>
    <xsl:template match="@template:*">
        <xsl:param name="pContext"/>
        <xsl:attribute name="{local-name()}">
            <xsl:value-of select="$pContext//@*[name()=current()]"/>
        </xsl:attribute>
    </xsl:template>
</xsl:stylesheet>

С этим входом:

<config xmlns:template="object-template">
    <objects>
        <object code="1000" name="object1">
            <template name="decoration" buyCoins="60" />
        </object>
    </objects>
    <templates>
        <template name="decoration">
            <connection type="make" />
            <placeable width="1" length="1" moveable="true" collision="D" />
            <buyable>
                <requirement template:coins="buyCoins"/>
                <reward xp="1" />
            </buyable>
            <sellable>
                <reward coins="1"/>
            </sellable>
        </template>
    </templates>
</config>

Выход:

<objects>
    <object code="1000" name="object1">
        <connection type="make"></connection>
        <placeable width="1" length="1" moveable="true" collision="D"></placeable>
        <buyable>
            <requirement coins="60"></requirement>
            <reward xp="1"></reward>
        </buyable>
        <sellable>
            <reward coins="1"></reward>
        </sellable>
    </object>
</objects>
...