Мне нужно было выполнить ту же задачу. Я решил это с двумя 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: .]]>
</well-formed-content>
</root>
Рис 6.- Добавлена символьная сущность
в 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: .
</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="/"
добавляет сущность
):
<?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 " ">
]>
]]>
</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 " ">
]>
<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: .
</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. У меня такое ощущение, что это должно быть еще проще ...