Преобразование XML в экранированный текст в XSLT

Другое событие NullPointerException возникает, когда объявляется массив объектов, а затем сразу же пытается разыменовать его внутри.

String[] phrases = new String[10];
String keyPhrase = "Bird";
for(String phrase : phrases) {
    System.out.println(phrase.equals(keyPhrase));
}

Этот конкретный NPE можно избежать, если порядок сравнения отменяется ; а именно, использовать .equals для гарантированного непустого объекта.

Все элементы внутри массива инициализируются их общим начальным значением ; для любого типа массива объектов, это означает, что все элементы null.

Вы должны инициализировать элементы в массиве перед доступом или разыменованием их.

String[] phrases = new String[] {"The bird", "A bird", "My bird", "Bird"};
String keyPhrase = "Bird";
for(String phrase : phrases) {
    System.out.println(phrase.equals(keyPhrase));
}

25
задан Frank Liao 22 July 2009 в 00:02
поделиться

6 ответов

Ваш код работает так, как он работает, потому что xsl: value-of извлекает строковое значение набора узлов.

Боюсь, что для того, чтобы делать то, что вы хотите, вам придется явно кодировать его:

    <xsl:template match="/">
        <TestElement>
            <xsl:apply-templates mode="escape"/>
        </TestElement>
    </xsl:template>

    <xsl:template match="*" mode="escape">
        <!-- Begin opening tag -->
        <xsl:text>&lt;</xsl:text>
        <xsl:value-of select="name()"/>

        <!-- Namespaces -->
        <xsl:for-each select="namespace::*">
            <xsl:text> xmlns</xsl:text>
            <xsl:if test="name() != ''">
                <xsl:text>:</xsl:text>
                <xsl:value-of select="name()"/>
            </xsl:if>
            <xsl:text>='</xsl:text>
            <xsl:call-template name="escape-xml">
                <xsl:with-param name="text" select="."/>
            </xsl:call-template>
            <xsl:text>'</xsl:text>
        </xsl:for-each>

        <!-- Attributes -->
        <xsl:for-each select="@*">
            <xsl:text> </xsl:text>
            <xsl:value-of select="name()"/>
            <xsl:text>='</xsl:text>
            <xsl:call-template name="escape-xml">
                <xsl:with-param name="text" select="."/>
            </xsl:call-template>
            <xsl:text>'</xsl:text>
        </xsl:for-each>

        <!-- End opening tag -->
        <xsl:text>&gt;</xsl:text>

        <!-- Content (child elements, text nodes, and PIs) -->
        <xsl:apply-templates select="node()" mode="escape" />

        <!-- Closing tag -->
        <xsl:text>&lt;/</xsl:text>
        <xsl:value-of select="name()"/>
        <xsl:text>&gt;</xsl:text>
    </xsl:template>

    <xsl:template match="text()" mode="escape">
        <xsl:call-template name="escape-xml">
            <xsl:with-param name="text" select="."/>
        </xsl:call-template>
    </xsl:template>

    <xsl:template match="processing-instruction()" mode="escape">
        <xsl:text>&lt;?</xsl:text>
        <xsl:value-of select="name()"/>
        <xsl:text> </xsl:text>
        <xsl:call-template name="escape-xml">
            <xsl:with-param name="text" select="."/>
        </xsl:call-template>
        <xsl:text>?&gt;</xsl:text>
    </xsl:template>

    <xsl:template name="escape-xml">
        <xsl:param name="text"/>
        <xsl:if test="$text != ''">
            <xsl:variable name="head" select="substring($text, 1, 1)"/>
            <xsl:variable name="tail" select="substring($text, 2)"/>
            <xsl:choose>
                <xsl:when test="$head = '&amp;'">&amp;amp;</xsl:when>
                <xsl:when test="$head = '&lt;'">&amp;lt;</xsl:when>
                <xsl:when test="$head = '&gt;'">&amp;gt;</xsl:when>
                <xsl:when test="$head = '&quot;'">&amp;quot;</xsl:when>
                <xsl:when test="$head = &quot;&apos;&quot;">&amp;apos;</xsl:when>
                <xsl:otherwise><xsl:value-of select="$head"/></xsl:otherwise>
            </xsl:choose>
            <xsl:call-template name="escape-xml">
                <xsl:with-param name="text" select="$tail"/>
            </xsl:call-template>
        </xsl:if>
    </xsl:template>

