Java: удалить тег cdata из XML - PullRequest
7 голосов
/ 27 июля 2011

xpath удобен для анализа XML-файлов, но он не работает для данных внутри тега cdata:

<![CDATA[ Some Text <p>more text and tags</p>... ]]>

Мое решение: сначала получите содержимое xml и удалите

"<![CDATA["  and  "]]>".

После этого я запускаю xpath «чтобы достичь всего» из файла xml. Есть ли лучшее решение? Если нет, то как я могу сделать это с помощью регулярного выражения?

Ответы [ 5 ]

2 голосов
/ 27 июля 2011

Причина тегов CDATA в том, что внутри них есть чистый текст , ничего, что следует интерпретировать непосредственно как XML. Вы можете написать свой фрагмент документа в вопросе как

 Some Text &lt;p&gt;more text and tags&lt;/p&gt;... 

(с пробелом в начале и в конце).

Если вы действительно хотите интерпретировать это как XML, извлеките текст из документа и снова отправьте его в анализатор XML.

1 голос
/ 20 августа 2012

Чтобы вырезать CDATA и сохранить теги как теги, вы можете использовать XSLT.

Учитывая этот ввод XML:

<?xml version="1.0" encoding="ISO-8859-1"?>
<root>
    <child>Here is some text.</child>
    <child><![CDATA[Here is more text <p>with tags</p>.]]></child>
</root>

Используя этоXSLT:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs"
    version="2.0">

    <xsl:output method="xml" indent="yes"/>
    <xsl:strip-space elements="*"/>

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

</xsl:stylesheet>

Вернет следующий XML:

<?xml version="1.0" encoding="UTF-8"?>
<root>
   <child>Here is some text.</child>
   <child>Here is more text <p>with tags</p>.</child>
</root>

(протестировано с Saxon HE 9.3.0.5 в oXygen 12.2)

Тогда вы могли бы использовать xPath для извлечения содержимого элемента p:

/root/child/p
1 голос
/ 15 июня 2012

Мне нужно было выполнить ту же задачу. Я решил это с двумя xslt.

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

Для полноты позвольте мне добавить в ваш пример xml корневой элемент:

<root>
   <well-formed-content><![CDATA[ Some Text <p>more text and tags</p>]]>
   </well-formed-content>
</root>

Рис 1.- Запуск xml

<Ч />

Первый шаг

На первом шаге преобразования я обернул все текстовые узлы в новую введенную сущность xml old_text:

