• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 753
  • Last Modified:

XSLT

I'm using XSLT to transform an XML document into a new XML document.  What I would like to know is if there is any way that I can perform some text manipulation on the contents of an element.  Fore example, let's say I've got the following XML element:

    <time>2001-07-23T19:41:07.788Z</time>

IN the output document I would like this to appear as:

    <time>July 23, 2001 at 7:41 PM</time>

While this is a date, what I'm asking is if applying a gnereic programmatic transform to element text is possible with XSLT?  If not it seems to me that this would be quite a significant shortcoming.  

Also, could someone give me an idea of a good way to do this while sticking with XML as my data source?  I guess I could do it with straight DOM manipulation in Java, or XPath and Java?  In which case I'd have to build the output document programatically.  Any thoughts?
0
derekl
Asked:
derekl
1 Solution
 
sdussingerCommented:
What you want to do can't be done by XSLT alone. XSLT is basically a structure-modification language, not a pattern-manipulation language. Primitives or functions for doing advanced string manipulation just don't exist in XSLT... :-(

That being said, it's pretty simple to add Java class functions as extension functions to XSLT.

The sample programs which come with the XALAN XSLT processor have an example which uses the Java SimpleDateFormatter class to do nearly what you want to do.

Check out the ${XALAN_HOME}/samples/Extensions/2java-namespace xml and xsl files to see how it works.

HTH

--Steve
0
 
edmund_mitchellCommented:
Hello  derekl

What you want to do can be done with XSLT, but date parsing is going to get verbose.  Steve, you have got to quit being so pessimistic about XSLT :>)
It's a simple theory, but it has some sheer tonnage:

sample.xml:

<a>
 <time>2001-07-23T19:41:07.788Z</time>
 <time>2000-11-09T05:05:07.788Z</time>
 </a>

sample.xsl:

<?xml version='1.0' encoding='utf-8'?>
  <xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:months="months.uri">
 
 
  <months:month abbr="January" num="01"/>
  <months:month abbr="February" num="02"/>
  <months:month abbr="March" num="03"/>
  <months:month abbr="April" num="04"/>
  <months:month abbr="May" num="05"/>
  <months:month abbr="June" num="06"/>
  <months:month abbr="July" num="07"/>
  <months:month abbr="August" num="08"/>
  <months:month abbr="September" num="09"/>
  <months:month abbr="October" num="10"/>
  <months:month abbr="November" num="11"/>
  <months:month abbr="December" num="12"/>

  <!-- betcha haven't seen this trick before -->
  <xsl:variable name="the-months" select="document('')//months:month"
  />
  <!-- pretty cool, huh? ;>)  -->

  <xsl:template match="//time">
  <xsl:variable name='hour'>
       <xsl:choose>
          <xsl:when test="(substring(current(), 12, 2)) &lt; 12">
          <xsl:value-of select='substring(current(), 12, 2)'/>
       </xsl:when>
       <xsl:when test='substring(current(), 12, 2) = 12'>
           <xsl:value-of select='12'/>
       </xsl:when>
       <xsl:otherwise>
          <xsl:value-of select='(substring(current(), 12, 2)) - 12'/>
       </xsl:otherwise>
        </xsl:choose>
  </xsl:variable>
  <xsl:variable name='minute' select='substring(current(), 15, 2)'/>
  <xsl:variable name='am-pm'>
    <xsl:choose>
     <xsl:when test="substring(current(), 12, 2) > 11">
        PM
      </xsl:when>
      <xsl:otherwise>
        AM
      </xsl:otherwise>
    </xsl:choose>
  </xsl:variable>
 
  <xsl:element name='time'>
  <xsl:value-of select="concat($the-months[@num = substring(current(), 6,
  2)]/@abbr, ' ', substring(current(), 9, 2), ', ',
  substring(current(), 1, 4), ' at ', $hour, ':', $minute, $am-pm)"/>
  </xsl:element>  
 </xsl:template>
</xsl:stylesheet>

results in


