XML - XSLT - специальные символы Escape - PullRequest
0 голосов
/ 06 июля 2018

этот вопрос связан с другим вопросом, который я опубликовал и до сих пор пытаюсь выяснить, здесь: XML - XSLT - Использование двух файлов XML - Дополнения к файлу XML, обращающиеся к другому файлу XML , но поскольку это Проще говоря, я решил сделать новый пост об этом, чтобы сделать эту проблему более «читабельной» и полезной для будущих читателей этого поста,

У меня есть следующий XML-файл:

<?xml version="1.0" encoding="UTF-8"?>
<entry>
    <text-prop name="content"><![CDATA[<value-of>new Date()</value-of>]]></text-prop>
</entry>

И я просто выполняю простой метод преобразования идентификаторов с помощью XSLT:

   <xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <xsl:output method="xml" omit-xml-declaration="no" indent="yes" encoding="utf-8"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="@*|node()">
       <xsl:copy>
         <xsl:apply-templates select="@*|node()"/>
       </xsl:copy>
    </xsl:template>

   </xsl:stylesheet>

Но я получаю вывод:

<?xml version="1.0" encoding="utf-8"?>
<entry>
   <text-prop name="content">&lt;value-of&gt;new Date()&lt;/value-of&gt;</text-prop>
</entry>

Но я хочу, чтобы выходной XML был точно таким же, как входной XML

<?xml version="1.0" encoding="UTF-8"?>
    <entry>
       <text-prop name="content"><![CDATA[<value-of>new Date()</value-of>]]> </text-prop>
    </entry>

Есть ли простой способ сделать это, и, возможно, избежать всех возможных специальных символов в XML?

Я использую Saxon 9.8, поэтому я могу использовать последнюю версию XSLT, которая, как мне кажется, 3.0,

Спасибо!

Александр Хасинто

EDIT

Мне удается убежать от персонажей, используя cdata-section-elements, например:

 <xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <xsl:output method="xml" omit-xml-declaration="no" indent="yes" encoding="utf-8" cdata-section-elements="text-prop"/>
    <xsl:strip-space elements="*"/>

  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

Но когда я пытаюсь сделать это с другим входом, который я использую в своем посте, на который я ссылался ранее, это:

<?xml version="1.0" encoding="UTF-8"?>
<report xmlns="http://www.eclipse.org/birt/2005/design" version="3.2.23" id="1">
    <text-prop name="displayName">PersonTemplate</text-prop>
    <setup>
        <simple-master-page name="MasterPage" id="2">
            <footer>
                <text id="3">
                    <prop name="contentType">html</prop>
                    <text-prop name="content"><![CDATA[<value-of>new Date()</value-of>]]></text-prop>
                </text>
            </footer>
        </simple-master-page>
    </setup>
    <body>
        <table id="4">  
            <column id="17"/>
            <column id="18"/>
            <column id="19"/>
            <header>
                <row id="5">
                    <cell id="6">
                        <label id="20">
                            <text-prop name="text">NameTitle</text-prop>
                        </label>
                    </cell>
                    <cell id="7">
                        <label id="21">
                            <text-prop name="text">CityTitle</text-prop>
                        </label>
                    </cell>
                    <cell id="8">
                        <label id="22">
                            <text-prop name="text">AgeTitle</text-prop>
                        </label>
                    </cell>
                </row>
            </header>
            <detail>
                <row id="9">
                    <cell id="10"/>
                    <cell id="11"/>
                    <cell id="12"/>
                </row>
            </detail>
        </table>
    </body>
</report>

Экранирование не работает, поэтому я получаю это:

<?xml version="1.0" encoding="utf-8"?>
<report xmlns="http://www.eclipse.org/birt/2005/design" version="3.2.23" id="1">
   <text-prop name="displayName">PersonTemplate</text-prop>
   <setup>
      <simple-master-page name="MasterPage" id="2">
         <footer>
            <text id="3">
               <prop name="contentType">html</prop>
               <text-prop name="content">&lt;value-of&gt;new Date()&lt;/value-of&gt;</text-prop>
            </text>
         </footer>
      </simple-master-page>
   </setup>
   <body>
      <table id="4">
         <column id="17"/>
         <column id="18"/>
         <column id="19"/>
         <header>
            <row id="5">
               <cell id="6">
                  <label id="20">
                     <text-prop name="text">NameTitle</text-prop>
                  </label>
               </cell>
               <cell id="7">
                  <label id="21">
                     <text-prop name="text">CityTitle</text-prop>
                  </label>
               </cell>
               <cell id="8">
                  <label id="22">
                     <text-prop name="text">AgeTitle</text-prop>
                  </label>
               </cell>
            </row>
         </header>
         <detail>
            <row id="9">
               <cell id="10"/>
               <cell id="11"/>
               <cell id="12"/>
            </row>
         </detail>
      </table>
   </body>
