1. /*
  2. * Copyright 2002-2004 the original author or authors.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package org.springframework.web.servlet.view.xslt;
  17. import java.text.DateFormat;
  18. import java.text.NumberFormat;
  19. import java.text.SimpleDateFormat;
  20. import java.util.Date;
  21. import java.util.Locale;
  22. import javax.xml.parsers.DocumentBuilderFactory;
  23. import org.springframework.core.NestedRuntimeException;
  24. import org.w3c.dom.Document;
  25. import org.w3c.dom.Element;
  26. import org.w3c.dom.Node;
  27. /**
  28. * Xalan extension functions to provide date and currency formatting
  29. * beyond the capabilities of XSLT 1.0 or 1.1.
  30. *
  31. * <p>Note that all extension functions are static.
  32. * These extension functions must be declared to use this class.
  33. *
  34. * <p>Based on an example by Taylor Cowan.
  35. *
  36. * @author Rod Johnson
  37. * @see AbstractXsltView
  38. */
  39. public class FormatHelper {
  40. /**
  41. * Creates a formatted-date node with the given ISO language and country strings.
  42. * If either the language or country parameters are null, the system default
  43. * <code>Locale</code> will be used.
  44. *
  45. * @param time the time in ms since the epoch that should be used to obtain
  46. * the formatted date
  47. * @param language the two character language code required to construct a
  48. * <code>java.util.Locale</code>
  49. * @param country the two character country code required to construct a
  50. * <code>java.util.Locale</code>
  51. * @return a W3C Node containing child Elements with the formatted date-time fragments
  52. */
  53. public static Node dateTimeElement(long time, String language, String country) {
  54. Locale locale = getLocale(language, country);
  55. return dateTimeElement(time, locale);
  56. }
  57. /**
  58. * Creates a formatted-date node with system default <code>Locale</code>
  59. *
  60. * @param time the time in ms since the epoch that should be used to obtain
  61. * the formatted date
  62. * @return a W3C Node containing child Elements with the formatted date-time fragments
  63. */
  64. public static Node dateTimeElement(long time) {
  65. return dateTimeElement(time, Locale.getDefault());
  66. }
  67. /**
  68. * Creates a formatted-date node with the given <code>Locale</code>
  69. *
  70. * @param time the time in ms since the epoch that should be used to obtain
  71. * the formatted date
  72. * @param locale the <code>java.util.Locale</code> to determine the date formatting
  73. * @return a W3C Node containing child Elements with the formatted date-time fragments
  74. */
  75. public static Node dateTimeElement(long time, Locale locale) {
  76. try {
  77. Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
  78. Element dateNode = doc.createElement("formatted-date");
  79. // Works in most locales
  80. SimpleDateFormat df = (SimpleDateFormat) DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, locale);
  81. Date d = new Date(time);
  82. df.applyPattern("MMMM");
  83. addChild(dateNode, "month", df.format(d));
  84. df.applyPattern("EEEE");
  85. addChild(dateNode, "day-of-week", df.format(d));
  86. df.applyPattern("yyyy");
  87. addChild(dateNode, "year", df.format(d));
  88. df.applyPattern("dd");
  89. addChild(dateNode, "day-of-month", df.format(d));
  90. df.applyPattern("h");
  91. addChild(dateNode, "hours", df.format(d));
  92. df.applyPattern("mm");
  93. addChild(dateNode, "minutes", df.format(d));
  94. df.applyPattern("a");
  95. addChild(dateNode, "am-pm", df.format(d));
  96. return dateNode;
  97. }
  98. catch (Exception ex) {
  99. throw new XsltFormattingException("Failed to create XML date element", ex);
  100. }
  101. }
  102. /**
  103. * Format a currency amount in a given locale.
  104. *
  105. * @param amount the currency value to format
  106. * @param locale the <code>java.util.Locale</code> to use to format the amount
  107. * @return a formatted <code>String</code> representing the amount
  108. */
  109. public static String currency(double amount, Locale locale) {
  110. NumberFormat nf = NumberFormat.getCurrencyInstance(locale);
  111. return nf.format(amount);
  112. }
  113. /**
  114. * Format a currency amount for a given language and country.
  115. *
  116. * @param amount the currency value to format
  117. * @param language the two character language code required to construct a
  118. * <code>java.util.Locale</code>
  119. * @param country the two character country code required to construct a
  120. * <code>java.util.Locale</code>
  121. * @return a formatted <code>String</code> representing the amount
  122. */
  123. public static String currency(double amount, String language, String country) {
  124. Locale locale = getLocale(language, country);
  125. return currency(amount, locale);
  126. }
  127. /**
  128. * Utility method for adding text nodes.
  129. */
  130. private static void addChild(Node parent, String name, String text) {
  131. Element child = parent.getOwnerDocument().createElement(name);
  132. child.appendChild(parent.getOwnerDocument().createTextNode(text));
  133. parent.appendChild(child);
  134. }
  135. /**
  136. * Utility method to guarantee a Locale.
  137. */
  138. private static Locale getLocale(String language, String country) {
  139. Locale locale = null;
  140. if (language == null || country == null) {
  141. locale = Locale.getDefault();
  142. }
  143. else {
  144. locale = new Locale(language, country);
  145. }
  146. return locale;
  147. }
  148. /**
  149. * XsltFormattingException
  150. *
  151. * @author Rod Johnson
  152. */
  153. public static class XsltFormattingException extends NestedRuntimeException {
  154. public XsltFormattingException(String msg, Throwable ex) {
  155. super(msg, ex);
  156. }
  157. }
  158. }