Можно ли создать переменную, которая также может использоваться в других шаблонах в XSLT 3.0? - PullRequest
0 голосов
/ 15 мая 2018

Я начал исследовать основные изменения в XSLT 3.0. Насколько я знаю, в XSLT 2.0 мы не можем создать глобальную переменную для использования в разных шаблонах.

С помощью режима Streaming в XLST 3.0 и функции xsl: iterate или функции высшего порядка или некоторых других способностей мы теперь можем «запоминать» значения из предыдущих функций и, следовательно, мы можем использовать значения в разных местах над и снова.

Мой вопрос основан на следующем простом примере:

 <?xml version="1.0" encoding="UTF-8"?>
<PERSONAE PLAY="OTHELLO">
    <TITLE>Dramatis Personae</TITLE>
    <PERSON>
        <NAME>DUKE OF VENICE</NAME>
        <ID>123456</ID>
        <PROPERTIES>
            <BIRTHDAY>10.10.1980</BIRTHDAY>
            <CITY>New York</CITY>
            <COUNTRY>US</COUNTRY>
        </PROPERTIES>
    </PERSON>
    <PERSON>
        <NAME>BRABANTIO, a senator.</NAME>
        <ID>123456</ID>
        <PROPERTIES>
            <BIRTHDAY>10.10.1980</BIRTHDAY>
            <CITY>New York</CITY>
            <COUNTRY>US</COUNTRY>
        </PROPERTIES>
    </PERSON>
    <PERSON>
        <NAME>Other Senators.</NAME>
        <ID>123456</ID>
        <PROPERTIES>
            <BIRTHDAY>10.10.1980</BIRTHDAY>
            <CITY>New York</CITY>
            <COUNTRY>US</COUNTRY>
        </PROPERTIES>
    </PERSON>
</PERSONAE>

Допустим, это мой пример xml, и я хочу изменить эти значения с помощью уникальных идентификаторов, сгенерированных java: util function

XSLT:

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:util="java:java.util.UUID"
  version="3.0" expand-text="yes">

  <xsl:strip-space elements="PERSONAE"/>
  <xsl:template match="/">

    <xsl:apply-templates/>
    <xsl:call-template name="birthdayTemplate"/>
  </xsl:template>
  <xsl:template match="PERSONAE">
    <html>
      <head>
        <title>The Cast of {@PLAY}</title>
      </head>
      <body>
        <xsl:apply-templates/>
      </body>
    </html>
  </xsl:template>

  <xsl:template match="TITLE">
    <h1>{.}</h1>
  </xsl:template>

  <xsl:template match="PERSON/NAME[count(tokenize(., ',') = 2)]">
    <p><b>{substring-before(., ',')}</b>: {substring-after(., ',')}</p>
  </xsl:template>

  <xsl:template match="PERSON/NAME">
    <p>
      <b>{.}</b>
    </p>
  </xsl:template>
  <xsl:template match="PERSON/ID">

    <p>
      <xsl:value-of select="util:toString(util:randomUUID())"/>
    </p>

  </xsl:template>
  <xsl:template match="PERSON/PROPERTIES"></xsl:template>
<xsl:template name="birthdayTemplate">

  <xsl:for-each select="PERSON/PROPERTIES">
      <PROPERTIES>
        <ID>THE UUID VALUE THAT IS CREATED IN THE RESULT DOCUMENT</ID>
      </PROPERTIES>
  </xsl:for-each>
</xsl:template>


</xsl:stylesheet>

Результат, который я хочу получить:

<html xmlns:util="java:java.util.UUID">
   <head>
      <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
      <title>The Cast of OTHELLO</title>
   </head>
   <body>
      <h1>Dramatis Personae</h1>

      <p><b>DUKE OF VENICE</b></p>

      <p>a6759c7b-ff13-4b27-b726-ecd6ebaea96c</p>



      <p><b>BRABANTIO, a senator.</b></p>

      <p>1a58c699-ee9e-4093-8224-5319127fbf8c</p>



      <p><b>Other Senators.</b></p>

      <p>482908c6-2437-406d-a421-c7d2a103aba7</p>


      <p>
         <PROPERTIES>
            <ID>a6759c7b-ff13-4b27-b726-ecd6ebaea96c</ID>
            <BIRTHDAY>10.10.1980</BIRTHDAY>
            <CITY>New York</CITY>
            <COUNTRY>US</COUNTRY>
         </PROPERTIES>
      </p>
      <p>
         <PROPERTIES>
            <ID>1a58c699-ee9e-4093-8224-5319127fbf8c</ID>
            <BIRTHDAY>10.10.1980</BIRTHDAY>
            <CITY>New York</CITY>
            <COUNTRY>US</COUNTRY>
         </PROPERTIES>
      </p>
      <p>
         <PROPERTIES>
            <ID>482908c6-2437-406d-a421-c7d2a103aba7</ID>
            <BIRTHDAY>10.10.1980</BIRTHDAY>
            <CITY>New York</CITY>
            <COUNTRY>US</COUNTRY>
         </PROPERTIES>
      </p>
   </body>