</report>

Как видите, символ < продолжает печататься как &lt;, например,

Я просто не понимаю, почему он работает с первым и более простым входным XML, но не работает со вторым,

Как я могу решить это?

Спасибо!

EDIT

Я применил этот XSLT-код:

    <xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                              xmlns:xmlbirtns="http://www.eclipse.org/birt/2005/design">
    <xsl:output method="xml" omit-xml-declaration="no" indent="yes" encoding="utf-8" cdata-section-elements="xmlbirtns:text-prop"/>
    <xsl:strip-space elements="*"/>

  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

объявление пространства имен, используемого входным XML в файле XSLT,

Я правильно понял <CDATA>, но теперь, поскольку у меня больше элементов <text-prop>, вывод идет с тегами <CDATA> в каждом элементе <text-prop>, например:

<?xml version="1.0" encoding="utf-8"?>
<report xmlns="http://www.eclipse.org/birt/2005/design" version="3.2.23" id="1">
   <text-prop name="displayName"><![CDATA[PersonTemplate]]></text-prop>
   <setup>
      <simple-master-page name="MasterPage" id="2">
         <footer>
            <text id="3">
               <prop name="contentType">html</prop>
               <text-prop name="content"><![CDATA[<value-of>new Date()</value-of>]]></text-prop>
            </text>
         </footer>
      </simple-master-page>
   </setup>
   <body>
      <table id="4">
         <column id="17"/>
         <column id="18"/>
         <column id="19"/>
         <header>
            <row id="5">
               <cell id="6">
                  <label id="20">
                     <text-prop name="text"><![CDATA[NameTitle]]></text-prop>
                  </label>
               </cell>
               <cell id="7">
                  <label id="21">
                     <text-prop name="text"><![CDATA[CityTitle]]></text-prop>
                  </label>
               </cell>
               <cell id="8">
                  <label id="22">
                     <text-prop name="text"><![CDATA[AgeTitle]]></text-prop>
                  </label>
               </cell>
            </row>
         </header>
         <detail>
            <row id="9">
               <cell id="10"/>
               <cell id="11"/>
               <cell id="12"/>
            </row>
         </detail>
      </table>
   </body>
</report>

настаивает на получении выходного XML, как я хочу, это точно так же, как входной XML

Я знаю, что, вероятно, не могу использовать атрибут cdata-section-elements xsl:output.

ПРИМЕЧАНИЕ: У меня есть только один элемент <text-prop> со значением внутри него во входном XML, все остальные имеют нормальный текст внутри него.

Ответы [ 2 ]

0 голосов
/ 06 июля 2018

Во-первых, CDATA не является частью модели данных XDM, считается, что это просто альтернативный способ экранирования специальных символов: две формы

<X><![CDATA[<>]]></X>

и

<X>&lt;&gt;</X>

считаются полностью взаимозаменяемыми.

Это означает, что ваша таблица стилей не может отличить, какой из двух использовался при вводе: нет способа узнать.

Свойство cdata-section-elements в xsl: output дает вам некоторый контроль над тем, какая форма используется на выходе, но, как вы обнаружили, оно не дает вам полного контроля.

Вы можете получить больше контроля, используя отключение-выход-экранирование, или карты персонажей, или утилиту Эндрю Уэлча lexev, но все эти обходные пути напрашиваются над вопросом, почему это так важно? Если кто-то рассматривает полученный документ по-разному, в зависимости от того, использует он CDATA или нет, он неправильно использует XML и нуждается в переобучении.

0 голосов
/ 06 июля 2018

Поскольку XSLT всегда сначала соответствует наиболее точному шаблону, вы можете просто сопоставить setup / text-prop и создать блок CDATA специально для этой части. Затем, в зависимости от XML, вы можете использовать apply-templates для продолжения сопоставления с другими элементами.

Вероятно, это будет выглядеть примерно так:

 <xsl:template match="setup/text-prop">
  <xsl:copy>
    <setup>
      <text-prop>
         <xsl:text disable-output-escaping="yes">&lt;![CDATA[</xsl:text>
         <xsl:value-of>whatever</xsl:value-of>
         <xsl:text disable-output-escaping="yes">]]&gt;</xsl:text>
      </text-prop>
    </setup>
   <xsl:copy>
   <xsl:apply-templates/>
  </xsl:template>
...