Обратите внимание, что это решение игнорирует узлы комментариев и вставляет ненужные узлы пространства имен (как namespace :: ось будет включать все узлы, унаследованные от родителя). Однако что касается пространств имен, полученный в результате цитируемый XML будет семантически эквивалентен примеру, который вы указали в своем ответе (поскольку эти повторяющиеся повторные объявления на самом деле ничего не меняют).

Кроме того, это не ускользнет от объявления просто потому, что оно отсутствует в модели данных XPath 1.0 (это не инструкция обработки). Если он вам действительно нужен в выводе, вам придется вставить его вручную (и убедитесь, что указанная в нем кодировка соответствует кодировке сериализации вашего процессора XSLT).

37
ответ дан 28 November 2019 в 06:40
поделиться

Вам нужен для использования XSLT? Потому что по причинам, которые объяснил Павел Минаев, было бы намного проще использовать другой инструмент. Пример с xmlstartlet :

% xmlstarlet escape
<?xml version="1.0" encoding="utf-8"?>
<abc>
  <def ghi="jkl">
    mnop
  </def>
</abc>
[Control-D]
&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;abc&gt;
  &lt;def ghi="jkl"&gt;
    mnop
  &lt;/def&gt;
&lt;/abc&gt;
0
ответ дан 28 November 2019 в 06:40
поделиться

Если у вас есть к нему доступ, я бы порекомендовал расширение Saxon serialize . Он делает именно то, что вы хотите. Если вы не хотите этого делать, вам придется вручную вставлять ссылки на сущности при создании документа. Это было бы непросто, но сработало бы для большинства документов:

<xsl:template match="/">
    <TestElement>
        <xsl:apply-templates/>
    </TestElement>
</xsl:template>
<xsl:template match="*">
    <xsl:text>&lt;</xsl:text>
    <xsl:value-of select="name()"/>
    <xsl:apply-templates select="@*"/>
    <xsl:text>&gt;</xsl:text>
    <xsl:apply-templates select="node()"/>
    <xsl:text>&lt;/</xsl:text>
    <xsl:value-of select="name()"/>
    <xsl:text>&gt;</xsl:text>
</xsl:template>
<xsl:template match="@*">
    <xsl:text>&#32;</xsl:text>
    <xsl:value-of select="name()"/>
    <xsl:text>="</xsl:text>
    <xsl:value-of select="."/>
    <xsl:text>"</xsl:text>
</xsl:template>
<xsl:template match="text()">
    <xsl:value-of select="."/>
</xsl:template>

В частности, это, вероятно, сломается, если ваши атрибуты содержат символ двойных кавычек. На самом деле лучше использовать saxon или написанное пользователем расширение, которое использует правильный сериализатор, если вы не можете.

0
ответ дан 28 November 2019 в 06:40
поделиться

Почему вы не можете просто запустить

<xsl:template match="/">
  <TestElement>
  <xsl:copy-of select="." />
  </TestElement>
</xsl:template>
-1
ответ дан 28 November 2019 в 06:40
поделиться

вместо экранирования вы можете добавить текст внутри раздела CDATA. Текст внутри раздела CDATA будет проигнорирован синтаксическим анализатором, как если бы он был экранирован.

ваш пример будет выглядеть так

<TestElement>
<![CDATA[
<abc>
  <def ghi="jkl">
    mnop
  </def>
</abc>
]]>
</TestElement>

, используя следующий фрагмент XSLT:

<xsl:text disable-output-escaping="yes">&lt;![CDATA[</xsl:text>
 <xsl:copy-of select="/"/>
 <xsl:text disable-output-escaping="yes">]]</xsl:text>
 <xsl:text disable-output-escaping="yes">&gt;</xsl:text>
17
ответ дан 28 November 2019 в 06:40
поделиться

Любого, кого беспокоит двусмысленность лицензирования при повторном использовании фрагментов кода из stack overflow, может заинтересовать следующий код с BSD-лицензией в 3 пунктах, который, похоже, делает то, о чем просил оригинальный постер:

http://lenzconsulting.com/xml-to-string/

4
ответ дан 28 November 2019 в 06:40
поделиться
Другие вопросы по тегам:

Похожие вопросы: