Перейти к содержанию

xsl:attribute

Элемент xsl:attribute служит для создания узлов атрибутов в выходном документе.

Синтаксис

1
2
3
<xsl:attribute name="имя" namespace="пространство имен">
  <!-- Содержимое: template -->
</xsl:attribute>

Атрибуты:

name
обязательный атрибут, указывает имя создаваемого атрибута. Может содержать шаблон значения, т. е. имя атрибута может быть вычислено во время выполнения.
namespace
необязательный атрибут, указывает URI пространства имен создаваемого атрибута. Может содержать шаблон значения, что позволяет вычислять пространство имен создаваемого элемента при помощи выражений.

Описание и примеры

Особенности обращения с xsl:attribute:

  • Атрибуты могут создаваться только в узлах элементов. Если атрибут создается в узле, который не является узлом элемента, процессор может либо выдать ошибку, либо проигнорировать создаваемый атрибут.
  • Атрибуты могут содержать только текстовые узлы. Процессор может либо выдать ошибку, либо проигнорировать нетекстовые узлы.
  • Узлы атрибутов должны быть первыми узлами, которые создаются в элементах. XSLT не разрешает создавать атрибуты после того, как в элемент включены дочерние узлы других типов.
  • В случае, когда документ преобразуется в другой XML-документ, символы перевода строки в элементе заменяются символьными сущностями.

Пример 1

Покажем, как преобразовать структуру вида:

1
2
3
4
<element name="record">
  <attribute name="fieldcount" value="12" />
  <attribute name="title" value="Aggregation" />
</element>

в элемент <record fieldcount="12" title="Aggregation"/>.

Для достижения цели воспользуемся следующим преобразованием:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
<xsl:stylesheet
  version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
  <xsl:template match="element">
    <xsl:element name="{@name}">
      <xsl:apply-templates select="attribute" />
    </xsl:element>
  </xsl:template>
  <xsl:template match="attribute">
    <xsl:attribute name="{@name}">
      <xsl:value-of select="@value" />
    </xsl:attribute>
  </xsl:template>
</xsl:stylesheet>

Элемент xsl:attribute не может использоваться где угодно: узлы атрибутов должны создаваться только как дочерние узлы узлов элементов. Более того, узлы атрибутов должны создаваться до создания дочерних узлов других типов — текста, элементов и так далее. Таким образом, xsl:attribute может быть использован в содержимом любого из следующих родителей:

  • литерального элемента результата;
  • элемента xsl:element;
  • элемента xsl:copy в случае, если текущий, копируемый узел является элементом;
  • элемента xsl:attribute-set в случае определения именованного набора атрибутов.

При этом, xsl:attribute не обязан использоваться только в качестве их непосредственного дочернего элемента. Главное, чтобы атрибуты создавались в элементах и только в элементах.

Элемент xsl:attribute также не может использоваться для генерации объявлений пространств имен. В соответствии с технической рекомендацией XSLT, xsl:attribute не может создавать атрибуты, имена которых имеют префикс xmlns.

Если атрибут создается в элементе, который уже имеет атрибут с таким же именем, старый атрибут будет переопределен новым значением.

Пример 2

Фрагмент шаблона:

1
2
3
4
5
 href="http://www.aaa.com">
  <xsl:attribute name="href">
    <xsl:text>http://www.bbb.com</xsl:text>
  </xsl:attribute>
</a>

Результат: <a href="http://www.bbb.com" />.

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

Текстовое значение атрибута может задаваться не только символьными данными. Оно может генерироваться также элементами XSLT, такими, как, например, xsl:text и xsl:value-of. То есть вполне корректным будет следующее определение:

1
2
3
4
5
<xsl:attribute name="href">
  <xsl:text>http://</xsl:text>
  <xsl:value-of select="concat('www', '.', 'bbb')" />
  <xsl:text>.com</xsl:text>
</xsl:attribute>

В том случае, если текстовое значение атрибута содержит символы перевода строки, при генерации атрибута они будут заменены сущностями, то есть определение

1
2
3
4
<xsl:attribute name="href">
  а
b
</xsl:attribute>

создаст атрибут с именем href и значением <code>a&</code><code>#xA;b</code>:

1
 href="a&<!--  -->#xA;b" />

Техническая рекомендация объясняет такую ситуацию следующим образом: в соответствии со стандартом языка XML, символы перевода строки должны нормализоваться в значениях атрибутов пробелами, сущности же нормализовать не нужно. Но если бы символ перевода строки нормализовался в XSLT при выводе пробелом, то определения:

1
<xsl:attribute name="href">a b</xsl:attribute>

и

1
<xsl:attribute name="href">a&<!-- -->#xA;b</xsl:attribute>

(из-за особенностей парсера пример следует читать без пустого комментария)

