Подсчет различных предметов в XSLT независимо от глубины - PullRequest
1 голос
/ 15 июля 2010

Если я запускаю следующий код XSLT:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="text"/>

 <xsl:key name="kValueByVal" match="variable_name/@value"
  use="."/>

 <xsl:template match="assessment">
  <xsl:for-each select="
   /*/*/variable/attributes/variable_name/@value
             [generate-id()
             =
              generate-id(key('kValueByVal', .)[1])
             ]
   ">
     <xsl:value-of select=
     "concat(., ' ', count(key('kValueByVal', .)), '&#xA;')"/>
  </xsl:for-each>
 </xsl:template>
</xsl:stylesheet>

для следующего XML:

<assessment>
    <variables>
        <variable>
            <attributes>
                <variable_name value="FRED"/>
            </attributes>
        </variable>
    </variables>
    <variables>
        <variable>
            <attributes>
                <variable_name value="MORTIMER"/>
            </attributes>
        </variable>
    </variables>
    <variables>
        <variable>
            <attributes>
                <variable_name value="FRED"/>
            </attributes>
        </variable>
    </variables>
</assessment>

Я получаю желаемый вывод:

FRED 2
MORTIMER 1

(См. мой оригинальный вопрос для получения дополнительной информации, если хотите.)

Однако, если я выполню его на этом входе:

<ExamStore>
    <assessment>
        <variables>
            <variable>
                <attributes>
                    <variable_name value="FRED"/>
                </attributes>
            </variable>
        </variables>
        <variables>
            <variable>
                <attributes>
                    <variable_name value="MORTIMER"/>
                </attributes>
            </variable>
        </variables>
        <variables>
            <variable>
                <attributes>
                    <variable_name value="FRED"/>
                </attributes>
            </variable>
        </variables>
    </assessment>
</ExamStore>

Я ничего не получу.(Обратите внимание, что я просто обернул исходный ввод в тег ExamStore.) Я ожидал и надеюсь получить тот же вывод.

Почему бы и нет?Как я могу изменить исходный код XSLT, чтобы получить тот же вывод?

Ответы [ 3 ]

1 голос
/ 16 июля 2010

Когда вы ввели в XML-документ еще один уровень, это испортило абсолютное выражение XPath, используемое в исходном решении (таяло точно после исходного XML-файла).

Поэтому, чтобы заставить выражение XPath работать в новой ситуации, просто сделайте следующее:

Замените :

/*/*/variable/attributes/variable_name/@value 

с

/*/*/*/variable/attributes/variable_name/@value

и теперь вы снова получите желаемый аккуратный результат:

FRED 2
MORTIMER 1

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

В исходном вопросе вы использовали:

.//variables/variable/attributes/variable_name

off assessment,

и именно поэтому я использовал абсолютное выражение XPath в своем решении.Не было никакой гарантии, что в другом XML-документе некоторые элементы variable_name не будут существовать, так что их цепочка предков не будет variables/variable/attributes. Если бы это было так, это означало бы, что вы, вероятно, не были заинтересованы в значениях таких«нерегулярные» variable_name элементы.

Урок заключается в том, что не следует слишком конкретизировать вопрос при определении вопроса, а затем искать общие решения.:)

1 голос
/ 15 июля 2010

Что ж, ваш select xpath /*/*/variable/attributes/variable_name/... больше не является правильным, потому что вы добавили еще один узел выше в дерево узлов.

Если вы хотите иметь истинную независимость, вам нужно использовать что-то вроде:

//variable/attributes/variable_name/...

... (не двойная косая черта в начале), но это довольно опасно, потому что оно уловит все случаи этой структуры - будьте уверены, что это именно то, что вы имеете в виду.

В противном случае просто добавьте к своему xpath другой /*

0 голосов
/ 15 июля 2010

Для реальной структуры независимость вы должны использовать:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="text"/>

 <xsl:key name="kValueByVal" match="variable_name/@value"
  use="."/>

 <xsl:template match="variable_name[@value
             [generate-id()
             =
              generate-id(key('kValueByVal', .)[1])
             ]]">
     <xsl:value-of select=
     "concat(@value, ' ', count(key('kValueByVal', @value)), '&#xA;')"/>
 </xsl:template>
</xsl:stylesheet>

Результат с первым входом:

FRED 2
MORTIMER 1

Результат со вторым входом:

FRED 2
MORTIMER 1

Примечание : Никогда не используйте // в качестве первого оператора XPath.

...