Как вывести <ul>и <li>элементы из XML в XSL? - PullRequest
0 голосов
/ 09 июня 2019

У меня есть несколько неупорядоченных списков в файле XML, которые мне нужно преобразовать в HTML с файлом XSL.Эти списки внутри моего XML выглядят следующим образом:

<Food>
   <FoodItem ID="1">
      <Content><![CDATA[<ul><li>Apples</li><li>Pears</li><li>Oranges</li><ul>]]></Content>
   </FoodItem>
</Food>

Я хотел бы получить неупорядоченные списки из файла XML и вывести их в свой XSL-файл, как, например, чтобы я мог их стилизовать с помощью CSS.Результат должен выглядеть примерно так:

<div class="food">
    <ul class="fooditems">
        <li class="fooditem">Apples</li>
        <li class="fooditem">Pears</li>
        <li class="fooditem">Oranges</li>
    </ul>
</div>

Однако <xsl:value-of select="key('fooditem', 1)/Content дал мне только строку <ul><li>Apples</li><li>Pears</li><li>Oranges</li></ul>.

Ключ определен как <xsl:key name="fooditem" match="FoodItem" use="@ID" />.

Как я могу получить отдельные теги списка, включая их содержимое, из тега <![CDATA[]]>?

Ответы [ 2 ]

1 голос
/ 09 июня 2019

Прежде всего, элементы ul / li - это не узлы во входном XML, а экранированная разметка в разделе CDATA. Таким образом, вам нужно будет проанализировать эту разметку, прежде чем можно будет преобразовывать узлы. С XSLT 3 (как поддерживается Saxon 9.8 и более поздними версиями или AltovaXML 2017 и более поздними версиями) вы можете использовать функцию parse-xml или parse-xml-fragment XPath 3 для анализа строки с документом XML или фрагмента XML на узлы.

Однако, по крайней мере, в примере вашего вопроса, экранированная разметка не является правильно сформированным XML, поскольку у него нет правильно закрытого ul элемента, это <ul><li>Apples</li><li>Pears</li><li>Oranges</li><ul>, где он должен быть <ul><li>Apples</li><li>Pears</li><li>Oranges</li></ul>, чтобы быть анализируемым как XML.

Таким образом, в зависимости от реального образца, если он правильно сформирован, вы можете использовать

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="#all"
    version="3.0">

  <xsl:mode on-no-match="shallow-copy"/>

  <xsl:output method="html" indent="yes" html-version="5"/>

  <xsl:template match="FoodItem">
      <div class="food">
          <xsl:apply-templates select="parse-xml-fragment(Content)/node()" mode="food"/>
      </div>
  </xsl:template>

  <xsl:mode name="food" on-no-match="shallow-copy"/>

  <xsl:template match="ul" mode="food">
      <ul class="fooditems">
          <xsl:apply-templates select="@* , node()" mode="#current"/>
      </ul>
  </xsl:template> 

  <xsl:template match="li" mode="food">
      <li class="fooditem">
          <xsl:apply-templates select="@* , node()" mode="#current"/>
      </li>
  </xsl:template>

</xsl:stylesheet>

как показано в https://xsltfiddle.liberty -development.net / 3NJ38ZH / 1 и получите желаемый результат

   <div class="food">
      <ul class="fooditems">
         <li class="fooditem">Apples</li>
         <li class="fooditem">Pears</li>
         <li class="fooditem">Oranges</li>
      </ul>
   </div>
1 голос
/ 09 июня 2019

Как получить из списка теги отдельных списков, включая их содержимое?

Для решения XSLT-1.0 вы должны использовать двухэтапный подход:

  1. Получите предметы из раздела CDATA.
  2. Примените шаблоны, которые вы хотите применить.

Одна проблема состоит в том, что образец CDATA не является правильно сформированным XML. Таким образом, вы должны изменить свой входной XML (изменив последний <ul> на </ul>) на следующее:

<Food>
   <FoodItem ID="1">
      <Content><![CDATA[<ul><li>Apples</li><li>Pears</li><li>Oranges</li></ul>]]></Content>
   </FoodItem>
</Food>

Для первого шага вы можете использовать это (при условии, что ваш процессор XSLT поддерживает атрибут disable-output-escaping ):

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

    <!-- Identity template -->
    <xsl:template match="node()[not(self::text())]|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>    

    <xsl:template match="text()">            
        <xsl:value-of select="." disable-output-escaping="yes" />
    </xsl:template>

</xsl:stylesheet>

Теперь вы можете применить свой шаблон XSLT к выходным данным вышеуказанной таблицы стилей.

Результат этого преобразования должен быть:

<?xml version="1.0" encoding="UTF-8"?>  
<Food>
    <FoodItem ID="1">
        <Content>
            <ul>
                <li>Apples</li>
                <li>Pears</li>
                <li>Oranges</li>
            <ul>
        </Content>
    </FoodItem>
</Food>

Теперь вторым шагом является применение другой таблицы стилей XSLT-1.0 к этому выводу.
Поэтому примените эту вторую таблицу стилей XSLT-1.0:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

    <xsl:template match="/Food/FoodItem/Content/ul">    
        <div class="food">
            <ul class="fooditems">
                <xsl:apply-templates select="*" />
            </ul>
        </div>
    </xsl:template>

    <xsl:template match="li"> 
        <li class="fooditem"><xsl:value-of select="." /></li>
    </xsl:template>

</xsl:stylesheet>

Результат этого второго шага:

<div class="food">
    <ul class="fooditems">
        <li class="fooditem">Apples</li>
        <li class="fooditem">Pears</li>
        <li class="fooditem">Oranges</li>
    </ul>
</div>

по желанию.

РЕШИТЬ!


В более новых версиях процессоров XSLT (3.0 и выше) вы можете (возможно) выполнить оба шага в одной таблице стилей.

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