ejm ->java com.icl.saxon.StyleSheet eexml.xml eexsl.xsl
<?xml version="1.0" encoding="utf-8"?>
 <time>July 23, 2001 at 7:41
        PM
      </time>
 <time>November 09, 2000 at 05:05
        AM
      </time>

Obviously, you'll want to pretty it up a bit, and maybe throw in another nested choose to get rid of the leading zeros in dates and am times.

One last point about XSLT:
It is a Turing-complete language, which means that according to Alan Turing, given data it can handle, XSLT can perform algorithms of arbitrary complexity - i.e., it can do almost anything.  Since it's a functional, not procedural, programming language, it can take a different mind-set to solve some problems, but that's what we're here to help you with :>)

I hope that answers your question,

Edmund
0
 
sdussingerCommented:
Sorry Edmund. I'm not being pessimistic about XSL, but that script really makes my point.

There is no advanced mechanisms for doing string manipulation in XSL (and no I don't consider substring an advanced string manipulation mechanism :-)). So you've been forced to resort to something that while it works is going to be most difficult to modify/maintain. Ripping things with substrings works, but its tough to read/modify/maintain. I pity the poor guy who has to change the date formatting five years down the road :-)

The reference to Turing-completeness is accurate, but it belies the point: Granted that (given data it can handle) it can process algorithms of arbitrary complexity, but those algorithms are so difficult to create and read that it becomes nearly unusable.

The other point here is that of performance: I'd be willing to bet that doing all of that substring manipulation is going to cost you more than a single call to a Java class to do the same thing. Additionally, the code for doing the date conversion in Java will be much easier to understand and modify than the substring manipulation in an XSL file.

That being said, it is a rather cool approach, even if it is unwieldy... :-). I especially like the referencing of elements from the XSL file, I didn't know you could do that...

--Steve

0
What Kind of Coding Program is Right for You?

There are many ways to learn to code these days. From coding bootcamps like Flatiron School to online courses to totally free beginner resources. The best way to learn to code depends on many factors, but the most important one is you. See what course is best for you.

 
sdussingerCommented:
Here is the code for the XSL/Java extension approach.

