Набор узлов xsl: не находить дочерние элементы по имени

Я новичок в xsl, поэтому, возможно, это очень простой вопрос. У меня есть файл xsl, в котором я хочу найти конкретное значение, определенное в параметре-объекте:

<xsl:param name="locales">
    <label name="testname"><locale name="de">german text</locale><locale name="en">english text</locale></label>
</xsl:param>

<xsl:template match="foo">
    <topLevelElement xmlns="http://foo.bar.org">
        <xsl:value-of select="ext:node-set($locales)/label[@name='testname']/locale[@name='en']"/>
    </topLevelElement>
</xsl:template>

Я ожидал получить значение 'english text', потому что я хочу найти в параметре localeslabel с именем testname. Там я хочу найти locale с именем en. Но это не работает. Когда я заменяю имя конкретных элементов (метка и языковой стандарт) звездочкой, это работает:

<xsl:param name="locales">
    <label name="testname"><locale name="de">german text</locale><locale name="en">english text</locale></label>
</xsl:param>

<xsl:template match="foo">
    <topLevelElement xmlns="http://foo.bar.org">
        <xsl:value-of select="ext:node-set($locales)/*[@name='testname']/*[@name='en']"/>
    </topLevelElement>
</xsl:template>

Кто-нибудь может сказать мне, почему я не могу найти ребенка по имени? Большое спасибо!

Редактировать: В коде не отображается пространство имен (я думаю, оно интерпретируется браузером). Без скобок в начале и в конце:

xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://foo.bar.org"xmlns:ext="http://exslt.org/common" version="1.0" xsl:output method="xml" version="1.0" encoding="UTF-8"/

Дайте угадаю: в вашем XSLT-файле определено пространство имен по умолчанию xmlns="...".

Tomalak 10.08.2018 15:49

Да. Я отредактировал свой вопрос. Так в чем проблема? У моей метки и локалей теперь есть другое пространство имен, так что я не могу их найти?

Markus 10.08.2018 15:58

Где функция замедления ext: node-set (...)?

Amrendra Kumar 10.08.2018 16:01
1
3
276
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Так что у тебя есть

<xsl:stylesheet
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns="http://foo.bar.org"
    xmlns:ext="http://exslt.org/common"
>

и это определяет пространство имен по умолчанию. Это означает, что каждый элемент XML, создаваемый вашей программой XSLT (который явно не создается с пространством имен) будет в этом пространстве имен. Это также относится к любому элементу, который вы не выводите.

А это означает, что вы больше не можете выбирать эти элементы с помощью «простого» XPath, потому что простой XPath предполагает, что элементы не находятся в пространстве имен.

ext:node-set($locales)/label[@name='testname']/locale[@name='en']

ищет элементы <label>, которые не находятся в пространстве имен, и элементы <locale>, которые не находятся в пространстве имен. И способ сослаться на пространство имен в XPath - использовать префикс.

Таким образом, вы можете дать этому пространству имен префикс только для внутренней обработки.

<xsl:stylesheet
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns="http://foo.bar.org"
    xmlns:foo="http://foo.bar.org"
    xmlns:ext="http://exslt.org/common"
>

Здесь пространство имен "http://foo.bar.org" объявлено как дефолт, но также имеет префикс foo. Теперь вы можете это сделать:

ext:node-set($locales)/foo:label[@name='testname']/foo:locale[@name='en']

И все заработает.


Лично я бы не стал использовать <xsl:param> для того, что вы делаете. Я бы создал дополнительный XML-документ без пространств имен, назвал бы его locales.xml, а затем сделал бы:

<!-- top-level -->
<xsl:variable name="locales" select="document('locales.xml')" />

<!-- ...later -->
<xsl:value-of select="$locales/*/label[@name='testname']/locale[@name='en']" />

Таким образом, не требуются ни вспомогательные пространства имен, ни ext:node-set(), а также повышается модульность.

Большое спасибо за всю вашу информацию! Это мне очень помогло. Я рассмотрю ваше предложение использовать дополнительный файл XML.

Markus 10.08.2018 16:15
Ответ принят как подходящий

Один из способов исправить это без изменения XPath - изменить

<xsl:param name="locales">
    <label name="testname"><locale name="de">german text</locale><locale name="en">english text</locale></label>
</xsl:param>

к

<xsl:param name="locales" xmlns="">
    <label name="testname"><locale name="de">german text</locale><locale name="en">english text</locale></label>
</xsl:param>

Благодарность! это простое решение, которое идеально подходит для меня!

Markus 10.08.2018 16:13

@Markus Обратите внимание и на нижнюю часть моего ответа. Для этого даже не нужны пространства имен и node-set().

Tomalak 10.08.2018 16:14

да спасибо большое томалак. Я подумаю над твоим решением. Но я новичок в xsl, поэтому для полного понимания вашего решения требуется некоторое время;) Но ваш ответ мне очень помогает.

Markus 10.08.2018 16:18

Другие вопросы по теме