001: /*
002: *****************************************************************
003: Copyright (c) 2001-2007, Jeff Martin, Tim Bacon
004: All rights reserved.
005:
006: Redistribution and use in source and binary forms, with or without
007: modification, are permitted provided that the following conditions
008: are met:
009:
010: * Redistributions of source code must retain the above copyright
011: notice, this list of conditions and the following disclaimer.
012: * Redistributions in binary form must reproduce the above
013: copyright notice, this list of conditions and the following
014: disclaimer in the documentation and/or other materials provided
015: with the distribution.
016: * Neither the name of the xmlunit.sourceforge.net nor the names
017: of its contributors may be used to endorse or promote products
018: derived from this software without specific prior written
019: permission.
020:
021: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
022: "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
023: LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
024: FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
025: COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
026: INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
027: BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
028: LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
029: CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
030: LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
031: ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
032: POSSIBILITY OF SUCH DAMAGE.
033:
034: ******************************************************************
035: */
036:
037: package org.custommonkey.xmlunit;
038:
039: import org.custommonkey.xmlunit.exceptions.ConfigurationException;
040:
041: import javax.xml.parsers.DocumentBuilder;
042: import javax.xml.parsers.DocumentBuilderFactory;
043: import javax.xml.parsers.ParserConfigurationException;
044: import javax.xml.parsers.SAXParserFactory;
045: import javax.xml.transform.TransformerFactory;
046: import javax.xml.transform.URIResolver;
047:
048: import java.io.IOException;
049: import java.io.Reader;
050: import java.io.StringReader;
051: import java.text.NumberFormat;
052: import java.text.ParseException;
053: import java.util.Locale;
054: import org.w3c.dom.Document;
055: import org.xml.sax.InputSource;
056: import org.xml.sax.SAXException;
057: import org.xml.sax.EntityResolver;
058:
059: /**
060: * Allows access to project control parameters such as which Parser to use and
061: * provides some convenience methods for building Documents from Strings etc.
062: * <br />Examples and more at <a href="http://xmlunit.sourceforge.net"/>xmlunit.sourceforge.net</a>
063: */
064: public final class XMLUnit {
065: private static DocumentBuilderFactory controlBuilderFactory;
066: private static DocumentBuilderFactory testBuilderFactory;
067: private static TransformerFactory transformerFactory;
068: private static boolean ignoreWhitespace = false;
069: private static URIResolver uriResolver = null;
070: private static EntityResolver testEntityResolver = null;
071: private static EntityResolver controlEntityResolver = null;
072: private static NamespaceContext namespaceContext = null;
073: private static boolean ignoreDiffBetweenTextAndCDATA = false;
074: private static boolean ignoreComments = false;
075: private static boolean normalize = false;
076: private static boolean normalizeWhitespace = false;
077: private static boolean ignoreAttributeOrder = false;
078: private static String xsltVersion = "1.0";
079: private static String xpathFactoryName = null;
080:
081: private static final String XSLT_VERSION_START = " version=\"";
082: private static final String XSLT_VERSION_END = "\">";
083:
084: private static final String STRIP_WHITESPACE_STYLESHEET_START = new StringBuffer(
085: XMLConstants.XML_DECLARATION).append(
086: XSLTConstants.XSLT_START_NO_VERSION).append(
087: XSLT_VERSION_START).toString();
088:
089: private static final String STRIP_WHITESPACE_STYLESHEET_END = new StringBuffer(
090: XSLT_VERSION_END).append(
091: XSLTConstants.XSLT_XML_OUTPUT_NOINDENT).append(
092: XSLTConstants.XSLT_STRIP_WHITESPACE).append(
093: XSLTConstants.XSLT_IDENTITY_TEMPLATE).append(
094: XSLTConstants.XSLT_END).toString();
095:
096: private static final String STRIP_COMMENTS_STYLESHEET_START = new StringBuffer(
097: XMLConstants.XML_DECLARATION).append(
098: XSLTConstants.XSLT_START_NO_VERSION).append(
099: XSLT_VERSION_START).toString();
100:
101: private static final String STRIP_COMMENTS_STYLESHEET_END = new StringBuffer(
102: XSLT_VERSION_END).append(
103: XSLTConstants.XSLT_XML_OUTPUT_NOINDENT).append(
104: XSLTConstants.XSLT_STRIP_COMMENTS_TEMPLATE).append(
105: XSLTConstants.XSLT_END).toString();
106:
107: /**
108: * Private constructor.
109: * Makes class non-instantiable
110: */
111: private XMLUnit() {
112: // access via static methods please
113: }
114:
115: /**
116: * Overide the DocumentBuilder to use to parse control documents.
117: * This is useful when comparing the output of two different
118: * parsers. Note: setting the control parser before any test cases
119: * are run will affect the test parser as well.
120: */
121: public static void setControlParser(String className) {
122: System.setProperty("javax.xml.parsers.DocumentBuilderFactory",
123: className);
124: controlBuilderFactory = null;
125: controlBuilderFactory = getControlDocumentBuilderFactory();
126: }
127:
128: /**
129: * Get the <code>DocumentBuilder</code> instance used to parse the control
130: * XML in an XMLTestCase.
131: * @return parser for control values
132: * @throws ConfigurationException
133: */
134: public static DocumentBuilder newControlParser()
135: throws ConfigurationException {
136: try {
137: controlBuilderFactory = getControlDocumentBuilderFactory();
138: DocumentBuilder builder = controlBuilderFactory
139: .newDocumentBuilder();
140: if (controlEntityResolver != null) {
141: builder.setEntityResolver(controlEntityResolver);
142: }
143: return builder;
144: } catch (ParserConfigurationException ex) {
145: throw new ConfigurationException(ex);
146: }
147: }
148:
149: /**
150: * Sets an EntityResolver to be added to all new test parsers.
151: * Setting to null will reset to the default EntityResolver
152: */
153: public static void setTestEntityResolver(EntityResolver resolver) {
154: testEntityResolver = resolver;
155: }
156:
157: /**
158: * Sets an EntityResolver to be added to all new control parsers.
159: * Setting to null will reset to the default EntityResolver
160: */
161: public static void setControlEntityResolver(EntityResolver resolver) {
162: controlEntityResolver = resolver;
163: }
164:
165: /**
166: * Obtains the EntityResolver to be added to all new control parsers.
167: */
168: public static EntityResolver getControlEntityResolver() {
169: return controlEntityResolver;
170: }
171:
172: /**
173: * Get the <code>DocumentBuilderFactory</code> instance used to instantiate
174: * parsers for the control XML in an XMLTestCase.
175: * @return factory for control parsers
176: */
177: public static DocumentBuilderFactory getControlDocumentBuilderFactory() {
178: if (controlBuilderFactory == null) {
179: controlBuilderFactory = DocumentBuilderFactory
180: .newInstance();
181: controlBuilderFactory.setNamespaceAware(true);
182: }
183: return controlBuilderFactory;
184: }
185:
186: /**
187: * Override the <code>DocumentBuilderFactory</code> used to instantiate
188: * parsers for the control XML in an XMLTestCase.
189: */
190: public static void setControlDocumentBuilderFactory(
191: DocumentBuilderFactory factory) {
192: if (factory == null) {
193: throw new IllegalArgumentException(
194: "Cannot set control DocumentBuilderFactory to null!");
195: }
196: controlBuilderFactory = factory;
197: }
198:
199: /**
200: * Overide the DocumentBuilder to use to parser test documents.
201: * This is useful when comparing the output of two different
202: * parsers. Note: setting the test parser before any test cases
203: * are run will affect the control parser as well.
204: */
205: public static void setTestParser(String className) {
206: System.setProperty("javax.xml.parsers.DocumentBuilderFactory",
207: className);
208: testBuilderFactory = null;
209: testBuilderFactory = getTestDocumentBuilderFactory();
210: }
211:
212: /**
213: * Get the <code>DocumentBuilder</code> instance used to parse the test XML
214: * in an XMLTestCase.
215: * @return parser for test values
216: * @throws ConfigurationException
217: */
218: public static DocumentBuilder newTestParser()
219: throws ConfigurationException {
220: try {
221: testBuilderFactory = getTestDocumentBuilderFactory();
222: DocumentBuilder builder = testBuilderFactory
223: .newDocumentBuilder();
224: if (testEntityResolver != null) {
225: builder.setEntityResolver(testEntityResolver);
226: }
227: return builder;
228: } catch (ParserConfigurationException ex) {
229: throw new ConfigurationException(ex);
230: }
231: }
232:
233: /**
234: * Get the <code>DocumentBuilder</code> instance used to parse the test XML
235: * in an XMLTestCase.
236: * @return parser for test values
237: * @throws ConfigurationException
238: * @deprecated use newTestParser()
239: */
240: public static DocumentBuilder getTestParser()
241: throws ConfigurationException {
242: return newTestParser();
243: }
244:
245: /**
246: * Get the <code>DocumentBuilder</code> instance used to parse the test XML
247: * in an XMLTestCase.
248: * @return parser for control values
249: * @deprecated use newControlParser()
250: * @throws ConfigurationException
251: */
252: public static DocumentBuilder getControlParser()
253: throws ConfigurationException {
254: return newControlParser();
255: }
256:
257: /**
258: * Get the <code>DocumentBuilderFactory</code> instance used to instantiate
259: * parsers for the test XML in an XMLTestCase.
260: * @return factory for test parsers
261: */
262: public static DocumentBuilderFactory getTestDocumentBuilderFactory() {
263: if (testBuilderFactory == null) {
264: testBuilderFactory = DocumentBuilderFactory.newInstance();
265: testBuilderFactory.setNamespaceAware(true);
266: }
267: return testBuilderFactory;
268: }
269:
270: /**
271: * Override the <code>DocumentBuilderFactory</code> used to instantiate
272: * parsers for the test XML in an XMLTestCase.
273: */
274: public static void setTestDocumentBuilderFactory(
275: DocumentBuilderFactory factory) {
276: if (factory == null) {
277: throw new IllegalArgumentException(
278: "Cannot set test DocumentBuilderFactory to null!");
279: }
280: testBuilderFactory = factory;
281: }
282:
283: /**
284: * Whether to ignore whitespace when comparing node values.
285: *
286: * <p>This method also invokes
287: * <code>setIgnoringElementContentWhitespace()</code> on the
288: * underlying control AND test document builder factories.</p>
289: *
290: * <p>Setting this parameter has no effect on {@link
291: * setNormalizeWhitespace whitespace inside texts}.</p>
292: */
293: public static void setIgnoreWhitespace(boolean ignore) {
294: ignoreWhitespace = ignore;
295: getControlDocumentBuilderFactory()
296: .setIgnoringElementContentWhitespace(ignore);
297: getTestDocumentBuilderFactory()
298: .setIgnoringElementContentWhitespace(ignore);
299: }
300:
301: /**
302: * Whether to ignore whitespace when comparing node values.
303: * @return true if whitespace should be ignored when comparing nodes, false
304: * otherwise
305: */
306: public static boolean getIgnoreWhitespace() {
307: return ignoreWhitespace;
308: }
309:
310: /**
311: * Utility method to build a Document using the control DocumentBuilder
312: * to parse the specified String.
313: * @param fromXML
314: * @return Document representation of the String content
315: * @throws SAXException
316: * @throws IOException
317: */
318: public static Document buildControlDocument(String fromXML)
319: throws SAXException, IOException {
320: return buildDocument(newControlParser(), new StringReader(
321: fromXML));
322: }
323:
324: /**
325: * Utility method to build a Document using the control DocumentBuilder
326: * and the specified InputSource
327: * @param fromSource
328: * @return Document representation of the String content
329: * @throws SAXException
330: * @throws IOException
331: */
332: public static Document buildControlDocument(InputSource fromSource)
333: throws IOException, SAXException {
334: return buildDocument(newControlParser(), fromSource);
335: }
336:
337: /**
338: * Utility method to build a Document using the test DocumentBuilder
339: * to parse the specified String.
340: * @param fromXML
341: * @return Document representation of the String content
342: * @throws SAXException
343: * @throws IOException
344: */
345: public static Document buildTestDocument(String fromXML)
346: throws SAXException, IOException {
347: return buildDocument(newTestParser(), new StringReader(fromXML));
348: }
349:
350: /**
351: * Utility method to build a Document using the test DocumentBuilder
352: * and the specified InputSource
353: * @param fromSource
354: * @return Document representation of the String content
355: * @throws SAXException
356: * @throws IOException
357: */
358: public static Document buildTestDocument(InputSource fromSource)
359: throws IOException, SAXException {
360: return buildDocument(newTestParser(), fromSource);
361: }
362:
363: /**
364: * Utility method to build a Document using a specific DocumentBuilder
365: * and reading characters from a specific Reader.
366: * @param withBuilder
367: * @param fromReader
368: * @return Document built
369: * @throws SAXException
370: * @throws IOException
371: */
372: public static Document buildDocument(DocumentBuilder withBuilder,
373: Reader fromReader) throws SAXException, IOException {
374: return buildDocument(withBuilder, new InputSource(fromReader));
375: }
376:
377: /**
378: * Utility method to build a Document using a specific DocumentBuilder
379: * and a specific InputSource
380: * @param withBuilder
381: * @param fromSource
382: * @return Document built
383: * @throws SAXException
384: * @throws IOException
385: */
386: public static Document buildDocument(DocumentBuilder withBuilder,
387: InputSource fromSource) throws IOException, SAXException {
388: return withBuilder.parse(fromSource);
389: }
390:
391: /**
392: * Overide the transformer to use for XSLT transformations (and by
393: * implication serialization and XPaths).
394: * This is useful when comparing transformer implementations.
395: */
396: public static void setTransformerFactory(String className) {
397: System.setProperty("javax.xml.transform.TransformerFactory",
398: className);
399: transformerFactory = null;
400: getTransformerFactory();
401: }
402:
403: /**
404: * Get the transformer to use for XSLT transformations (and by
405: * implication serialization and XPaths).
406: * @return the current transformer factory in use
407: * a new instance of the default transformer factory
408: */
409: public static TransformerFactory getTransformerFactory() {
410: if (transformerFactory == null) {
411: transformerFactory = TransformerFactory.newInstance();
412: if (uriResolver != null) {
413: transformerFactory.setURIResolver(uriResolver);
414: }
415: }
416: return transformerFactory;
417: }
418:
419: /**
420: * Sets the URIResolver to use during transformations.
421: */
422: public static void setURIResolver(URIResolver resolver) {
423: if (uriResolver != resolver) {
424: uriResolver = resolver;
425: transformerFactory = null;
426: getTransformerFactory();
427: }
428: }
429:
430: /**
431: * Gets the URIResolver used during Transformations.
432: */
433: public static URIResolver getURIResolver() {
434: return uriResolver;
435: }
436:
437: /**
438: * Override the SAX parser to use in tests.
439: * Currently only used by {@link Validator Validator class}
440: * @param className
441: */
442: public static void setSAXParserFactory(String className) {
443: System.setProperty("javax.xml.parsers.SAXParserFactory",
444: className);
445: getSAXParserFactory();
446: }
447:
448: /**
449: * Get the SAX parser to use in tests.
450: * @return the SAXParserFactory instance used by the {@link Validator Validator}
451: * to perform DTD validation
452: */
453: public static SAXParserFactory getSAXParserFactory() {
454: SAXParserFactory newFactory = SAXParserFactory.newInstance();
455: newFactory.setNamespaceAware(true);
456: return newFactory;
457: }
458:
459: private static String getStripWhitespaceStylesheet() {
460: return STRIP_WHITESPACE_STYLESHEET_START + getXSLTVersion()
461: + STRIP_WHITESPACE_STYLESHEET_END;
462: }
463:
464: /**
465: * Obtain the transformation that will strip whitespace from a DOM
466: * containing empty Text nodes
467: * @param forDocument
468: * @return a <code>Transform</code> to do the whitespace stripping
469: */
470: public static Transform getStripWhitespaceTransform(
471: Document forDocument) {
472: return new Transform(forDocument,
473: getStripWhitespaceStylesheet());
474: }
475:
476: private static String getStripCommentsStylesheet() {
477: return STRIP_COMMENTS_STYLESHEET_START + getXSLTVersion()
478: + STRIP_COMMENTS_STYLESHEET_END;
479: }
480:
481: /**
482: * Obtain the transformation that will strip comments from a DOM.
483: * @param forDocument
484: * @return a <code>Transform</code> to do the whitespace stripping
485: */
486: public static Transform getStripCommentsTransform(
487: Document forDocument) {
488: return new Transform(forDocument, getStripCommentsStylesheet());
489: }
490:
491: /**
492: * Place holder for current version info.
493: * @return current version
494: */
495: public static String getVersion() {
496: return "1.1";
497: }
498:
499: /**
500: * Compare XML documents provided by two InputSource classes
501: * @param control Control document
502: * @param test Document to test
503: * @return Diff object describing differences in documents
504: * @throws SAXException
505: * @throws IOException
506: */
507: public static Diff compareXML(InputSource control, InputSource test)
508: throws SAXException, IOException {
509: return new Diff(control, test);
510: }
511:
512: /**
513: * Compare XML documents provided by two Reader classes
514: * @param control Control document
515: * @param test Document to test
516: * @return Diff object describing differences in documents
517: * @throws SAXException
518: * @throws IOException
519: */
520: public static Diff compareXML(Reader control, Reader test)
521: throws SAXException, IOException {
522: return new Diff(control, test);
523: }
524:
525: /**
526: * Compare XML documents provided by two Reader classes
527: * @param control Control document
528: * @param test Document to test
529: * @return Diff object describing differences in documents
530: * @throws SAXException
531: * @throws IOException
532: */
533: public static Diff compareXML(String control, Reader test)
534: throws SAXException, IOException {
535: return new Diff(new StringReader(control), test);
536: }
537:
538: /**
539: * Compare XML documents provided by two Reader classes
540: * @param control Control document
541: * @param test Document to test
542: * @return Diff object describing differences in documents
543: * @throws SAXException
544: * @throws IOException
545: */
546: public static Diff compareXML(Reader control, String test)
547: throws SAXException, IOException {
548: return new Diff(control, new StringReader(test));
549: }
550:
551: /**
552: * Compare two XML documents provided as strings
553: * @param control Control document
554: * @param test Document to test
555: * @return Diff object describing differences in documents
556: * @throws SAXException
557: * @throws IOException
558: */
559: public static Diff compareXML(String control, String test)
560: throws SAXException, IOException {
561: return new Diff(control, test);
562: }
563:
564: /**
565: * Compare two XML documents provided as strings
566: * @param control Control document
567: * @param test Document to test
568: * @return Diff object describing differences in documents
569: */
570: public static Diff compareXML(Document control, Document test) {
571: return new Diff(control, test);
572: }
573:
574: /**
575: * Get the NamespaceContext to use in XPath tests.
576: */
577: public static NamespaceContext getXpathNamespaceContext() {
578: return namespaceContext;
579: }
580:
581: /**
582: * Set the NamespaceContext to use in XPath tests.
583: */
584: public static void setXpathNamespaceContext(NamespaceContext ctx) {
585: namespaceContext = ctx;
586: }
587:
588: /**
589: * Obtains an XpathEngine to use in XPath tests.
590: */
591: public static XpathEngine newXpathEngine() {
592: XpathEngine eng = null;
593: try {
594: Class.forName("javax.xml.xpath.XPath");
595: Class c = Class.forName("org.custommonkey.xmlunit.jaxp13"
596: + ".Jaxp13XpathEngine");
597: eng = (XpathEngine) c.newInstance();
598: } catch (Throwable ex) {
599: // should probably only catch ClassNotFoundException, but some
600: // constellations - like Ant shipping a more recent version of
601: // xml-apis than the JDK - may contain the JAXP 1.3 interfaces
602: // without implementations
603: eng = new SimpleXpathEngine();
604: }
605: if (namespaceContext != null) {
606: eng.setNamespaceContext(namespaceContext);
607: }
608: return eng;
609: }
610:
611: /**
612: * Whether CDATA sections and Text nodes should be considered the same.
613: *
614: * <p>The default is false.</p>
615: */
616: public static void setIgnoreDiffBetweenTextAndCDATA(boolean b) {
617: ignoreDiffBetweenTextAndCDATA = b;
618: }
619:
620: /**
621: * Whether CDATA sections and Text nodes should be considered the same.
622: *
623: * <p>The default is false.</p>
624: */
625: public static boolean getIgnoreDiffBetweenTextAndCDATA() {
626: return ignoreDiffBetweenTextAndCDATA;
627: }
628:
629: /**
630: * Whether comments should be ignored.
631: *
632: * <p>The default value is false</p>
633: */
634: public static void setIgnoreComments(boolean b) {
635: ignoreComments = b;
636: }
637:
638: /**
639: * Whether comments should be ignored.
640: *
641: * <p>The default value is false</p>
642: */
643: public static boolean getIgnoreComments() {
644: return ignoreComments;
645: }
646:
647: /**
648: * Whether Text nodes should be normalized.
649: *
650: * <p>The default value is false</p>
651: *
652: * <p><b>Note:</b> if you are only working with documents read
653: * from streams (like files or network connections) or working
654: * with strings, there is no reason to change the default since
655: * the XML parser is required to normalize the documents. If you
656: * are testing {@link org.w3c.Document Document} instances you've
657: * created in code, you may want to alter the default
658: * behavior.</p>
659: *
660: * <p><b>Note2:</b> depending on the XML parser or XSLT
661: * transformer you use, setting {@link setIgnoreWhitespace
662: * ignoreWhitespace} or {@link setIgnoreComments ignoreComments}
663: * to true may have already normalized your document and this
664: * setting doesn't have any effect anymore.</p>
665: */
666: public static void setNormalize(boolean b) {
667: normalize = b;
668: }
669:
670: /**
671: * Whether Text nodes should be normalized.
672: *
673: * <p>The default value is false</p>
674: */
675: public static boolean getNormalize() {
676: return normalize;
677: }
678:
679: /**
680: * Whether whitespace characters inside text nodes or attributes
681: * should be "normalized".
682: *
683: * <p>Normalized in this context means that all whitespace is
684: * replaced by the space character and adjacent whitespace
685: * characters are collapsed to a single space character.</p>
686: *
687: * <p>The default value is false.</p>
688: *
689: * <p>Setting this parameter has no effect on {@link
690: * setIgnoreWhitespace ignorable whitespace}.</p>
691: */
692: public static void setNormalizeWhitespace(boolean b) {
693: normalizeWhitespace = b;
694: }
695:
696: /**
697: * Whether whitespace characters inside text nodes or attributes
698: * should be "normalized".
699: *
700: * <p>Normalized in this context means that all whitespace is
701: * replaced by the space character and adjacent whitespace
702: * characters are collapsed to a single space character.</p>
703: *
704: * <p>The default value is false.</p>
705: */
706: public static boolean getNormalizeWhitespace() {
707: return normalizeWhitespace;
708: }
709:
710: /**
711: * Whether to ignore the order of attributes on an element.
712: *
713: * <p>The order of attributes has never been relevant for XML
714: * documents, still XMLUnit will consider two pieces of XML
715: * not-identical (but similar) if they differ in order of
716: * attributes. Set this option to false to ignore the order.</p>
717: *
718: * <p>The default value is false for backwards compatibility
719: * reasons.</p>
720: */
721: public static void setIgnoreAttributeOrder(boolean b) {
722: ignoreAttributeOrder = b;
723: }
724:
725: /**
726: * Whether to ignore the order of attributes on an element.
727: *
728: * <p>The order of attributes has never been relevant for XML
729: * documents, still XMLUnit will consider two pieces of XML
730: * not-identical (but similar) if they differ in order of
731: * attributes. Set this option to false to ignore the order.</p>
732: *
733: * <p>The default value is false for backwards compatibility
734: * reasons.</p>
735: */
736: public static boolean getIgnoreAttributeOrder() {
737: return ignoreAttributeOrder;
738: }
739:
740: /**
741: * Sets the XSLT version to set on stylesheets used internally.
742: *
743: * <p>Defaults to "1.0".</p>
744: *
745: * @throws ConfigurationException if the argument cannot be parsed
746: * as a positive number.
747: */
748: public static void setXSLTVersion(String s) {
749: try {
750: Number n = NumberFormat.getInstance(Locale.US).parse(s);
751: if (n.doubleValue() < 0) {
752: throw new ConfigurationException(s
753: + " doesn't reperesent a" + " positive number.");
754: }
755: } catch (ParseException e) {
756: throw new ConfigurationException(e);
757: }
758: xsltVersion = s;
759: }
760:
761: /**
762: * The XSLT version set on stylesheets used internally.
763: *
764: * <p>Defaults to "1.0".</p>
765: */
766: public static String getXSLTVersion() {
767: return xsltVersion;
768: }
769:
770: /**
771: * Sets the class to use as XPathFactory when using JAXP 1.3.
772: */
773: public static void setXPathFactory(String className) {
774: xpathFactoryName = className;
775: }
776:
777: /**
778: * Gets the class to use as XPathFactory when using JAXP 1.3.
779: */
780: public static String getXPathFactory() {
781: return xpathFactoryName;
782: }
783:
784: /**
785: * XSLT stylesheet element using the configured XSLT version.
786: */
787: static String getXSLTStart() {
788: return XSLTConstants.XSLT_START_NO_VERSION + XSLT_VERSION_START
789: + getXSLTVersion() + XSLT_VERSION_END;
790: }
791: }
|