问题
I am trying to get the CDATA
content of an XML node using XSL. The
node currently looks like this:
<node id="1" text="Book Information" ><![CDATA[This is sample text]]></node>
I need the This is sample text
piece. Does anyone have any idea about this?
Thanks in advance.
回答1:
Well, if I use this stylesheet:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="node/text()">
<xsl:copy/>
</xsl:template>
</xsl:stylesheet>
on this XML file:
<?xml version="1.0" encoding="utf-8"?>
<node id=1 text="Book Information" ><![CDATA[This is sample text]]></node>
I get a parse error, because id=1
is invalid XML.
Putting quotes around the attribute value (id="1"
) and rerunning the stylesheet, I get as output:
This is sample text
So there's a start. Basically, just treat the CDATA as a text node and you're on your way.
You said:
I found something like:
<xsl:output cdata-section-elements="text"/>
and then to fetch CDATA:<xsl:value-of select="node" />
This approach works just fine if you're using value-of
as well. Here would be an example along the lines of your comment, using value-of
instead. Note, though, that cdata-section-elements
only works on the output side, indicating which output XML elements you want to print as CDATA sections instead of plain old character data. It doesn't have anything to do with fetching the data.
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output cdata-section-elements="foo"/>
<xsl:template match="/">
<foo>
<xsl:value-of select="node"/>
</foo>
</xsl:template>
</xsl:stylesheet>
prints out
<?xml version="1.0"?>
<foo><![CDATA[This is sample text]]></foo>
回答2:
Some other easy steps to achieve this;
Used W3cschools editor to try out.
Sample XML File :
<?xml version="1.0" encoding="ISO-8859-1"?>
<!-- Edited by XMLSpy® -->
<catalog>
<cd>
<disk id="title"><![CDATA[Sample xml]]></disk >
<disk id="artist"><![CDATA[Vijay]]></disk >
</cd>
</catalog>
Sample XSL file :
<?xml version="1.0" encoding="ISO-8859-1"?>
<!-- Edited by XMLSpy® -->
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<body>
<h2>My CD Collection</h2>
<table border="1">
<tr bgcolor="#9acd32">
<th>Title</th>
<th>Artist</th>
</tr>
<xsl:for-each select="catalog/cd">
<tr>
<td><xsl:value-of select="/catalog/cd/disk[@id='title']"/></td>
<td><xsl:value-of select="/catalog/cd/disk[@id='artist']"/></td>
</tr>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
Final result is;

回答3:
For output CDATA sections:
You have to use xsl:output/@cdata-section-elements
. From http://www.w3.org/TR/xslt#output
The cdata-section-elements attribute contains a whitespace-separated list of QNames. Each QName is expanded into an expanded-name using the namespace declarations in effect on the xsl:output element in which the QName occurs; if there is a default namespace, it is used for QNames that do not have a prefix. The expansion is performed before the merging of multiple xsl:output elements into a single effective xsl:output element. If the expanded-name of the parent of a text node is a member of the list, then the text node should be output as a CDATA section.
Besides DOE, of course.
You can't select CDATA sections with XPath. According to http://www.w3.org/TR/xpath/#data-model
There are seven types of node:
root nodes
element nodes
text nodes
attribute nodes
namespace nodes
processing instruction nodes
comment nodes
And from http://www.w3.org/TR/xpath/#section-Text-Nodes
Each character within a CDATA section is treated as character data. Thus,
<![CDATA[<]]>
in the source document will treated the same as <. Both will result in a single < character in a text node in the tree. Thus, a CDATA section is treated as if the<![CDATA[
and]]>
were removed and every occurrence of<
and&
were replaced by<
and&
respectively.
回答4:
The only solution I've found on the web that works is this -
{XSLT}
<title>
<xsl:text disable-output-escaping="yes"><![CDATA[ <![CDATA[ ]]></xsl:text>
<xsl:value-of select="label" disable-output-escaping="yes"/>
<xsl:text disable-output-escaping="yes"><![CDATA[]]]]><![CDATA[>]]></xsl:text>
</title>
However, this isn't the cleanest of solutions especially if you need to implement this in various parts of your XSLT. Also, if your input XML already has the CDATA (i.e. you are attempting to preserve CDATA) using disable-output-escaping won't work since by that time the CDATA has already been parsed by the XSLT engine and all that'll be left is the content which can end up breaking the xml.
Here's my solution -
Depending on how you're using XSLT, it is possible to use external/injected functions. Doing that you can easily minimise the amount of code you are writing and end up with a much cleaner looking template:
{C#}
public string CDATAWrap(string data)
{
return "<![CDATA[" + data + "]]>";
}
{XSLT}
<title>
<xsl:value-of select="CDataType:CDATAWrap(label)" disable-output-escaping="yes" />
</title>
回答5:
I tried with various combinations and got the solution for this;
<xsl:value-of select="/node/."/>
来源:https://stackoverflow.com/questions/2963633/how-to-get-cdata-from-xml-node-using-xsl