Совпадение условно с текущим значением узла
Вопрос
Учитывая следующий XML-файл:
<current>
<login_name>jd</login_name>
</current>
<people>
<person>
<first>John</first>
<last>Doe</last>
<login_name>jd</login_name>
</preson>
<person>
<first>Pierre</first>
<last>Spring</last>
<login_name>ps</login_name>
</preson>
</people>
Как я могу получить "John Doe" из текущего сопоставления / login?
Я попробовал следующее:
<xsl:template match="current/login_name">
<xsl:value-of select="../people/first[login_name = .]"/>
<xsl:text> </xsl:text>
<xsl:value-of select="../people/last[login_name = .]"/>
</xsl:template>
Решение
Я бы определил ключ для индексации людей:
<xsl:key name="people" match="person" use="login_name" />
Использование ключа здесь просто сохраняет код чистым, но вы также можете счесть это полезным для повышения эффективности, если вам часто приходится извлекать <person>
элементы, основанные на их <login_name>
ребенок.
У меня был бы шаблон, который возвращал бы форматированное имя заданного <person>
:
<xsl:template match="person" mode="name">
<xsl:value-of select="concat(first, ' ', last)" />
</xsl:template>
И тогда я бы сделал:
<xsl:template match="current/login_name">
<xsl:apply-templates select="key('people', .)" mode="name" />
</xsl:template>
Другие советы
Ты хочешь current()
функция
<xsl:template match="current/login_name">
<xsl:value-of select="../../people/person[login_name = current()]/first"/>
<xsl:text> </xsl:text>
<xsl:value-of select="../../people/person[login_name = current()]/last"/>
</xsl:template>
или немного чище:
<xsl:template match="current/login_name">
<xsl:for-each select="../../people/person[login_name = current()]">
<xsl:value-of select="first"/>
<xsl:text> </xsl:text>
<xsl:value-of select="last"/>
</xsl:for-each>
</xsl:template>
Если вам нужен доступ к нескольким пользователям, то У Дженит <xsl:key />
подход это идеально.
Вот мой альтернативный взгляд на это:
<xsl:template match="current/login_name">
<xsl:variable name="person" select="//people/person[login_name = .]" />
<xsl:value-of select="concat($person/first, ' ', $person/last)" />
</xsl:template>
Мы присваиваем выбранному <person>
узла к переменной, затем мы используем concat()
функция для вывода имени / фамилии.
В вашем примере XML также есть ошибка.Тот Самый <person>
узел неправильно заканчивается на </preson>
(опечатка)
Лучшее решение могло бы быть дано, если бы мы знали общую структуру XML-документа (с корневыми узлами и т.д.).
Я думаю, что на самом деле он хотел замены в совпадении для "текущего" узла, а не совпадения в узле person:
<xsl:variable name="login" select="//current/login_name/text()"/>
<xsl:template match="current/login_name">
<xsl:value-of select='concat(../../people/person[login_name=$login]/first," ", ../../people/person[login_name=$login]/last)'/>
</xsl:template>
Просто чтобы добавить свои мысли в общую копилку
<xsl:template match="login_name[parent::current]">
<xsl:variable name="login" select="text()"/>
<xsl:value-of select='concat(ancestor::people/child::person[login_name=$login]/child::first/text()," ",ancestor::people/child::person[login_name=$login]/child::last/text())'/>
</xsl:template>
Я всегда предпочитаю использовать оси явно в моем XPath, более подробном, но понятном IMHO.
В зависимости от того, как выглядят остальные XML-документы (предполагая, что это всего лишь фрагмент), вам может потребоваться ограничить ссылку на "ancestor:: people", например, используя "ancestor:: people [1]" для ограничения первого предка people.