Да, внесенные вами изменения действительно важны. : -)
Что делает цикл for-each, это выбирает каждый элемент <em:VanityUrl>
, соответствующий вашему выражению XPath, делает этот элемент контекстным узлом для того, что находится внутри for-each (называемый template , даже если это не <xsl:template>
), а затем создать экземпляр этого внутреннего шаблона с новым узлом контекста.
Когда вы продолжали использовать «$ doc / ...» внутри цикла for-each, вы отбрасывали узел контекста, поэтому for-each не имел никакого эффекта (за исключением повторения n раз).
Ваши операторы <xsl:if test="$doc/...">
оценивали наличие такого узла во всем документе вместо элемента контекста <em:VanityUrl>
.
Оператор <xsl:value-of>
обращает внимание только на первый узел в выбранном наборе узлов, поэтому вы всегда получали значение из first <em:VanityUrl>
, независимо от узла контекста.
Когда вы начали выбирать и тестировать относительно узла контекста:
<xsl:if test="em:old">
все стало лучше. : -)
Вы попросили внести ценный вклад. По стилистическим соображениям вы можете заменить свои <xsl:if>
тесты на <xsl:apply-templates>
. (Во-первых, @Dimitre Novatchev порадует вас. :-) Так что
<xsl:if test="$doc/tcm:Component/tcm:Data/tcm:Content/em:MappingCollection/em:VanityUrl/em:comments">
<xsl:comment>
<xsl:value-of select="$doc/tcm:Component/tcm:Data/tcm:Content/em:MappingCollection/em:VanityUrl/em:comments"/>
</xsl:comment>
</xsl:if>
становится
<xsl:apply-templates select="$doc/tcm:Component/tcm:Data/tcm:Content/em:MappingCollection/em:VanityUrl/em:comments" />
и тогда вам нужен отдельный шаблон для них:
<xsl:template match="em:comments">
<xsl:comment>
<xsl:value-of select="."/>
</xsl:comment>
</xsl:template>
Есть несколько преимуществ для этого. Самое главное, что вам не нужно дублировать это длинное выражение XPath, которое было подвержено ошибкам, если выражение когда-либо нужно было изменить. Если нет элементов em: comment, apply-templates ничего не будут делать, поэтому не будут выдавать комментарий.
Он также модулирует вашу таблицу стилей, так что вы можете изменить способ отображения em: комментариев отдельно от места их возникновения. Это может не иметь большого значения в простых XML-документах, где em: comments встречается только в одном месте, но именно этот стиль наилучшим образом использует возможности XSLT. Также обратите внимание, что эта измененная версия будет выводить несколько комментариев, если есть несколько em: комментариев, которых нет в вашей версии. Опять же, у вас, вероятно, нет множителей на входе, поэтому это не имеет значения.
Аналогично для выходных атрибутов:
<xsl:if test="em:old">
<xsl:attribute name="old">
<xsl:value-of select="em:old"/>
</xsl:attribute>
</xsl:if>
может стать
<xsl:apply-templates select="em:old[1]" />
с отдельным шаблоном
<xsl:template match="em:old">
<xsl:attribute name="old">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:template>
Обратите внимание на [1]
, в котором избегается попытка вывести несколько атрибутов old="..."
для одного и того же элемента, если входные данные em: VanityUrl имеют несколько элементов em: old. Это может привести к ошибке в вашей таблице стилей. Но, может быть, вы хотите вызвать ошибку в этом случае. Если это так, вы, вероятно, уже проверяете свой входной XML.
На самом деле вы можете обобщить apply-шаблоны и шаблон здесь, чтобы применить их ко всем трем атрибутам:
<xsl:apply-templates select="em:old[1] | em:new[1] | em:dateAdded[1]" />
Опять же, если какой-либо из этих элементов отсутствует, для них ничего не будет сделано (пустой атрибут не будет создан). Шаблон:
<xsl:template match="em:old | em:new | em:dateAdded">
<xsl:attribute name="{local-name()}">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:template>
local-name()
дает нам имя элемента без префикса пространства имен.
Обновление:
Еще один способ справиться с этим - использовать режим:
<xsl:apply-templates select="em:old[1] | em:new[1] | em:dateAdded[1]"
mode="make-attribute" />
<xsl:template match="em:*" mode="make-attribute">
<xsl:attribute name="{local-name()}">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:template>
Тогда ваш шаблон make-attribute можно использовать из любой точки мира, и шаблон соответствия не нужно обновлять, чтобы соответствовать каждому возможному элементу, из которого вы можете создать атрибут.
Единственное, что я хотел бы сказать, это то, что использование указанных выше пространств имен сбивает с толку ... оно не должно работать как есть. Например. Ваша таблица стилей использует этот URI пространства имен для таких элементов, как VanityURL:
"http://www.espire.com/tridion/schemas"
но второй входной документ использует этот URI пространства имен для этих элементов:
"uuid:922EEC29-2DE3-4BA1-A46A-A300CB8FA85F"
Неважно, что префиксы пространства имен отличаются ("em:" и default), но URI пространства имен должны совпадать. Я предполагаю, что URI пространства имен VanityURL должен был измениться, иначе ваша таблица стилей не будет работать ...
НТН!