2015-12-31 2 views
1

Я хотел бы заменить элемент в XML (большой) с несколькими элементами, как показано ниже:XSLT-замена одного элемента с несколькими элементами

Оригинальный XML:

<root> 
    <cr> 
    <id>1</id> 
    <release>A</release> 
    </cr> 
    <cr> 
    <id>2</id> 
    <release>B</release> 
    </cr> 
</root> 

Я хотел бы выход быть:

<root> 
    <cr> 
    <id>1</id> 
    <release>Aa</release> 
    <release>Ab</release> 
    <release>Ad</release> 
    </cr> 
    <cr> 
    <id>2</id> 
    <release>Bd</release> 
    <release>Be</release> 
    </cr> 
</root> 

принцип заключается в том, когда есть // выпустить [текст() = 'А'], заменить элемент с тремя выше, когда есть // выпустить [текст() = 'в'], замените элемент на два выше и т. д. Если текст release() - это «C» или «D» или другие значения, они остаются теми же значениями.

Моя попытка:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 

<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/> 
<xsl:strip-space elements="*"/> 

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

<xsl:template match="//cr/release/text()"> 
    <xsl:if test=".='A'"> 
     <xsl:value-of select="Aa"/> 
    </xsl:if> 
</xsl:template> 
</xsl:stylesheet> 

Он работает с одним -> одной замены, но как это сделать множественный? Большое спасибо,

+0

Можете ли вы показать вам текущую попытку, пожалуйста? Кроме того, можете ли вы уточнить, как именно много элементов вы хотите показать. Например, для «B» вы говорите, что хотите «Bd» и «Be» и т. Д., Но почему бы не «Bc»? Вы хотите пройти весь путь до «Bz»? Спасибо? –

+0

Является ли число повторений фиксированным и известным при написании XSLT? В этом случае вы можете использовать три режима для трех повторений и три 'apply-templates' для трех повторений. Я еще не понял, что определяет ценности новых элементов. –

+0

Спасибо, отредактировал его. – dellair

ответ

2

Вот полностью общее и короткое решение XSLT 1.0. Он использует отображение XML-файл, который указывает на замену для каждого хотел выпустить: (. Пожалуйста, найдите в конце этого ответа на конечном счете, родовое и короткое решение, написанное в XSLT 2.0)

<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:variable name="vMap" select="document('mapping.xml')/*/*"/> 

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

    <xsl:template match="release[. = document('mapping.xml')/*/release/@old]"> 
    <xsl:copy-of select="$vMap[@old = current()]/*"/> 
    </xsl:template> 
</xsl:stylesheet> 

Если файл mapping.xml находится в том же каталоге, что и преобразования (файл .xsl), и:

<map> 
    <release old="A"> 
     <release>Aa</release> 
     <release>Ab</release> 
     <release>Ad</release> 
    </release> 
    <release old="B"> 
     <release>Ba</release> 
     <release>Bb</release> 
     <release>Bd</release> 
    </release> 
</map> 

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

<root> 
    <cr> 
    <id>1</id> 
    <release>A</release> 
    </cr> 
    <cr> 
    <id>2</id> 
    <release>B</release> 
    </cr> 
    <cr> 
    <id>3</id> 
    <release>C</release> 
    </cr> 
    <cr> 
    <id>4</id> 
    <release>D</release> 
    </cr> 
</root> 

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

<root> 
    <cr> 
     <id>1</id> 
     <release>Aa</release> 
     <release>Ab</release> 
     <release>Ad</release> 
    </cr> 
    <cr> 
     <id>2</id> 
     <release>Ba</release> 
     <release>Bb</release> 
     <release>Bd</release> 
    </cr> 
    <cr> 
     <id>3</id> 
     <release>C</release> 
    </cr> 
    <cr> 
     <id>4</id> 
     <release>D</release> 
    </cr> 
</root> 

Примечание: Многие, иначе названные элементы могут быть заменены такое же преобразование.

Если у нас есть этот файл отображения:

<map> 
    <release old="A"> 
     <release>Aa</release> 
     <release>Ab</release> 
     <release>Ad</release> 
    </release> 
    <release old="B"> 
     <release>Ba</release> 
     <release>Bb</release> 
     <release>Bd</release> 
    </release> 
    <history old="p"> 
     <history>Pp</history> 
     <history>Pq</history> 
     <history>Pr</history> 
    </history> 
</map> 

и этот исходный XML-документ:

<root> 
    <cr> 
    <id>1</id> 
    <history>p</history> 
    <release>A</release> 
    </cr> 
    <cr> 
    <id>2</id> 
    <history>q</history> 
    <release>B</release> 
    </cr> 
    <cr> 
    <id>3</id> 
    <history>r</history> 
    <release>C</release> 
    </cr> 
    <cr> 
    <id>4</id> 
    <history>t</history> 
    <release>D</release> 
    </cr> 
