Извлечение значения атрибута по умолчанию в XSLT - PullRequest
4 голосов
/ 29 сентября 2010

У меня очень специфическая проблема, когда я хочу иметь возможность извлечь значение атрибута по умолчанию для элемента, как показано в примере ниже.

Каждый элемент во входном XML содержит несколько дочерних элементов имени, один для представления основного имени, которое является значением атрибута по умолчанию (type = 'main'), и другое вторичное имя (type = 'short'). В основном имени не указано значение атрибута 'main'. Вот пример входного XML-файла с намеренно закомментированным первым элементом name, чтобы проиллюстрировать проблему дальше:

<?xml version="1.0"?>
<food_list>
  <food_item>
    <!--name>Apple</name-->
    <name type="short">APL</name>
  </food_item>
  <food_item>
    <name>Asparagus</name>
    <name type="short">ASP</name>
  </food_item>
  <food_item>
    <name>Cheese</name>
    <name type="short">CHS</name>
  </food_item>
</food_list>

XSD для NameType выглядит следующим образом:

<complexType name="NameType">
    <simpleContent>
        <extension base="TextualBaseType">
            <attribute name="type" use="optional" default="main">
                <simpleType>
                    <restriction base="NMTOKEN">
                        <enumeration value="main"/>
                        <enumeration value="short"/>
                        <enumeration value="alternative"/>
                    </restriction>
                </simpleType>
            </attribute>
        </extension>
    </simpleContent>
</complexType>

XSLT для преобразования входного XML и извлечения Основного имени и Сокращенного имени приведен ниже:

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="/">
  <xsl:apply-templates/>
</xsl:template>

<xsl:template match="food_list">
  <table>
    <tr style="background-color:#ccff00">
      <th>Food Name</th>
      <th>Food Short Name</th>
   </tr>
    <xsl:for-each select="food_item">
        <tr style="background-color:#00cc00">
          <td><xsl:value-of select="name"/></td>
          <td><xsl:value-of select="name[@type='short']"/></td>
       </tr>
   </xsl:for-each>
  </table>
</xsl:template>

</xsl:stylesheet>

Когда входной XML преобразуется, Первичное имя для первого элемента питания неправильно выбирается из элемента с type = 'short'. Вопрос: Как ограничить первый оператор value-of в xslt значением only для выбора значений имени, когда определен элемент по умолчанию?

Ответы [ 5 ]

2 голосов
/ 29 сентября 2010

Вопрос : Как ограничить первый оператор value-of в xslt тем, что он выбирает только имена, когда определен элемент по умолчанию?

XSLT1.0 не поддерживает схему и может не поддерживать внутреннюю DTD.

Базовый процессор XSLT 2.0 не поддерживает схему.

Итог, вам нужна схема XSLT 2.0.

Обходной путь - проверить отсутствие такого атрибута для обработки такого элемента, как определение атрибута по умолчанию:

name[not(@type) or @type='main']
1 голос
/ 29 сентября 2010

Проблема, с которой вы столкнулись, заключается в том, что <xsl:value-of select="name" /> выберет любой элемент name, независимо от того, имеет ли он атрибут, включая те, которые имеют тип «short»;вам нужно ограничить его только теми, у кого нет атрибута типа, или теми, у которых атрибут типа имеет значение 'main'.

Вы можете сделать это с помощью: <xsl:value-of select="name[not(@type) or @type='main']" />.

Это изКонечно, явно не ссылается на схему, но поскольку сама схема является XML-документом, вы можете потенциально заменить 'main' ссылкой на схему, используя функцию document();если вы решите сделать это, я бы порекомендовал сохранить значение в переменной в корне xslt, поэтому он выбирает его только один раз.Например:

<xsl:variable name="defaultType" select="document('<schema url>')//complexType[@name='NameType']/simpleContent/extension/attribute/@default" />

Тогда вы можете просто заменить ссылку на 'main' на $defaulttype.

1 голос
/ 29 сентября 2010

XSLT ничего не знает о схемах XSD, поэтому вам нужно добавить информацию (это значение по умолчанию) в вашу таблицу стилей. Соответствующий xsl: if решит проблему. Конечно, если вы измените XSD, вам придется обновить таблицу стилей. Единственный способ быть более гибким при использовании схемы - это читать и анализировать схему из таблицы стилей, но это будет очень сложно, и вам придется ограничить возможные изменения в вашей схеме, чтобы упростить проблему.

0 голосов
/ 29 сентября 2010

Это преобразование :

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="/">
  <xsl:apply-templates/>
 </xsl:template>

 <xsl:template match="food_list">
  <table>
    <tr style="background-color:#ccff00">
      <th>Food Name</th>
      <th>Food Short Name</th>
   </tr>
    <xsl:apply-templates/>
  </table>
 </xsl:template>

 <xsl:template match="food_item">
  <tr style="background-color:#00cc00">
   <td><xsl:value-of select=
        "concat(name[not(@type)],
                name[@type='main'],
                substring('some hardcoded default',
                          1
                         div
                           (not(name[not(@type)])
                             and
                            not(name[@type='main'])
                           )
                          )
                )
         "/></td>
   <td><xsl:value-of select="name[@type='short']"/></td>
  </tr>
 </xsl:template>
</xsl:stylesheet>

применительно к следующему документу XML (на основе предоставленного, но немного увеличенного для представления более возможных случаев):

<food_list>
  <food_item>
    <!--name>Apple</name-->
    <name type="short">APL</name>
    <name type="alternative">Gala APL</name>
  </food_item>
  <food_item>
    <name>Asparagus</name>
    <name type="short">ASP</name>
  </food_item>
  <food_item>
    <name>Cheese</name>
    <name type="short">CHS</name>
  </food_item>
  <food_item>
    <name type="main">Grapes</name>
    <name type="short">GPS</name>
  </food_item>
</food_list>

дает желаемый, правильный результат :

<table>
    <tr style="background-color:#ccff00">
        <th>Food Name</th>
        <th>Food Short Name</th>
    </tr>
    <tr style="background-color:#00cc00">
        <td>some hardcoded default</td>
        <td>APL</td>
    </tr>
    <tr style="background-color:#00cc00">
        <td>Asparagus</td>
        <td>ASP</td>
    </tr>
    <tr style="background-color:#00cc00">
        <td>Cheese</td>
        <td>CHS</td>
    </tr>
    <tr style="background-color:#00cc00">
        <td>Grapes</td>
        <td>GPS</td>
    </tr>
</table>
0 голосов
/ 29 сентября 2010

Если я правильно понимаю ваш вопрос, вы можете поставить <xsl:if> вокруг <xsl:value-of>, который проверяет, не имеет ли имя атрибута @type. (вероятно что-то вроде <xsl:if test="not(name[@type])">)

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