XSLT 2.0: скопируйте и измените ветвь, но сохраните исходный код в исходном состоянии

#xml #xslt #xslt-2.0

#xml #xslt #xslt-2.0

Вопрос:

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

Вот пример, который пытается достичь вышеупомянутого, изменяя содержимое всех элементов с атрибутом change=»true» в верхнем регистре.

Ввод XML

 <?xml version="1.0" encoding="UTF-8"?>
<root>
  <original>
    <element change="true">abc</element>
    <element change="false">def</element>
  </original>
  <copy/>
  <other>preserve this</other>
</root>
  

Таблица стилей XSLT

 <?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" exclude-result-prefixes="#all" version="2.0">
  <xsl:output method="xml" encoding="UTF-8"/>

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

  <xsl:template match="/root/copy">
    <copy>
      <xsl:copy-of select="/root/original/*"/>
    </copy>
  </xsl:template>

  <xsl:template match="/root/original/element[@change='true']/text()">
    <xsl:value-of select="upper-case(.)"/>   
  </xsl:template>

</xsl:stylesheet>
  

Текущий вывод

 <?xml version="1.0" encoding="UTF-8"?>
<root>
  <original>
    <element change="true">ABC</element>
    <element change="false">def</element>
  </original>
  <copy>
    <element change="true">abc</element>
    <element change="false">def</element>
  </copy>
  <other>preserve this</other>
</root>
  

Однако мой текущий XSLT в основном делает обратное тому, что я хочу, он изменяет только исходный элемент на верхний регистр, дублируя версию в нижнем регистре на ветку «копировать».

Желаемый результат

 <?xml version="1.0" encoding="UTF-8"?>
<root>
  <original>
    <element change="true">abc</element>
    <element change="false">def</element>
  </original>
  <copy>
    <element change="true">ABC</element>
    <element change="false">def</element>
  </copy>
  <other>preserve this</other>
</root>
  

Я провел несколько тестов с помощью xsl: call-template, но не смог создать ничего, близкого к тому, что я хочу.

Ответ №1:

Если вы хотите copy содержать измененный вывод, вы должны использовать его xsl:apply-templates в шаблоне, а не xsl:copy-of . И чтобы убедиться, что original он не изменился, вам понадобится отдельный шаблон, который делает это xsl:copy-of .

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

 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" exclude-result-prefixes="#all" version="2.0">
  <xsl:output method="xml" encoding="UTF-8" indent="yes"/>

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

  <xsl:template match="/root/copy">
    <copy>
      <xsl:apply-templates select="/root/original/*"/>
    </copy>
  </xsl:template>

  <xsl:template match="/root/original">
    <xsl:copy-of select="." />
  </xsl:template>

  <xsl:template match="/root/original/element[@change='true']/text()">
    <xsl:value-of select="upper-case(.)"/>   
  </xsl:template>

</xsl:stylesheet>
  

Ответ №2:

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

  <xsl:template match="/root/copy">
    <copy>
  <xsl:apply-templates select="/root/original/*"/>
</copy>
  </xsl:template>

  <xsl:template match="/root/original">
    <xsl:copy-of select="." />
  </xsl:template>

  <xsl:template match="/root/original/element[@change='true']/text()">
    <xsl:value-of select="upper-case(.)"/>   
  </xsl:template>
  

Комментарии:

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