Как скопировать все дочерние узлы как есть в результирующее дерево? - PullRequest
1 голос
/ 25 марта 2012

ОБНОВЛЕНИЕ (спойлер): на этот вопрос дан ответ (см. Ответ Дэвида Карлайла ниже), и похоже, что это ошибка в реализации XSLT, включенная в некоторые версии в JRE (например, она работает в jdk, но не работает в jre 1.6.0_20 -b02 и вообще не работает в 1.6.0_31-b05). Я зарегистрировал ошибку для этого на сайте Oracle.

У меня почти нет и по функциональности сейчас работает. Но я не доволен некоторыми его частями, некоторые из них (я считаю) могут быть короче. Это вопрос ... Подробнее см. Ниже

Это пример ввода xml

<?xml version="1.0" encoding="UTF-8"?>
<t1>
    <t2 a1="v1">
        <ot1 a2="v2" />
        <ot2 a3="v3">
            <t3 a5="v4">
                <ot1 a2="v5" />
            </t3>
        </ot2>
    </t2>
</t1>

Это пример ожидаемого результата xml (см. Файл xslt ниже, чтобы понять, что-что)

<?xml version="1.0" encoding="UTF-8"?>
<t1>
    <t2 a1="v1">
        <gt2 a="ot2" b="gtv1">
            <gt1 a="ot1">v2</gt1>
        </gt2>
        <gt2 a="ot2" b="v3">
            <t3 a5="v4">
                <gt2 a="ot2" b="gtv1">
                    <gt1 a="ot1">v5</gt1>
                </gt2>
            </t3>
        </gt2>
    </t2>
</t1>

Это xslt, с которым я наконец-то получаю (но не слишком счастливый).

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:exslt="http://exslt.org/common" version="1.0"
    exclude-result-prefixes="exslt">
    <xsl:output method="xml" />

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

    <xsl:template match="ot1|ot2">
        <xsl:variable name="thisResult">
            <xsl:apply-templates select="." mode="impl" />
        </xsl:variable>
        <xsl:apply-templates select="exslt:node-set($thisResult)" />
    </xsl:template>

    <xsl:template match="ot1" mode="impl">
        <ot2 a3="gtv1">
            <gt1 a="ot1">
                <xsl:value-of select="@a2" />
            </gt1>
        </ot2>
    </xsl:template>

    <xsl:template match="ot2" mode="impl">
        <gt2 a="ot2" b="{@a3}">
            <xsl:for-each select="child::*">
                <xsl:element name="{name()}">
                    <xsl:copy-of select="@*|node()" />
                </xsl:element>
            </xsl:for-each>
        </gt2>
    </xsl:template>
</xsl:stylesheet>

Вопрос: как сделать это короче?

<xsl:for-each select="child::*">
    <xsl:element name="{name()}">
        <xsl:copy-of select="@*|node()" />
    </xsl:element>
</xsl:for-each>

Я попытался выполнить следующие действия, но в этом случае часть получающегося xml будет потеряна (в частности, атрибуты для элемента gt2 будут потеряны)

<xsl:copy-of select="node()"/>

также пробовал

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

безуспешно

Ответы [ 2 ]

3 голосов
/ 25 марта 2012

Мне нужно определить преобразование xslt, которое может выполнять так называемые "многопроходное преобразование".

Нет необходимости использовать многопроходную обработку здесь .

Это короткое и простое преобразование:

<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="ot1">
  <gt1 a="ot1"><xsl:value-of select="@a2"/></gt1>
  <xsl:apply-templates/>
 </xsl:template>

 <xsl:template match="ot2">
  <gt2 a="ot2" b="{@a3}"/>
  <xsl:apply-templates/>
 </xsl:template>
</xsl:stylesheet>

при применении к предоставленному документу XML :

<t1>
    <t2 a1="v1">
        <ot1 a2="v2" />
        <ot2 a3="v3">
            <t3 a5="v4">
                <ot1 a2="v5" />
            </t3>
        </ot2>
    </t2>
</t1>

дает желаемый, правильный результат :

