1

I have some XML like

<ITEM><TITLE>Video: High Stakes for <KW>Obama</KW> &amp; Romney</TITLE></ITEM>

which I would like to translate to the below XML using XSLT.

<ITEM><TITLE>Video: High Stakes for &lt;KW&gt;Obama&lt;/KW&gt; &amp; Romney</TITLE></ITEM>

I tried <xls:copy-of select="./TITLE"/> but that is not escaping the XML tags. Any idea?

2 Answers 2

2

These sorts of questions always attract a lot of competing answers, because the best answer depends on how generalized you need it to be, and that is not clear from your question.

If you want a super-generalised solution, I will leave that to the regular XSLT SO stars. Or you could just search SO for questions which ask how to serialize/ or stringize XML. There are plenty.

I will offer you a very simple but specific solution, for a very narrow interpretation of your question. For this I will assume that:

  1. You are just interested in serializing the content of the TITLE element.
  2. The element children of TITLE' (such asKW`) are restricted, in that they have no children and no attributes, and are not in a namespace.

With this interpretation, this input document...

<ITEM>
 <TITLE>Video: High Stakes for <KW>Obama</KW> &amp; Romney</TITLE>
</ITEM>

...transformed by this XSLT 1.0 style-sheet (works just the same in 2.0)...

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:strip-space elements="*" />  

<xsl:template match="@*|node()">
 <xsl:copy>
  <xsl:apply-templates select="@*|node()"/>
 </xsl:copy>
</xsl:template>

<xsl:template match="TITLE/*">
  <xsl:value-of select="concat('&lt;',name(),'&gt;',.,'&lt;/',name(),'&gt;')" />
</xsl:template>

</xsl:stylesheet>

...yields...

<ITEM>
  <TITLE>Video: High Stakes for &lt;KW&gt;Obama&lt;/KW&gt; &amp; Romney</TITLE>
</ITEM>
Sign up to request clarification or add additional context in comments.

Comments

0

XSLT doesn't have a specific, direct feature to destruct markup to text (and you have to think well if this is really useful in your case).

This said, here is a short solution using a tiny C# extension function (a similar extension function can easily be written for most other PLs and platforms):

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:msxsl="urn:schemas-microsoft-com:xslt"
 xmlns:my="my:my" exclude-result-prefixes="msxsl my">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="node()|@*">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="/*/TITLE/*">
  <xsl:value-of select="my:stringize(.)"/>
  <xsl:apply-templates/>
 </xsl:template>

 <msxsl:script language="c#" implements-prefix="my">
  public string stringize(XPathNavigator doc)
  {
   return doc.OuterXml;
  }
 </msxsl:script>
</xsl:stylesheet>

When this transformation is applied to the provided XML document:

<ITEM><TITLE>Video: High Stakes for <KW>Obama</KW> &amp; Romney</TITLE></ITEM>

the wanted, correct result is produced:

<ITEM>
  <TITLE>Video: High Stakes for &lt;KW&gt;Obama&lt;/KW&gt; &amp; Romney</TITLE>
</ITEM>

Do note:

  1. This solution flattens out to text the whole subtree rooted in a TITLE element that is a child of the top element of the XML document -- regardless of depth -- which the other posted answer doesn't.

  2. This solution correctly flattens elements with attributes or empty elements -- which the other posted answer -- doesn't.

2 Comments

Do you have a similar solution for Java?
@Learner, I am not a Java programmer, but there should be a similar way to do this in Java.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.