</html>

Как вы можете видеть из примера xml, идентификаторы узлов PERSON одинаковы, чтобы решить эту проблему, я решил использовать генератор случайных uuid для предоставления разных идентификаторов всем узлам лиц, поэтому их можно было бы идентифицировать однозначно.

Мое другое намерение - создать еще один шаблон для различных свойств узла PERSON и связать эти свойства с одним и тем же уникальным идентификатором.

Вопрос в том, существует ли какой-либо способ в XSLT 3.0 (или, если в XSLT 2.0, но приоритет 3.0,) прочитать эти случайные uuid перед их отображением (или я не знаю, как он обрабатывается) и использовать то же самое. значения в разных местах относительно рекурсивного сопоставления?

РЕДАКТИРОВАТЬ: Я исправил проблему, создав еще одно преобразование XSLT, которое просто изменяет значения со случайными UUID, а затем во втором преобразовании я копирую значения. Что, если это возможно в одном единственном преобразовании с XSLT 3.0 в режиме потоковой передачи? или же ? или что-то другое? Я понимаю ваш ответ @ Томалак, но я просто хочу знать, существует ли какой-либо другой способ решить эту проблему?

Ответы [ 2 ]

0 голосов
/ 15 мая 2018

Реальная проблема в этих примерах - побочные эффекты.Функция util:randomUUID() не является чистой функцией, потому что она каждый раз возвращает другое значение.Вызовы таких функций очень зависят от реализации, используете ли вы XSLT 1.0, 2.0 или 3.0.

XSLT 3.0 предоставляет вам некоторые дополнительные инструменты для решения этой проблемы.Есть fn:random-number-generator(), который позволяет вам генерировать случайные числа в чисто функциональном подходе.Также есть аннотации к пользовательским функциям (cache=yes/no, new-each-time=yes/no/maybe), которые позволяют указывать процессору, как он должен обрабатывать повторяющиеся вызовы одной и той же функции.Но остается верным, что семантика языка нечеткая по краям, когда вы начинаете вызывать внешние методы, которые имеют побочные эффекты.

0 голосов
/ 15 мая 2018

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

<xsl:variable name="idrefs">
  <xsl:for-each select="//PERSON">
      <PERSON newid="id_{position()}">
          <ID>{generate-id(ID)}</ID>
      </PERSON>
  </xsl:for-each>
</xsl:variable>

(я использую position() здесь для генерации нового идентификатора просто для демонстрации)

Тогда, если вы определите ключ как этот ...

<xsl:key name="idrefs" match="PERSON" use="ID" />

Вы можете получить новый идентификатор следующим образом (при условии, что вы находитесь на старом узле идентификатора)

<xsl:value-of select="key('idrefs', generate-id(), $idrefs)/@newid"/>

Попробуйте это XSLT

<xsl:stylesheet
  version="3.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
  xmlns:util="java:java.util.UUID"
  expand-text="yes">
  <xsl:strip-space elements="PERSONAE"/>

  <xsl:variable name="idrefs">
      <xsl:for-each select="//PERSON">
          <PERSON newid="id_{position()}">
              <ID>{generate-id(ID)}</ID>
          </PERSON>
      </xsl:for-each>
  </xsl:variable>

  <xsl:key name="idrefs" match="PERSON" use="ID" />

  <xsl:template match="/">
    <xsl:apply-templates/>
  </xsl:template>

  <xsl:template match="PERSONAE">
    <html>
      <head>
        <title>The Cast of {@PLAY}</title>
      </head>
      <body>
        <xsl:apply-templates/>
        <xsl:call-template name="birthdayTemplate"/>
      </body>
    </html>
  </xsl:template>

  <xsl:template match="TITLE">
    <h1>{.}</h1>
  </xsl:template>

  <xsl:template match="PERSON/NAME[count(tokenize(., ',') = 2)]">
    <p><b>{substring-before(., ',')}</b>: {substring-after(., ',')}</p>
  </xsl:template>

  <xsl:template match="PERSON/NAME">
    <p>
      <b>{.}</b>
    </p>
  </xsl:template>

  <xsl:template match="PERSON/ID">
    <p>
      <xsl:value-of select="key('idrefs', generate-id(), $idrefs)/@newid"/>
    </p>
  </xsl:template>

  <xsl:template match="PERSON/PROPERTIES"></xsl:template>

  <xsl:template name="birthdayTemplate">
    <xsl:for-each select="PERSON/PROPERTIES">
      <PROPERTIES>
        <ID>{key('idrefs', generate-id(../ID), $idrefs)/@newid}</ID>
        <xsl:copy-of select="*" />
      </PROPERTIES>
    </xsl:for-each>
  </xsl:template>    
</xsl:stylesheet>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...