XSLT 2.0 Ошибка Xpath "не элемент узла" - PullRequest
3 голосов
/ 22 декабря 2011

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

У меня есть xml, содержащий спецификации формата, такие как

<Format>
    <TagNr>92</TagNr>
    <Option>A</Option>
    <Format>//[N]15d</Format>
</Format>
<Format>
    <TagNr>92</TagNr>
    <Option>B</Option>
    <Format>//3!a/3!a/15d</Format>
</Format>

TagNr + - уникальная комбинация вэтот набор узлов.

Я определил ключ, чтобы упростить использование набора форматов:

<xsl:key name="xx" match="//Format/Format" use="concat(../TagNr, ../Option)"/>

Я действительно могу использовать этот ключ и получить правильное значение, но только в не специальных элементах;Я получаю сообщение об ошибке «Ошибка в выражении XPath 2.0 Не элемент узла» при использовании этого ключа в рамках for-каждой или других конструкций, подобных приведенной ниже.

Я пытаюсь добиться следующего: в других обработанных узлахесть строка опций, для которых я хочу получить формат для каждого символа.Например:

<Tag>
    <TagNr>92</TagNr>
    <Options>AB</Options>
</Tag>

Я пробовал много вариантов из нижеприведенного, но не повезло:

<xsl:variable name="TN"><xsl:value-of select="TagNr"/></xsl:variable>
<xsl:variable name="optList">
    <xsl:analyze-string select="./Options" regex="[A-Z]">
        <xsl:matching-substring>
            <xsl:variable name="TNO" select="concat($TN, .)"/>
            <opt>
                <tag><xsl:value-of select="$TNO"/></tag>
                <fmt><xsl:value-of select="key('xx', $TNO)"/></fmt>
            </opt>
        </xsl:matching-substring>
    </xsl:analyze-string>
</xsl:variable>

Разбиение на отдельные символы с помощью регулярных выражений проходит нормально и при получении (только)значение для opt / tag тоже подходит.Но когда я добавляю opt / fmt, я сталкиваюсь с упомянутым сообщением об ошибке для выражения Xpath select = "key ('xx', $ TNO)" .

Я попытался определить переменнуюна основе функции клавиш, как было предложено в другой теме на этом сайте, но не удалось.

Кто-нибудь может мне помочь?

Ответы [ 3 ]

5 голосов
/ 22 декабря 2011

Функция key () (с двумя аргументами) ищет документ, содержащий узел контекста. Если элемент контекста не является узлом - например, внутри строки анализа - вы получите эту ошибку, потому что он не знает, какой документ искать. Ответ заключается в использовании третьего аргумента key () для предоставления этой информации.

1 голос
/ 22 декабря 2011

Самый простой способ обработки строкового символа за символом в XSLT 2.0 - это :

<xsl:for-each select="string-to-codepoints($vStr)">
 <xsl:variable name="$vChar" select=
     "codepoints-to-string(.)"/>

 <!-- Process $vChar here: -->
</xsl:for-each/>

Вы можете комбинировать это с сохранением исходного контекста документа в переменную (скажем, $vDoc) и использованием этой переменной в качестве 3-го аргумента функции key() - которая снова является функцией только для XSLT 2.0.

Итак, у вас будет что-то вроде:

key('xx', concat($TN, $vChar), $vDoc)

Резюме

  1. Используйте функции string-to-codepoints() и codepoints-to-string() для обработки символов за символом.

  2. Используйте 3-й аргумент функции key(), чтобы указать контекст, отличный от текущего.

1 голос
/ 22 декабря 2011

Проблема в том, что контекст вашего элемента analyze-string изменяется.Возможно, вам поможет следующее решение.

Для такого XML-файла:

<a>
    <Format>
        <TagNr>92</TagNr>
        <Option>A</Option>
        <Format>//[N]15d</Format>
    </Format>
    <Format>
        <TagNr>92</TagNr>
        <Option>B</Option>
        <Format>//3!a/3!a/15d</Format>
    </Format>
    <Tag>
        <TagNr>92</TagNr>
        <Options>AB</Options>
    </Tag>
</a>

Рассмотрим следующий XSLT:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" version="2.0">
    <xsl:output indent="yes"/>
    <xsl:key name="xx" match="//Format/Format" use="concat(../TagNr, ../Option)"/>
    <xsl:template match="/">
        <result>
            <xsl:apply-templates select="//Tag"/>            
        </result>
    </xsl:template>
    <xsl:template match="Tag">
        <xsl:call-template name="createOPT">
            <xsl:with-param name="str" as="xs:string" select="Options"/>
        </xsl:call-template>                
    </xsl:template>
    <xsl:template name="createOPT">
        <xsl:param name="str"/>
        <xsl:if test="string-length($str) > 0">
            <xsl:variable name="firstChar" select="substring($str,1,1)"/>
            <xsl:variable name="TNO" select="concat(TagNr,$firstChar)"/>
            <opt>
                <tag><xsl:value-of select="$TNO"/></tag>
                <fmt><xsl:value-of select="key('xx', $TNO)"/></fmt>
            </opt>
            <xsl:call-template name="createOPT">
                <xsl:with-param name="str" select="substring($str,2)"/>
            </xsl:call-template>
        </xsl:if>
    </xsl:template>
</xsl:stylesheet>

Результат:

<?xml version="1.0" encoding="UTF-8"?>
<result>
   <opt>
      <tag>92A</tag>
      <fmt>//[N]15d</fmt>
   </opt>
   <opt>
      <tag>92B</tag>
      <fmt>//3!a/3!a/15d</fmt>
   </opt>
</result>
...