#html #xml #xslt
#HTML #xml #xslt
Вопрос:
ниже приведен мой XML-код —
<topic no=1>
<desc>......</desc>
<references>
<book>XSLT Essentials</book>
<chapter>11</chapter>
<book>XSLT Cookbook</book>
<chapter>10</chapter>
</references>
</topic>
<topic no=2>
<desc>......</desc>
<references>
<book>Javascript in 10 mins</book>
<chapter>11</chapter>
</references>
</topic>
<topic no=3>
<desc>......</desc>
<references>
<book></book>
<chapter></chapter>
</references>
</topic>
Сначала я объясняю ситуацию.
Вывод HTML только в отношении тега references, который я ищу, выглядит так —
для темы no =1
<table><tr>
<td>Book</td><td>Chapter</td></tr>
<tr>
<td>XSLT Essentials</td><td>11</td></tr>
<tr>
<td>XSLT Cookbook</td><td>10</td></tr>
</table>
……
для темы no = 2
<table><tr>
<td>Book</td><td>Chapter</td></tr>
<tr>
<td>Javascript in 10 mins</td><td>11</td></tr>
</table>
……
для темы no = 3 Нет таблицы, поскольку ссылки не используются.
Это пример, поэтому в первом случае XML-файл содержит только 2 ссылки, но в некоторых случаях эти ссылки могут даже достигать 12, а в некоторых случаях 0 (ноль).
Хорошего дня — Джон 🙂
Ответ №1:
Это, вероятно, одно из самых простых и коротких решений. Обратите внимание, что явные условные инструкции вообще не используются:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="topic/*|text()"/>
<xsl:template match="/*[topic]">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="topic/references[book/text()]">
<table>
<tr><td>Book</td><td>Chapter</td></tr>
<xsl:apply-templates select="book"/>
</table>
</xsl:template>
<xsl:template match="book">
<tr>
<td><xsl:value-of select="."/></td>
<td><xsl:value-of select=
"following-sibling::chapter[1]"/>
</td>
</tr>
</xsl:template>
</xsl:stylesheet>
при применении к предоставленному входному тексту (исправлено, чтобы стать правильно сформированным XML-документом):
<t>
<topic no="1">
<desc>......</desc>
<references>
<book>XSLT Essentials</book>
<chapter>11</chapter>
<book>XSLT Cookbook</book>
<chapter>10</chapter>
</references>
</topic>
<topic no="2">
<desc>......</desc>
<references>
<book>Javascript in 10 mins</book>
<chapter>11</chapter>
</references>
</topic>
<topic no="3">
<desc>......</desc>
<references>
<book></book>
<chapter></chapter>
</references>
</topic>
</t>
получен желаемый, правильный результат:
<table>
<tr>
<td>Book</td>
<td>Chapter</td>
</tr>
<tr>
<td>XSLT Essentials</td>
<td>11</td>
</tr>
<tr>
<td>XSLT Cookbook</td>
<td>10</td>
</tr>
</table>
<table>
<tr>
<td>Book</td>
<td>Chapter</td>
</tr>
<tr>
<td>Javascript in 10 mins</td>
<td>11</td>
</tr>
</table>
Объяснение: Правильное использование шаблонов сопоставления с образцом.
Правило Димитра: всякий раз, когда у вас есть явная условная инструкция ( <xsl:if>
, <xsl:choose>
, <xsl:when>
, и т.д.), Это, вероятно, означает, что вы не использовали соответствие шаблону шаблона, как следовало бы.
Чтобы узнать больше, почему полезно полностью избегать условных инструкций: прочитайте этот важный курс Pluralsight:
Комментарии:
1. Большое спасибо … :). Скорее, я ждал вашего ответа. Так любезно с вашей стороны .. 🙂 и то, как вы отвечаете с объяснением, — лучший способ учиться (и учить тоже ;)). Это вы разработали это, я имею в виду XSLT ..? Еще раз большое спасибо .. 🙂
2. @John: Добро пожаловать. Да, XSLT — это быстрый, элегантный, мощный функциональный язык. Я не был среди создателей XSLT 1.0 / 2.0, но XSLT был моим хобби и иногда использовался в моих профессиональных задачах в течение последних 11 лет.
3. @Dimitre, молодец! Я знаю, что XQuery здесь не запрашивается, но вы упомянули короткие решения, а этот XQuery довольно короткий:
//book[text()]/..!element table{<tr><td>Book</td><td>Chapter</td></tr>,book!<tr><td>{text()}</td><td>{following::*[1]/text()}</td></tr>}
4. @Gunther, да, Xpath 3.0 в целом и оператор simple-mapping
!
придают нам исключительную выразительность и элегантность.
Ответ №2:
Для этого, похоже, вам сначала нужно передать параметр вашему XSLT, чтобы указать, какую тему вы хотите. То, как это делается, во многом зависит от того, какой процессор вы используете, но в вашем XSLT вам понадобится следующая строка:
<xsl:param name="topic" select="'1'"/>
(1 здесь является параметром по умолчанию)
Затем, чтобы получить все соответствующие разделы для параметра, это просто случай выполнения следующего:
<xsl:apply-templates select="//topic[@no=$topic][references/book != '']"/>
При этом также будут игнорироваться темы, на которые нет ссылок.
Итак, учитывая следующий XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name="topic" select="'1'"/>
<xsl:template match="/">
<xsl:if test="//topic[@no=$topic][references/book != '']">
<table>
<tr>
<td>Book</td>
<td>Chapter</td>
</tr>
<xsl:apply-templates select="//topic[@no=$topic][references/book != '']"/>
</table>
</xsl:if>
</xsl:template>
<xsl:template match="topic">
<xsl:apply-templates select="references"/>
</xsl:template>
<xsl:template match="references">
<xsl:apply-templates select="book"/>
</xsl:template>
<xsl:template match="book">
<tr>
<td>
<xsl:value-of select="."/>
</td>
<td>
<xsl:value-of select="following-sibling::chapter[1]"/>
</td>
</tr>
</xsl:template>
</xsl:stylesheet>
При применении к следующему входному XML
<topics>
<topic no="1">
<desc>......</desc>
<references>
<book>XSLT Essentials</book>
<chapter>11</chapter>
<book>XSLT Cookbook</book>
<chapter>10</chapter>
</references>
</topic>
<topic no="2">
<desc>......</desc>
<references>
<book>Javascript in 10 mins</book>
<chapter>11</chapter>
</references>
</topic>
<topic no="3">
<desc>......</desc>
<references>
<book/>
<chapter/>
</references>
</topic>
</topics>
Выводится следующее
<table>
<tr>
<td>Book</td>
<td>Chapter</td>
</tr>
<tr>
<td>XSLT Essentials</td>
<td>11</td>
</tr>
<tr>
<td>XSLT Cookbook</td>
<td>10</td>
</tr>
</table>
Когда параметр изменяется на 2, выводится следующее:
<table>
<tr>
<td>Book</td>
<td>Chapter</td>
</tr>
<tr>
<td>Javascript in 10 mins</td>
<td>11</td>
</tr>
</table>
Когда параметр изменяется на 3, ничего не выводится.
Комментарии:
1. Тим — Большое спасибо. Я думаю, что было бы легко и эффективно добавить атрибут со значением Y или N в
<references>
тег вместо<topic>
тега.
Ответ №3:
Сделайте это так:
<xsl:template match="content">
<xsl:apply-templates select="references" />
</xsl:template>
<xsl:template match="references">
<xsl:if test="book != '']">
<table>
<tr><td>Book</td><td>Chapter</td></tr>
<xsl:apply-templates select="book" />
</table>
</xsl:if>
</xsl:template>
<xsl:template match="book">
<tr><td><xsl:value-of select="." /></td><td><xsl:value-of select="following-sibling::chapter[1]" /></td></tr>
</xsl:template>
протестировано, и это работает 😉
Комментарии:
1. Я использовал
//following-sibling::*
вместо того, что вы дали… Теперь работает в соответствии с моими потребностями… Большое спасибо … 🙂2. @kim — Это работает, но только тогда, когда используются ссылки. Если у меня нет ссылок, тогда рисуйте таблицу… пожалуйста, прочитайте мой вопрос еще раз и посмотрите, что я написал жирным шрифтом .. 🙂