2011-01-24 3 views
8

Я хотел бы знать, как перемещать узлы на один уровень с помощью XSLT, если выполняются определенные условия. Чтобы привести пример, обратитесь к следующему источнику XML:XSLT: переместить узел на один уровень вверх

<Settings> 
    <String [...]> 
    <Boolean [...]/> 
    </String> 
</Settings> 

Это как есть исходный код XML. Чтобы быть ясным, имена узлов «Настройки», «String», «Boolean» являются специальными узлами, которые мы определили.

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

<Settings> 
    <String [...]></String> 
    <Boolean [...]/> 
</Settings> 

XSLT также должен работать с каждым узлом Струнного который имеет родственный булеву узел, независимо от положения в XML-дереве.

До сих пор я узнал, что вы должны сначала скопировать все ваши XML с помощью «правила идентичности», а затем применить некоторые специальные правила для желаемых преобразований:

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet version="2.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"   
    xmlns:fo="http://www.w3.org/1999/XSL/Format" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema" 
    xmlns:fn="http://www.w3.org/2005/xpath-functions"> 

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

    <!-- special rules ... --> 

</xsl:stylesheet> 

То, что я борюсь с это правило для перемещения всех «булевых» узлов, которые являются братьями и сестрами узлов «String» на один уровень вверх. Как мне это сделать?!?

+0

Хороший вопрос, +1. См. Мой ответ для варианта шаблона шаблона «переопределить идентификатор» - я предоставил несколько более точное переопределение. :) –

ответ

6

Моя интерпретация требований дает решение в виде

<?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" indent="yes"/> 

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

<xsl:template match="String"> 
    <xsl:copy> 
     <xsl:apply-templates select="child::node()[not(self::Boolean)]"/> 
    </xsl:copy> 
    <xsl:apply-templates select="Boolean"/> 
</xsl:template> 

</xsl:stylesheet> 
+1

Спасибо, Майкл. Ваш ответ, похоже, работает нормально.Только бы только предложить одно незначительное изменение: становится С этим изменением также скопируются атрибуты узлов String. Большое спасибо. – Jens

+0

+1 Правильный ответ. –

3

Попробуйте следующее:

<!-- copy all --> 
<xsl:template match="*"> 
    <xsl:copy> 
     <xsl:copy-of select="@*" /> 
     <xsl:apply-templates /> 
    </xsl:copy> 
</xsl:template> 

<!-- ignore booleans-inside-strings --> 
<xsl:template match="String/Boolean" /> 

<!-- place the booleans-inside-strings into the settings element --> 
<xsl:template match="Settings"> 
    <xsl:copy> 
     <xsl:copy-of select="//String/Boolean" /> 
     <xsl:apply-templates /> 
    </xsl:copy> 
</xsl:template> 
+1

Есть ли причина, почему не 'match =" @ * | node() "и' select = "@ * | node()" 'в вашем шаблоне« копировать все »? Просто любопытно ... – Filburt

+0

Спасибо за ваш ответ. Это хорошо работает для моего примера. Но он не будет работать всегда, поскольку он всегда копирует булевский узел в элемент настроек. Правило должно скопировать элемент Boolean на один уровень вверх. Подумайте Это должно преобразовать в: Jens

+0

Кроме того, почему начиная '//' в '// Строка/Boolean'? –

3

Это решение вполне аналогично @ Michae-Кей. Тем не менее, наиважнейшие правила идентичности является немного более точным - только String элементы, которые действительно имеют Boolean ребенка подбираются:

<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="String[Boolean]"> 
    <xsl:copy> 
    <xsl:apply-templates select="node()[not(self::Boolean)]|@*"/> 
    </xsl:copy> 
    <xsl:apply-templates select="Boolean"/> 
</xsl:template> 
</xsl:stylesheet> 

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

<Settings> 
    <String> 
     <Boolean /> 
    </String> 
    <String/> 
</Settings> 

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

<Settings> 
    <String/> 
    <Boolean/> 
    <String/> 
</Settings> 
+0

Можете ли вы также взглянуть на мой ответ? Я не могу найти ошибку там, где стоит спать. Я не забочусь о самом downvote, просто хочу посмотреть, пропустил ли я какую-то ошибку. – Flack

+0

@Flack: Я думаю, ваше решение в порядке. Вам нужно всего лишь применить шаблоны к атрибутам 'Setings', иначе они будут потеряны. Я подтвердил ваш ответ, но, пожалуйста, добавьте это рекомендуемое исправление. –

+0

Это было сознательное упущение из-за предоставленного образца ОП. Хотя я решил удалить свой ответ, поскольку есть два, которые лучше разработаны. Будьте в курсе. Ждал респаун доступных голосов. – Flack

Смежные вопросы