The XML (same as from Edmund's post):

<?xml version="1.0" encoding="utf-8"?>
<a>
   <time>2001-07-23T19:41:07.788Z</time>
   <time>2000-11-09T05:05:07.788Z</time>
</a>

The XSL Stylesheet:

<?xml version='1.0' encoding='utf-8'?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:java="http://xml.apache.org/xslt/java">
                 
<xsl:output method="xml" indent="yes"/>

<xsl:template match="/">
  <root>
    <xsl:apply-templates/>
  </root>
</xsl:template>

<xsl:template match="//time">

  <time>
    <xsl:value-of select="java:DateFormatter.convertDate(string(.))"/>
  </time>

</xsl:template>

</xsl:stylesheet>

The Java code:

import java.text.*;
import java.util.*;

public class DateFormatter
{

  public static String convertDate (String sourceDate)
  {
    SimpleDateFormat sourceFormat = new SimpleDateFormat ("yyyy-MM-dd'T'hh:mm:ss.SSS'Z'");
    SimpleDateFormat destFormat = new SimpleDateFormat ("MMMM dd, yyyy 'at' hh:mm a");

    Date d = sourceFormat.parse (sourceDate, new ParsePosition (0));
    return (destFormat.format (d));
  }

}


Now when this is run, you get:

<root>
   <time>July 23, 2001 at 07:41 PM</time>
   <time>November 09, 2000 at 05:05 AM</time>
</root>

BTW, this was run using Xerces/Xalan.

--Steve
0
 
BigRatCommented:
To be fair Steve, XALAN is a server-side Java processor. Not everybody uses this technology. A lot of people still use ASP and they don't have <xsl:eval/> any more, since the purists said it was non-standard. Furthermore I don't remember seeing value-of="java:..." in the XML standard!

I take my hat off to Edmund, I just haven't the time to spend on such problems. There is a futher point about this, which the designers and the purists forget, and that is the productivity factor. It costs a lot of money to figure something like that out!

It really is a pity that xsl:eval went. The inclusion of Javascript would have been really super. I would have even supported REGEX or any other pattern language to be able to manipulate the data instead of just being able to manipulate format.
0
 
sdussingerCommented:
Sure and I understand that not all people are using server-side XML and I certainly would not propose that anyone change the way that they are doing things just so that they adopt a technology which I consider to be useful.

Perhaps using Java extensions isn't in the standard, but nonetheless it is a way to do what was requested.  Since no reference was made to the way in which XSL was being used, and the original post made reference to Java as a technology which was a potential solution to the problem, I took off from that point with my post.  I believe, though I could be wrong, that the value-of="java:" is a take off on the idea of extension functions which is part of the specification.

I have nothing against the idea of using XSL to provide this behavior, but I also believe that my points are still valid.  Especially, as you point out that the productivity factor associated with trying to develop a solution using raw XSL is time consuming and potentially error prone.

I'm certainly, as you can tell, not purist when it comes to technology. Any port in a storm and all that; I'll use whatever's available. I'm certainly not judging anyone's approach here, but I think its important to explore all avenues.  If the XSL-only approach is what the original poster wants, then that's what he should use. I posted mine as an alternative which could also be used and which I feel has merits over the other in certain situations.

It may not sound like it, but I think the idea that Edmund proposed was pretty cool... I'm upset that I didn't think of it, although I would only use it as an academic exercise. I wouldn't want to put it into production, for fear of someone who didn't understand it bunging it up while making changes.

I certainly didn't want to get anyone upset over my posting, and if that's the case I apologize. I merely wanted the original poster to have the benefit of several different approaches to try.

--Steve
0
 
DeathwishCommented:
Instead of eval, if you are using the MSXML parser you can tie scripting directly into the xslt. For example here is one I did with date formatting. In this case my date was something like 1/1/01 and what was wanted was to show the fule date. It uses vbscript in this case. It can be modified to accommodate what you want and the format you want. Whats cool about is that you can use any scripting language that the server supports. You can even do com components and such within the script blocks for more advance calculations.


The template to output it:

<?xml version='1.0'?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
     xmlns:msxsl="urn:schemas-microsoft-com:xslt"
     xmlns:dt="urn:schemas-microsoft-com:datatypes"
     xmlns:date="urn:schemas-irp-com:date" version="1.0">
     <xsl:output method="html"/>
     
     <xsl:template name="test">
     <td><xsl:value-of select="date:FormatDate(string(@PlanEffectiveDate))"/></td>
     <td>Requestor:</td>
     <td><xsl:value-of select="@Requestor"/></td>
                   </tr>
     </xsl:template>
</xsl:stylesheet>





The script template:


<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:msxsl="urn:schemas-microsoft-com:xslt"
                xmlns:date="urn:schemas-irp-com:date"
                version="1.0">
  <msxsl:script language="VBScript" implements-prefix="date">
    Function FormatDate(datDateItem)
          FormatDate = Right("0" &amp; Month(datDateItem),2) &amp; "/" &amp; Right("0" &amp; Day(datDateItem),2) &amp; "/" &amp; Year(datDateItem)
     End Function
  </msxsl:script>

</xsl:stylesheet>
0
 
DeathwishCommented:
Oops I meant they wanted to show the full year at the end.
0
 
dereklAuthor Commented:
Thanks for all of the comments guys they were very insightful.  Edmund I have to say your solution to the problem was exceptionally clever, but Steve's answer was more of what I had in mind when I asked the question.  Again, thanks for the insight!
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

What Kind of Coding Program is Right for You?

There are many ways to learn to code these days. From coding bootcamps like Flatiron School to online courses to totally free beginner resources. The best way to learn to code depends on many factors, but the most important one is you. See what course is best for you.

Tackle projects and never again get stuck behind a technical roadblock.
Join Now