Заменить текст узла на XSLT? - PullRequest
3 голосов
/ 04 ноября 2011

Ниже приведен мой XML-файл, который используется для хранения данных -

<Locations>
   <location>
      <place>Newyork</place>
      <dt>01-Dec-2011</dt>
   </location>
   <location>
      <place>Berlin</place>
      <dt>02-Dec-2011</dt>
   </location>
   <location>
      <place>Tokyo</place>
      <dt>04-Dec-2011</dt>
   </location>
</Location>

Чего я хочу добиться -

Я хочу заменить значение даты тегов <dt>, если посещение запланировано повторно. Например- Если дата посещения Берлина изменилась, сохраняется в тегах <dt>, то как редактировать / заменять их в файле XML с помощью XSLT ..? Заранее спасибо - Джон

Ответы [ 3 ]

5 голосов
/ 04 ноября 2011

Это преобразование показывает, как использовать глобальный параметр (смоделированный здесь со встроенным элементом) для указания (возможно, нескольких) обновлений :

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

 <my:updates>
  <update place="Berlin" dt="11-Dec-2011"/>
 </my:updates>

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

 <xsl:template match=
  "location
     [place = document('')/*/my:updates/update/@place]
       /dt/text()
  ">
  <xsl:value-of select=
    "document('')/*/my:updates/update
                      [@place = current()/../../place]
                        /@dt
    "/>
 </xsl:template>
</xsl:stylesheet>

При применении к предоставленному документу XML (исправлено, чтобы сделать его правильно сформированным):

<Locations>
   <location>
      <place>Newyork</place>
      <dt>01-Dec-2011</dt>
   </location>
   <location>
      <place>Berlin</place>
      <dt>02-Dec-2011</dt>
   </location>
   <location>
      <place>Tokyo</place>
      <dt>04-Dec-2011</dt>
   </location>
</Locations>

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

<Locations>
   <location>
      <place>Newyork</place>
      <dt>01-Dec-2011</dt>
   </location>
   <location>
      <place>Berlin</place>
      <dt>11-Dec-2011</dt>
   </location>
   <location>
      <place>Tokyo</place>
      <dt>04-Dec-2011</dt>
   </location>
</Locations>

Объяснение

  1. Правило идентификации копирует каждый узел "как есть"".

  2. Существует только один переопределяющий шаблон - соответствующий дочернему элементу текстового узла любого dt, чье строковое значение брата place имеет соответствующий элемент my:updates/update. В этом шаблоне мы выводим значение атрибута dt соответствующего элемента my:updates/update.

Do note : При преобразовании реального мира встроенный элемент my:updates будет лучше заменен внешним глобальным параметром. Прочитайте документацию вашего процессора XSLT, как передать внешний параметр в преобразование - это зависит от реализации.

ОБНОВЛЕНИЕ : Поскольку операционному оператору трудно преобразовать это решение в глобальное, переданное извне xsl:param, вот это преобразованное решение:

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

 <xsl:param name="pUpdates">
  <update place="Berlin" dt="11-Dec-2011"/>
 </xsl:param>

 <xsl:variable name="vUpdates" select=
     "ext:node-set($pUpdates)/*"/>

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

 <xsl:template match="dt/text()">
  <xsl:choose>
      <xsl:when test="../../place=$vUpdates/@place">
       <xsl:value-of select=
           "$vUpdates[@place = current()/../../place]/@dt"/>
      </xsl:when>
      <xsl:otherwise>
       <xsl:value-of select="."/>
      </xsl:otherwise>
  </xsl:choose>
 </xsl:template>
</xsl:stylesheet>

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

<Locations>
   <location>
      <place>Newyork</place>
      <dt>01-Dec-2011</dt>
   </location>
   <location>
      <place>Berlin</place>
      <dt>11-Dec-2011</dt>
   </location>
   <location>
      <place>Tokyo</place>
      <dt>04-Dec-2011</dt>
   </location>
</Locations>

Обратите внимание : в этом решении значение xsl:param по-прежнему жестко закодировано, и это единственная причина, по которой мы используем функцию расширения ext:node-set(). Если параметр действительно передается извне, то это преобразование из RTF в обычное дерево не требуется, и на этот параметр следует ссылаться напрямую.

Кроме того, в XSLT 1.0 мы должны более точно соответствовать и использовать сравнения (xsl:choose) внутри тела шаблона. Это так, потому что в XSLT 1.0 не разрешено ссылаться на переменные / параметры внутри шаблона сопоставления.

В XSLT 2.0 это ограничение было устранено , поэтому мы можем просто сделать намного более простое преобразование:

<xsl:stylesheet version="2.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="pUpdates">
  <update place="Berlin" dt="11-Dec-2011"/>
 </xsl:param>

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

 <xsl:template match=
   "location[place=$pUpdates/*/@place]/dt/text()">
       <xsl:value-of select=
           "$pUpdates/*[@place = current()/../../place]/@dt"/>
 </xsl:template>
</xsl:stylesheet>
2 голосов
/ 04 ноября 2011

Шаблон удостоверения будет копировать документ:

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

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

Пример (не проверено):

<xsl:template match="//location/dt[preceding-sibling::place='Berlin']">
    <dt>Your date</dt>
</xsl:template>
1 голос
/ 04 ноября 2011

Реальный вопрос в том, как вы собираетесь проверить, запланировано ли посещение? На мой взгляд, у вас есть три варианта:

  • Сохраните запланированные даты с местами во вторичном XML и используйте функцию XPath document для чтения из нее;
  • сгенерировать таблицу стилей XSLT программно с уже внесенными исправлениями или
  • использовать функцию расширения XSLT или элемент расширения (возможно, функции достаточно) для выполнения проверок на каком-либо другом языке. Например Java.

РЕДАКТИРОВАТЬ - или следуйте превосходному совету Краба: используйте параметры XSLT таким образом, чтобы вы могли передавать данные в статическую таблицу стилей.

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