<t1>
   <t2 a1="v1">
      <gt1 a="ot1">v2</gt1>
      <gt2 a="ot2" b="v3"/>
      <t3 a5="v4">
         <gt1 a="ot1">v5</gt1>
      </t3>
   </t2>
</t1>

ОБНОВЛЕНИЕ : ОП обновил вопрос тем, что, по его мнению, требует многопроходной обработки - это все еще не так.

Вот краткое и простое решение нового вопроса, снова за один проход :

<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="ot1">
  <gt2 a="ot2" b="gtv{substring-after(name(), 'ot')}">
    <gt1 a="ot1"><xsl:value-of select="@a2"/></gt1>
  </gt2>
  <xsl:apply-templates/>
 </xsl:template>

 <xsl:template match="ot2">
  <gt2 a="ot2" b="{@a3}"/>
  <xsl:apply-templates/>
 </xsl:template>
</xsl:stylesheet>

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

<t1>
    <t2 a1="v1">
        <ot1 a2="v2" />
        <ot2 a3="v3">
            <t3 a5="v4">
                <ot1 a2="v5" />
            </t3>
        </ot2>
    </t2>
</t1>

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

<t1>
   <t2 a1="v1">
      <gt2 a="ot2" b="gtv1">
         <gt1 a="ot1">v2</gt1>
      </gt2>
      <gt2 a="ot2" b="v3"/>
      <t3 a5="v4">
         <gt2 a="ot2" b="gtv1">
            <gt1 a="ot1">v5</gt1>
         </gt2>
      </t3>
   </t2>
</t1>

UPDATE2 : Поскольку ОП просит рефакторинга своего текущего кода, и, в частности, ему нужно лучше выразить этот отрывок:

<xsl:for-each select="child::*">
  <xsl:element name="{name()}">
      <xsl:copy-of select="@*|node()" />
  </xsl:element>
</xsl:for-each>

вот один очевидный рефакторинг - просто замените вышеприведенное на :

<xsl:apply-templates/>

После этой модификации полный код становится :

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:exslt="http://exslt.org/common" version="1.0"
        exclude-result-prefixes="exslt">
        <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="ot1|ot2">
            <xsl:variable name="thisResult">
                <xsl:apply-templates select="." mode="impl" />
            </xsl:variable>
            <xsl:apply-templates select=
            "exslt:node-set($thisResult)" />
        </xsl:template>

        <xsl:template match="ot1" mode="impl">
            <ot2 a3="gtv1">
                <gt1 a="ot1">
                    <xsl:value-of select="@a2" />
                </gt1>
            </ot2>
        </xsl:template>

        <xsl:template match="ot2" mode="impl">
            <gt2 a="ot2" b="{@a3}">
                <xsl:apply-templates/>
            </gt2>
        </xsl:template>
</xsl:stylesheet>

и при применении к последнему предоставленному исходному XML-документу :

<t1>
    <t2 a1="v1">
        <ot1 a2="v2" />
        <ot2 a3="v3">
            <t3 a5="v4">
                <ot1 a2="v5" />
            </t3>
        </ot2>
    </t2>
</t1>

желаемый результат получен :

<t1>
   <t2 a1="v1">
      <gt2 a="ot2" b="gtv1">
         <gt1 a="ot1">v2</gt1>
      </gt2>
      <gt2 a="ot2" b="v3">
         <t3 a5="v4">
            <gt2 a="ot2" b="gtv1">
               <gt1 a="ot1">v5</gt1>
            </gt2>
         </t3>
      </gt2>
   </t2>
</t1>
2 голосов
/ 25 марта 2012

Димитр показал альтернативную стратегию, но, чтобы ответить на вопрос в вашей первоначальной публикации, xsl: for-each (кроме некоторых эффектов пространства имен, которые здесь не отображаются) эквивалентен одному

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

и я получаю идентичный вывод, если заменить xsl: for-each на это.

Предлагаемая замена

<xsl:copy-of select="node()"/>

почти такая же, но выбирает пробельные узлы, используемые дляотступ для источника, поэтому выходные данные отличаются пробелами.

Вы говорите

(в частности, атрибуты для элемента gt3 будут потеряны)

, ночто изменение кодировки не изменит атрибутов, и в примере ввода или вывода отсутствует элемент gt3?

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