были бы эквивалентны, что не отражает реального положения вещей. Для того чтобы исправить эту несуразицу, символ перевода строки при выводе в атрибуте нормализуется в XSLT символьной сущностью.

Пример 3

Следующий короткий пример демонстрирует применение новых атрибутов select и separator. В таблице стилей диапазонное выражение XPath 2.0 (выражение "to") используется для присваивания последовательности значений атрибуту example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
<?xml version="1.0" encoding="utf-8" ?>
<!-- attribute2.xsl -->
<xsl:stylesheet
  version="2.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
  <xsl:output method="xml" omit-xml-declaration="yes" />
  <xsl:template match="/">
    <sampledoc>
      <xsl:attribute
        name="example"
        select="1 to 7"
        separator=", "
      />
    </sampledoc>
  </xsl:template>
</xsl:stylesheet>

Таблица стилей генерирует очень короткий документ:

1
<sampledoc example="1, 2, 3, 4, 5, 6, 7" />

Благодаря атрибуту XSLT 2.0 separator вам не придется самостоятельно реализовывать логику следующего вида:

1
2
3
4
5
6
<xsl:for-each>
  <xsl:value-of select="." />
  <xsl:if test="position() != last()">
    <xsl:text>,</xsl:text>
  </xsl:if>
</xsl:for-each>

Пример 4

В последнем примере используются схемосовместимые атрибуты <xsl:attribute>. Наша таблица стилей содержит импортированную схему, определяющую новый тип данных; атрибут <xsl:attribute> используется для создания атрибутов с этим типом данных. Таблица стилей выглядит так:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
<?xml version="1.0" encoding="utf-8" ?>
<!-- attribute3.xsl -->
<xsl:stylesheet
  version="2.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:zip="http://www.oreilly.com/xslt/zip"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  exclude-result-prefixes="xs"
>
  <xsl:output method="xml" indent="yes" />
  <xsl:import-schema
    namespace="http://www.oreilly.com/xslt/zip"
  >
    <xsd:schema
      xmlns="http://www.oreilly.com/xslt/zip"
      targetNamespace="http://www.oreilly.com/xslt/zip"
      xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    >
      <xsd:simpleType name="zipcode">
        <xsd:restriction base="xsd:string">
          <xsd:pattern value="[0-9]{5}(-[0-9]{4})?" />
        </xsd:restriction>
      </xsd:simpleType>
    </xsd:schema>
  </xsl:import-schema>
  <xsl:template match="/">
    <postcodes>
      <xsl:for-each select="postcodes/postcode">
        <postcode>
          <xsl:choose>
            <xsl:when test=". castable as zip:zipcode">
              <xsl:attribute
                name="zip:zip"
                type="zip:zipcode"
              >
                <xsl:value-of
                  select=". cast as zip:zipcode"
                />
              </xsl:attribute>
            </xsl:when>
            <xsl:otherwise>
              <xsl:attribute name="other" type="xs:string">
                <xsl:value-of select="." />
              </xsl:attribute>
            </xsl:otherwise>
          </xsl:choose>
        </postcode>
      </xsl:for-each>
    </postcodes>
  </xsl:template>
</xsl:stylesheet>

Таблица стилей используется для обработки следующего документа:

1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="utf-8" ?>
<!-- postcodes.xml -->
<postcodes>
  <postcode>3S8 E0X</postcode>
  <postcode>37174</postcode>
  <postcode>NSW 3829</postcode>
  <postcode>27516</postcode>
</postcodes>

Таблица стилей использует оператор XPath castable as для определения того, может ли значение из исходного документа быть преобразовано в значение zip:zipcode. Если проверка дает положительный результат, мы создаем новый атрибут с типом данных zip:zipcode. Результат:

1
2
3
4
5
6
7
<?xml version="1.0" encoding="UTF-8" ?>
<postcodes xmlns:zip="http://www.oreilly.com/xslt/zip">
  <postcode other="3S8 E0X" />
  <postcode zip:zip="37174" />
  <postcode other="NSW 3829" />
  <postcode zip:zip="27516" />
</postcodes>

Два атрибута из сгенерированного набора уточняются пространством имен и содержат значения соответствующего типа данных.

Пример 5

1
2
3
4
5
6
<?xml version="1.0" ?>
<?xml-stylesheet type="text/xsl" href="attrcopied.xsl" ?>
<root>
  <myElement>My Data</myElement>
  <myElement>My Other Data</myElement>
</root>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<?xml version="1.0" ?>
<xsl:stylesheet
  version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
  <xsl:template match="myElement">
    <xsl:copy>
      <xsl:attribute name="copied">true</xsl:attribute>
      <xsl:apply-templates />
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>
1
2
3
<?xml version="1.0"?>
<myElement copied="true">My Data</myElement>
<myElement copied="true">My Other Data</myElement>

См. также

  • xsl:attribute-set - определяет именованный набор атрибутов.

Ссылки

Комментарии