2016-08-16 2 views
0

У меня есть следующая проблема в xslt. Учитывая пример XML:Как выводить в xslt под произвольный путь?

<?xml version="1.0" encoding="UTF-8"?> 
<catalog> 
    <cd>A</cd> 
    <dvd id='A'>B</dvd> 
    <dvd id='B'>C</dvd> 
</catalog> 

Я хочу теги вывода cd в CD и dvd[@id="B"] в CD, а все остальные dvd как DVD. Простое преобразование с трех шаблонов (CD, DVD и двд с ид = B) отлично работает, но выдает что-то вроде этого:

<CD>A</CD> 
<DVD>B</DVD> 
<CD>C</CD> 

Проблема заключается в том, что схема проверки ожидает DVD с, чтобы следовать CD с, так CD -> DVD-> CD неправильный. Я придумал эту схему для решения этого:

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 

    <xsl:template match="catalog"> 
    <xsl:apply-templates/> 
    </xsl:template> 

    <xsl:template match="cd"> 
    <CD> 
     <xsl:value-of select="."/> 
    </CD> 
    <xsl:if test="../dvd[@id='B']"> 
     <xsl:apply-templates select="../dvd[@id='B']" mode="keep"/> 
    </xsl:if> 
    </xsl:template> 

    <xsl:template match="dvd"> 
    <DVD> 
     <xsl:value-of select="."/> 
    </DVD> 
    </xsl:template> 

    <xsl:template match="dvd[@id='B']" mode="keep"> 
    <CD> 
     <xsl:value-of select="."/> 
    </CD> 
    </xsl:template> 

    <xsl:template match="dvd[@id='B']"> 
    <!-- do nothing --> 
    </xsl:template> 
</xsl:stylesheet> 

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

Не могли бы вы предложить способ, которым dvd[@id="B"] будет иметь только один шаблон, который будет выводить <CD> под дорогой, например, «после последнего компакт-диска на этом уровне»?

ответ

0

Как насчет:

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:template match="catalog"> 
    <xsl:apply-templates select="cd | dvd[@id='B']"/> 
    <xsl:apply-templates select="dvd[not(@id='B')]"/> 
</xsl:template> 

<xsl:template match="cd"> 
    <CD> 
     <xsl:value-of select="."/> 
    </CD> 
</xsl:template> 

<xsl:template match="dvd"> 
    <DVD> 
     <xsl:value-of select="."/> 
    </DVD> 
</xsl:template> 

<xsl:template match="dvd[@id='B']"> 
    <CD> 
     <xsl:value-of select="."/> 
    </CD> 
</xsl:template> 

</xsl:stylesheet> 

Или, если вы предпочитаете:

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:template match="catalog"> 
    <xsl:apply-templates select="cd | dvd[@id='B']"/> 
    <xsl:apply-templates select="dvd[not(@id='B')]"/> 
</xsl:template> 

<xsl:template match="cd | dvd[@id='B']"> 
    <CD> 
     <xsl:value-of select="."/> 
    </CD> 
</xsl:template> 

<xsl:template match="dvd"> 
    <DVD> 
     <xsl:value-of select="."/> 
    </DVD> 
</xsl:template> 

</xsl:stylesheet> 

Обратите внимание, что результат не является корректным XML, так как он не имеет ни одного корневого элемента.

+0

Doh ... Большое спасибо :) Это такой вид мышления xslt, который трудно понять самостоятельно, но как только вы там, он имеет прекрасный смысл и поможет мне решить еще много проблем в будущем. – backflip

+0

Btw с точки зрения неформации, примеры были просто упрощением гораздо более сложной реальной проблемы. – backflip

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