XSLT v1.0 Обновление атрибута в наборе узлов на основе атрибута предыдущего узла
У меня есть следующий файл XML.
<Record
Name="My_Record"
<Fields
StartingBit="0"
Size="3"
Name="Field_1">
</Fields>
<Fields
StartingBit="1"
Size="5"
Name="Field_2">
</Fields>
<Fields
StartingBit="2"
Size="8"
Name="Field_3">
</Fields>
<Fields
StartingBit="3"
Size="4"
Name="Field_4"
</Fields>
</Record>
И я хотел бы использовать XSLT для правильного обновления атрибута @StartingBit из @StartingBit + @Size предыдущего узла - это будет значение @StartingBit текущего узла. Полученный XML должен быть следующим:
<Record
Name="My_Record"
<Fields
StartingBit="0"
Size="3"
Name="Field_1">
</Fields>
<Fields
StartingBit="3"
Size="5"
Name="Field_2">
</Fields>
<Fields
StartingBit="8"
Size="8"
Name="Field_3">
</Fields>
<Fields
StartingBit="16"
Size="4"
Name="Field_4"
</Fields>
</Record>
Пока что мои последние попытки использовать XSLT следующие:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match ="Fields/@StartingBit">
<xsl:value-of select ="(preceding-sibling::Fields[1]/@StartingBit + preceding-sibling::Fields[1]/@Size)"/>
</xsl:template>
</xsl:stylesheet>
Вышеуказанное преобразование не генерирует то, что я хотел бы - в основном @StartingBit не изменяется. Я не разбираюсь в навигации по узлам, чтобы получить результаты, которые мне нравятся - кто-то может помочь в моем преобразовании? Заранее спасибо.
- лоренц
1 ответ
Решение
Когда этот простой XSLT:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output omit-xml-declaration="no" indent="yes" />
<xsl:strip-space elements="*" />
<xsl:variable name="vStartingBit" select="/*/Fields[1]/@StartingBit" />
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="Fields[position() > 1]">
<xsl:copy>
<xsl:attribute name="StartingBit">
<xsl:value-of
select="$vStartingBit + sum(preceding-sibling::Fields/@Size)" />
</xsl:attribute>
<xsl:apply-templates select="@*[not(name() = 'StartingBit')]" />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
... применяется к исходному XML (исправлен, чтобы быть правильно сформированным):
<?xml version="1.0" encoding="utf-8"?>
<Record Name="My_Record">
<Fields StartingBit="0" Size="3" Name="Field_1" />
<Fields StartingBit="1" Size="5" Name="Field_2" />
<Fields StartingBit="2" Size="8" Name="Field_3" />
<Fields StartingBit="3" Size="4" Name="Field_4" />
</Record>
... ожидаемый результат получается:
<?xml version="1.0"?>
<Record Name="My_Record">
<Fields StartingBit="0" Size="3" Name="Field_1" />
<Fields StartingBit="3" Size="5" Name="Field_2" />
<Fields StartingBit="8" Size="8" Name="Field_3" />
<Fields StartingBit="16" Size="4" Name="Field_4" />
</Record>
Объяснение:
- Первый шаблон
Identity Template
, Его цель - скопировать все узлы и атрибуты из исходного документа в конечный документ как есть. - Один шаблон переопределяет шаблон идентификации. Его цель - добавить оригинальный стартовый бит к правильному
@Size
атрибуты (те, которые предшествуют текущему<Fields>
элемент), который формирует значение каждого последующего<Fields>
элемента@StartingBit
приписывать.