</root> 

то это преобразование:

<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:variable name="vMap" select="document('mapping.xml')/*/*"/> 

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

    <xsl:template match="release[. = document('mapping.xml')/*/release/@old]"> 
    <xsl:copy-of select="$vMap[@old = current()]/*"/> 
    </xsl:template> 
    <xsl:template match="history[. = document('mapping.xml')/*/history/@old]"> 
    <xsl:copy-of select="$vMap[@old = current()]/*"/> 
    </xsl:template> 
</xsl:stylesheet> 

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

<root> 
    <cr> 
     <id>1</id> 
     <history>Pp</history> 
     <history>Pq</history> 
     <history>Pr</history> 
     <release>Aa</release> 
     <release>Ab</release> 
     <release>Ad</release> 
    </cr> 
    <cr> 
     <id>2</id> 
     <history>q</history> 
     <release>Ba</release> 
     <release>Bb</release> 
     <release>Bd</release> 
    </cr> 
    <cr> 
     <id>3</id> 
     <history>r</history> 
     <release>C</release> 
    </cr> 
    <cr> 
     <id>4</id> 
     <history>t</history> 
     <release>D</release> 
    </cr> 
</root> 

Наконец: еще короче и более общими преобразование можно записать в XSLT 2.0:

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

<xsl:variable name="vMap" select="document('mapping.xml')/*/*"/> 

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

    <xsl:template match= 
    "*[. = $vMap[name() eq name(current())]/@old]"> 
    <xsl:copy-of select="$vMap[name() eq name(current()) and @old eq current()]/*"/> 
    </xsl:template> 
</xsl:stylesheet> 

Обратите внимание: нет имя элемента не зашито в этом преобразовании!

Еще большее преимущество: Мы можем изменить преобразование, чтобы мы могли передавать URI документа отображения в качестве глобального параметра при вызове преобразования - таким образом, мы можем иметь одно общее генерирующее преобразование, которое работает с любым , неизвестное заранее отображение.

только эти необходимые изменения:

<xsl:param name="pmapUrl" select="'file:///c:/temp/mapping.xml'"/> 

<xsl:variable name="vMap" select="document($pmapUrl)/*/*"/> 

Полное преобразование (глобальный параметр pmapUrl может и обычно будет указано динамически вызвавшего трансформации):

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

<xsl:param name="pmapUrl" select="'file:///c:/temp/mapping.xml'"/> 

<xsl:variable name="vMap" select="document($pmapUrl)/*/*"/> 

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

    <xsl:template match= 
    "*[for $name in name() 
     return 
      . = $vMap[name() eq $name]/@old]"> 
    <xsl:copy-of select="$vMap[@old = current()]/*"/> 
    </xsl:template> 
</xsl:stylesheet> 
+0

Решение отличное. – dellair

+0

dellair: Добро пожаловать. –

2

Попробуй так:

XSLT 1,0

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

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

<xsl:template match="release[.='A']"> 
    <release>Aa</release> 
    <release>Ab</release> 
    <release>Ad</release> 
</xsl:template> 

<xsl:template match="release[.='B']"> 
    <release>Bd</release> 
    <release>Be</release> 
</xsl:template> 

</xsl:stylesheet> 

Тестовый вход

<root> 
    <cr> 
    <id>1</id> 
    <release>A</release> 
    </cr> 
    <cr> 
    <id>2</id> 
    <release>B</release> 
    </cr> 
    <cr> 
    <id>3</id> 
    <release>C</release> 
    </cr> 
</root> 

Результат

<?xml version="1.0" encoding="UTF-8"?> 
<root> 
    <cr> 
     <id>1</id> 
     <release>Aa</release> 
     <release>Ab</release> 
     <release>Ad</release> 
    </cr> 
    <cr> 
     <id>2</id> 
     <release>Bd</release> 
     <release>Be</release> 
    </cr> 
    <cr> 
     <id>3</id> 
     <release>C</release> 
    </cr> 
</root> 
+1

Спасибо, Этот вид соответствует моему требованию, жестко закодированный xslt не очень нужен. – dellair

+0

@dellair Я не вижу, какую выгоду вы получаете при жестком кодировании отображения во внешнем документе. Даже если бы я думал, что это желательно, я бы отформатировал этот документ как XSLT и сохранил сопоставления там * в качестве шаблонов * - для включения/импорта в основную таблицу стилей. –

+0

@ michael.hor257k: Одно очевидное преимущество заключается в том, что URL-адрес документа сопоставления может быть передан как глобальный параметр при вызове преобразования - таким образом, мы можем иметь одно универсальное преобразование, которое работает с любым неизвестным заранее отображением. –

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