использование XSL для замены узлов XML новыми узлами - PullRequest
8 голосов
/ 01 июня 2010

Мне нужно решение XSL для замены узлов XML новыми узлами.

Скажем, у меня есть следующая существующая структура XML:

<root>
    <criteria>
        <criterion>AAA</criterion>
    </criteria>
</root>

И я хочу заменить один узел критерия следующим:

<criterion>BBB</criterion>
<criterion>CCC</criterion>
<criterion>DDD</criterion>

Так что конечный результат XML будет:

<root>
    <criteria>
        <criterion>BBB</criterion>
        <criterion>CCC</criterion>
        <criterion>DDD</criterion>
    </criteria>
</root>

Я попытался использовать substring-before и substring-after, чтобы просто скопировать первую половину структуры, а затем просто скопировать вторую половину (чтобы заполнить мои новые узлы между двумя половинами), но кажется, функции подстроки распознают только текст между тегами узлов, а не сами теги, как я хочу. :(: (

Есть ли другие решения?

Ответы [ 3 ]

23 голосов
/ 01 июня 2010

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


Пример:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
>
    <xsl:output method="xml" indent="yes"/>

    <!-- This is an identity template - it copies everything
         that doesn't match another template -->
    <xsl:template match="@* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
    </xsl:template>

  <!-- This is the "other template". It says to use your BBB-DDD elements
       instead of the AAA element -->
  <xsl:template match="criterion[.='AAA']">
    <xsl:element name="criterion">
      <xsl:text>BBB</xsl:text>
    </xsl:element>
    <xsl:element name="criterion">
      <xsl:text>CCC</xsl:text>
    </xsl:element>
    <xsl:element name="criterion">
      <xsl:text>DDD</xsl:text>
    </xsl:element>
  </xsl:template>
</xsl:stylesheet>

Соответствие шаблона @* | node() соответствует любому атрибуту или любому другому виду узла. Хитрость в том, что у шаблонных совпадений есть приоритеты. Вы можете думать о правиле как о «более конкретном совпадении». Что-нибудь будет более конкретным, чем "любой атрибут или другой узел". Это делает «идентичность» совпадающей с очень низким приоритетом.

Когда соответствует , он просто копирует любые узлы, которые он находит внутри соответствующего атрибута или узла.

Любые другие ваши шаблоны будут иметь более высокий приоритет. Независимо от того, что они соответствуют, это код внутри более конкретного шаблона, который будет иметь эффект. Например, если вы просто удалили все внутри шаблона criterion[.='AAA'], вы обнаружите, что вы точно скопировали свои данные, кроме элемента «AAA».

6 голосов
/ 02 июня 2010

Вот одно правильное решение, которое, вероятно, является одним из самых коротких :

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

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

 <xsl:template match="criterion[. = 'AAA']">
  <criterion>BBB</criterion>
  <criterion>CCC</criterion>
  <criterion>DDD</criterion> </xsl:template>
</xsl:stylesheet>

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

<root>
    <criteria>
        <criterion>BBB</criterion>
        <criterion>CCC</criterion>
        <criterion>DDD</criterion>
    </criteria>
</root>

Примечание :

  1. Использование шаблона идентификации .

  2. Как шаблон идентификации переопределяется конкретным шаблоном - только для элемента criterion, строковое значение которого равно 'AAA'.

0 голосов
/ 01 июня 2010

По общему правилу "больше, чем один путь к коже кошки"

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml"/>
    <xsl:template match="/">
        <xsl:apply-templates />
    </xsl:template>
    <!--  
        when you capture a node with the text 'AAA'
            emit the BBB, CCC, DDD nodes
     -->
    <xsl:template match="criterion[text() = 'AAA']">
        <xsl:element name="criterion">
            <xsl:text>BBB</xsl:text>
        </xsl:element>
        <xsl:element name="criterion">
            <xsl:text>CCC</xsl:text>
        </xsl:element>
        <xsl:element name="criterion">
            <xsl:text>DDD</xsl:text>
        </xsl:element>
    </xsl:template>
    <!--  identity template  -->
    <xsl:template match="@*|node()">
      <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
      </xsl:copy>
    </xsl:template>
</xsl:stylesheet>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...