#xml #xslt #nested
#xml #xslt #вложенный
Вопрос:
Я новичок в XSL и в процессе создания этого с нуля, чтобы решить проблему.
У меня есть исходный XML-файл, который содержит следующую структуру:-
<root>
<Header>
</Header>
<DetailRecord>
<CustomerNumber>1</CustomerNumber>
<DetailSubRecord>
<Address>London</Address>
</DetailSubRecord>
<DetailSubRecord>
<Address>Hull</Address>
</DetailSubRecord>
</DetailRecord>
<DetailRecord>
<CustomerNumber>2</CustomerNumber>
<DetailSubRecord>
<Address>Birmingham</Address>
</DetailSubRecord>
<DetailSubRecord>
<Address>Manchester</Address>
</DetailSubRecord>
</DetailRecord>
<Footer>
</Footer>
</root>
где есть несколько <DetailRecord>
файлов, каждый из которых содержит несколько <DetailSubRecord>
файлов.
Мне удалось собрать XSL, который выводит единый вложенный набор из нескольких подробных записей в плоский файл, но я не смог разобраться, как ссылаться на 2-й вложенный уровень записей адресов в XSL…
Вот мой XSL на данный момент:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:strip-space elements="*"/>
<xsl:output method="text"/>
<xsl:variable name="spaces" select="' '"/>
<xsl:variable name="newline">
<xsl:text>amp;#10;</xsl:text>
</xsl:variable>
<xsl:template match="/">
<xsl:value-of select="root/Header/HeaderField"/>
<xsl:copy-of select="$newline"/>
<xsl:for-each select="root/DetailRecord">
<xsl:value-of select="CustomerNumber"/>
<xsl:copy-of select="$newline"/>
</xsl:for-each>
Trailer - recordCount - <xsl:value-of select="count(root/DetailRecord)"/>
</xsl:template>
</xsl:stylesheet>
Комментарии:
1. Вот мой XSL на данный момент…
2. <xsl: элементы с пробелами =»*»/> <xsl: метод вывода =»текст»/> <xsl: имя переменной =»пробелы» select=»‘ ‘»/> <xsl: имя переменной = «перевод строки»> <xsl:text>amp;#10;</xsl:text> </xsl:переменная> <xsl: соответствие шаблону=»/»> <xsl: значение выбора=»root/Header/HeaderField»/> <xsl:копия выбора=»$newline»/ > <xsl:для каждого выбора =»root/DetailRecord»> <xsl: значение выбора =»CustomerNumber»/> <xsl: копия выбора =»$newline»/> </xsl: для каждого> Trailer — RecordCount — <xsl: значение выбора=»count(root/DetailRecord)»/> </xsl: шаблон> </xsl: таблица стилей>
3. Можете ли вы опубликовать пример вашего целевого вывода?
Ответ №1:
XSLT — это функциональный язык, а не процедурный; чего большинство новичков в XSLT не понимают, так это того, что процессор XSLT автоматически обрабатывает каждый узел в дереве в том порядке, в каком они отображаются в исходном коде. Однако без шаблона, определяющего, что делать с каждым узлом, ничего не выводится.
В большинстве случаев вам не нужно использовать <xsl:for-each>
только для обработки дочерних элементов, это уже сделано за вас, вам просто нужно определить шаблон, который описывает, как вы хотите, чтобы каждый элемент выводился. Вот так:
<xsl:template match="root">
<xsl:apply-templates />
<xsl:text>Trailer - recordCount - </xsl:text>
<xsl:value-of select="count(DetailRecord)" />
</xsl:template>
<xsl:template match="HeaderField | CustomerNumber | Address">
<xsl:value-of select="concat(.,$newline)" />
</xsl:template>
<xsl:template match="DetailSubRecord">
<!-- do something with subrecord here -->
<xsl:apply-templates />
</xsl:template>
<xsl:apply-templates />
В первом шаблоне просто сообщает процессору XSLT обработать дочерние элементы, после чего он добавляет количество записей.
Второй шаблон обрабатывает любой элемент с тремя именами в его match
atrtibute, и в каждом случае выводит содержимое ( .
), объединенное с новой строкой.
Третий шаблон в его текущем виде на самом деле излишен, процессор сделает это в любом случае, но вы можете заменить этот комментарий чем-то более полезным.
Вы заметите, что это не дает никакой информации о том, как обращаться с DetailRecord
элементом; поскольку все, что вы хотите сделать, это обработать его дочерние элементы, вам не нужно ничего указывать, поскольку это принимается как данность.
Ответ №2:
Здесь у вас есть простой пример того, как (буквально) применить шаблоны к вашей ситуации. Поскольку вы не очень четко описали требуемый вывод, я изобрел его.
XSLT 1.0 протестирован под Saxon 6.5.5
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:strip-space elements="*"/>
<xsl:output method="text"/>
<xsl:variable name="spaces" select="' '"/>
<xsl:variable name="nl">
<xsl:text>amp;#10;</xsl:text>
</xsl:variable>
<xsl:template match="/root">
<xsl:apply-templates select="DetailRecord"/>
<xsl:apply-templates select="Footer"/>
</xsl:template>
<xsl:template match="DetailRecord">
<xsl:value-of select="concat(
'Customer ',
CustomerNumber, $nl)"
/>
<xsl:apply-templates select="DetailSubRecord"/>
<xsl:value-of select="concat(
'Address Count:',
count(DetailSubRecord),$nl,$nl
)"
/>
</xsl:template>
<xsl:template match="DetailSubRecord">
<xsl:value-of select="concat('-',Address,$nl)"/>
</xsl:template>
<xsl:template match="Footer">
<xsl:value-of select="concat(
'Customer Count:',
count(preceding-sibling::DetailRecord),$nl
)"
/>
</xsl:template>
</xsl:stylesheet>
Примененный к вашему вводу, получает:
Customer 1
-London
-Hull
Address Count:2
Customer 2
-Birmingham
-Manchester
Address Count:2
Customer Count:2