<?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" indent="no" version="1.0"
    encoding="UTF-8" standalone="yes" />

    <xsl:template match="*">
        <xsl:copy>
            <xsl:apply-templates select="*|text()|@*|comment()|processing-instruction()" />
        </xsl:copy>
    </xsl:template>

    <!-- Attribute-nodes and comment-nodes: Pass through without modifying -->
    <xsl:template match="@*|comment()|processing-instruction()">
        <xsl:copy-of select="." />
    </xsl:template>

    <!-- Text-nodes: Wrap them in a new node without escaping it. -->
    <!-- (note precondition: CDATA should be valid xml.           -->
    <xsl:template match="text()">
        <xsl:element name="old_text">
            <xsl:value-of select="." disable-output-escaping="yes" />
        </xsl:element>
    </xsl:template>

</xsl:stylesheet>

Рис 2.- Первый xslt (упаковка CDATA в элементы "old_text")

Если вы примените это преобразование к исходному xml, это то, что вы получите (я не переформатирую его, чтобы избежать путаницы относительно того, кто что делает):

<?xml version="1.0" encoding="UTF-8" standalone="yes"?><root><old_text>
    </old_text><well-formed-content><old_text> Some Text <p>more text and tags</p>
    </old_text></well-formed-content><old_text>
</old_text></root>

Рис. 3. Преобразованный xml (первый шаг)

<Ч />

Второй шаг

Теперь вам нужно очистить введенные элементы old_text и повторно экранировать текст, который не создал новые узлы:

<?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" indent="no" version="1.0"
    encoding="UTF-8" standalone="yes" />

    <!-- Element-nodes: Process nodes and their children -->
    <xsl:template match="*">
        <xsl:copy>
            <xsl:apply-templates select="*|text()|@*|comment()" />
        </xsl:copy>
    </xsl:template>

    <!-- Attribute-nodes and comment-nodes: Pass through without modifying -->
    <xsl:template match="@*|comment()">
        <xsl:copy-of select="." />
    </xsl:template>

    <!--
        'Wrapper'-node: remove the wrapper element but process its children.
        With this matcher, the "old_text" is cleaned, but the originally CDATA
        well-formed nodes surface in the resulting xml.
    -->
    <xsl:template match="old_text">
        <xsl:apply-templates select="*|text()" />
    </xsl:template>

    <!--
        Text-nodes: Text here comes from original CDATA and must be now
        escaped. Note that the previous rule has extracted all the existing
        nodes in the CDATA. -->
    <xsl:template match="text()">
        <xsl:value-of select="." disable-output-escaping="no" />
    </xsl:template>

</xsl:stylesheet>

Рис. 4.- 2-й xslt (очищенные искусственно введенные элементы)

<Ч />

Результат

Это конечный результат с узлами, которые изначально были в CDATA, расширены в вашем новом XML-файле:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?><root>
    <well-formed-content> Some Text <p>more text and tags</p>
    </well-formed-content>
</root>

Рис 5.- Конечный xml

<Ч />

* Оговорка * тысяча пятьдесят-один Если ваш CDATA содержит символьные сущности html, не поддерживаемые в xml (посмотрите примеры в этой статье wikipedia о символьных сущностях ), вам необходимо добавить эти ссылки в промежуточный xml. Позвольте мне показать это на примере: <root> <well-formed-content> <![CDATA[ Some Text <p>more text and tags</p>, now with a non-breaking-space before the stop:&nbsp;.]]> </well-formed-content> </root> Рис 6.- Добавлена ​​символьная сущность &nbsp; в xml на Рис. 1 Исходный xslt из Рис 2 преобразует xml в это: <?xml version="1.0" encoding="UTF-8" standalone="yes"?><root><old_text> </old_text><well-formed-content><old_text> Some Text <p>more text and tags</p>, now with a non-breaking-space before the stop:&nbsp;. </old_text></well-formed-content><old_text> </old_text></root> Рис. 7. Результат первой попытки преобразования xml на Рис. 6 (Не правильно сформирован!) Проблема с этим файлом в том, что он плохо сформирован и, следовательно, не может быть обработан с помощью XSLT-процессора: The entity "nbsp" was referenced, but not declared. XML checking finished. Рис. 8. Результат проверки правильности формы для xml на Рис. 7 Этот обходной путь помогает (шаблон match="/" добавляет сущность &nbsp;): <?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" indent="no" version="1.0" encoding="UTF-8" standalone="yes" /> <!-- Add an html entity to the xml character entities declaration. --> <xsl:template match="/"> <xsl:text disable-output-escaping="yes"><![CDATA[<!DOCTYPE root [ <!ENTITY nbsp "&#160;"> ]> ]]> </xsl:text> <xsl:apply-templates select="*" /> </xsl:template> <xsl:template match="*"> <xsl:copy> <xsl:apply-templates select="*|text()|@*|comment()|processing-instruction()" /> </xsl:copy> </xsl:template> <!-- Attribute-nodes and comment-nodes: Pass through without modifying --> <xsl:template match="@*|comment()|processing-instruction()"> <xsl:copy-of select="." /> </xsl:template> <!-- Text-nodes: Wrap them in a new node without escaping it. --> <!-- (note precondition: CDATA should be valid xml. --> <xsl:template match="text()"> <xsl:element name="old_text"> <xsl:value-of select="." disable-output-escaping="yes" /> </xsl:element> </xsl:template> </xsl:stylesheet> Рис. 9. xslt создает объявление объекта Теперь, после применения этого xslt к Fig 6 source xml, это промежуточный xml: <?xml version="1.0" encoding="UTF-8" standalone="yes"?><!DOCTYPE root [ <!ENTITY nbsp "&#160;"> ]> <root><old_text> </old_text><well-formed-content><old_text> Some Text <p>more text and tags</p>, now with a non-breaking-space before the stop:&nbsp;. </old_text></well-formed-content><old_text> </old_text></root> Рис. 10.- Промежуточный xml (xml из рис. 3 плюс объявление объекта) Вы можете использовать преобразование xslt из Рис. 4 , чтобы получить окончательный XML: <?xml version="1.0" encoding="UTF-8" standalone="yes"?><root> <well-formed-content> Some Text <p>more text and tags</p>, now with a non-breaking-space before the stop: . </well-formed-content> </root> Рис. 11.- Конечный xml с HTML-энтитами, преобразованными в UTF-8 <Ч /> Примечания В этих примерах я использовал встроенный XSLT-процессор NetBeans 7.1.2 (com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl - default JRE XSLT processor) Отказ от ответственности: я не эксперт по XML. У меня такое ощущение, что это должно быть еще проще ...

0 голосов
/ 24 ноября 2016

Попробуйте это:

public static removeCDATA (String text) {
    String resultString = "";
    Pattern regex = Pattern.compile("(?<!(<!\\[CDATA\\[))|((.*)\\w+\\W)");
    Matcher regexMatcher = regex.matcher(text);
    while (regexMatcher.find()) {
        resultString += regexMatcher.group();
    }
    return resultString;
}

Когда я вызываю этот метод с вашим тестовым вводом <![CDATA[ Some Text <p>more text and tags</p>... ]]> метод return Some Text <p>more text and tags</p>

Но я думаю, что этот метод без регулярных выражений будет более надежным,Как то так:

public static removeCDATA (String text) {
    s = s.trim();
    if (s.startsWith("<![CDATA[")) {
        s = s.substring(9);
        int i = s.indexOf("]]>");
        if (i == -1) throw new IllegalStateException("argument starts with <![CDATA[ but cannot find pairing ]]>");
        s = s.substring(0, i);
    }
    return s;
}
0 голосов
/ 22 марта 2016

Определенно вы можете удалить cdata из xml, используя регулярное выражение для удаления желаемого содержимого из вашего xml.

например:

String s = "<sn><![CDATA[poctest]]></sn>";
s = s.replaceAll("!\\[CDATA", "");
s = s.replaceAll("]]", "");
s = s.replaceAll("\\[", "");        

Результат будет:

<sn><poctest></sn>

Пожалуйста, проверьте, решает ли это вашу проблему.

...