xsl:copy-of
копирует все дочерние узлы, а дочерние узлы не оцениваются.
Таким образом, ваши шаблоны TShip и TItems даже никогда не оцениваются. <xsl:copy-of select="ship">
копирует все <ship>...</ship>
.
Эта модификация вашего шаблона продемонстрирует, что ваши шаблоны TShip и TItems не вызываются.
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="/order">
<xsl:copy>
<xsl:copy-of select="customer" />
<xsl:copy-of select="ship">
<xsl:call-template name="TShip" />
</xsl:copy-of>
<xsl:copy-of select="items">
<xsl:call-template name="TItems" />
</xsl:copy-of>
<xsl:copy-of select="price" />
</xsl:copy>
</xsl:template>
<xsl:template name="TShip">
<xsl:copy>
<test>TShip called</test>
<xsl:copy-of select="street" />
<xsl:copy-of select="city" />
<xsl:copy-of select="zipcode" />
<xsl:copy-of select="country" />
</xsl:copy>
</xsl:template>
<xsl:template name="TItems">
<xsl:for-each select="items">
<xsl:copy>
<test>TItems called</test>
<xsl:copy-of select="itemno" />
<xsl:copy-of select="quantity" />
</xsl:copy>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Обратите внимание, что вывод не содержит добавленные мной элементы <test>
.
Вместо этого нужно рекурсивное неявное копирование. Обычно xsl:copy
, xsl:copy-of
и xsl:for-each
являются признаком плохого дизайна шаблона xsl - очень мало проблем, которые xsl:template
и xsl:apply-template
с преобразованием идентичности не справляются лучше.
Вот как бы я это сделал:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output encoding="UTF-8" indent="yes" method="xml" />
<xsl:template match="order">
<xsl:copy>
<!-- copy all attributes; maybe you don't want this -->
<xsl:apply-templates select="@*" />
<!-- copy some elements in a specific order -->
<xsl:apply-templates select="customer" />
<xsl:apply-templates select="ship" />
<xsl:apply-templates select="items" />
<xsl:apply-templates select="price" />
<!-- now copy any other children that we haven't explicitly reordered; again, possibly this is not what you want -->
<xsl:apply-templates select="*[not(self::customer or self::ship or self::items or self::price)]"/>
</xsl:copy>
</xsl:template>
<xsl:template match="ship">
<xsl:copy>
<xsl:apply-templates select="@*" />
<xsl:apply-templates select="street" />
<xsl:apply-templates select="city" />
<xsl:apply-templates select="zipcode" />
<xsl:apply-templates select="country" />
<xsl:apply-templates select="*[not(self::street or self::city or self::zipcode or self::country)]"/>
</xsl:copy>
</xsl:template>
<xsl:template match="items">
<xsl:copy>
<xsl:apply-templates select="@*" />
<xsl:apply-templates select="itemno" />
<xsl:apply-templates select="quantity" />
<xsl:apply-templates select="*[not(self::itemno or self::quantity)]"/>
</xsl:copy>
</xsl:template>
<!-- this is the identity transform: it copies everything that isn't matched by a more specific template -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Обратите внимание, сколько меньше предположений делает этот шаблонный дизайн относительно структуры вашего исходного XML. Это также намного проще изменить: например, если вы хотите заставить замолчать или переименовать конкретный элемент, который может сам иметь детей, вы просто добавляете новый xsl:template
, который соответствует этому элементу, делаете все, что вам нужно, и xsl:apply-templates
на детей.
Вам следует узнать больше об этом шаблоне XSLT , потому что он очень универсален и делает создание шаблонов гораздо менее утомительным, а ваши шаблоны - гораздо менее хрупкими.