Как динамически выбирать узлы в XSLT - PullRequest
1 голос
/ 22 апреля 2009

У меня есть XML-файл:

<?xml version="1.0" standalone="yes"?>
<Questionnaire>
  <Temp_GridTypeTable_6>
    <Column2>Select Yes/No</Column2>
  </Temp_GridTypeTable_6>
  <Temp_GridTypeTable_1>
    <Column2>Rank 1,2,3</Column2>
  </Temp_GridTypeTable_1>
  <Temp_GridTypeTable_1>
    <Column1>I needed the income</Column1>
    <Column2>Why did you take a job on this project?</Column2>
  </Temp_GridTypeTable_1>
  <Temp_GridTypeTable_1>
    <Column1>Other</Column1>
    <Column2></Column2>
  </Temp_GridTypeTable_1>
  <Temp_GridTypeTable_2>
    <Column2>Select "Yes/No"</Column2>
  </Temp_GridTypeTable_2>
  <Temp_GridTypeTable_2>
    <Column1>No jobs</Column1>
    <Column2>344</Column2>
  </Temp_GridTypeTable_2>
  <Temp_GridTypeTable_3>
    <Column2>Input</Column2>
  </Temp_GridTypeTable_3>
  <Temp_GridTypeTable_3>
    <Column1>Unit</Column1>
    <Column2>123</Column2>
  </Temp_GridTypeTable_3>
</Questionnaire> 

Я хочу получить доступ

<xsl:for-each select="Questionnaire/concat('Temp_GridTypeTablenode_',"1"))>

но это утверждение не работает.

Ответы [ 3 ]

11 голосов
/ 22 апреля 2009

Это пример того, как не использовать XML. Числа «Temp_GridTypeTable» и «Column» являются данными, а не структурой, они не должны содержаться в именах элементов. Так почему бы тебе не использовать что-то менее болезненное, скажи:

<Questionnaire>
  <Temp_GridTypeTable type="6">
    <Column num="2">Select Yes/No</Column>
  </Temp_GridTypeTable>
  <Temp_GridTypeTable type="1">
    <!-- ... -->
  <Temp_GridTypeTable>
  <!-- ... -->
</Questionnaire>

Как говорится, для вашей текущей ситуации это необходимо:

<xsl:for-each select="Questionnaire/*[
  local-name()
  =
  concat('Temp_GridTypeTable_', '1')
]">

Для "менее болезненной" версии ввода это потребовалось бы:

<xsl:for-each select="Questionnaire/Temp_GridTypeTable[@type = 1]">

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


РЕДАКТИРОВАТЬ: Следуя аргументу, который раскрылся в комментариях, я пытаюсь подчеркнуть разницу между local-name() и name() XPath-функциями, и где разница вопросы:

                            | XML has namespaces  |  XML has no namespaces
----------------------------+---------------------+-----------------------
I care about namespaces     | use `name()`        |  use either function
                            |                     |
don't care about namespaces | use `local-name()`  |  use either function

Обычно: если вы попадаете в группу "не заботятся о пространствах имен" (большинство новичков XML или случайных пользователей XML), то все в порядке (иногда даже полезно) просто всегда использовать local-name(). Тем не менее, будьте готовы узнать о пространствах имен XML, когда полученные результаты и ожидаемые результаты начинают расходиться. На данный момент вы больше не принадлежите к указанной группе.

Если вы попадаете в группу «Я забочусь о пространствах имен», вам все равно не нужен этот совет. ; -)

2 голосов
/ 22 апреля 2009

Использование:

Questionnaire/*[name() = concat('', $vSuffix)]

где переменная $vSuffix содержит статически неизвестную строку - в данном случае '1'.

Использование local-name(), как в ответе Томалака, является излишне длинным и неточным , поскольку в общем случае позволяет выбирать элементы с различными (возможно нежелательными и неожиданными) именами , например:

  • OhMy:Temp_GridTypeTable_1
  • Different:Temp_GridTypeTable_1
  • UnWanted:Temp_GridTypeTable_1
1 голос
/ 22 апреля 2009

Вы не можете оценивать строки как выражения XPath во время выполнения с чистым XSLT.

Вам нужна функция расширения, которая может оценивать выражение xpath во время выполнения. Смотрите, например, EXSLT проект .

В моей системе, используя xsltproc, я могу выполнить то, что вы хотите:

<!-- load the saxon extensions -->
<xsl:stylesheet version="1.0" xmlns:xx="http://icl.com/saxon" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
...
...
<xsl:for-each 
    select="xx:evaluate(concat('Questionnaire/Temp_GridTypeTable_', '1'))">

Здесь я использую функцию оценки из библиотеки расширений саксонии. Функция оценки EXSLT должна работать так же.

В процессоры / библиотеки XSLT должны быть встроены какие-то функции evaluate. См. Документацию вашей библиотеки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...