问题
this question is related to another question I posted and still am trying to figure out, here: XML - XSLT - Using two XML files - Additions to XML file consulting another XML file, but since this is a simplier problem, I decided to make a new post about it, to make this problem more "readable" and usefull for future readers of this post,
I have the following XML file:
<?xml version="1.0" encoding="UTF-8"?>
<entry>
<text-prop name="content"><![CDATA[<value-of>new Date()</value-of>]]></text-prop>
</entry>
And I'm just performing the simple identity transform method with the 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>
But I'm getting the output:
<?xml version="1.0" encoding="utf-8"?>
<entry>
<text-prop name="content"><value-of>new Date()</value-of></text-prop>
</entry>
But I want the output XML to be exactly like the input XML
<?xml version="1.0" encoding="UTF-8"?>
<entry>
<text-prop name="content"><![CDATA[<value-of>new Date()</value-of>]]> </text-prop>
</entry>
Is there a simple way of doing this, and maybe that escapes all possible special characters in the XML?
I'm using Saxon 9.8 so I can use the latest version of XSLT, that I think is 3.0,
Thanks!
Alexandre Jacinto
EDIT
I manage to escape the characters using the cdata-section-elements
like this:
<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>
But when I try it with a different input, the one I use in my post that I referenced before, this:
<?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>
The escaping does not work, so I get this:
<?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"><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>
As you can see the <
character continues to be printed as <
, for example,
I just don't understand why it works with the first and simpler input XML but doesn't work with the second one,
How can I solve this?
Thanks!
EDIT
I applied this XSLT code:
<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>
declaring the namespace that the input XML uses in the XSLT file,
I am getting the <CDATA>
right, but now, because I have more <text-prop>
elements, the output is coming with <CDATA>
tags in every <text-prop>
element, like this:
<?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>
insted of getting the output XML like I want it, that is exactly the same as the input XML
I know I probably cant use the cdata-section-elements
attribute of the xsl:output
.
NOTE: I only have one <text-prop>
element with value inside it in my input XML, all the others have normal text inside it.
回答1:
As XSLT always matches the most accurate template first you can just match setup/text-prop and create a CDATA block for this part specifically. Then depending on the XML, you can use apply-templates to continue matching the other elements.
It will probably look something like this:
<xsl:template match="setup/text-prop">
<xsl:copy>
<setup>
<text-prop>
<xsl:text disable-output-escaping="yes"><![CDATA[</xsl:text>
<xsl:value-of>whatever</xsl:value-of>
<xsl:text disable-output-escaping="yes">]]></xsl:text>
</text-prop>
</setup>
<xsl:copy>
<xsl:apply-templates/>
</xsl:template>
回答2:
Firstly, CDATA is not part of the XDM data model, it is considered to be purely a alternative way of escaping special characters: the two forms
<X><![CDATA[<>]]></X>
and
<X><></X>
are considered to be completely interchangeable.
This means your stylesheet can't distinguish which of the two was used on input: there is no way of knowing.
The cdata-section-elements property on xsl:output gives you some control over which form is used on output, but as you have discovered, it doesn't give you total control.
You can get more control by using disable-output-escaping, or character maps, or Andrew Welch's lexev utility, but all of these workarounds beg the question, why is it so important? If someone is treating the result document differently depending on whether it uses CDATA or not, then they are misusing XML and need to be re-educated.
来源:https://stackoverflow.com/questions/51208940/xml-xslt-escape-special-characters