2013-05-22 1 views
0

Вчера я спросил a question о динамической загрузке внешних XML-данных из XSLT. На него ответили, но теперь у меня другая проблема. Если вы прочтете этот вопрос, вы увидите <include ref="/path/to/some.xml" /> на третьем уровне. Что, если уровень, на котором происходит <include>, меняется?В XSLT можно ли отслеживать путь и использовать его динамически?

Есть ли способ динамически выбирать извлечение узлов из этого XML на том же уровне, на котором они происходят в исходном файле?

EDIT: Чтобы было ясно: я говорю о «элемента пути» в XML (положение включаемого элемента в XML), а не путь к файлу.

merge.xslt:

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

    <xsl:output indent="yes" method="xml" encoding="utf-8" 
    omit-xml-declaration="yes" /> 

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

    <xsl:template match="include"> 
     <!-- the depth of the extraction path (fruit/*/*/*... etc) should 
      be based on the position of the matched <include> element --> 
     <xsl:apply-templates select="document(@ref)/fruit/*/*/*"/> 
    </xsl:template> 
</xsl:stylesheet> 

fruit.xml:

<fruit> 
    <local> 
    <apples> 
     <include ref="apples.xml" /> 
    </apples> 
    </local> 
    <exotic> 
    <bananas> 
     <deeperlevel> 
     <include ref="bananas.xml" /> 
     </deeperlevel> 
    </bananas> 
    <oranges> 
     <include ref="oranges.xml" /> 
    </oranges> 
    </exotic> 
</fruit> 

bananans.xml:

<fruit> 
    <exotic> 
    <bananas> 
     <deeperlevel> 
     <banana type="chiquita" color="yellow" /> 
     <banana type="generic" color="yellow" /> 
     </deeperlevel> 
    </bananas> 
    </exotic> 
</fruit> 

Результат:

<fruit> 
    <local> 
    <apples> 
     <apple type="jonagold" color="red"/><apple type="granny-smith" color="green"/> 
    </apples> 
    </local> 
    <exotic> 
    <bananas> 
     <deeperlevel> 
     <deeperlevel> <!-- I don't want the second <deeperlevel> here, instead 
          <bananas .../> should be extracted, right after the 
          first <deeperlevel> --> 
      <banana type="chiquita" color="yellow"/> 
      <banana type="generic" color="yellow"/> 
     </deeperlevel> 
     </deeperlevel> 
    </bananas> 
    <oranges> 
     <orange type="juice-orange" color="orange"/><orange type="red-orange" color="red"/> 
    </oranges> 
    </exotic> 
</fruit> 
+0

Вы говорите о количестве шагов в 'ref' значение атрибута (т.е.'/путь/к/some.xml') когда речь идет о уровнях? Или вы говорите о позиции элементов 'include'? В последнем случае предлагаемое решение должно работать, оно просто соответствует любому элементу 'include', независимо от уровня вложенности, в котором он встречается. Возможно, вы захотите опубликовать новый образец ввода XML и результат, который вы хотите объяснить нам, какие дополнительные требования твое лицо. –

+0

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

ответ

0

Я нашел решение моей проблемы. Это не очень приятно ИМХО, потому что это решение типа «eval», но оно работает. Я применил третье предложение в ответе this question к моей проблеме, динамическому расширению оценки XPath (dyn:evaluate()). К счастью, инструмент xsltproc из библиотеки libxslt (установленный через macports, версия 1.1.27) поддерживает его.

Я собираюсь оставить вопрос открытым какое-то время, возможно, у кого-то есть лучшее решение.

XSLT:

<xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:dyn="http://exslt.org/dynamic" 
    extension-element-prefixes="dyn"> 

    <xsl:output indent="yes" method="xml" encoding="utf-8" 
    omit-xml-declaration="yes" /> 

    <xsl:template match="@*|node()"> 
    <xsl:param name="depth" select="'/*'" /> 
    <xsl:copy> 
     <xsl:apply-templates select="@*|node()"> 
     <xsl:with-param name="depth" select="concat($depth, '/*')" /> 
     </xsl:apply-templates> 
    </xsl:copy> 
    </xsl:template> 

    <xsl:template match="include"> 
    <xsl:param name="depth" /> 
    <xsl:apply-templates select="dyn:evaluate(concat('document(@ref)', $depth))"> 
     <xsl:with-param name="depth" select="$depth" /> 
    </xsl:apply-templates> 
    </xsl:template> 

</xsl:stylesheet>