saxonb-9.1.0.8/0000755000175000017500000000000012216261742012466 5ustar eugeneeugenesaxonb-9.1.0.8/build/0000755000175000017500000000000012216261742013565 5ustar eugeneeugenesaxonb-9.1.0.8/build/build.xml0000644000175000017500000013777511121474243015426 0ustar eugeneeugene net.sf.saxon.xpath.XPathFactoryImpl http\://java.sun.com/jaxp/xpath/dom: net.sf.saxon.xpath.XPathFactoryImpl http\://saxon.sf.net/jaxp/xpath/om: net.sf.saxon.xpath.XPathFactoryImpl http\://www.xom.nu/jaxp/xpath/xom: net.sf.saxon.xpath.XPathFactoryImpl http\://jdom.org/jaxp/xpath/jdom: net.sf.saxon.xpath.XPathFactoryImpl http\://www.dom4j.org/jaxp/xpath/dom4j: net.sf.saxon.xpath.XPathFactoryImpl com.saxonica.jaxp.SchemaFactoryImpl http\://www.w3.org/2001/XMLSchema: com.saxonica.jaxp.SchemaFactoryImpl set NET="%PROGRAMFILES%\Microsoft.NET\SDK\v2.0\Bin" %NET%\gacutil /if IKVM.Runtime.dll %NET%\gacutil /if IKVM.OpenJDK.ClassLibrary.dll %NET%\gacutil /if saxon9.dll %NET%\gacutil /if saxon9api.dll set NET="%PROGRAMFILES%\Microsoft.NET\SDK\v2.0\Bin" %NET%\gacutil /if IKVM.Runtime.dll %NET%\gacutil /if IKVM.OpenJDK.ClassLibrary.dll %NET%\gacutil /if saxon9.dll %NET%\gacutil /if saxon9sa.dll %NET%\gacutil /if saxon9api.dll saxonb-9.1.0.8/build/csharp-compile.cmd0000644000175000017500000000670511034475204017165 0ustar eugeneeugene rem ==================================================== rem compile the API files rem ==================================================== rem param 1: source code directory e.g. MyJava\build\n\csource rem param 2: .NET dll dir e.g. MyJava\build\n\dll rem param 3: version e.g. 8.9.0.1 set Path=C:\Program Files\Microsoft.NET\SDK\v2.0\Bin\;C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\;%PATH% rem set LIB=C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\lib\;"C:\Program Files\Microsoft.NET\SDK\v1.1\Lib\";%LIB% rem set INCLUDE=C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\include\;"C:\Program Files\Microsoft.NET\SDK\v1.1\include\";%INCLUDE% set APISOURCE=%1/api/Saxon.Api set CMDSOURCE=%1/cmd set SMPSOURCE=%1/samples set DLLDIR=%2 set VER=%3 cd %APISOURCE% csc /target:module /out:%DLLDIR%/saxon9api.netmodule /doc:../apidoc.xml ^ /r:%DLLDIR%/IKVM.OpenJDK.ClassLibrary.dll;%DLLDIR%/IKVM.Runtime.dll;%DLLDIR%/saxon9.dll;%DLLDIR%/saxon9sa.dll ^ *.cs al /keyfile:c:\MyJava\build\saxondotnet.snk /comp:Saxonica /prod:Saxon /v:%VER% %DLLDIR%/saxon9api.netmodule ^ /out:%DLLDIR%/saxon9api.dll rem ===================================================== rem - install saxon9api assembly in the Global Assembly Cache rem ===================================================== cd %DLLDIR% set NET="c:\Program Files\Microsoft.NET\SDK\v2.0\Bin" runas /user:adminstrator %NET%\gacutil /if saxon9api.dll rem ==================================================== rem compile the command files rem ==================================================== cd %CMDSOURCE% csc /target:exe /win32icon:c:\MyDotNet\icons\gyfu.ico ^ /r:%DLLDIR%/IKVM.OpenJDK.ClassLibrary.dll;%DLLDIR%/IKVM.Runtime.dll;%DLLDIR%/saxon9.dll;%DLLDIR%/saxon9sa.dll ^ /out:%DLLDIR%/Transform.exe ^ Transform.cs csc /target:exe /win32icon:c:\MyDotNet\icons\gyfu.ico ^ /r:%DLLDIR%/IKVM.OpenJDK.ClassLibrary.dll;%DLLDIR%/IKVM.Runtime.dll;%DLLDIR%/saxon9.dll;%DLLDIR%/saxon9sa.dll ^ /out:%DLLDIR%/Query.exe ^ Query.cs csc /target:exe /win32icon:c:\MyDotNet\icons\gyfu.ico ^ /r:%DLLDIR%/IKVM.OpenJDK.ClassLibrary.dll;%DLLDIR%/IKVM.Runtime.dll;%DLLDIR%/saxon9.dll;%DLLDIR%/saxon9sa.dll ^ /out:%DLLDIR%/Validate.exe ^ Validate.cs rem ===================================================== rem compile the issued sample applications rem ===================================================== cd %SMPSOURCE% csc /target:exe /win32icon:c:\MyDotNet\icons\csharp.ico /debug+ ^ /r:%DLLDIR%/IKVM.OpenJDK.ClassLibrary.dll;%DLLDIR%/saxon9api.dll ^ /out:%DLLDIR%/samples/Examples.exe ^ Examples.cs csc /target:library /debug+ ^ /r:%DLLDIR%/IKVM.OpenJDK.ClassLibrary.dll;%DLLDIR%/saxon9.dll;%DLLDIR%/saxon9api.dll ^ /out:%DLLDIR%/samples/SampleExtensions.dll ^ SampleExtensions.cs rem ===================================================== rem compile test drivers rem ===================================================== cd %SMPSOURCE% csc /target:exe /win32icon:c:\MyDotNet\icons\csharp.ico /debug+ ^ /r:%DLLDIR%/IKVM.OpenJDK.ClassLibrary.dll;%DLLDIR%/saxon9api.dll ^ /out:%DLLDIR%/tests/TestRunner.exe ^ TestRunnerForm.cs TestRunnerForm.Designer.cs TestRunnerProgram.cs XsltTestSuiteDriver.cs XQueryTestSuiteDriver.cs ^ SchemaTestSuiteDriver.cs IFeedbackListener.cs FileComparer.cs saxonb-9.1.0.8/build/ikvmc.cmd0000644000175000017500000000565211034475204015370 0ustar eugeneeugene rem === This batch file builds the saxon9.dll and saxon9sa.dll assemblies, rem === leaving them in c:\MyDotNet\bin\release. They are also moved into the rem === General Assembly Cache. The script takes off where the Ant build finishes, rem === that is with the two JAR files in c:/MyJava/build/temp/n/jar rem === This file is designed to be invoked from task ikvmc in the Ant build file build.xml rem === Set argument 1 to "debug" to build for development/debugging, or to "live" for live running rem === Set argument 2 to the directory containing the JAR files e.g. MyJava\build\n\jar rem === Set argument 3 to the .NET DLL directory e.g. MyJava\build\n\dll rem === Set argument 4 to the Saxon version e.g. 8.9.0.1 set SAXON_NET_VERSION=%4 set IKVMVER=ikvm-0.36.0.11 set IKVM=c:\MyDotNet\%IKVMVER%\bin set SRC=c:\MyJava\build\temp\n\jsource set SAXON_BUILD_BN=c:\saxon-build\%SAXON_NET_VERSION%\bn set SAXON_BUILD_SAN=c:\saxon-build\%SAXON_NET_VERSION%\san set SAXON_JAR_DIR=%2 rem === Variables identifying release version === set SAXON_RELEASE_DIR=%3 echo Building saxon9 %SAXON_NET_VERSION% DLL rem use the two lines below when building for release... if %1==debug goto c1debug %IKVM%\ikvmc -assembly:saxon9 -target:library -keyfile:saxondotnet.snk -version:%SAXON_NET_VERSION% ^ -debug -srcpath:c:\MyJava\saxon8.x %SAXON_JAR_DIR%\saxon9.jar ^ -reference:mscorlib.dll -reference:System.Xml -reference:System ^ -out:%SAXON_RELEASE_DIR%\saxon9.dll %IKVM%\ikvmc -assembly:saxon9sa -target:library -keyfile:saxondotnet.snk -version:%SAXON_NET_VERSION% ^ -reference:%SAXON_RELEASE_DIR%\saxon9.dll ^ -reference:mscorlib.dll -reference:System.Xml -reference:System ^ -reference:System.Security ^ -debug -srcpath:c:\MyJava\saxon8.x %SAXON_JAR_DIR%\saxon9sa.jar ^ -out:%SAXON_RELEASE_DIR%\saxon9sa.dll rem Need to install the dlls in the Global Assembly Cache now for the rest of the script to work cd %SAXON_RELEASE_DIR% set NET="c:\Program Files\Microsoft.NET\SDK\v2.0\Bin" runas /user:adminstrator %NET%\gacutil /if saxon9.dll runas /user:adminstrator %NET%\gacutil /if saxon9sa.dll goto c1resume :c1debug rem use the two lines below when building debug version... %IKVM%\ikvmc -assembly:saxon9 -target:library ^ -reference:mscorlib.dll -reference:System.Xml -reference:System ^ -debug -srcpath:c:\MyJava\saxon8.x %SAXON_JAR_DIR%\saxon9.jar ^ -out:%SAXON_RELEASE_DIR%\saxon9.dll %IKVM%\ikvmc -assembly:saxon9sa -target:library ^ -reference:%SAXON_RELEASE_DIR%\saxon9.dll ^ -reference:mscorlib.dll -reference:System.Xml -reference:System ^ -reference:System.Security ^ -debug -srcpath:c:\MyJava\saxon8.x %SAXON_JAR_DIR%\saxon9sa.jar ^ -out:%SAXON_RELEASE_DIR%\saxon9sa.dll :c1resume saxonb-9.1.0.8/bj/0000755000175000017500000000000012216261752013062 5ustar eugeneeugenesaxonb-9.1.0.8/bj/net/0000755000175000017500000000000012216261742013647 5ustar eugeneeugenesaxonb-9.1.0.8/bj/net/sf/0000755000175000017500000000000012216261742014257 5ustar eugeneeugenesaxonb-9.1.0.8/bj/net/sf/saxon/0000755000175000017500000000000012216261751015407 5ustar eugeneeugenesaxonb-9.1.0.8/bj/net/sf/saxon/java/0000755000175000017500000000000012216261747016335 5ustar eugeneeugenesaxonb-9.1.0.8/bj/net/sf/saxon/java/JTokenIterator.java0000644000175000017500000000567011033112257022077 0ustar eugeneeugenepackage net.sf.saxon.java; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.om.Item; import net.sf.saxon.value.StringValue; import java.util.regex.Pattern; import java.util.regex.Matcher; /** * A JTokenIterator is an iterator over the strings that result from tokenizing a string using a regular expression */ public class JTokenIterator implements SequenceIterator { private CharSequence input; private Pattern pattern; private Matcher matcher; private CharSequence current; private int position = 0; private int prevEnd = 0; /** * Construct a JTokenIterator. */ public JTokenIterator (CharSequence input, Pattern pattern) { this.input = input; this.pattern = pattern; matcher = pattern.matcher(input); prevEnd = 0; } public Item next() { if (prevEnd < 0) { current = null; position = -1; return null; } if (matcher.find()) { current = input.subSequence(prevEnd, matcher.start()); prevEnd = matcher.end(); } else { current = input.subSequence(prevEnd, input.length()); prevEnd = -1; } position++; return StringValue.makeStringValue(current); } public Item current() { return (current==null ? null : StringValue.makeStringValue(current)); } public int position() { return position; } public void close() { } public SequenceIterator getAnother() { return new JTokenIterator(input, pattern); } /** * Get properties of this iterator, as a bit-significant integer. * * @return the properties of this iterator. This will be some combination of * properties such as {@link #GROUNDED}, {@link #LAST_POSITION_FINDER}, * and {@link #LOOKAHEAD}. It is always * acceptable to return the value zero, indicating that there are no known special properties. * It is acceptable for the properties of the iterator to change depending on its state. */ public int getProperties() { return 0; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/java/JavaCollationFactory.java0000644000175000017500000002073711033112257023252 0ustar eugeneeugenepackage net.sf.saxon.java; import net.sf.saxon.Configuration; import net.sf.saxon.sort.*; import net.sf.saxon.trans.XPathException; import java.text.Collator; import java.text.ParseException; import java.text.RuleBasedCollator; import java.util.Comparator; import java.util.Locale; import java.util.Properties; /** * A JavaCollationFactory allows a Collation to be created given * a set of properties that the collation should have. This class creates a collator using * the facilities of the Java platform; there is a corresponding class that uses the .NET * platform. */ public abstract class JavaCollationFactory { /** * The class is a never instantiated */ private JavaCollationFactory() { } /** * Make a collator with given properties * @param config the Configuration * @param props the desired properties of the collation * @return a collation with these properties */ public static StringCollator makeCollation(Configuration config, String uri, Properties props) throws XPathException { Collator collator = null; StringCollator stringCollator = null; // If a specific collation class is requested, this overrides everything else String classAtt = props.getProperty("class"); if (classAtt != null) { Object comparator = config.getInstance(classAtt, null); if (comparator instanceof Collator) { collator = (Collator)comparator; } else if (comparator instanceof StringCollator) { stringCollator = (StringCollator)comparator; } else if (comparator instanceof Comparator) { stringCollator = new NamedCollation(uri, (Comparator)comparator); } else { throw new XPathException("Requested collation class " + classAtt + " is not a Comparator"); } } // If rules are specified, create a RuleBasedCollator if (collator == null && stringCollator == null) { String rulesAtt = props.getProperty("rules"); if (rulesAtt!=null && collator==null) { try { collator = new RuleBasedCollator(rulesAtt); } catch (ParseException e) { throw new XPathException("Invalid collation rules: " + e.getMessage()); } } // Start with the lang attribute if (collator == null) { String langAtt = props.getProperty("lang"); if (langAtt!=null) { collator = Collator.getInstance(getLocale(langAtt)); } else { collator = Collator.getInstance(); // use default locale } } } if (collator != null) { // See if there is a strength attribute String strengthAtt = props.getProperty("strength"); if (strengthAtt!=null) { if (strengthAtt.equals("primary") && collator instanceof Collator) { collator.setStrength(Collator.PRIMARY); } else if (strengthAtt.equals("secondary")) { collator.setStrength(Collator.SECONDARY); } else if (strengthAtt.equals("tertiary")) { collator.setStrength(Collator.TERTIARY); } else if (strengthAtt.equals("identical")) { collator.setStrength(Collator.IDENTICAL); } else { throw new XPathException("strength must be primary, secondary, tertiary, or identical"); } } // Look for the properties ignore-case, ignore-modifiers, ignore-width String ignore = props.getProperty("ignore-width"); if (ignore != null) { if (ignore.equals("yes") && strengthAtt == null && collator instanceof Collator) { collator.setStrength(Collator.TERTIARY); } else if (ignore.equals("no")) { // no-op } else { throw new XPathException("ignore-width must be yes or no"); } } ignore = props.getProperty("ignore-case"); if (ignore != null && strengthAtt == null && collator instanceof Collator) { if (ignore.equals("yes")) { collator.setStrength(Collator.SECONDARY); } else if (ignore.equals("no")) { // no-op } else { throw new XPathException("ignore-case must be yes or no"); } } ignore = props.getProperty("ignore-modifiers"); if (ignore != null) { if (ignore.equals("yes") && strengthAtt == null && collator instanceof Collator) { collator.setStrength(Collator.PRIMARY); } else if (ignore.equals("no")) { // no-op } else { throw new XPathException("ignore-modifiers must be yes or no"); } } // The ignore-symbols property is ignored // See if there is a decomposition attribute String decompositionAtt = props.getProperty("decomposition"); if (decompositionAtt!=null && collator instanceof Collator) { if (decompositionAtt.equals("none")) { collator.setDecomposition(Collator.NO_DECOMPOSITION); } else if (decompositionAtt.equals("standard")) { collator.setDecomposition(Collator.CANONICAL_DECOMPOSITION); } else if (decompositionAtt.equals("full")) { collator.setDecomposition(Collator.FULL_DECOMPOSITION); } else { throw new XPathException("decomposition must be non, standard, or full"); } } } if (stringCollator == null) { stringCollator = new NamedCollation(uri, collator); } // See if there is a case-order property String caseOrder = props.getProperty("case-order"); if (caseOrder != null && !"#default".equals(caseOrder)) { // force base collator to ignore case differences collator.setStrength(Collator.SECONDARY); if (caseOrder.equals("lower-first")) { stringCollator = new LowercaseFirstCollator(stringCollator); } else if (caseOrder.equals("upper-first")) { stringCollator = new UppercaseFirstCollator(stringCollator); } else { throw new XPathException("case-order must be lower-first, upper-first, or #default"); } }; // See if there is an alphanumeric property String alphanumeric = props.getProperty("alphanumeric"); if (alphanumeric != null && !"no".equals(alphanumeric)) { if (alphanumeric.equals("yes")) { stringCollator = new AlphanumericCollator(stringCollator); } else { throw new XPathException("alphanumeric must be yes or no"); } } return stringCollator; } /** * Get a locale given a language code in XML format */ private static Locale getLocale(String lang) { int hyphen = lang.indexOf("-"); String language, country; if (hyphen < 1) { language = lang; country = ""; } else { language = lang.substring(0, hyphen); country = lang.substring(hyphen+1); } return new Locale(language, country); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/java/JDK15RegexTranslator.java0000644000175000017500000011275411033112257023020 0ustar eugeneeugenepackage net.sf.saxon.java; import net.sf.saxon.charcode.UTF16; import net.sf.saxon.charcode.XMLCharacterData; import net.sf.saxon.om.FastStringBuffer; import net.sf.saxon.regex.CaseVariants; import net.sf.saxon.regex.RegexData; import net.sf.saxon.regex.RegexSyntaxException; import net.sf.saxon.regex.RegexTranslator; import net.sf.saxon.value.Whitespace; import net.sf.saxon.value.StringValue; import net.sf.saxon.sort.IntRangeSet; import net.sf.saxon.Configuration; import java.util.ArrayList; import java.util.List; import java.util.regex.Pattern; /** * This class translates XML Schema regex syntax into JDK 1.5 regex syntax. This differs from the JDK 1.4 * translator because JDK 1.5 handles non-BMP characters (wide characters) in places where JDK 1.4 does not, * for example in a range such as [X-Y]. This enables much of the code from the 1.4 translator to be * removed. * Author: James Clark, Thai Open Source Software Center Ltd. See statement at end of file. * Modified by Michael Kay (a) to integrate the code into Saxon, and (b) to support XPath additions * to the XML Schema regex syntax. This version also removes most of the complexities of handling non-BMP * characters, since JDK 1.5 handles these natively. */ public class JDK15RegexTranslator extends RegexTranslator { // TODO: retrofit the changes for handling caseBlind comparison to the JDK 1.4 translator /** * Translates XML Schema and XPath regexes into java.util.regex regexes. * * @see java.util.regex.Pattern * @see XML Schema Part 2 */ public static final CharClass[] categoryCharClasses = new CharClass[RegexData.categories.length()]; public static final CharClass[] subCategoryCharClasses = new CharClass[RegexData.subCategories.length() / 2]; /** * CharClass for each block name in specialBlockNames. */ public static final CharClass[] specialBlockCharClasses = { new CharRange(0x10300, 0x1032F), new CharRange(0x10330, 0x1034F), new CharRange(0x10400, 0x1044F), new CharRange(0x1D000, 0x1D0FF), new CharRange(0x1D100, 0x1D1FF), new CharRange(0x1D400, 0x1D7FF), new CharRange(0x20000, 0x2A6D6), new CharRange(0x2F800, 0x2FA1F), new CharRange(0xE0000, 0xE007F), new Union(new CharClass[]{ new CharRange(0xE000, 0xF8FF), new CharRange(0xF0000, 0xFFFFD), new CharRange(0x100000, 0x10FFFD) }), Empty.getInstance(), Empty.getInstance(), Empty.getInstance() }; private static final CharClass DOT_SCHEMA = new Complement(new Union(new CharClass[]{new SingleChar('\n'), new SingleChar('\r')})); private static final CharClass ESC_d = new Property("Nd"); private static final CharClass ESC_D = new Complement(ESC_d); private static final CharClass ESC_W = new Union(new CharClass[]{computeCategoryCharClass('P'), computeCategoryCharClass('Z'), computeCategoryCharClass('C')}); //was: new Property("P"), new Property("Z"), new Property("C") } private static final CharClass ESC_w = new Complement(ESC_W); private static final CharClass ESC_s = new Union(new CharClass[]{ new SingleChar(' '), new SingleChar('\n'), new SingleChar('\r'), new SingleChar('\t') }); private static final CharClass ESC_S = new Complement(ESC_s); // private static final CharClass ESC_i = makeCharClass(RegexData.NMSTRT_CATEGORIES, // RegexData.NMSTRT_INCLUDES, // RegexData.NMSTRT_EXCLUDE_RANGES); private static final CharClass ESC_i_10 = makeNameCharClass(XMLCharacterData.NAME_START_10_MASK); private static final CharClass ESC_i_11 = makeNameCharClass(XMLCharacterData.NAME_START_11_MASK); private static final CharClass ESC_I_10 = new Complement(ESC_i_10); private static final CharClass ESC_I_11 = new Complement(ESC_i_11); private static final CharClass ESC_c_10 = makeNameCharClass(XMLCharacterData.NAME_10_MASK); private static final CharClass ESC_c_11 = makeNameCharClass(XMLCharacterData.NAME_11_MASK); private static final CharClass ESC_C_10 = new Complement(ESC_c_10); private static final CharClass ESC_C_11 = new Complement(ESC_c_11); // private static final CharClass ESC_I = new Complement(ESC_i); // private static final CharClass ESC_c = makeCharClass(RegexData.NMCHAR_CATEGORIES, // RegexData.NMCHAR_INCLUDES, // RegexData.NMCHAR_EXCLUDE_RANGES); // // private static final CharClass ESC_C = new Complement(ESC_c); private JDK15RegexTranslator() { } /** * Translates a regular expression in the syntax of XML Schemas Part 2 into a regular * expression in the syntax of java.util.regex.Pattern. The translation * assumes that the string to be matched against the regex uses surrogate pairs correctly. * If the string comes from XML content, a conforming XML parser will automatically * check this; if the string comes from elsewhere, it may be necessary to check * surrogate usage before matching. * @param xmlVersion set to {@link net.sf.saxon.Configuration#XML10} for XML 1.0 * or {@link net.sf.saxon.Configuration#XML11} for XML 1.1 * @param regExp a String containing a regular expression in the syntax of XML Schemas Part 2 * @param xpath a boolean indicating whether the XPath 2.0 F+O extensions to the schema * regex syntax are permitted * @param ignoreWhitespace true if whitespace is to be ignored ('x' flag) * @param caseBlind true if case is to be ignored ('i' flag) * @return a JDK 1.5 regular expression * @throws RegexSyntaxException if regexp is not a regular expression in the * syntax of XML Schemas Part 2, or XPath 2.0, as appropriate * @see java.util.regex.Pattern * @see XML Schema Part 2 */ public static String translate(CharSequence regExp, int xmlVersion, boolean xpath, boolean ignoreWhitespace, boolean caseBlind) throws RegexSyntaxException { //System.err.println("Input regex: " + regexp); JDK15RegexTranslator tr = new JDK15RegexTranslator(); tr.regExp = regExp; tr.length = regExp.length(); tr.xmlVersion = xmlVersion; tr.isXPath = xpath; tr.ignoreWhitespace = ignoreWhitespace; tr.caseBlind = caseBlind; tr.advance(); tr.translateTop(); //System.err.println("Output regex: " + tr.result.toString()); return tr.result.toString(); } static abstract class CharClass { protected CharClass() { } abstract void output(FastStringBuffer buf); abstract void outputComplement(FastStringBuffer buf); int getSingleChar() { return -1; } } static abstract class SimpleCharClass extends CharClass { SimpleCharClass() { } void output(FastStringBuffer buf) { buf.append('['); inClassOutput(buf); buf.append(']'); } void outputComplement(FastStringBuffer buf) { buf.append("[^"); inClassOutput(buf); buf.append(']'); } abstract void inClassOutput(FastStringBuffer buf); } static class SingleChar extends SimpleCharClass { private final int c; SingleChar(int c) { this.c = c; } int getSingleChar() { return c; } void output(FastStringBuffer buf) { inClassOutput(buf); } void inClassOutput(FastStringBuffer buf) { if (isJavaMetaChar(c)) { buf.append('\\'); buf.append((char) c); } else { switch (c) { case '\r': buf.append("\\r"); break; case '\n': buf.append("\\n"); break; case '\t': buf.append("\\t"); break; case ' ': buf.append("\\x20"); break; default: buf.appendWideChar(c); } } } } static class Empty extends SimpleCharClass { private static final Empty instance = new Empty(); private Empty() { } static Empty getInstance() { return instance; } void output(FastStringBuffer buf) { buf.append("\\x00"); // no character matches } void outputComplement(FastStringBuffer buf) { buf.append("[^\\x00]"); // every character matches } void inClassOutput(FastStringBuffer buf) { throw new RuntimeException("BMP output botch"); } } static class CharRange extends SimpleCharClass { private final int lower; private final int upper; CharRange(int lower, int upper) { this.lower = lower; this.upper = upper; } void inClassOutput(FastStringBuffer buf) { if (isJavaMetaChar(lower)) { buf.append('\\'); } buf.appendWideChar(lower); buf.append('-'); if (isJavaMetaChar(upper)) { buf.append('\\'); } buf.appendWideChar(upper); } } static class Property extends SimpleCharClass { private final String name; Property(String name) { this.name = name; } void inClassOutput(FastStringBuffer buf) { buf.append("\\p{"); buf.append(name); buf.append('}'); } void outputComplement(FastStringBuffer buf) { buf.append("\\P{"); buf.append(name); buf.append('}'); } } static class Subtraction extends CharClass { private final CharClass cc1; private final CharClass cc2; Subtraction(CharClass cc1, CharClass cc2) { // min corresponds to intersection // complement corresponds to negation this.cc1 = cc1; this.cc2 = cc2; } void output(FastStringBuffer buf) { buf.append('['); cc1.output(buf); buf.append("&&"); cc2.outputComplement(buf); buf.append(']'); } void outputComplement(FastStringBuffer buf) { buf.append('['); cc1.outputComplement(buf); cc2.output(buf); buf.append(']'); } } static class Union extends CharClass { private final List members; Union(CharClass[] v) { this(toList(v)); } private static List toList(CharClass[] v) { List members = new ArrayList(5); for (int i = 0; i < v.length; i++) members.add(v[i]); return members; } Union(List members) { this.members = members; } void output(FastStringBuffer buf) { buf.append('['); for (int i = 0, len = members.size(); i < len; i++) { CharClass cc = (CharClass) members.get(i); cc.output(buf); } buf.append(']'); } void outputComplement(FastStringBuffer buf) { boolean first = true; int len = members.size(); for (int i = 0; i < len; i++) { CharClass cc = (CharClass) members.get(i); if (cc instanceof SimpleCharClass) { if (first) { buf.append("[^"); first = false; } ((SimpleCharClass) cc).inClassOutput(buf); } } for (int i = 0; i < len; i++) { CharClass cc = (CharClass) members.get(i); if (!(cc instanceof SimpleCharClass)) { if (first) { buf.append('['); first = false; } else { buf.append("&&"); } cc.outputComplement(buf); } } if (first) { // empty union, so the complement is everything buf.append("[\u0001-"); buf.appendWideChar(UTF16.NONBMP_MAX); buf.append("]"); } else { buf.append(']'); } } } static class BackReference extends CharClass { private final int i; BackReference(int i) { this.i = i; } void output(FastStringBuffer buf) { inClassOutput(buf); } void outputComplement(FastStringBuffer buf) { inClassOutput(buf); } void inClassOutput(FastStringBuffer buf) { if (i != -1) { buf.append("(?:\\" + i + ")"); // terminate the back-reference with a syntactic separator } else { buf.append("(?:)"); // matches a zero-length string, while allowing a quantifier } } } static class Complement extends CharClass { private final CharClass cc; Complement(CharClass cc) { this.cc = cc; } void output(FastStringBuffer buf) { cc.outputComplement(buf); } void outputComplement(FastStringBuffer buf) { cc.output(buf); } } protected boolean translateAtom() throws RegexSyntaxException { switch (curChar) { case RegexData.EOS: if (!eos) break; // else fall through case '?': case '*': case '+': case ')': case '{': case '}': case '|': case ']': return false; case '(': copyCurChar(); int thisCapture = ++currentCapture; translateRegExp(); expect(')'); captures.add(thisCapture); copyCurChar(); return true; case '\\': advance(); parseEsc().output(result); return true; case '[': inCharClassExpr = true; advance(); parseCharClassExpr().output(result); return true; case '.': if (isXPath) { // under XPath, "." has the same meaning as in JDK 1.5 break; } else { // under XMLSchema, "." means anything except \n or \r, which is different from the XPath/JDK rule DOT_SCHEMA.output(result); advance(); return true; } case '$': case '^': if (isXPath) { copyCurChar(); return true; } result.append('\\'); break; default: if (caseBlind) { int thisChar = absorbSurrogatePair(); int[] variants = CaseVariants.getCaseVariants(thisChar); if (variants.length > 0) { CharClass[] chars = new CharClass[variants.length+1]; chars[0] = new SingleChar(thisChar); for (int i=0; i= 0) { // limit a back-reference to two digits, but only allow two if there is such a capture // TODO: the spec does not limit the number of digits in a back-reference to two. int n = c0 * 10 + c1; advance(); if (captures.contains(n)) { // treat it as a two-digit back-reference return new BackReference(n); } else { recede(); } } if (captures.contains(c0)) { return new BackReference(c0); } else { // Changed by erratum FO.E4 to be an error throw makeException("invalid backreference \\" + c0 + " (no such group)"); } } else { throw makeException("digit not allowed after \\"); } case '$': if (isXPath) { break; } // otherwise fall through default: throw makeException("invalid escape sequence"); } CharClass tem = new SingleChar(curChar); advance(); return tem; } private CharClass parseProp() throws RegexSyntaxException { expect('{'); int start = pos; for (; ;) { advance(); if (curChar == '}') break; if (!isAsciiAlnum(curChar) && curChar != '-') expect('}'); } CharSequence propertyNameCS = regExp.subSequence(start, pos - 1); if (ignoreWhitespace && !inCharClassExpr) { propertyNameCS = Whitespace.removeAllWhitespace(propertyNameCS); } String propertyName = propertyNameCS.toString(); advance(); switch (propertyName.length()) { case 0: throw makeException("empty property name"); case 2: int sci = RegexData.subCategories.indexOf(propertyName); if (sci < 0 || sci % 2 == 1) throw makeException("unknown category"); return getSubCategoryCharClass(sci / 2); case 1: int ci = RegexData.categories.indexOf(propertyName.charAt(0)); if (ci < 0) throw makeException("unknown category", propertyName); return getCategoryCharClass(ci); default: if (!propertyName.startsWith("Is")) break; String blockName = propertyName.substring(2); for (int i = 0; i < RegexData.specialBlockNames.length; i++) if (blockName.equals(RegexData.specialBlockNames[i])) return specialBlockCharClasses[i]; if (!isBlock(blockName)) throw makeException("invalid block name", blockName); return new Property("In" + blockName); } throw makeException("invalid property name", propertyName); } private CharClass parseCharClassExpr() throws RegexSyntaxException { boolean compl; if (curChar == '^') { advance(); compl = true; } else { compl = false; } List members = new ArrayList(10); //boolean firstOrLast = true; do { CharClass lower = parseCharClassEscOrXmlChar(); members.add(lower); if (curChar == ']' || eos) { addCaseVariant(lower, members); break; } //firstOrLast = isLastInGroup(); if (curChar == '-') { char next = regExp.charAt(pos); if (next == '[') { // hyphen denotes subtraction addCaseVariant(lower, members); advance(); break; } else if (next == ']') { // hyphen denotes a regular character - no need to do anything addCaseVariant(lower, members); // TODO: the spec rules are unclear here. We are allowing hyphen to represent // itself in contexts like [A-Z-0-9] } else { // hyphen denotes a character range advance(); CharClass upper = parseCharClassEscOrXmlChar(); if (lower.getSingleChar() < 0 || upper.getSingleChar() < 0) throw makeException("the ends of a range must be single characters"); if (lower.getSingleChar() > upper.getSingleChar()) throw makeException("invalid range (start > end)"); members.set(members.size() - 1, new CharRange(lower.getSingleChar(), upper.getSingleChar())); if (caseBlind) { // Special-case A-Z and a-z if (lower.getSingleChar() == 'a' && upper.getSingleChar() == 'z') { members.add(new CharRange('A', 'Z')); for (int v=0; v= 0; ci = RegexData.CATEGORY_NAMES.indexOf(code, ci + 1)) { int[] addRanges = RegexData.CATEGORY_RANGES[ci / 2]; for (int i = 0; i < addRanges.length; i += 2) classes.add(new CharRange(addRanges[i], addRanges[i + 1])); } if (code == 'P') classes.add(makeCharClass(RegexData.CATEGORY_Pi + RegexData.CATEGORY_Pf)); if (code == 'L') { classes.add(new SingleChar(RegexData.UNICODE_3_1_ADD_Ll)); classes.add(new SingleChar(RegexData.UNICODE_3_1_ADD_Lu)); } if (code == 'C') { // JDK 1.4 leaves Cn out of C? classes.add(new Subtraction(new Property("Cn"), new Union(new CharClass[]{new SingleChar(RegexData.UNICODE_3_1_ADD_Lu), new SingleChar(RegexData.UNICODE_3_1_ADD_Ll)}))); List assignedRanges = new ArrayList(5); for (int i = 0; i < RegexData.CATEGORY_RANGES.length; i++) for (int j = 0; j < RegexData.CATEGORY_RANGES[i].length; j += 2) assignedRanges.add(new CharRange(RegexData.CATEGORY_RANGES[i][j], RegexData.CATEGORY_RANGES[i][j + 1])); classes.add(new Subtraction(new CharRange(UTF16.NONBMP_MIN, UTF16.NONBMP_MAX), new Union(assignedRanges))); } if (classes.size() == 1) return (CharClass) classes.get(0); return new Union(classes); } private static CharClass computeSubCategoryCharClass(String name) { CharClass base = new Property(name); int sci = RegexData.CATEGORY_NAMES.indexOf(name); if (sci < 0) { if (name.equals("Cn")) { // Unassigned List assignedRanges = new ArrayList(5); assignedRanges.add(new SingleChar(RegexData.UNICODE_3_1_ADD_Lu)); assignedRanges.add(new SingleChar(RegexData.UNICODE_3_1_ADD_Ll)); for (int i = 0; i < RegexData.CATEGORY_RANGES.length; i++) for (int j = 0; j < RegexData.CATEGORY_RANGES[i].length; j += 2) assignedRanges.add(new CharRange(RegexData.CATEGORY_RANGES[i][j], RegexData.CATEGORY_RANGES[i][j + 1])); return new Subtraction(new Union( new CharClass[]{base, new CharRange(UTF16.NONBMP_MIN, UTF16.NONBMP_MAX)}), new Union(assignedRanges)); } if (name.equals("Pi")) return makeCharClass(RegexData.CATEGORY_Pi); if (name.equals("Pf")) return makeCharClass(RegexData.CATEGORY_Pf); return base; } List classes = new ArrayList(5); classes.add(base); int[] addRanges = RegexData.CATEGORY_RANGES[sci / 2]; for (int i = 0; i < addRanges.length; i += 2) classes.add(new CharRange(addRanges[i], addRanges[i + 1])); if (name.equals("Lu")) classes.add(new SingleChar(RegexData.UNICODE_3_1_ADD_Lu)); else if (name.equals("Ll")) classes.add(new SingleChar(RegexData.UNICODE_3_1_ADD_Ll)); else if (name.equals("Nl")) classes.add(new CharRange(RegexData.UNICODE_3_1_CHANGE_No_to_Nl_MIN, RegexData.UNICODE_3_1_CHANGE_No_to_Nl_MAX)); else if (name.equals("No")) return new Subtraction(new Union(classes), new CharRange(RegexData.UNICODE_3_1_CHANGE_No_to_Nl_MIN, RegexData.UNICODE_3_1_CHANGE_No_to_Nl_MAX)); return new Union(classes); } private static CharClass makeCharClass(String members) { List list = new ArrayList(5); for (int i = 0, len = members.length(); i < len; i++) list.add(new SingleChar(members.charAt(i))); return new Union(list); } /** * Main method for testing. Outputs to System.err the Java translation of a supplied * regular expression * @param args command line arguments * arg[0] a regular expression * arg[1] = xpath to invoke the XPath rules * @throws RegexSyntaxException */ public static void main(String[] args) throws RegexSyntaxException { String s = translate(args[0], 11, args[1].equals("xpath"), false, true); System.err.println(StringValue.diagnosticDisplay(s)); try { Pattern.compile(s); } catch (Exception err) { System.err.println("Error: " + err.getMessage()); } System.err.println(); } //} } /* Copyright (c) 2001-2003 Thai Open Source Software Center Ltd All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of the Thai Open Source Software Center Ltd nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file except changes marked. // // The Initial Developer of the Original Code is James Clark // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): Michael Kay // saxonb-9.1.0.8/bj/net/sf/saxon/java/JavaPlatform.java0000644000175000017500000003204711033112257021557 0ustar eugeneeugenepackage net.sf.saxon.java; import net.sf.saxon.Configuration; import net.sf.saxon.trans.Err; import net.sf.saxon.Platform; import net.sf.saxon.event.PipelineConfiguration; import net.sf.saxon.functions.*; import net.sf.saxon.regex.RegularExpression; import net.sf.saxon.sort.CodepointCollator; import net.sf.saxon.sort.NamedCollation; import net.sf.saxon.sort.StringCollator; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.SchemaType; import javax.xml.transform.Source; import javax.xml.transform.stream.StreamSource; import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.text.Collator; import java.util.Properties; /** * Implementation of the Platform class containing methods specific to the Java platform * (as distinct from .NET). This is a singleton class with no instance data. */ public class JavaPlatform implements Platform { private static JavaPlatform theInstance = new JavaPlatform(); /** * Get the singleton instance of this class * @return the singleton instance */ public static JavaPlatform getInstance() { return theInstance; } private JavaPlatform() {} /** * Perform platform-specific initialization of the configuration */ public void initialize(Configuration config) { config.setExtensionFunctionFactory("java", new JavaExtensionFunctionFactory(config)); } /** * Return true if this is the Java platform */ public boolean isJava() { return true; } /** * Return true if this is the .NET platform */ public boolean isDotNet() { return false; } /** * Construct an absolute URI from a relative URI and a base URI. The method uses the resolve * method of the java.net.URI class, except where the base URI uses the (non-standard) "jar:" scheme, * in which case the method used is new URL(baseURL, relativeURL). * *

Spaces in either URI are converted to %20

* *

If no base URI is available, and the relative URI is not an absolute URI, then the current * directory is used as a base URI.

* * @param relativeURI the relative URI. Null is permitted provided that the base URI is an absolute URI * @param base the base URI * @return the absolutized URI * @throws java.net.URISyntaxException if either of the strings is not a valid URI or * if the resolution fails */ public URI makeAbsolute(String relativeURI, String base) throws URISyntaxException { URI absoluteURI; // System.err.println("makeAbsolute " + relativeURI + " against base " + base); if (relativeURI == null) { absoluteURI = new URI(ResolveURI.escapeSpaces(base)); if (!absoluteURI.isAbsolute()) { throw new URISyntaxException(base, "Relative URI not supplied, so base URI must be absolute"); } else { return absoluteURI; } } relativeURI = ResolveURI.escapeSpaces(relativeURI); base = ResolveURI.escapeSpaces(base); try { if (base==null || base.length() == 0) { absoluteURI = new URI(relativeURI); if (!absoluteURI.isAbsolute()) { String expandedBase = ResolveURI.tryToExpand(base); if (!expandedBase.equals(base)) { // prevent infinite recursion return makeAbsolute(relativeURI, expandedBase); } } } else if (base != null && (base.startsWith("jar:") || base.startsWith("file:////"))) { // jar: URIs can't be resolved by the java.net.URI class, because they don't actually // conform with the RFC standards for hierarchic URI schemes (quite apart from not being // a registered URI scheme). But they seem to be widely used. // URIs starting file://// are accepted by the java.net.URI class, they are used to // represent Windows UNC filenames. However, the java.net.URI algorithm for resolving // a relative URI against such a base URI fails to produce a usable UNC filename (it's not // clear whether Java is implementing RFC 3986 correctly here, it depends on interpretation). // So we use the java.net.URL algorithm for this case too, because it works. try { URL baseURL = new URL(base); URL absoluteURL = new URL(baseURL, relativeURI); absoluteURI = new URI(absoluteURL.toString()); // TODO: JDK1.5: use absoluteURL.toURI() } catch (MalformedURLException err) { throw new URISyntaxException(base + " " + relativeURI, err.getMessage()); } } else { URI baseURI; try { baseURI = new URI(base); } catch (URISyntaxException e) { throw new URISyntaxException(base, "Invalid base URI: " + e.getMessage()); } try { new URI(relativeURI); // for validation only } catch (URISyntaxException e) { throw new URISyntaxException(base, "Invalid relative URI: " + e.getMessage()); } absoluteURI = (relativeURI.length()==0 ? baseURI : baseURI.resolve(relativeURI) ); } } catch (IllegalArgumentException err0) { // can be thrown by resolve() when given a bad URI throw new URISyntaxException(relativeURI, "Cannot resolve URI against base " + Err.wrap(base)); } return absoluteURI; } /** * Get the platform version */ public String getPlatformVersion() { return "Java version " + System.getProperty("java.version"); } /** * Get a suffix letter to add to the Saxon version number to identify the platform */ public String getPlatformSuffix() { return "J"; } /** * Convert a StreamSource to either a SAXSource or a PullSource, depending on the native * parser of the selected platform * * @param pipe the pipeline configuration * @param input the supplied StreamSource * @param validation indicates whether schema validation is required * @param dtdValidation indicates whether DTD validation is required * @param stripspace indicates whether whitespace text nodes should be stripped * @return the PullSource or SAXSource, initialized with a suitable parser, or the original * input Source, if now special handling is required or possible. This implementation * always returns the original input unchanged. */ public Source getParserSource(PipelineConfiguration pipe, StreamSource input, int validation, boolean dtdValidation, int stripspace) { return input; } /** * Create a compiled regular expression * @param regex the source text of the regular expression, in XML Schema or XPath syntax * @param xmlVersion set to integer 10 for XML 1.0, 11 for XML 1.1 * @param syntax requests XPath or XML Schema regex syntax *@param flags the flags argument as supplied to functions such as fn:matches(), in string form @throws XPathException if the syntax of the regular expression or flags is incorrect @return the compiled regular expression */ public RegularExpression compileRegularExpression( CharSequence regex, int xmlVersion, int syntax, CharSequence flags) throws XPathException { int flagBits = JRegularExpression.setFlags(flags); return new JRegularExpression(regex, xmlVersion, syntax, flagBits); } /** * Obtain a collation with a given set of properties. The set of properties is extensible * and variable across platforms. Common properties with example values include lang=ed-GB, * strength=primary, case-order=upper-first, ignore-modifiers=yes, alphanumeric=yes. * Properties that are not supported are generally ignored; however some errors, such as * failing to load a requested class, are fatal. * @param config the configuration object * @param props the desired properties of the collation * @param uri the collation URI * @return a collation with these properties * @throws XPathException if a fatal error occurs */ public StringCollator makeCollation(Configuration config, Properties props, String uri) throws XPathException { return JavaCollationFactory.makeCollation(config, uri, props); } /** * Given a collation, determine whether it is capable of returning collation keys. * The essential property of collation keys * is that if two values are equal under the collation, then the collation keys are * equal under the equals() method. * * @param collation the collation, provided as a Comparator * @return true if this collation can supply collation keys */ public boolean canReturnCollationKeys(StringCollator collation) { return (collation instanceof CodepointCollator) || ((collation instanceof NamedCollation) && (((NamedCollation)collation).getCollation() instanceof Collator)); } /** * Given a collation, get a collation key. The essential property of collation keys * is that if two values are equal under the collation, then the collation keys are * compare correctly under the equals() method. * * @throws ClassCastException if the collation is not one that is capable of supplying * collation keys (this should have been checked in advance) */ public Object getCollationKey(NamedCollation namedCollation, String value) { return ((Collator)namedCollation.getCollation()).getCollationKey(value); } /** * Make the default extension function factory appropriate to the platform */ public void makeExtensionLibrary(Configuration config) { config.setExtensionBinder("java", new JavaExtensionLibrary(config)); } /** * Add the platform-specific function libraries to a function library list. The libraries * that are added are those registered with the Configuration using * {@link Configuration#setExtensionBinder(String, net.sf.saxon.functions.FunctionLibrary)} * @param list the function library list that is to be extended * @param config the Configuration * @param hostLanguage the host language, for example Configuration.XQUERY */ public void addFunctionLibraries(FunctionLibraryList list, Configuration config, int hostLanguage) { FunctionLibrary extensionBinder = config.getExtensionBinder("java"); if (extensionBinder instanceof JavaExtensionLibrary) { ((JavaExtensionLibrary)extensionBinder).setStrictJavaUriFormat( hostLanguage != Configuration.XSLT ); } list.addFunctionLibrary(extensionBinder); } /** * Register a namespace-to-Java-class mapping declared using saxon:script in an XSLT stylesheet * @param library the library to contain the function, which must be a JavaExtensionLibrary * @param uri the namespace of the function name * @param theClass the Java class that implements this namespace */ public void declareJavaClass(FunctionLibrary library, String uri, Class theClass) { if (library instanceof JavaExtensionLibrary) { ((JavaExtensionLibrary)library).declareJavaClass(uri, theClass); } else { throw new IllegalStateException("saxon:script cannot be used with a custom extension library factory"); } } public SchemaType getExternalObjectType(Configuration config, String uri, String localName) { throw new UnsupportedOperationException("getExternalObjectType for Java"); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. //saxonb-9.1.0.8/bj/net/sf/saxon/java/JRegexIterator.java0000644000175000017500000001633411033112257022070 0ustar eugeneeugenepackage net.sf.saxon.java; import net.sf.saxon.om.ArrayIterator; import net.sf.saxon.om.Item; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.om.EmptyIterator; import net.sf.saxon.value.StringValue; import net.sf.saxon.regex.RegexIterator; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Class JRegexIterator - provides an iterator over matched and unmatched substrings. * This implementation of RegexIterator uses the JDK regular expression engine. */ public class JRegexIterator implements RegexIterator { private String theString; // the input string being matched private Pattern pattern; // the regex against which the string is matched private Matcher matcher; // the Matcher object that does the matching, and holds the state private String current; // the string most recently returned by the iterator private String next; // if the last string was a matching string, null; otherwise the next substring // matched by the regex private int position = 0; // the value of XPath position() private int prevEnd = 0; // the position in the input string of the end of the last match or non-match /** * Construct a RegexIterator. Note that the underlying matcher.find() method is called once * to obtain each matching substring. But the iterator also returns non-matching substrings * if these appear between the matching substrings. * @param string the string to be analysed * @param pattern the regular expression */ public JRegexIterator (String string, Pattern pattern) { theString = string; this.pattern = pattern; matcher = pattern.matcher(string); next = null; } /** * Get the next item in the sequence * @return the next item in the sequence */ public Item next() { if (next == null && prevEnd >= 0) { // we've returned a match (or we're at the start), so find the next match if (matcher.find()) { int start = matcher.start(); int end = matcher.end(); if (prevEnd == start) { // there's no intervening non-matching string to return next = null; current = theString.substring(start, end); prevEnd = end; } else { // return the non-matching substring first current = theString.substring(prevEnd, start); next = theString.substring(start, end); } } else { // there are no more regex matches, we must return the final non-matching text if any if (prevEnd < theString.length()) { current = theString.substring(prevEnd); next = null; } else { // this really is the end... current = null; position = -1; prevEnd = -1; return null; } prevEnd = -1; } } else { // we've returned a non-match, so now return the match that follows it, if there is one if (prevEnd >= 0) { current = next; next = null; prevEnd = matcher.end(); } else { current = null; position = -1; return null; } } position++; return StringValue.makeStringValue(current); } /** * Get the current item in the sequence * @return the item most recently returned by next() */ public Item current() { return StringValue.makeStringValue(current); } /** * Get the position of the current item in the sequence * @return the position of the item most recently returned by next(), starting at 1 */ public int position() { return position; } public void close() { } /** * Get another iterator over the same items * @return a new iterator, positioned before the first item */ public SequenceIterator getAnother() { return new JRegexIterator(theString, pattern); } /** * Get properties of this iterator, as a bit-significant integer. * * @return the properties of this iterator. This will be some combination of * properties such as {@link #GROUNDED}, {@link #LAST_POSITION_FINDER}, * and {@link #LOOKAHEAD}. It is always * acceptable to return the value zero, indicating that there are no known special properties. * It is acceptable for the properties of the iterator to change depending on its state. */ public int getProperties() { return 0; } /** * Determine whether the current item is a matching item or a non-matching item * @return true if the current item (the one most recently returned by next()) is * an item that matches the regular expression, or false if it is an item that * does not match */ public boolean isMatching() { return next == null && prevEnd >= 0; } /** * Get a substring that matches a parenthesised group within the regular expression * @param number the number of the group to be obtained * @return the substring of the current item that matches the n'th parenthesized group * within the regular expression */ public String getRegexGroup(int number) { if (!isMatching()) return null; if (number > matcher.groupCount() || number < 0) return ""; String s = matcher.group(number); if (s==null) return ""; return s; } /** * Get a sequence containing all the regex groups (except group 0, because we want to use indexing from 1). * This is used by the saxon:analyze-string() higher-order extension function. */ public SequenceIterator getRegexGroupIterator() { int c = matcher.groupCount(); if (c == 0) { return EmptyIterator.getInstance(); } else { StringValue[] groups = new StringValue[c]; for (int i=1; i<=groups.length; i++) { groups[i-1] = StringValue.makeStringValue(matcher.group(i)); } return new ArrayIterator(groups); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/java/JDK14RegexTranslator.java0000644000175000017500000010455611033112257023020 0ustar eugeneeugenepackage net.sf.saxon.java; import net.sf.saxon.om.FastStringBuffer; import net.sf.saxon.value.Whitespace; import net.sf.saxon.value.StringValue; import net.sf.saxon.regex.SurrogateRegexTranslator; import net.sf.saxon.regex.RegexData; import net.sf.saxon.regex.RegexSyntaxException; import net.sf.saxon.charcode.UTF16; import net.sf.saxon.charcode.XMLCharacterData; import net.sf.saxon.sort.IntRangeSet; import net.sf.saxon.Configuration; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /** * This class translates XML Schema regex syntax into JDK 1.4 regex syntax. * Author: James Clark, Thai Open Source Software Center Ltd. See statement at end of file. * Modified by Michael Kay (a) to integrate the code into Saxon, and (b) to support XPath additions * to the XML Schema regex syntax. *

* This version of the regular expression translator treats each half of a surrogate pair as a separate * character, translating anything in an XPath regex that can match a non-BMP character into a Java * regex that matches the two halves of a surrogate pair independently. This approach doesn't work * under JDK 1.5, whose regex engine treats a surrogate pair as a single character. *

*/ public class JDK14RegexTranslator extends SurrogateRegexTranslator { /** * Translates XML Schema regexes into java.util.regex regexes. * * @see java.util.regex.Pattern * @see XML Schema Part 2 */ /** * CharClass for each block name in specialBlockNames. */ private static final CharClass[] specialBlockCharClasses = { new CharRange(0x10300, 0x1032F), new CharRange(0x10330, 0x1034F), new CharRange(0x10400, 0x1044F), new CharRange(0x1D000, 0x1D0FF), new CharRange(0x1D100, 0x1D1FF), new CharRange(0x1D400, 0x1D7FF), new CharRange(0x20000, 0x2A6D6), new CharRange(0x2F800, 0x2FA1F), new CharRange(0xE0000, 0xE007F), new Union(new CharClass[]{ new CharRange(0xE000, 0xF8FF), new CharRange(0xF0000, 0xFFFFD), new CharRange(0x100000, 0x10FFFD) }), Empty.getInstance(), Empty.getInstance(), Empty.getInstance() }; private static final CharClass DOT_SCHEMA = new Complement(new Union(new CharClass[]{new SingleChar('\n'), new SingleChar('\r')})); private static final CharClass DOT_XPATH = new Dot(); private static final CharClass ESC_d = new Property("Nd"); private static final CharClass ESC_D = new Complement(ESC_d); private static final CharClass ESC_W = new Union(new CharClass[]{computeCategoryCharClass('P'), computeCategoryCharClass('Z'), computeCategoryCharClass('C')}); //was: new Property("P"), new Property("Z"), new Property("C") } private static final CharClass ESC_w = new Complement(ESC_W); private static final CharClass ESC_s = new Union(new CharClass[]{ new SingleChar(' '), new SingleChar('\n'), new SingleChar('\r'), new SingleChar('\t') }); private static final CharClass ESC_S = new Complement(ESC_s); // private static final CharClass ESC_i = makeCharClass(RegexData.NMSTRT_CATEGORIES, // RegexData.NMSTRT_INCLUDES, // RegexData.NMSTRT_EXCLUDE_RANGES); // // private static final CharClass ESC_I = new Complement(ESC_i); // // private static final CharClass ESC_c = makeCharClass(RegexData.NMCHAR_CATEGORIES, // RegexData.NMCHAR_INCLUDES, // RegexData.NMCHAR_EXCLUDE_RANGES); // // private static final CharClass ESC_C = new Complement(ESC_c); private static final CharClass ESC_i_10 = makeNameCharClass(XMLCharacterData.NAME_START_10_MASK); private static final CharClass ESC_i_11 = makeNameCharClass(XMLCharacterData.NAME_START_11_MASK); private static final CharClass ESC_I_10 = new Complement(ESC_i_10); private static final CharClass ESC_I_11 = new Complement(ESC_i_11); private static final CharClass ESC_c_10 = makeNameCharClass(XMLCharacterData.NAME_10_MASK); private static final CharClass ESC_c_11 = makeNameCharClass(XMLCharacterData.NAME_11_MASK); private static final CharClass ESC_C_10 = new Complement(ESC_c_10); private static final CharClass ESC_C_11 = new Complement(ESC_c_11); /** * Create a regex translator for JDK 1.4 */ public JDK14RegexTranslator() { } /** * Indicate whether whitespace should be ignored * @param ignore true if whitespace should be ignored */ public void setIgnoreWhitespace(boolean ignore) { ignoreWhitespace = ignore; } /** * Translates a regular expression in the syntax of XML Schemas Part 2 into a regular * expression in the syntax of java.util.regex.Pattern. The translation * assumes that the string to be matched against the regex uses surrogate pairs correctly. * If the string comes from XML content, a conforming XML parser will automatically * check this; if the string comes from elsewhere, it may be necessary to check * surrogate usage before matching. * * @param regExp a String containing a regular expression in the syntax of XML Schemas Part 2 * @param xmlVersion integer constant indicating XML 1.0 or XML 1.1 * @param xpath a boolean indicating whether the XPath 2.0 F+O extensions to the schema * regex syntax are permitted * @return a String containing a regular expression in the syntax of java.util.regex.Pattern * @throws net.sf.saxon.regex.RegexSyntaxException if regexp is not a regular expression in the * syntax of XML Schemas Part 2, or XPath 2.0, as appropriate * @see java.util.regex.Pattern * @see XML Schema Part 2 */ public String translate(CharSequence regExp, int xmlVersion, boolean xpath) throws RegexSyntaxException { //System.err.println("Input regex: " + FastStringBuffer.diagnosticPrint(regExp)); //JDK14RegexTranslator tr = new JDK14RegexTranslator(regexp); this.regExp = regExp; this.xmlVersion = xmlVersion; isXPath = xpath; length = regExp.length(); advance(); translateTop(); //System.err.println("Output regex: " + FastStringBuffer.diagnosticPrint(result)); return result.toString(); } static class Subtraction extends CharClass { private final CharClass cc1; private final CharClass cc2; Subtraction(CharClass cc1, CharClass cc2) { // min corresponds to intersection // complement corresponds to negation super(Math.min(cc1.getContainsBmp(), -cc2.getContainsBmp()), Math.min(cc1.getContainsNonBmp(), -cc2.getContainsNonBmp())); this.cc1 = cc1; this.cc2 = cc2; } public void outputBmp(FastStringBuffer buf) { buf.append('['); cc1.outputBmp(buf); buf.append("&&"); cc2.outputComplementBmp(buf); buf.append(']'); } // void outputBmp(FastStringBuffer buf) { // buf.append("(?="); // cc1.outputBmp(buf); // buf.append(")(?:"); // cc2.outputComplementBmp(buf); // buf.append(')'); // } public void outputComplementBmp(FastStringBuffer buf) { buf.append('['); cc1.outputComplementBmp(buf); cc2.outputBmp(buf); buf.append(']'); } // void outputComplementBmp(FastStringBuffer buf) { // buf.append("(?="); // cc1.outputComplementBmp(buf); // buf.append(")(?:"); // cc2.outputBmp(buf); // buf.append(')'); // } public void addNonBmpRanges(List ranges) { List posList = new ArrayList(5); cc1.addNonBmpRanges(posList); List negList = new ArrayList(5); cc2.addNonBmpRanges(negList); sortRangeList(posList); sortRangeList(negList); Iterator negIter = negList.iterator(); Range negRange; if (negIter.hasNext()) { negRange = (Range) negIter.next(); } else { negRange = null; } for (int i = 0, len = posList.size(); i < len; i++) { Range posRange = (Range) posList.get(i); while (negRange != null && negRange.getMax() < posRange.getMin()) { if (negIter.hasNext()) { negRange = (Range) negIter.next(); } else { negRange = null; } } // if negRange != null, negRange.max >= posRange.min int min = posRange.getMin(); while (negRange != null && negRange.getMin() <= posRange.getMax()) { if (min < negRange.getMin()) { ranges.add(new Range(min, negRange.getMin() - 1)); } min = negRange.getMax() + 1; if (min > posRange.getMax()) { break; } if (negIter.hasNext()) { negRange = (Range) negIter.next(); } else { negRange = null; } } if (min <= posRange.getMax()) { ranges.add(new Range(min, posRange.getMax())); } } } } static class Union extends CharClass { private final List members; Union(CharClass[] v) { this(toList(v)); } private static List toList(CharClass[] v) { List members = new ArrayList(5); for (int i = 0; i < v.length; i++) { members.add(v[i]); } return members; } Union(List members) { super(computeContainsBmp(members), computeContainsNonBmp(members)); this.members = members; } public void outputBmp(FastStringBuffer buf) { buf.append('['); for (int i = 0, len = members.size(); i < len; i++) { CharClass cc = (CharClass) members.get(i); if (cc.getContainsBmp() != NONE) { if (cc instanceof SimpleCharClass) { ((SimpleCharClass) cc).inClassOutputBmp(buf); } else { cc.outputBmp(buf); } } } buf.append(']'); } public void outputComplementBmp(FastStringBuffer buf) { boolean first = true; int len = members.size(); for (int i = 0; i < len; i++) { CharClass cc = (CharClass) members.get(i); if (cc.getContainsBmp() != NONE && cc instanceof SimpleCharClass) { if (first) { buf.append("[^"); first = false; } ((SimpleCharClass) cc).inClassOutputBmp(buf); } } for (int i = 0; i < len; i++) { CharClass cc = (CharClass) members.get(i); if (cc.getContainsBmp() != NONE && !(cc instanceof SimpleCharClass)) { if (first) { buf.append('['); first = false; } else { buf.append("&&"); } // can't have any members that are ALL, because that would make this ALL, which violates // the precondition for outputComplementBmp cc.outputComplementBmp(buf); } } if (first) // all members are NONE, so this is NONE, so complement is everything { buf.append("[\u0000-\uFFFF]"); } else { buf.append(']'); } } public void addNonBmpRanges(List ranges) { for (int i = 0, len = members.size(); i < len; i++) { ((CharClass) members.get(i)).addNonBmpRanges(ranges); } } private static int computeContainsBmp(List members) { int ret = NONE; for (int i = 0, len = members.size(); i < len; i++) { ret = Math.max(ret, ((CharClass) members.get(i)).getContainsBmp()); } return ret; } private static int computeContainsNonBmp(List members) { int ret = NONE; for (int i = 0, len = members.size(); i < len; i++) { ret = Math.max(ret, ((CharClass) members.get(i)).getContainsNonBmp()); } return ret; } } protected boolean translateAtom() throws RegexSyntaxException { switch (curChar) { case RegexData.EOS: if (!eos) { break; } // fall through case '?': case '*': case '+': case ')': case '{': case '}': case '|': case ']': return false; case '(': copyCurChar(); int thisCapture = ++currentCapture; translateRegExp(); expect(')'); captures.add(thisCapture); copyCurChar(); return true; case '\\': advance(); parseEsc().output(result); return true; case '[': inCharClassExpr = true; advance(); parseCharClassExpr().output(result); return true; case '.': if (isXPath) { DOT_XPATH.output(result); advance(); return true; } else { DOT_SCHEMA.output(result); advance(); return true; } case '$': case '^': if (isXPath) { copyCurChar(); return true; } result.append('\\'); break; } copyCurChar(); return true; } private static CharClass makeNameCharClass(byte mask) { List ranges = new ArrayList(); // Add colon to the set of characters matched ranges.add(new SingleChar(':')); // Plus all the characters from the NCName tables IntRangeSet members = XMLCharacterData.getCategory(mask); int used = members.getNumberOfRanges(); int[] startPoints = members.getStartPoints(); int[] endPoints = members.getEndPoints(); for (int i=0; i= 0) { // limit a back-reference to two digits, but only allow two if there is such a capture int n = c0 * 10 + c1; advance(); if (captures.contains(n)) { // treat it as a two-digit back-reference return new BackReference(n); } else { recede(); } } if (captures.contains(c0)) { return new BackReference(c0); } else { // Changed by erratum FO.E4 to be an error throw makeException("invalid backreference \\" + c0 + " (no such group)"); } } else { throw makeException("digit not allowed after \\"); } case '$': if (isXPath) { break; } // otherwise fall through default: throw makeException("invalid escape sequence"); } CharClass tem = new SingleChar(curChar); advance(); return tem; } private CharClass parseProp() throws RegexSyntaxException { expect('{'); int start = pos; for (; ;) { advance(); if (curChar == '}') { break; } if (!isAsciiAlnum(curChar) && curChar != '-') { expect('}'); } } CharSequence propertyNameCS = regExp.subSequence(start, pos - 1); if (ignoreWhitespace && !inCharClassExpr) { propertyNameCS = Whitespace.removeAllWhitespace(propertyNameCS); } String propertyName = propertyNameCS.toString(); advance(); switch (propertyName.length()) { case 0: throw makeException("empty property name"); case 2: int sci = RegexData.subCategories.indexOf(propertyName); if (sci < 0 || sci % 2 == 1) { throw makeException("unknown category"); } return getSubCategoryCharClass(sci / 2); case 1: int ci = RegexData.categories.indexOf(propertyName.charAt(0)); if (ci < 0) { throw makeException("unknown category", propertyName); } return getCategoryCharClass(ci); default: if (!propertyName.startsWith("Is")) { break; } String blockName = propertyName.substring(2); for (int i = 0; i < RegexData.specialBlockNames.length; i++) { if (blockName.equals(RegexData.specialBlockNames[i])) { return specialBlockCharClasses[i]; } } if (!isBlock(blockName)) { throw makeException("invalid block name", blockName); } return new Property("In" + blockName); } throw makeException("invalid property name", propertyName); } private CharClass parseCharClassExpr() throws RegexSyntaxException { boolean compl; if (curChar == '^') { advance(); compl = true; } else { compl = false; } List members = new ArrayList(10); //boolean firstOrLast = true; do { CharClass lower = parseCharClassEscOrXmlChar(); members.add(lower); if (curChar == ']' || eos) { break; } //firstOrLast = isLastInGroup(); if (curChar == '-') { char next = regExp.charAt(pos); if (next == '[') { // hyphen denotes subtraction advance(); break; } else if (next == ']') { // hyphen denotes a regular character - no need to do anything // TODO: the spec rules are unclear here. We are allowing hyphen to represent // itself in contexts like [A-Z-0-9] } else { // hyphen denotes a character range advance(); CharClass upper = parseCharClassEscOrXmlChar(); if (lower.getSingleChar() < 0 || upper.getSingleChar() < 0) { throw makeException("the ends of a range must be single characters"); } if (lower.getSingleChar() > upper.getSingleChar()) { throw makeException("invalid range (start > end)"); } members.set(members.size() - 1, new CharRange(lower.getSingleChar(), upper.getSingleChar())); // look for a subtraction if (curChar == '-' && regExp.charAt(pos) == '[') { advance(); break; } } } } while (curChar != ']'); if (eos) { expect(']'); } CharClass result; if (members.size() == 1) { result = (CharClass) members.get(0); } else { result = new Union(members); } if (compl) { result = new Complement(result); } if (curChar == '[') { advance(); result = new Subtraction(result, parseCharClassExpr()); expect(']'); } inCharClassExpr = false; advance(); return result; } private CharClass parseCharClassEscOrXmlChar() throws RegexSyntaxException { switch (curChar) { case RegexData.EOS: if (eos) { expect(']'); } break; case '\\': advance(); return parseEsc(); case '[': case ']': throw makeException("character must be escaped", new String(new char[]{curChar})); case '-': break; } CharClass tem; if (UTF16.isSurrogate(curChar)) { if (!UTF16.isHighSurrogate(curChar)) { throw makeException("invalid surrogate pair"); } char c1 = curChar; advance(); if (!UTF16.isLowSurrogate(curChar)) { throw makeException("invalid surrogate pair"); } tem = new WideSingleChar(UTF16.combinePair(c1, curChar)); } else { tem = new SingleChar(curChar); } advance(); return tem; } private static synchronized CharClass getCategoryCharClass(int ci) { if (categoryCharClasses[ci] == null) { categoryCharClasses[ci] = computeCategoryCharClass(RegexData.categories.charAt(ci)); } return categoryCharClasses[ci]; } private static synchronized CharClass getSubCategoryCharClass(int sci) { if (subCategoryCharClasses[sci] == null) { subCategoryCharClasses[sci] = computeSubCategoryCharClass(RegexData.subCategories.substring(sci * 2, (sci + 1) * 2)); } return subCategoryCharClasses[sci]; } private static CharClass computeCategoryCharClass(char code) { List classes = new ArrayList(5); classes.add(new Property(new String(new char[]{code}))); for (int ci = RegexData.CATEGORY_NAMES.indexOf(code); ci >= 0; ci = RegexData.CATEGORY_NAMES.indexOf(code, ci + 1)) { int[] addRanges = RegexData.CATEGORY_RANGES[ci / 2]; for (int i = 0; i < addRanges.length; i += 2) { classes.add(new CharRange(addRanges[i], addRanges[i + 1])); } } if (code == 'P') { classes.add(makeCharClass(RegexData.CATEGORY_Pi + RegexData.CATEGORY_Pf)); } if (code == 'L') { classes.add(new SingleChar(RegexData.UNICODE_3_1_ADD_Ll)); classes.add(new SingleChar(RegexData.UNICODE_3_1_ADD_Lu)); } if (code == 'C') { // JDK 1.4 leaves Cn out of C? classes.add(new Subtraction(new Property("Cn"), new Union(new CharClass[]{new SingleChar(RegexData.UNICODE_3_1_ADD_Lu), new SingleChar(RegexData.UNICODE_3_1_ADD_Ll)}))); List assignedRanges = new ArrayList(5); for (int i = 0; i < RegexData.CATEGORY_RANGES.length; i++) { for (int j = 0; j < RegexData.CATEGORY_RANGES[i].length; j += 2) { assignedRanges.add(new CharRange(RegexData.CATEGORY_RANGES[i][j], RegexData.CATEGORY_RANGES[i][j + 1])); } } classes.add(new Subtraction(new CharRange(UTF16.NONBMP_MIN, UTF16.NONBMP_MAX), new Union(assignedRanges))); } if (classes.size() == 1) { return (CharClass) classes.get(0); } return new Union(classes); } private static CharClass computeSubCategoryCharClass(String name) { CharClass base = new Property(name); int sci = RegexData.CATEGORY_NAMES.indexOf(name); if (sci < 0) { if (name.equals("Cn")) { // Unassigned List assignedRanges = new ArrayList(5); assignedRanges.add(new SingleChar(RegexData.UNICODE_3_1_ADD_Lu)); assignedRanges.add(new SingleChar(RegexData.UNICODE_3_1_ADD_Ll)); for (int i = 0; i < RegexData.CATEGORY_RANGES.length; i++) { for (int j = 0; j < RegexData.CATEGORY_RANGES[i].length; j += 2) { assignedRanges.add(new CharRange(RegexData.CATEGORY_RANGES[i][j], RegexData.CATEGORY_RANGES[i][j + 1])); } } return new Subtraction(new Union(new CharClass[]{base, new CharRange(UTF16.NONBMP_MIN, UTF16.NONBMP_MAX)}), new Union(assignedRanges)); } if (name.equals("Pi")) { return makeCharClass(RegexData.CATEGORY_Pi); } if (name.equals("Pf")) { return makeCharClass(RegexData.CATEGORY_Pf); } return base; } List classes = new ArrayList(5); classes.add(base); int[] addRanges = RegexData.CATEGORY_RANGES[sci / 2]; for (int i = 0; i < addRanges.length; i += 2) { classes.add(new CharRange(addRanges[i], addRanges[i + 1])); } if (name.equals("Lu")) { classes.add(new SingleChar(RegexData.UNICODE_3_1_ADD_Lu)); } else if (name.equals("Ll")) { classes.add(new SingleChar(RegexData.UNICODE_3_1_ADD_Ll)); } else if (name.equals("Nl")) { classes.add(new CharRange(RegexData.UNICODE_3_1_CHANGE_No_to_Nl_MIN, RegexData.UNICODE_3_1_CHANGE_No_to_Nl_MAX)); } else if (name.equals("No")) { return new Subtraction(new Union(classes), new CharRange(RegexData.UNICODE_3_1_CHANGE_No_to_Nl_MIN, RegexData.UNICODE_3_1_CHANGE_No_to_Nl_MAX)); } return new Union(classes); } private static CharClass makeCharClass(String members) { List list = new ArrayList(5); for (int i = 0, len = members.length(); i < len; i++) { list.add(new SingleChar(members.charAt(i))); } return new Union(list); } /** * Diagnostic entry point * @param args argument 1 - XPath regex; argument 2 - xpath|xmlschema * @throws RegexSyntaxException */ public static void main(String[] args) throws RegexSyntaxException { String s = new JDK14RegexTranslator().translate(args[0], Configuration.XML11, args[1].equals("xpath")); System.err.println(StringValue.diagnosticDisplay(s)); } //} } /* Copyright (c) 2001-2003 Thai Open Source Software Center Ltd All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of the Thai Open Source Software Center Ltd nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file except changes marked. // // The Initial Developer of the Original Code is James Clark // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): Michael Kay // saxonb-9.1.0.8/bj/net/sf/saxon/java/JRegularExpression.java0000644000175000017500000002135111033112257022760 0ustar eugeneeugenepackage net.sf.saxon.java; import net.sf.saxon.om.EmptyIterator; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.regex.RegexIterator; import net.sf.saxon.regex.RegexSyntaxException; import net.sf.saxon.regex.RegularExpression; import net.sf.saxon.trans.XPathException; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * A compiled regular expression implemented using the Java JDK regex package */ public class JRegularExpression implements RegularExpression { Pattern pattern; String javaRegex; int flagBits; /** * Create a regular expression, starting with an already-translated Java regex * @param javaRegex the regular expression after translation to Java notation * @param flagBits the option bits, derived from the user-specified flags */ public JRegularExpression(String javaRegex, int flagBits) { this.flagBits = flagBits; this.javaRegex = javaRegex; String j = System.getProperty("java.version"); if (j.startsWith("1.4")) { pattern = Pattern.compile(javaRegex, flagBits & (~Pattern.COMMENTS)); } else { pattern = Pattern.compile(javaRegex, flagBits & (~(Pattern.COMMENTS | Pattern.CASE_INSENSITIVE))); } } /** * Create (compile) a regular expression * @param regex the source text of the regular expression, in XML Schema or XPath syntax * @param xmlVersion indicates whether \i and \c have their XML 1.0 or XML 1.1 meanings * @param syntax indicates whether XPath, XML Schema, or Java native regular expression syntax is to be used * @param flagBits the flags argument translated to the Java bit-significant integer representation * @throws net.sf.saxon.trans.XPathException if the syntax of the regular expression or flags is incorrect */ public JRegularExpression(CharSequence regex, int xmlVersion, int syntax, int flagBits) throws XPathException { this.flagBits = flagBits; try { String j = System.getProperty("java.version"); if (syntax == NATIVE_SYNTAX) { javaRegex = regex.toString(); pattern = Pattern.compile(javaRegex, flagBits); } else if (j.startsWith("1.4")) { JDK14RegexTranslator translator = new JDK14RegexTranslator(); translator.setIgnoreWhitespace((flagBits & Pattern.COMMENTS) != 0); javaRegex = translator.translate( regex, xmlVersion, syntax==XPATH_SYNTAX); pattern = Pattern.compile(javaRegex, flagBits & (~Pattern.COMMENTS)); } else { boolean ignoreWhitespace = ((flagBits & Pattern.COMMENTS) != 0); boolean caseBlind = ((flagBits & Pattern.CASE_INSENSITIVE) != 0); javaRegex = JDK15RegexTranslator.translate( regex, xmlVersion, syntax==XPATH_SYNTAX, ignoreWhitespace, caseBlind); pattern = Pattern.compile(javaRegex, flagBits & (~(Pattern.COMMENTS | Pattern.CASE_INSENSITIVE))); } } catch (RegexSyntaxException e) { XPathException err = new XPathException(e.getMessage()); err.setErrorCode("FORX0002"); throw err; } } /** * Get the Java regular expression (after translation from an XPath regex, but before compilation) * @return the regular expression in Java notation */ public String getJavaRegularExpression() { return javaRegex; } /** * Get the flag bits as used by the Java regular expression engine * @return the flag bits */ public int getFlagBits() { return flagBits; } /** * Use this regular expression to analyze an input string, in support of the XSLT * analyze-string instruction. The resulting RegexIterator provides both the matching and * non-matching substrings, and allows them to be distinguished. It also provides access * to matched subgroups. */ public RegexIterator analyze(CharSequence input) { return new JRegexIterator(input.toString(), pattern); } /** * Determine whether the regular expression contains a match for a given string * * @param input the string to match * @return true if the string matches, false otherwise */ public boolean containsMatch(CharSequence input) { return pattern.matcher(input).find(); } /** * Determine whether the regular expression match a given string in its entirety * * @param input the string to match * @return true if the string matches, false otherwise */ public boolean matches(CharSequence input) { return pattern.matcher(input).matches(); } /** * Replace all substrings of a supplied input string that match the regular expression * with a replacement string. * * @param input the input string on which replacements are to be performed * @param replacement the replacement string in the format of the XPath replace() function * @return the result of performing the replacement * @throws net.sf.saxon.trans.XPathException * if the replacement string is invalid */ public CharSequence replace(CharSequence input, CharSequence replacement) throws XPathException { Matcher matcher = pattern.matcher(input); try { return matcher.replaceAll(replacement.toString()); } catch (IndexOutOfBoundsException e) { // this occurs if the replacement string references a group $n and there are less than n // capturing subexpressions in the regex. In this case we're supposed to replace $n by an // empty string. We do this by modifying the replacement string. int gps = matcher.groupCount(); if (gps >= 9) { // don't know what's gone wrong here throw e; } String r = replacement.toString(); // remove occurrences of $n from the replacement string, if n is greater than the number of groups String f = "\\$[" + (gps+1) + "-9]"; String rep = Pattern.compile(f).matcher(r).replaceAll(""); return matcher.replaceAll(rep); } } /** * Use this regular expression to tokenize an input string. * * @param input the string to be tokenized * @return a SequenceIterator containing the resulting tokens, as objects of type StringValue */ public SequenceIterator tokenize(CharSequence input) { if (input.length() == 0) { return EmptyIterator.getInstance(); } return new JTokenIterator(input, pattern); } /** * Set the Java flags from the supplied XPath flags. * @param inFlags the flags as a string, e.g. "im" * @return the flags as a bit-significant integer * @throws XPathException if the supplied value is invalid */ public static int setFlags(CharSequence inFlags) throws XPathException { int flags = Pattern.UNIX_LINES; for (int i=0; i Package overview: net.sf.saxon.java

This package contains Saxon code that is specific to the Java platform, as distinct from .NET

The areas where Saxon has different implementations for the two platforms are primarily URI handling, interfaces to XML parsers, regular expression handling, and use of collations.

Access to these classes is generally via the Platform object, of which the implementation for the Java platform is named JavaPlatform. This is obtained in turn via the static method Configuration.getPlatform()

saxonb-9.1.0.8/bj/net/sf/saxon/RelativeURIResolver.java0000644000175000017500000001157611033112257022131 0ustar eugeneeugenepackage net.sf.saxon; import javax.xml.transform.TransformerException; import javax.xml.transform.URIResolver; import javax.xml.transform.Source; /** * The standard JAXP URIResolver is given a relative URI and a base URI and returns the resource * identified by this combination. However, to support a stable implementation of the doc() function, * Saxon needs to know what the absolute URI is before the resource is fetched, so it can determine whether * a document with that absolute URI actually exists. *

* This extended interface defines a URIResolver that separates the two functions of resolving a relative URI * against a base URI, and fetching a resource with that absolute URI. If the URI resolver supplied to Saxon * implements this interface, the absolute URI associated with a loaded document will be the URI returned by * this resolver. *

* The particular motivation for providing this interface is to allow a URIResolver to wrap a .NET XmlResolver, * which has additional capability not present in the JAXP interface. */ public interface RelativeURIResolver extends URIResolver { /** * Create an absolute URI from a relative URI and a base URI. This method performs the * process which is correctly called "URI resolution": this is purely a syntactic operation * on the URI strings, and does not retrieve any resources. * @param href A relative or absolute URI, to be resolved against the specified base URI * @param base The base URI against which the first argument will be made * absolute if the absolute URI is required. * @return A string containing the absolute URI that results from URI resolution. If the resource * needs to be fetched, this absolute URI will be supplied as the href parameter in a subsequent * call to the resolve method. */ public String makeAbsolute(String href, String base) throws TransformerException; /** * Called by the processor when it encounters * an xsl:include, xsl:import, or document() function. * * @param uri The absolute URI to be dereferenced * * @return A Source object, or null if the href cannot be dereferenced, * and the processor should try to resolve the URI itself. * * @throws javax.xml.transform.TransformerException if an error occurs when trying to * resolve the URI. */ public Source dereference(String uri) throws TransformerException; /** * Called by the processor when it encounters * an xsl:include, xsl:import, or document() function. * *

Despite the name, the main purpose of this method is to dereference the URI, not merely * to resolve it.

* *

This method is provided because it is required by the interface. When using a RelativeURIResolver, * the single-argument dereference() method is preferred. The result of calling this method should be the * same as the result of calling dereference(makeAbsolute(href, base))

* * @param href An href attribute, which may be relative or absolute. * @param base The base URI against which the first argument will be made * absolute if the absolute URI is required. * * @return A Source object, or null if the href cannot be resolved, * and the processor should try to resolve the URI itself. * * @throws javax.xml.transform.TransformerException if an error occurs when trying to * resolve the URI. */ public Source resolve(String href, String base) throws TransformerException; /** * Specify the media type of the resource that is expected to be delivered. This information is * supplied by the processor primarily to indicate whether the URIResolver is allowed to return * an XML tree already parsed. If the value is "text/plain" then the Source returned by the * resolve() method should be a StreamSource. * @param mediaType the expected media type */ public void setExpectedMediaType(String mediaType); // TODO: method is not currently used } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. //saxonb-9.1.0.8/bj/net/sf/saxon/functions/0000755000175000017500000000000012216261751017417 5ustar eugeneeugenesaxonb-9.1.0.8/bj/net/sf/saxon/functions/Root.java0000644000175000017500000001004511033112257021175 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.expr.*; import net.sf.saxon.om.Item; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.om.Axis; import net.sf.saxon.trans.XPathException; import net.sf.saxon.pattern.AnyNodeTest; /** * Implement the XPath 2.0 root() function */ public class Root extends SystemFunction { /** * Simplify and validate. * @param visitor an expression visitor */ public Expression simplify(ExpressionVisitor visitor) throws XPathException { useContextItemAsDefault(); return simplifyArguments(visitor); } /** * Get the static properties of this expression (other than its type). The result is * bit-significant. These properties are used for optimizations. In general, if * property bit is set, it is true, but if it is unset, the value is unknown. */ public int computeSpecialProperties() { int prop = StaticProperty.ORDERED_NODESET | StaticProperty.SINGLE_DOCUMENT_NODESET | StaticProperty.NON_CREATIVE; if ((getNumberOfArguments() == 0) || (argument[0].getSpecialProperties() & StaticProperty.CONTEXT_DOCUMENT_NODESET) != 0) { prop |= StaticProperty.CONTEXT_DOCUMENT_NODESET; } return prop; } /** * Add a representation of this expression to a PathMap. The PathMap captures a map of the nodes visited * by an expression in a source tree. *

*

The default implementation of this method assumes that an expression does no navigation other than * the navigation done by evaluating its subexpressions, and that the subexpressions are evaluated in the * same context as the containing expression. The method must be overridden for any expression * where these assumptions do not hold. For example, implementations exist for AxisExpression, ParentExpression, * and RootExpression (because they perform navigation), and for the doc(), document(), and collection() * functions because they create a new navigation root. Implementations also exist for PathExpression and * FilterExpression because they have subexpressions that are evaluated in a different context from the * calling expression.

* * @param pathMap the PathMap to which the expression should be added * @param pathMapNodeSet * @return the pathMapNode representing the focus established by this expression, in the case where this * expression is the first operand of a path expression or filter expression. For an expression that does * navigation, it represents the end of the arc in the path map that describes the navigation route. For other * expressions, it is the same as the input pathMapNode. */ public PathMap.PathMapNodeSet addToPathMap(PathMap pathMap, PathMap.PathMapNodeSet pathMapNodeSet) { AxisExpression root = new AxisExpression(Axis.ANCESTOR_OR_SELF, AnyNodeTest.getInstance()); root.setContainer(getContainer()); return root.addToPathMap(pathMap, pathMapNodeSet); } /** * Evaluate in a general context */ public Item evaluateItem(XPathContext c) throws XPathException { NodeInfo start = (NodeInfo)argument[0].evaluateItem(c); if (start==null) { return null; } return start.getRoot(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/functions/StandardCollectionURIResolver.java0000644000175000017500000005020711071153007026134 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.AugmentedSource; import net.sf.saxon.CollectionURIResolver; import net.sf.saxon.Configuration; import net.sf.saxon.Controller; import net.sf.saxon.event.PipelineConfiguration; import net.sf.saxon.event.Stripper; import net.sf.saxon.expr.*; import net.sf.saxon.om.*; import net.sf.saxon.pattern.NodeKindTest; import net.sf.saxon.trans.Err; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.AnyURIValue; import net.sf.saxon.value.ObjectValue; import net.sf.saxon.value.Whitespace; import org.xml.sax.XMLReader; import javax.xml.transform.ErrorListener; import javax.xml.transform.Source; import javax.xml.transform.TransformerException; import javax.xml.transform.stream.StreamSource; import java.io.File; import java.io.FilenameFilter; import java.net.URI; import java.net.URISyntaxException; /** * This class implements the default collection URI Resolver. *

* This supports two implementations of collections. If the URI supplied uses the "file:/" scheme, and the * file that is referenced is a directory, then the collection is the set of files in that directory. Query parameters * may be included in the URI: *

*

* Otherwise, the resolver attempts to dereference the URI to obtain a catalog file. This is an XML file * containing a list of documents, in the format:

*
 * <collection>
 *   <doc href="doc1.xml"/>
 *   <doc href="doc2.xml"/>
 * </collection>
 * 
*/ public class StandardCollectionURIResolver implements CollectionURIResolver { /** * Resolve a URI. * * @param href The relative URI of the collection. This corresponds to the * argument supplied to the collection() function. If the collection() function * was called with no arguments (to get the "default collection") this argument * will be null. * @param base The base URI that should be used. This is the base URI of the * static context in which the call to collection() was made, typically the URI * of the stylesheet or query module * @return an Iterator over the documents in the collection. The items returned * by this iterator must be instances either of xs:anyURI, or of node() (specifically, * {@link net.sf.saxon.om.NodeInfo}.). If xs:anyURI values are returned, the corresponding * document will be retrieved as if by a call to the doc() function: this means that * the system first checks to see if the document is already loaded, and if not, calls * the registered URIResolver to dereference the URI. This is the recommended approach * to ensure that the resulting collection is stable: however, it has the consequence * that the documents will by default remain in memory for the duration of the query * or transformation. */ public SequenceIterator resolve(String href, String base, XPathContext context) throws XPathException { if (href == null) { // default collection. This returns empty, we previously threw an error. return null; } URIQueryParameters params = null; URI relativeURI; try { relativeURI = new URI(ResolveURI.escapeSpaces(href)); String query = relativeURI.getQuery(); if (query != null) { params = new URIQueryParameters(query, context.getConfiguration()); int q = href.indexOf('?'); href = ResolveURI.escapeSpaces(href.substring(0, q)); relativeURI = new URI(href); } } catch (URISyntaxException e) { XPathException err = new XPathException("Invalid relative URI " + Err.wrap(href, Err.VALUE) + " passed to collection() function"); err.setErrorCode("FODC0004"); err.setXPathContext(context); throw err; } URI resolvedURI; if (!relativeURI.isAbsolute()) { if (base == null) { base = ResolveURI.tryToExpand(base); if (base == null) { XPathException err = new XPathException("Cannot resolve relative URI: no base URI available"); err.setErrorCode("FODC0004"); err.setXPathContext(context); throw err; } } try { resolvedURI = Configuration.getPlatform().makeAbsolute(href, base); } catch (URISyntaxException e) { XPathException err = new XPathException("Cannot resolve relative URI: " + e.getMessage()); err.setErrorCode("FODC0004"); err.setXPathContext(context); throw err; } } else { resolvedURI = relativeURI; } if ("file".equals(resolvedURI.getScheme())) { File file = new File(resolvedURI); if (!file.exists()) { XPathException err = new XPathException("The file or directory " + resolvedURI + " does not exist"); err.setErrorCode("FODC0004"); err.setXPathContext(context); throw err; } if (file.isDirectory()) { return directoryContents(file, params, context); } } return catalogContents(resolvedURI, params, context); } private SequenceIterator directoryContents(File directory, URIQueryParameters params, XPathContext context) { FilenameFilter filter = null; if (params != null) { FilenameFilter f = params.getFilenameFilter(); if (f != null) { filter = f; } } File[] files; if (filter == null) { files = directory.listFiles(); } else { files = directory.listFiles(filter); } ObjectValue[] fileValues = new ObjectValue[files.length]; for (int f=0; f"); err.setErrorCode("FODC0004"); err.setXPathContext(context); throw err; } break; } String stableAtt = top.getAttributeValue(pool.allocate("", "", "stable")); if (stableAtt != null) { if ("true".equals(stableAtt)) { stable = true; } else if ("false".equals(stableAtt)) { stable = false; } else { XPathException err = new XPathException( "The 'stable' attribute of element must be true or false"); err.setErrorCode("FODC0004"); err.setXPathContext(context); throw err; } } final boolean finalStable = stable; SequenceIterator documents = top.iterateAxis(Axis.CHILD, NodeKindTest.ELEMENT); ItemMappingFunction catalogueMapper = new ItemMappingFunction() { public Item map(Item item) throws XPathException { NodeInfo element = (NodeInfo)item; if (!("doc".equals(element.getLocalPart()) && element.getURI().length() == 0)) { XPathException err = new XPathException("children of element must be elements"); err.setErrorCode("FODC0004"); err.setXPathContext(context); throw err; } String href = Navigator.getAttributeValue(element, "", "href"); if (href==null) { XPathException err = new XPathException("\" element in catalogue has no @href attribute\""); err.setErrorCode("FODC0004"); err.setXPathContext(context); throw err; } String uri; try { uri = new URI(element.getBaseURI()).resolve(href).toString(); } catch (URISyntaxException e) { XPathException err = new XPathException("Invalid base URI or href URI in collection catalog: (" + element.getBaseURI() + ", " + href + ")"); err.setErrorCode("FODC0004"); err.setXPathContext(context); throw err; } if (finalStable) { return new AnyURIValue(uri); } else { // stability not required, bypass the document pool and URI resolver return context.getConfiguration().buildDocument(new StreamSource(uri)); } } }; return new ItemMappingIterator(documents, catalogueMapper); } /** * Mapping function to process the files in a directory. This maps a sequence of external * objects representing files to a sequence of DocumentInfo nodes representing the parsed * contents of those files. */ private static class FileExpander implements MappingFunction { private URIQueryParameters params; boolean recurse = false; int strip = Whitespace.UNSPECIFIED; int validation = Validation.STRIP; Boolean xinclude = null; XMLReader parser = null; int onError = URIQueryParameters.ON_ERROR_FAIL; FilenameFilter filter = null; PipelineConfiguration pipe; public FileExpander(URIQueryParameters params, PipelineConfiguration pipe) { this.params = params; this.pipe = pipe; if (params != null) { FilenameFilter f = params.getFilenameFilter(); if (f != null) { filter = f; } Boolean r = params.getRecurse(); if (r != null) { recurse = r.booleanValue(); } Integer v = params.getValidationMode(); if (v != null) { validation = v.intValue(); } xinclude = params.getXInclude(); strip = params.getStripSpace(); Integer e = params.getOnError(); if (e != null) { onError = e.intValue(); } XMLReader p = params.getXMLReader(); if (p != null) { parser = p; } } } /** * Map one item to a sequence. * * @param item The item to be mapped. * If context is supplied, this must be the same as context.currentItem(). * @return either (a) a SequenceIterator over the sequence of items that the supplied input * item maps to, or (b) an Item if it maps to a single item, or (c) null if it maps to an empty * sequence. */ public SequenceIterator map(Item item) throws XPathException { File file = (File)((ObjectValue)item).getObject(); if (file.isDirectory()) { if (recurse) { File[] files; if (filter == null) { files = file.listFiles(); } else { files = file.listFiles(filter); } ObjectValue[] fileValues = new ObjectValue[files.length]; for (int f=0; f 60) { // TODO: make measurements to get the optimum cut-off point return translateUsingMap(sv0.getStringValueCS(), buildMap(sv1, sv2)); } CharSequence cs0 = sv0.getStringValueCS(); CharSequence cs1 = sv1.getStringValueCS(); CharSequence cs2 = sv2.getStringValueCS(); String st1 = cs1.toString(); FastStringBuffer sb = new FastStringBuffer(cs0.length()); int s2len = cs2.length(); int s0len = cs0.length(); for (int i=0; ia2.length-1 ? -1 : a2[i])); } } return map; } /** * Implement the translate() function using an index built at compile time * @param in the string to be translated * @param map index built at compile time, mapping input characters to output characters. The map returns * -1 for a character that is to be deleted from the input string, Integer.MAX_VALUE for a character that is * to remain intact * @return the translated character string */ public static CharSequence translateUsingMap(CharSequence in, IntToIntMap map) { int len = in.length(); FastStringBuffer sb = new FastStringBuffer(len); for (int i=0; i= 55296 && c <= 56319) { // we'll trust the data to be sound charval = ((c - 55296) * 1024) + ((int) in.charAt(i + 1) - 56320) + 65536; i++; } else { charval = c; } int newchar = map.get(charval); if (newchar == Integer.MAX_VALUE) { // character not in map, so is not to be translated newchar = charval; } if (newchar == -1) { // no action, delete the character } else if (newchar < 65536) { sb.append((char)newchar); } else { // output a surrogate pair //To compute the numeric value of the character corresponding to a surrogate //pair, use this formula (all numbers are hex): //(FirstChar - D800) * 400 + (SecondChar - DC00) + 10000 newchar -= 65536; sb.append((char)((newchar / 1024) + 55296)); sb.append((char)((newchar % 1024) + 56320)); } } return sb; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/functions/NamespaceForPrefix.java0000644000175000017500000000406011033112257023773 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.InscopeNamespaceResolver; import net.sf.saxon.om.Item; import net.sf.saxon.om.NamespaceResolver; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.AnyURIValue; import net.sf.saxon.value.StringValue; /** * This class supports the function namespace-uri-for-prefix() */ public class NamespaceForPrefix extends SystemFunction { /** * Evaluate the function * @param context the XPath dynamic context * @return the URI corresponding to the prefix supplied in the first argument, or null * if the prefix is not in scope * @throws XPathException if a failure occurs evaluating the arguments */ public Item evaluateItem(XPathContext context) throws XPathException { NodeInfo element = (NodeInfo)argument[1].evaluateItem(context); StringValue p = (StringValue)argument[0].evaluateItem(context); String prefix; if (p == null) { prefix = ""; } else { prefix = p.getStringValue(); } NamespaceResolver resolver = new InscopeNamespaceResolver(element); String uri = resolver.getURIForPrefix(prefix, true); if (uri == null) { return null; } return new AnyURIValue(uri); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/functions/StringFn.java0000644000175000017500000000554411033112257022014 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.expr.Expression; import net.sf.saxon.expr.ExpressionVisitor; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.expr.PathMap; import net.sf.saxon.om.Item; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.StringValue; /** * Implement XPath function string() */ public class StringFn extends SystemFunction { /** * Simplify and validate. * This is a pure function so it can be simplified in advance if the arguments are known * @param visitor an expression visitor */ public Expression simplify(ExpressionVisitor visitor) throws XPathException { useContextItemAsDefault(); argument[0].setFlattened(true); return simplifyArguments(visitor); } /** * Add a representation of a doc() call or similar function to a PathMap. * This is a convenience method called by the addToPathMap() methods for doc(), document(), collection() * and similar functions. These all create a new root expression in the path map. * * @param pathMap the PathMap to which the expression should be added * @param pathMapNodes the node in the PathMap representing the focus at the point where this expression * is called. Set to null if this expression appears at the top level. * @return the pathMapNode representing the focus established by this expression, in the case where this * expression is the first operand of a path expression or filter expression */ public PathMap.PathMapNodeSet addDocToPathMap(PathMap pathMap, PathMap.PathMapNodeSet pathMapNodes) { PathMap.PathMapNodeSet result = argument[0].addToPathMap(pathMap, pathMapNodes); if (result != null) { result.setAtomized(); } return null; } /** * Evaluate the function */ public Item evaluateItem(XPathContext c) throws XPathException { Item arg = argument[0].evaluateItem(c); if (arg==null) { return StringValue.EMPTY_STRING; } else { return StringValue.makeStringValue(arg.getStringValueCS()); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/functions/Component.java0000644000175000017500000000577711033112257022234 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.expr.Expression; import net.sf.saxon.expr.ExpressionVisitor; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.Item; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.AtomicValue; /** * This class supports the get_X_from_Y functions defined in XPath 2.0 */ public class Component extends SystemFunction { public static final int YEAR = 1; public static final int MONTH = 2; public static final int DAY = 3; public static final int HOURS = 4; public static final int MINUTES = 5; public static final int SECONDS = 6; public static final int TIMEZONE = 7; public static final int LOCALNAME = 8; public static final int NAMESPACE = 9; public static final int PREFIX = 10; public static final int MICROSECONDS = 11; // internal use only public static final int WHOLE_SECONDS = 12; // internal use only public static final int YEAR_ALLOWING_ZERO = 13; // internal use only int component; public Expression simplify(ExpressionVisitor visitor) throws XPathException { component = (operation >> 16) & 0xffff; return super.simplify(visitor); } /** * Get the required component */ public int getRequiredComponent() { return component; } /** * Get the required component name as a string */ public String getRequiredComponentAsString() { String[] components = {"", "YEAR", "MONTH", "DAY", "HOURS", "MINUTES", "SECONDS", "TIMEZONE", "LOCALNAME", "NAMESPACE", "PREFIX", "MICROSECONDS", "WHOLE_SECONDS", "YEAR_ALLOWING_ZERO"}; return components[component]; } /** * Evaluate the expression */ public Item evaluateItem(XPathContext context) throws XPathException { AtomicValue arg = (AtomicValue)argument[0].evaluateItem(context); if (arg == null) { return null; } return arg.getComponent(component); } /** * Copy an expression. This makes a deep copy. * * @return the copy of the original expression */ public Expression copy() { Component c = (Component)super.copy(); c.component = (c.operation >> 16) & 0xffff; return c; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/functions/Rounding.java0000644000175000017500000000562011033112257022042 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.expr.ArithmeticExpression; import net.sf.saxon.expr.Calculator; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.Item; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.AtomicValue; import net.sf.saxon.value.Int64Value; import net.sf.saxon.value.NumericValue; /** * This class supports the ceiling(), floor(), round(), and round-to-half-even() functions, * and also the abs() function */ public final class Rounding extends SystemFunction { public static final int FLOOR = 0; public static final int CEILING = 1; public static final int ROUND = 2; public static final int HALF_EVEN = 3; public static final int ABS = 4; /** * Evaluate the function */ public Item evaluateItem(XPathContext context) throws XPathException { AtomicValue val0 = (AtomicValue)argument[0].evaluateItem(context); if (val0==null) return null; NumericValue val = (NumericValue)val0; switch (operation) { case FLOOR: return val.floor(); case CEILING: return val.ceiling(); case ROUND: return val.round(); case HALF_EVEN: int scale = 0; if (argument.length==2) { AtomicValue scaleVal0 = (AtomicValue)argument[1].evaluateItem(context); NumericValue scaleVal = (NumericValue)scaleVal0; scale = (int)scaleVal.longValue(); } return val.roundHalfToEven(scale); case ABS: double sign = val.signum(); if (sign < 0) { return val.negate(); } else if (sign == 0) { // ensure that the result is positive zero //return val.arithmetic(Token.PLUS, Int64Value.ZERO, context); return ArithmeticExpression.compute(val, Calculator.PLUS, Int64Value.ZERO, context); } else { return val; } default: throw new UnsupportedOperationException("Unknown rounding function"); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/functions/Put.java0000644000175000017500000001261611033112257021030 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.Configuration; import net.sf.saxon.trans.Err; import net.sf.saxon.Platform; import net.sf.saxon.expr.Expression; import net.sf.saxon.expr.ExpressionVisitor; import net.sf.saxon.expr.PendingUpdateList; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.Type; import java.net.URI; import java.net.URISyntaxException; /** * Implements the fn:put() function in XQuery Update 1.0. */ public class Put extends SystemFunction { String expressionBaseURI = null; public void checkArguments(ExpressionVisitor visitor) throws XPathException { if (expressionBaseURI == null) { super.checkArguments(visitor); expressionBaseURI = visitor.getStaticContext().getBaseURI(); if (expressionBaseURI == null && argument.length == 1) { XPathException de = new XPathException("Base URI in static context of resolve-uri() is unknown"); de.setErrorCode("FONS0005"); throw de; } } } /** * Copy an expression. This makes a deep copy. * @return the copy of the original expression */ public Expression copy() { Put d = (Put)super.copy(); d.expressionBaseURI = expressionBaseURI; return d; } /** * Determine whether this is an updating expression as defined in the XQuery update specification * @return true if this is an updating expression */ public boolean isUpdatingExpression() { return true; } /** * Evaluate an expression as a single item. This always returns either a single Item or * null (denoting the empty sequence). No conversion is done. This method should not be * used unless the static type of the expression is a subtype of "item" or "item?": that is, * it should not be called if the expression may return a sequence. There is no guarantee that * this condition will be detected. * @param context The context in which the expression is to be evaluated * @return the node or atomic value that results from evaluating the * expression; or null to indicate that the result is an empty * sequence * @throws net.sf.saxon.trans.XPathException * if any dynamic error occurs evaluating the * expression */ // public Item evaluateItem(XPathContext context) throws XPathException { // NodeInfo node = (NodeInfo)argument[0].evaluateItem(context); // int kind = node.getNodeKind(); // if (kind != Type.ELEMENT && kind != Type.DOCUMENT) { // dynamicError("Node in put() must be a document or element node", // "FOUP0001", context); // return null; // } // String relative = argument[1].evaluateItem(context).getStringValue(); // Platform platform = Configuration.getPlatform(); // try { // URI resolved = platform.makeAbsolute(relative, expressionBaseURI); // return new AnyURIValue(resolved.toString()); // } catch (URISyntaxException err) { // dynamicError("Base URI " + Err.wrap(expressionBaseURI) + " is invalid: " + err.getMessage(), // "FOUP0002", context); // return null; // } // } /** * Evaluate an updating expression, adding the results to a Pending Update List. * The default implementation of this method, which is used for non-updating expressions, * throws an UnsupportedOperationException * @param context the XPath dynamic evaluation context * @param pul the pending update list to which the results should be written */ public void evaluatePendingUpdates(XPathContext context, PendingUpdateList pul) throws XPathException { NodeInfo node = (NodeInfo)argument[0].evaluateItem(context); int kind = node.getNodeKind(); if (kind != Type.ELEMENT && kind != Type.DOCUMENT) { dynamicError("Node in put() must be a document or element node", "FOUP0001", context); } String relative = argument[1].evaluateItem(context).getStringValue(); Platform platform = Configuration.getPlatform(); String abs; try { URI resolved = platform.makeAbsolute(relative, expressionBaseURI); abs = resolved.toString(); } catch (URISyntaxException err) { dynamicError("Base URI " + Err.wrap(expressionBaseURI) + " is invalid: " + err.getMessage(), "FOUP0002", context); abs = null; } pul.addPutAction(node, abs); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/functions/URIQueryParameters.java0000644000175000017500000001706511033112257023774 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.Configuration; import net.sf.saxon.om.FastStringBuffer; import net.sf.saxon.om.Validation; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.Whitespace; import org.xml.sax.XMLReader; import javax.xml.transform.TransformerException; import java.io.File; import java.io.FilenameFilter; import java.util.StringTokenizer; import java.util.regex.Pattern; /** * A set of query parameters on a URI passed to the collection() or document() function */ public class URIQueryParameters { FilenameFilter filter = null; Boolean recurse = null; Integer validation = null; int strip = Whitespace.UNSPECIFIED; Integer onError = null; XMLReader parser = null; Boolean xinclude = null; public static final int ON_ERROR_FAIL = 1; public static final int ON_ERROR_WARNING = 2; public static final int ON_ERROR_IGNORE = 3; /** * Create an object representing the query part of a URI * @param query the part of the URI after the "?" symbol * @param config the Saxon configuration */ public URIQueryParameters(String query, Configuration config) { if (query != null) { StringTokenizer t = new StringTokenizer(query, ";&"); while (t.hasMoreTokens()) { String tok = t.nextToken(); int eq = tok.indexOf('='); if (eq > 0 && eq < (tok.length()-1)) { String keyword = tok.substring(0, eq); String value = tok.substring(eq+1); if (keyword.equals("select")) { FastStringBuffer sb = new FastStringBuffer(value.length() + 6); sb.append('^'); for (int i=0; itrue if and only if the name should be * included in the file list; false otherwise. */ public boolean accept(File dir, String name) { return new File(dir, name).isDirectory() || pattern.matcher(name).matches(); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/functions/DistinctValues.java0000644000175000017500000001607211033112257023221 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.expr.ExpressionVisitor; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.Item; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.sort.AtomicComparer; import net.sf.saxon.sort.AtomicSortComparer; import net.sf.saxon.sort.ComparisonKey; import net.sf.saxon.sort.StringCollator; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.AtomicValue; import java.util.HashSet; /** * The XPath 2.0 distinct-values() function */ public class DistinctValues extends CollatingFunction { private transient AtomicComparer atomicComparer; public void checkArguments(ExpressionVisitor visitor) throws XPathException { super.checkArguments(visitor); if (stringCollator != null) { int type = argument[0].getItemType(visitor.getConfiguration().getTypeHierarchy()).getPrimitiveType(); atomicComparer = AtomicSortComparer.makeSortComparer( stringCollator, type, visitor.getStaticContext().makeEarlyEvaluationContext()); } } /** * Get the AtomicComparer allocated at compile time. * @return the AtomicComparer if one has been allocated at compile time; return null * if the collation is not known until run-time */ public AtomicComparer getAtomicComparer() { return atomicComparer; } /** * Evaluate the function to return an iteration of selected values or nodes. */ public SequenceIterator iterate(XPathContext context) throws XPathException { AtomicComparer comp = atomicComparer; if (comp == null) { int type = argument[0].getItemType(context.getConfiguration().getTypeHierarchy()).getPrimitiveType(); comp = makeAtomicSortComparer(type, context); } else { comp = comp.provideContext(context); } SequenceIterator iter = argument[0].iterate(context); return new DistinctIterator(iter, comp); } /** * Get a SortComparer that can be used to compare values * @param type the fingerprint of the static item type of the first argument after atomization * @param context The dynamic evaluation context. * @return the comparer */ private AtomicComparer makeAtomicSortComparer(int type, XPathContext context) throws XPathException { final StringCollator collator = getCollator(1, context); return AtomicSortComparer.makeSortComparer(collator, type, context); } /** * Iterator class to return the distinct values in a sequence */ public static class DistinctIterator implements SequenceIterator { private SequenceIterator base; private AtomicComparer comparer; private int position; private AtomicValue current; private HashSet lookup = new HashSet(40); /** * Create an iterator over the distinct values in a sequence * @param base the input sequence. This must return atomic values only. * @param comparer The comparer used to obtain comparison keys from each value; * these comparison keys are themselves compared using equals(). */ public DistinctIterator(SequenceIterator base, AtomicComparer comparer) { this.base = base; this.comparer = comparer; position = 0; } /** * Get the next item in the sequence.
* * @return the next item, or null if there are no more items. * @throws net.sf.saxon.trans.XPathException * if an error occurs retrieving the next item */ public Item next() throws XPathException { while (true) { AtomicValue nextBase = (AtomicValue)base.next(); if (nextBase==null) { current = null; position = -1; return null; } ComparisonKey key = comparer.getComparisonKey(nextBase); if (lookup.contains(key)) { //continue; } else { lookup.add(key); current = nextBase; position++; return nextBase; } } } /** * Get the current value in the sequence (the one returned by the * most recent call on next()). This will be null before the first * call of next(). * * @return the current item, the one most recently returned by a call on * next(); or null, if next() has not been called, or if the end * of the sequence has been reached. */ public Item current() { return current; } /** * Get the current position. This will be zero before the first call * on next(), otherwise it will be the number of times that next() has * been called. * * @return the current position, the position of the item returned by the * most recent call of next() */ public int position() { return position; } public void close() { base.close(); } /** * Get another SequenceIterator that iterates over the same items as the original, * but which is repositioned at the start of the sequence. * * @return a SequenceIterator that iterates over the same items, * positioned before the first item * @throws net.sf.saxon.trans.XPathException * if any error occurs */ public SequenceIterator getAnother() throws XPathException { return new DistinctIterator(base.getAnother(), comparer); } /** * Get properties of this iterator, as a bit-significant integer. * * @return the properties of this iterator. This will be some combination of * properties such as {@link #GROUNDED}, {@link #LAST_POSITION_FINDER}, * and {@link #LOOKAHEAD}. It is always * acceptable to return the value zero, indicating that there are no known special properties. * It is acceptable for the properties of the iterator to change depending on its state. */ public int getProperties() { return 0; } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/functions/Collection.java0000644000175000017500000001130511033112257022345 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.CollectionURIResolver; import net.sf.saxon.expr.*; import net.sf.saxon.om.EmptyIterator; import net.sf.saxon.om.Item; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.AnyURIValue; import javax.xml.transform.SourceLocator; /** * Implement the fn:collection() function. This is responsible for calling the * registered {@link CollectionURIResolver}. For the effect of the default * system-supplied CollectionURIResolver, see {@link StandardCollectionURIResolver} */ public class Collection extends SystemFunction { private String expressionBaseURI = null; public String getStaticBaseURI() { return expressionBaseURI; } public void checkArguments(ExpressionVisitor visitor) throws XPathException { if (expressionBaseURI == null) { super.checkArguments(visitor); expressionBaseURI = visitor.getStaticContext().getBaseURI(); } } /** * preEvaluate: this method suppresses compile-time evaluation by doing nothing * @param visitor an expression visitor */ public Expression preEvaluate(ExpressionVisitor visitor) { return this; } /** * Add a representation of this expression to a PathMap. The PathMap captures a map of the nodes visited * by an expression in a source tree. * * @param pathMap the PathMap to which the expression should be added * @param pathMapNodeSet * @return the pathMapNode representing the focus established by this expression, in the case where this * expression is the first operand of a path expression or filter expression */ public PathMap.PathMapNodeSet addToPathMap(PathMap pathMap, PathMap.PathMapNodeSet pathMapNodeSet) { return addDocToPathMap(pathMap, pathMapNodeSet); } /** * Iterate over the contents of the collection * @param context the dynamic context * @return an iterator, whose items will always be nodes (typically but not necessarily document nodes) * @throws XPathException */ public SequenceIterator iterate(final XPathContext context) throws XPathException { String href; if (getNumberOfArguments() == 0) { // No arguments supplied: this gets the default collection href = null; } else { href = argument[0].evaluateItem(context).getStringValue(); } CollectionURIResolver resolver = context.getConfiguration().getCollectionURIResolver(); SequenceIterator iter; try { iter = resolver.resolve(href, expressionBaseURI, context); } catch (XPathException e) { e.setLocator(this); throw e; } return getResolverResults(iter, expressionBaseURI, context, this); } public static SequenceIterator getResolverResults( SequenceIterator iter, final String baseURI, final XPathContext context, final SourceLocator locator) { if (iter == null) { return EmptyIterator.getInstance(); } else { ItemMappingFunction imf = new ItemMappingFunction() { public Item map(Item item) throws XPathException { if (item instanceof NodeInfo) { return item; } else if (item instanceof AnyURIValue) { return Document.makeDoc( item.getStringValue(), baseURI, context, locator); } else { throw new XPathException("Value returned by CollectionURIResolver must be an anyURI or a NodeInfo"); } }; }; return new ItemMappingIterator(iter, imf); } } // TODO: provide control over error recovery (etc) through options in the catalog file. } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/functions/ResolveURI.java0000644000175000017500000001154411033112257022256 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.Configuration; import net.sf.saxon.trans.Err; import net.sf.saxon.Platform; import net.sf.saxon.expr.ExpressionVisitor; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.expr.Expression; import net.sf.saxon.om.Item; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.AnyURIValue; import net.sf.saxon.value.AtomicValue; import java.io.File; import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; /** * This class supports the resolve-uri() functions in XPath 2.0 */ public class ResolveURI extends SystemFunction { String expressionBaseURI = null; public void checkArguments(ExpressionVisitor visitor) throws XPathException { if (expressionBaseURI == null) { super.checkArguments(visitor); expressionBaseURI = visitor.getStaticContext().getBaseURI(); if (expressionBaseURI == null && argument.length == 1) { XPathException de = new XPathException("Base URI in static context of resolve-uri() is unknown"); de.setErrorCode("FONS0005"); throw de; } } } /** * Get the static base URI of the expression */ public String getStaticBaseURI() { return expressionBaseURI; } /** * Copy an expression. This makes a deep copy. * @return the copy of the original expression */ public Expression copy() { ResolveURI d = (ResolveURI)super.copy(); d.expressionBaseURI = expressionBaseURI; return d; } /** * Evaluate the function at run-time */ public Item evaluateItem(XPathContext context) throws XPathException { AtomicValue arg0 = (AtomicValue)argument[0].evaluateItem(context); if (arg0 == null) { return null; } String relative = arg0.getStringValue(); String base; if (argument.length == 2) { base = argument[1].evaluateAsString(context).toString(); } else { base = expressionBaseURI; if (expressionBaseURI == null) { dynamicError("Base URI in static context of resolve-uri() is unknown", "FONS0005", context); return null; } } Platform platform = Configuration.getPlatform(); try { URI resolved = platform.makeAbsolute(relative, base); return new AnyURIValue(resolved.toString()); } catch (URISyntaxException err) { dynamicError("Base URI " + Err.wrap(base) + " is invalid: " + err.getMessage(), "FORG0002", context); return null; } } /** * If a system ID can't be parsed as a URL, try to expand it as a relative * URI using the current directory as the base URI. */ public static String tryToExpand(String systemId) { if (systemId==null) { systemId = ""; } try { new URL(systemId); return systemId; // all is well } catch (MalformedURLException err) { String dir; try { dir = System.getProperty("user.dir"); } catch (Exception geterr) { // this doesn't work when running an applet return systemId; } if (!(dir.endsWith("/") || systemId.startsWith("/"))) { dir = dir + '/'; } URI currentDirectoryURI = new File(dir).toURI(); URI baseURI = currentDirectoryURI.resolve(systemId); return baseURI.toString(); } } /** * Replace spaces by %20 */ public static String escapeSpaces(String s) { // It's not entirely clear why we have to escape spaces by hand, and not other special characters; // it's just that tests with a variety of filenames show that this approach seems to work. if (s == null) return s; int i = s.indexOf(' '); if (i < 0) { return s; } return (i == 0 ? "" : s.substring(0, i)) + "%20" + (i == s.length()-1 ? "" : escapeSpaces(s.substring(i+1))); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/functions/Compare.java0000644000175000017500000000351711033112257021646 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.Item; import net.sf.saxon.sort.GenericAtomicComparer; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.AtomicValue; import net.sf.saxon.value.Int64Value; /** * XSLT 2.0 compare() function */ // Supports string comparison using a collation public class Compare extends CollatingFunction { /** * Evaluate the expression */ public Item evaluateItem(XPathContext context) throws XPathException { AtomicValue arg0 = (AtomicValue)argument[0].evaluateItem(context); if (arg0==null) { return null; } AtomicValue arg1 = (AtomicValue)argument[1].evaluateItem(context); if (arg1==null) { return null; } GenericAtomicComparer collator = getAtomicComparer(2, context); int result = collator.compareAtomicValues(arg0, arg1); if (result < 0) { return Int64Value.MINUS_ONE; } else if (result > 0) { return Int64Value.PLUS_ONE; } else { return Int64Value.ZERO; } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/functions/Unordered.java0000644000175000017500000000372011033112257022203 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.expr.*; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ItemType; /** * XPath 2.0 unordered() function */ public class Unordered extends CompileTimeFunction { public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { Expression exp = super.typeCheck(visitor, contextItemType); if (exp instanceof Unordered) { Optimizer opt = visitor.getConfiguration().getOptimizer(); return ExpressionTool.unsorted(opt, ((Unordered)exp).argument[0], false); } return exp; } public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { Expression exp = super.optimize(visitor, contextItemType); if (exp instanceof Unordered) { return ExpressionTool.unsorted(visitor.getConfiguration().getOptimizer(), ((Unordered)exp).argument[0], false); } return exp; } /** * preEvaluate: called if the argument is constant * @param visitor an expression visitor */ public Expression preEvaluate(ExpressionVisitor visitor) throws XPathException { return argument[0]; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/functions/ExtensionFunctionFactory.java0000644000175000017500000000241111033112257025262 0ustar eugeneeugenepackage net.sf.saxon.functions; /** * This is a marker interface representing an abstract superclass of JavaExtensionFunctionFactory * and DotNetExtensionFunctionFactory. These play equivalent roles in the system: that is, they * are responsible for determining how the QNames of extension functions are bound to concrete * implementation classes; but they do not share the same interface. * *

This interface was introduced in Saxon 8.9. Prior to that, ExtensionFunctionFactory * was a concrete class - the class now named JavaExtensionFunctionFactory. */ public interface ExtensionFunctionFactory { } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/functions/DefaultCollation.java0000644000175000017500000000247411033112257023512 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.expr.Expression; import net.sf.saxon.expr.ExpressionVisitor; import net.sf.saxon.expr.StringLiteral; import net.sf.saxon.trans.XPathException; /** * Implement the XPath 2.0 default-collation() function */ public class DefaultCollation extends CompileTimeFunction { /** * Pre-evaluate the function * @param visitor an expression visitor */ public Expression preEvaluate(ExpressionVisitor visitor) throws XPathException { String s = visitor.getStaticContext().getDefaultCollationName(); return new StringLiteral(s); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/functions/FunctionLibraryList.java0000644000175000017500000001461311033112257024225 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.expr.Expression; import net.sf.saxon.expr.StaticContext; import net.sf.saxon.trans.XPathException; import net.sf.saxon.query.XQueryFunctionBinder; import net.sf.saxon.query.XQueryFunction; import net.sf.saxon.om.StructuredQName; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /** * A FunctionLibraryList is a list of FunctionLibraries. It is also a FunctionLibrary in its own right. * When required, it searches the list of FunctionLibraries to find the required function. */ public class FunctionLibraryList implements FunctionLibrary, XQueryFunctionBinder { public List libraryList = new ArrayList(8); /** * Add a new FunctionLibrary to the list of FunctionLibraries in this FunctionLibraryList. Note * that libraries are searched in the order they are added to the list. * @param lib A function library to be added to the list of function libraries to be searched. * @return the position of the library in the list */ public int addFunctionLibrary(FunctionLibrary lib) { libraryList.add(lib); return libraryList.size() - 1; } /** * Get the n'th function library in the list */ public FunctionLibrary get(int n) { return (FunctionLibrary)libraryList.get(n); } /** * Test whether an extension function with a given name and arity is available. This supports * the function-available() function in XSLT. This method may be called either at compile time * or at run time. * @param functionName * @param arity The number of arguments. This is set to -1 in the case of the single-argument * function-available() function; in this case the method should return true if there is some */ public boolean isAvailable(StructuredQName functionName, int arity) { for (Iterator it=libraryList.iterator(); it.hasNext();) { FunctionLibrary lib = (FunctionLibrary)it.next(); if (lib.isAvailable(functionName, arity)) { return true; } } return false; } /** * Bind an extension function, given the URI and local parts of the function name, * and the list of expressions supplied as arguments. This method is called at compile * time. * @param functionName * @param staticArgs The expressions supplied statically in arguments to the function call. * The length of this array represents the arity of the function. The intention is * that the static type of the arguments (obtainable via getItemType() and getCardinality() may * be used as part of the binding algorithm. In some cases it may be possible for the function * to be pre-evaluated at compile time, for example if these expressions are all constant values. * @param env * @return An object representing the extension function to be called, if one is found; * null if no extension function was found matching the required name and arity. * @throws net.sf.saxon.trans.XPathException if a function is found with the required name and arity, but * the implementation of the function cannot be loaded or used; or if an error occurs * while searching for the function. */ public Expression bind(StructuredQName functionName, Expression[] staticArgs, StaticContext env) throws XPathException { for (Iterator it=libraryList.iterator(); it.hasNext();) { FunctionLibrary lib = (FunctionLibrary)it.next(); Expression func = lib.bind(functionName, staticArgs, env); if (func != null) { return func; } } return null; } /** * Get the function declaration corresponding to a given function name and arity * * @return the XQueryFunction if there is one, or null if not. */ public XQueryFunction getDeclaration(StructuredQName functionName, Expression[] staticArgs) { for (Iterator it=libraryList.iterator(); it.hasNext();) { FunctionLibrary lib = (FunctionLibrary)it.next(); if (lib instanceof XQueryFunctionBinder) { XQueryFunction func = ((XQueryFunctionBinder)lib).getDeclaration(functionName, staticArgs); if (func != null) { return func; } } } return null; } /** * Get the list of contained FunctionLibraries. This method allows the caller to modify * the library list, for example by adding a new FunctionLibrary at a chosen position, * by removing a library from the list, or by changing the order of libraries in the list. * Note that such changes may violate rules in the * language specifications, or assumptions made within the product. * @return a list whose members are of class FunctionLibrary */ public List getLibraryList() { return libraryList; } /** * This method creates a copy of a FunctionLibrary: if the original FunctionLibrary allows * new functions to be added, then additions to this copy will not affect the original, or * vice versa. * * @return a copy of this function library. This must be an instance of the original class. */ public FunctionLibrary copy() { FunctionLibraryList fll = new FunctionLibraryList(); fll.libraryList = new ArrayList(libraryList.size()); for (int i=0; i= 0) { return this; } NodeInfo item = Document.preLoadDoc(href, expressionBaseURI, config, this); if (item!=null) { return new Literal(new SingletonNode(item)); } } catch (Exception err) { // ignore the exception and try again at run-time return this; } } return this; } public int computeCardinality() { return argument[0].getCardinality() & ~StaticProperty.ALLOWS_MANY; } /** * Add a representation of this expression to a PathMap. The PathMap captures a map of the nodes visited * by an expression in a source tree. * * @param pathMap the PathMap to which the expression should be added * @param pathMapNodeSet * @return the pathMapNode representing the focus established by this expression, in the case where this * expression is the first operand of a path expression or filter expression */ public PathMap.PathMapNodeSet addToPathMap(PathMap pathMap, PathMap.PathMapNodeSet pathMapNodeSet) { return addDocToPathMap(pathMap, pathMapNodeSet); } /** * Copy an expression. This makes a deep copy. * @return the copy of the original expression */ public Expression copy() { Doc d = (Doc)super.copy(); d.expressionBaseURI = expressionBaseURI; d.readOnce = readOnce; return d; } /** * Evaluate the expression * @param context the dynamic evaluation context * @return the result of evaluating the expression (a document node) * @throws XPathException */ public Item evaluateItem(XPathContext context) throws XPathException { return doc(context); } /** * Get the static properties of this expression (other than its type). The result is * bit-signficant. These properties are used for optimizations. In general, if * property bit is set, it is true, but if it is unset, the value is unknown. */ public int computeSpecialProperties() { return StaticProperty.ORDERED_NODESET | StaticProperty.PEER_NODESET | StaticProperty.NON_CREATIVE | StaticProperty.SINGLE_DOCUMENT_NODESET; // Declaring it as a peer node-set expression avoids sorting of expressions such as // doc(XXX)/a/b/c // The doc() function might appear to be creative: but it isn't, because multiple calls // with the same arguments will produce identical results. } private NodeInfo doc(XPathContext context) throws XPathException { AtomicValue hrefVal = (AtomicValue)argument[0].evaluateItem(context); if (hrefVal==null) { return null; } String href = hrefVal.getStringValue(); NodeInfo item = Document.makeDoc(href, expressionBaseURI, context, this); if (item==null) { // we failed to read the document dynamicError("Failed to load document " + href, "FODC0005", context); return null; } return item; } /** * Copy the document identified by this expression to a given Receiver. This method is used only when it is * known that the document is being copied, because there is then no problem about node identity. * @param context the XPath dynamic context * @param out the destination to which the document will be sent */ public void sendDocument(XPathContext context, Receiver out) throws XPathException { AtomicValue hrefVal = (AtomicValue)argument[0].evaluateItem(context); if (hrefVal==null) { return; } String href = hrefVal.getStringValue(); try { Document.sendDoc(href, expressionBaseURI, context, this, out); } catch (XPathException e) { e.maybeSetLocation(this); if (e.getErrorCodeLocalPart() == null) { e.setErrorCode("FODC0005"); } throw e; } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/functions/CompileTimeFunction.java0000644000175000017500000000414311033112257024171 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.expr.Expression; import net.sf.saxon.expr.ExpressionVisitor; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.Item; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.trans.XPathException; /** * Abtract class representing a function call that is always rewritten at compile-time: * it can never be executed */ public abstract class CompileTimeFunction extends SystemFunction { /** * preEvaluate: this method suppresses compile-time evaluation by doing nothing. * (this is because the default implementation of preEvaluate() calls evaluate() which * is not available for these functions) * @param visitor an expression visitor */ public Expression preEvaluate(ExpressionVisitor visitor) throws XPathException { return this; } /** * Evaluate as a single item */ public final Item evaluateItem(XPathContext c) throws XPathException { throw new IllegalStateException("Function " + getName(c) + " should have been resolved at compile-time"); } /** * Iterate over the results of the function */ public final SequenceIterator iterate(XPathContext c) { throw new IllegalStateException("Function " + getName(c) + " should have been resolved at compile-time"); } private String getName(XPathContext c) { return getDisplayName(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/functions/Minimax.java0000644000175000017500000003075411033112257021665 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.trans.Err; import net.sf.saxon.expr.*; import net.sf.saxon.om.Item; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.om.StandardNames; import net.sf.saxon.sort.AtomicComparer; import net.sf.saxon.sort.DescendingComparer; import net.sf.saxon.sort.GenericAtomicComparer; import net.sf.saxon.sort.StringCollator; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.*; import net.sf.saxon.value.*; /** * This class implements the min() and max() functions */ public class Minimax extends CollatingFunction { public static final int MIN = 2; public static final int MAX = 3; private BuiltInAtomicType argumentType = BuiltInAtomicType.ANY_ATOMIC; private boolean ignoreNaN = false; /** * Indicate whether NaN values should be ignored. For the external min() and max() function, a * NaN value in the input causes the result to be NaN. Internally, however, min() and max() are also * used in such a way that NaN values should be ignored. * @param ignore true if NaN values are to be ignored when computing the min or max. */ public void setIgnoreNaN(boolean ignore) { ignoreNaN = ignore; } /** * Test whether NaN values are to be ignored * @return true if NaN values are to be ignored. This is the case for internally-generated min() and max() * functions used to support general comparisons */ public boolean isIgnoreNaN() { return ignoreNaN; } /** * Static analysis: prevent sorting of the argument */ public void checkArguments(ExpressionVisitor visitor) throws XPathException { super.checkArguments(visitor); Optimizer opt = visitor.getConfiguration().getOptimizer(); argument[0] = ExpressionTool.unsorted(opt, argument[0], false); } /** * Determine the cardinality of the function. */ public int computeCardinality() { int c = super.computeCardinality(); if (!Cardinality.allowsZero(argument[0].getCardinality())) { c = StaticProperty.EXACTLY_ONE; } return c; } /** * Perform optimisation of an expression and its subexpressions. *

*

This method is called after all references to functions and variables have been resolved * to the declaration of the function or variable, and after all type checking has been done.

* * @param visitor an expression visitor * @param contextItemType the static type of "." at the point where this expression is invoked. * The parameter is set to null if it is known statically that the context item will be undefined. * If the type of the context item is not known statically, the argument is set to * {@link net.sf.saxon.type.Type#ITEM_TYPE} * @return the original expression, rewritten if appropriate to optimize execution * @throws XPathException if an error is discovered during this phase * (typically a type error) */ public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { TypeHierarchy th = visitor.getConfiguration().getTypeHierarchy(); argumentType = (BuiltInAtomicType)argument[0].getItemType(th).getAtomizedItemType().getPrimitiveItemType(); Expression e = super.optimize(visitor, contextItemType); if (e != this) { return e; } if (getNumberOfArguments() == 1) { // test for a singleton: this often happens after (A *

* To invoke these functions, use a function call of the form prefix:name() where * name is the method name, and prefix maps to a URI such as * http://saxon.sf.net/net.sf.saxon.functions.Extensions (only the part * of the URI after the last slash is important). */ public class Extensions { // The class is never instantiated private Extensions() { } /** * Switch tracing off. Only works if tracing was enabled at compile time. * * @param c the XPath dynamic context */ public static void pauseTracing(XPathContext c) { c.getController().pauseTracing(true); } /** * Resume tracing. Only works if tracing was originally enabled * but is currently paused. * * @param c the XPath dynamic context */ public static void resumeTracing(XPathContext c) { c.getController().pauseTracing(false); } /** * Return the system identifier of the context node * * @param c the XPath dynamic context * @return the system ID */ public static String systemId(XPathContext c) throws XPathException { Item item = c.getContextItem(); if (item == null) { XPathException e = new XPathException("The context item for saxon:systemId() is not set"); e.setXPathContext(c); throw e; } if (item instanceof NodeInfo) { return ((NodeInfo)item).getSystemId(); } else { return ""; } } /** * The function saxon:generate-id() is equivalent to the standard XSLT function generate-id(). * It is provided as an extension function to make it available in non-XSLT environments, for example * in XQuery. * * @param node the node whose identifier is required * @return as ASCII alphanumeric string that uniquely identifies this node */ public static String generateId(NodeInfo node) { FastStringBuffer buffer = new FastStringBuffer(16); node.generateId(buffer); return buffer.toString(); } /** * Return the line number of the context node. * * @param c the XPath dynamic context * @return the line number, or -1 if not available */ public static int lineNumber(XPathContext c) { Item item = c.getContextItem(); if (item instanceof NodeInfo) { return ((NodeInfo)item).getLineNumber(); } else { return -1; } } /** * Return the line number of the specified node. * * @param node the node whose line number is required * @return the line number of the node. This is only available if line numbering was switched on. */ public static int lineNumber(NodeInfo node) { if (node == null) { return -1; } return node.getLineNumber(); } /** * Return the column number of the context node. This is only * available if line numbering has been enabled for the containing tree * * @param c the XPath dynamic context * @return the column number, or -1 if not available */ public static int columnNumber(XPathContext c) { Item item = c.getCurrentIterator().current(); if (item instanceof NodeInfo) { return ((NodeInfo)item).getColumnNumber(); } else { return -1; } } /** * Return the column number of the specified node. * * @param node the node whose column number is required * @return the column number of the node. This is only available if line numbering was switched on. */ public static int columnNumber(NodeInfo node) { if (node == null) { return -1; } return node.getColumnNumber(); } /** * Remove a document from the document pool. The effect is that the document becomes eligible for * garbage collection, allowing memory to be released when processing of the document has finished. * The downside is that a subsequent call on document() with the same URI causes the document to be * reloaded and reparsed, and the new nodes will have different node identity from the old. * * @param context the evaluation context (supplied implicitly by the call mechanism) * @param doc the document to be released from the document pool * @return the document that was released. This allows a call such as * select="saxon:discard-document(document('a.xml'))" */ public static DocumentInfo discardDocument(XPathContext context, DocumentInfo doc) { if (doc == null) { return null; } Controller c = context.getController(); String uri = c.getDocumentPool().getDocumentURI(doc); if (uri != null) { c.removeUnavailableOutputDestination(uri); } return c.getDocumentPool().discard(doc); } /** * Determine whether two node-sets contain the same nodes * * @param p1 The first node-set. The iterator must be correctly ordered. * @param p2 The second node-set. The iterator must be correctly ordered. * @return true if p1 and p2 contain the same set of nodes */ public static boolean hasSameNodes(SequenceIterator p1, SequenceIterator p2) throws XPathException { SequenceIterator e1 = p1; SequenceIterator e2 = p2; if (e1 == null) { e1 = EmptyIterator.getInstance(); } if (e2 == null) { e2 = EmptyIterator.getInstance(); } while (true) { NodeInfo n1 = (NodeInfo)e1.next(); NodeInfo n2 = (NodeInfo)e2.next(); if (n1 == null || n2 == null) { return n1 == n2; } if (!n1.isSameNodeInfo(n2)) { return false; } } } /** * Sort a sequence of nodes or atomic values, using the atomic value itself, or the atomized value of the node, * as the sort key. The values must all be comparable. Strings are compared using * codepoint collation. When nodes are atomized, the result must not be a sequence containing * more than one item. * * @param context the XPath dynamic context * @param input the sequence to be sorted * @return an iterator over the sorted sequence */ public static SequenceIterator sort(XPathContext context, SequenceIterator input) { SortKeyEvaluator sortkey = new SortKeyEvaluator() { public Item evaluateSortKey(int n, XPathContext context) throws XPathException { Item c = context.getContextItem(); if (c instanceof NodeInfo) { Value v = ((NodeInfo)c).atomize(); if (v.getLength() == 0) { c = null; } else if (v.getLength() == 1) { c = v.itemAt(0); } else { throw new XPathException("error in saxon:sort() - a node has a typed value of length > 1"); } } return c; } }; AtomicComparer[] comparers = { new GenericAtomicComparer(CodepointCollator.getInstance(), context) }; return new SortedIterator(context, input, sortkey, comparers); } /** * Sort a sequence of nodes or atomic values, using a given expression to calculate the sort key. * as the sort key. The values must all be comparable. Strings are compared using * codepoint collation. When nodes are atomized, the result must not be a sequence containing * more than one item. * * @param context the XPath dynamic context * @param input the sequence to be sorted * @param sortKeyExpression the expression used to compute the sort keys * @return an iterator over the sorted sequence */ public static SequenceIterator sort(XPathContext context, SequenceIterator input, final Evaluate.PreparedExpression sortKeyExpression) { SortKeyEvaluator sortkey = new SortKeyEvaluator() { public Item evaluateSortKey(int n, XPathContext context) throws XPathException { Item c = sortKeyExpression.expression.evaluateItem(context); if (c instanceof NodeInfo) { Value v = ((NodeInfo)c).atomize(); if (v.getLength() == 0) { c = null; } else if (v.getLength() == 1) { c = v.itemAt(0); } else { throw new XPathException("error in saxon:sort() - a node has a typed value of length > 1"); } } return c; } }; AtomicComparer[] comparers = { new GenericAtomicComparer(CodepointCollator.getInstance(), context) }; return new SortedIterator(context, input, sortkey, comparers); } /** * Get the node with maximum numeric value of the string-value of each of a set of nodes * * @param nsv the input sequence * @return the node with the maximum numeric value */ public static Value highest(SequenceIterator nsv) throws XPathException { return net.sf.saxon.exslt.Math.highest(nsv); } /** * Get the maximum numeric value of a stored expression over a set of nodes * * @param context the XPath dynamic evaluation context * @param nsv the input sequence * @param pexpression the expression whose maximum is to be computed * @return an iterator over the items in the input sequence for which the expression takes its maximum value */ public static SequenceIterator highest(XPathContext context, SequenceIterator nsv, Evaluate.PreparedExpression pexpression) throws XPathException { if (nsv == null) { return EmptyIterator.getInstance(); } if (pexpression == null) { return EmptyIterator.getInstance(); } double max = Double.NEGATIVE_INFINITY; XPathContext c = context.newMinorContext(); c.setOriginatingConstructType(Location.SAXON_HIGHER_ORDER_EXTENSION_FUNCTION); Item highest = null; c.setCurrentIterator(nsv); while (true) { Item next = nsv.next(); if (next == null) { break; } Item val = pexpression.expression.evaluateItem(c); if (val instanceof NumericValue) { DoubleValue v = (DoubleValue)((NumericValue)val).convert(BuiltInAtomicType.DOUBLE, true, context).asAtomic(); if (v.getDoubleValue() > max) { max = v.getDoubleValue(); highest = nsv.current(); } } else { XPathException e = new XPathException("expression in saxon:highest() must return numeric values"); e.setXPathContext(context); throw e; } } return SingletonIterator.makeIterator(highest); } /** * Get the node with minimum numeric value of the string-value of each of a set of nodes * * @param nsv the input sequence * @return the node with the minimum numeric value */ public static Value lowest(SequenceIterator nsv) throws XPathException { return net.sf.saxon.exslt.Math.lowest(nsv); } /** * Get the node with minimum numeric value of the string-value of each of a set of nodes * * @param context the XPath dynamic evaluation context * @param nsv the input sequence * @param pexpression the expression whose minimum is to be computed * @return an iterator over the items in the input sequence for which the expression takes its minimum value */ public static SequenceIterator lowest(XPathContext context, SequenceIterator nsv, Evaluate.PreparedExpression pexpression) throws XPathException { if (nsv == null) { return EmptyIterator.getInstance(); } if (pexpression == null) { return EmptyIterator.getInstance(); } double min = Double.POSITIVE_INFINITY; XPathContext c = context.newMinorContext(); c.setOriginatingConstructType(Location.SAXON_HIGHER_ORDER_EXTENSION_FUNCTION); Item lowest = null; c.setCurrentIterator(nsv); while (true) { Item next = nsv.next(); if (next == null) { break; } Item val = pexpression.expression.evaluateItem(c); if (val instanceof NumericValue) { DoubleValue v = (DoubleValue)((NumericValue)val).convert(BuiltInAtomicType.DOUBLE, true, context).asAtomic(); if (v.getDoubleValue() < min) { min = v.getDoubleValue(); lowest = nsv.current(); } } else { XPathException e = new XPathException("expression in saxon:lowest() must return numeric values"); e.setXPathContext(context); throw e; } } return SingletonIterator.makeIterator(lowest); } /** * Get the items that satisfy the given expression, up to and excluding the first one * (in sequence order) that doesn't satisfy the expression. * * @param context the XPath dynamic evaluation context * @param in the input sequence * @param pexp the expression against which items are to be tested * @return an iterator over the items in the input sequence up to and excluding the first * one that doesn't satisfy the expression */ public static SequenceIterator leading(XPathContext context, SequenceIterator in, Evaluate.PreparedExpression pexp) { if (in == null) { return EmptyIterator.getInstance(); } if (pexp == null) { return EmptyIterator.getInstance(); } XPathContext c2 = context.newMinorContext(); c2.setOriginatingConstructType(Location.SAXON_HIGHER_ORDER_EXTENSION_FUNCTION); return new FilterIterator.Leading(in, pexp.expression, c2); } /** * Find all the nodes in ns1 that are after the first node in ns2. * Return ns1 if ns2 is empty, * * @param context the dynamic evaluation context * @param ns1 the first operand * @param ns2 the second operand * @return an iterator over the nodes in ns1 that are after the first node in ns2 */ // This function is no longer documented as a user-visible extension function. // But exslt:trailing depends on it. public static SequenceIterator after( XPathContext context, SequenceIterator ns1, SequenceIterator ns2) throws XPathException { NodeInfo first = null; // Find the first node in ns2 (in document order) GlobalOrderComparer comparer = GlobalOrderComparer.getInstance(); while (true) { Item item = ns2.next(); if (item == null) { if (first == null) { return ns1; } else { break; } } if (item instanceof NodeInfo) { NodeInfo node = (NodeInfo)item; if (first == null) { first = node; } else { if (comparer.compare(node, first) < 0) { first = node; } } } else { XPathException e = new XPathException("Operand of after() contains an item that is not a node"); e.setXPathContext(context); throw e; } } // Filter ns1 to select nodes that come after this one Expression filter = new IdentityComparison( new ContextItemExpression(), Token.FOLLOWS, new Literal(new SingletonNode(first))); return new FilterIterator(ns1, filter, context); } /** * Return an XPath expression that identifies a specified node * * @param node the node whose path is required * @return a path expression giving a path from the root of the tree to the specified node */ public static String path(NodeInfo node) throws XPathException { return Navigator.getPath(node); } /** * Return an XPath expression that identifies the current node * * @param c the XPath dynamic context * @return a path expression giving a path from the root of the tree to the context node */ public static String path(XPathContext c) throws XPathException { Item item = c.getContextItem(); if (item == null) { XPathException e = new XPathException("The context item for saxon:path() is not set"); e.setXPathContext(c); throw e; } if (item instanceof NodeInfo) { return Navigator.getPath((NodeInfo)item); } else { return ""; } } /** * Display the value of the type annotation of a node or an atomic value * * @param context the XPath dynamic context * @param item the node or atomic value whose type annotation is required * @return the type annotation or type label as a QName */ public static QNameValue typeAnnotation(XPathContext context, Item item) { if (item == null) { return null; } else if (item instanceof NodeInfo) { NodeInfo node = (NodeInfo)item; int code = node.getTypeAnnotation(); if ((code & NodeInfo.IS_DTD_TYPE) != 0) { code = StandardNames.XS_UNTYPED_ATOMIC; } if (code == -1) { int nodeKind = node.getNodeKind(); if (nodeKind == Type.ELEMENT || nodeKind == Type.DOCUMENT) { return new QNameValue("xs", NamespaceConstant.SCHEMA, "untyped"); } else { return new QNameValue("xs", NamespaceConstant.SCHEMA, "untypedAtomic"); } } return new QNameValue(context.getNamePool(), code); } else { AtomicType label = ((AtomicValue)item).getTypeLabel(); return new QNameValue(context.getNamePool(), label.getNameCode()); } } /** * Return the XPathContext object * * @param c the context object * @return the context object (this looks crazy, but it works given that the function is called from an XPath * environment where the context is supplied as an implicit argument) */ public static XPathContext getContext(XPathContext c) { return c; } /** * Return the Controller object * * @param c the XPath dynamic context * @return the Controller */ public static Controller getController(XPathContext c) { return c.getController(); } /** * Return the Configuration object * * @param c the XPath dynamic context * @return the Saxon configuration */ public static Configuration getConfiguration(XPathContext c) { return c.getConfiguration(); } /** * Return a string containing a diagnostic print of the current execution stack * @param c the XPath dynamic context * @return a diagnostic stack print */ public static String printStack(XPathContext c) { ByteArrayOutputStream baos = new ByteArrayOutputStream(1000); StandardErrorListener.printStackTrace(new PrintStream(baos), c); return baos.toString(); //return baos.toString().replace("\r", ""); - needs JDK 1.5 } /** * Get a pseudo-attribute of a processing instruction. Return an empty string * if the pseudo-attribute is not present. * Character references and built-in entity references are expanded * * @param c the XPath dynamic context. The context item should be a processing instruction, * though it doesn't matter if it isn't: the function will look at the string-value of the context item * whatever it is. * @param name the name of the required pseudo-attribute * @return the value of the pseudo-attribute if it is present */ public static String getPseudoAttribute(XPathContext c, String name) throws XPathException { if (name == null) { return null; } Item pi = c.getContextItem(); if (pi == null) { XPathException e = new XPathException("The context item for saxon:getPseudoAttribute() is not set"); e.setXPathContext(c); throw e; } // we'll assume it's a PI, it doesn't matter if it isn't... String val = ProcInstParser.getPseudoAttribute(pi.getStringValue(), name); if (val == null) { return ""; } return val; } /** * Get a dayTimeDuration value corresponding to a given number of seconds */ // no longer documented in Saxon 8.1 // public static DayTimeDurationValue dayTimeDurationFromSeconds(BigDecimal arg) throws XPathException { // return DayTimeDurationValue.fromSeconds(arg); // } /** * Get a yearMonthDuration value corresponding to a given number of months */ // no longer documented in Saxon 8.1 // public static YearMonthDurationValue yearMonthDurationFromMonths(int arg) { // return YearMonthDurationValue.fromMonths((int)arg); // } /** * Perform decimal division to a user-specified precision * * @param arg1 the numerator * @param arg2 the denominator * @param scale the required number of digits in the result of the division * @return the result of the division */ public static BigDecimal decimalDivide(BigDecimal arg1, BigDecimal arg2, int scale) { if (arg1 == null || arg2 == null) { return null; } return arg1.divide(arg2, scale, BigDecimal.ROUND_DOWN); } /** * Get the UTF-8 encoding of a string * * @param in the supplied string * @return a sequence of integers, each in the range 0-255, representing the octets of the UTF-8 * encoding of the given string */ public static List stringToUtf8(String in) { if (in == null) { return Collections.EMPTY_LIST; } ArrayList list = new ArrayList(in.length() * 2); byte[] octets = new byte[4]; for (int i = 0; i < in.length(); i++) { int used = UnicodeCharacterSet.getUTF8Encoding( in.charAt(i), (i + 1 < in.length() ? in.charAt(i + 1) : (char)0), octets); for (int j = 0; j < used; j++) { list.add(new Integer(255 & (int)octets[j])); } } return list; } /** * Convert a sequence of integers in the range 0-255, representing a sequence of octets, * to a base64Binary value * * @param in the input array of bytes (octets) * @return the corresponding base64Binary value */ public static Base64BinaryValue octetsToBase64Binary(byte[] in) { if (in == null) { return null; } return new Base64BinaryValue(in); } /** * Convert a sequence of integers in the range 0-255, representing a sequence of octets, * to a hexBinary value * * @param in the input array of bytes (octets) * @return the corresponding HexBinary value */ public static HexBinaryValue octetsToHexBinary(byte[] in) { if (in == null) { return null; } return new HexBinaryValue(in); } /** * Convert a base64Binary value to a sequence of integers representing the octets contained in the value * * @param in the supplied base64Binary value * @return the corresponding array of integers, representing the octet values */ public static byte[] base64BinaryToOctets(Base64BinaryValue in) { if (in == null) { return null; } return in.getBinaryValue(); } /** * Convert a hexBinary value to a sequence of integers representing the octets contained in the value * * @param in the input hexBinary value * @return the corresponding array of integers, representing the octet values */ public static byte[] hexBinaryToOctets(HexBinaryValue in) { if (in == null) { return null; } return in.getBinaryValue(); } /** * Convert a base64Binary value to a String, assuming a particular encoding * * @param context the XPath dynamic context * @param in the supplied base64Binary value * @param encoding the character encoding * @return the string that results from treating the base64binary value as a sequence of octets * that encode a string in the given encoding */ public static String base64BinaryToString(XPathContext context, Base64BinaryValue in, String encoding) throws Exception { if (in == null) { return null; } if (encoding == null) { encoding = "UTF-8"; } byte[] bytes = in.getBinaryValue(); ByteArrayInputStream stream = new ByteArrayInputStream(bytes); InputStreamReader reader = new InputStreamReader(stream, encoding); char[] array = new char[bytes.length]; int used = reader.read(array, 0, array.length); checkBytes(array, 0, used, context.getConfiguration().getNameChecker()); return new String(array, 0, used); } /** * Convert a string to a base64Binary value in a given encoding * * @param in the input string * @param encoding the desired encoding * @return the base64Binary value that results from encoding the string as a sequence of octets in the * given encoding. */ public static Base64BinaryValue stringToBase64Binary(String in, String encoding) throws IOException { if (in == null) { return null; } if (encoding == null) { encoding = "UTF-8"; } ByteArrayOutputStream stream = new ByteArrayOutputStream(in.length()); OutputStreamWriter writer = new OutputStreamWriter(stream, encoding); writer.write(in); writer.close(); byte[] bytes = stream.toByteArray(); return octetsToBase64Binary(bytes); } /** * Convert a hexBinary value to a String, assuming a particular encoding * * @param context the XPath dynamic context * @param in the supplied hexBinary value * @param encoding the character encoding * @return the string that results from treating the hexBinary value as a sequence of octets * that encode a string in the given encoding */ public static String hexBinaryToString(XPathContext context, HexBinaryValue in, String encoding) throws Exception { if (in == null) { return null; } if (encoding == null) { encoding = "UTF-8"; } byte[] bytes = in.getBinaryValue(); ByteArrayInputStream stream = new ByteArrayInputStream(bytes); InputStreamReader reader = new InputStreamReader(stream, encoding); char[] array = new char[bytes.length]; int used = reader.read(array, 0, array.length); checkBytes(array, 0, used, context.getConfiguration().getNameChecker()); return new String(array, 0, used); } /** * Check that characters are valid XML characters (UTF-16 encoded) * * @param array the array of characters * @param start the position of the first significant character in the array * @param end the position after the last significant character in the array * @param checker the NameChecker to be used (for XML 1.0 or XML 1.1 rules) * @throws XPathException if the string contains characters that are invalid in XML */ private static void checkBytes(char[] array, int start, int end, NameChecker checker) throws XPathException { for (int c = start; c < end; c++) { int ch32 = array[c]; if (UTF16.isHighSurrogate(ch32)) { char low = array[c++]; ch32 = UTF16.combinePair((char)ch32, low); } if (!checker.isValidChar(ch32)) { XPathException err = new XPathException("The byte sequence contains a character not allowed by XML (hex " + Integer.toHexString(ch32) + ')'); err.setErrorCode("XTDE1180"); throw err; } } } /** * Convert a string to a hexBinary value in a given encoding * * @param in the input string * @param encoding the desired encoding * @return the hexBinary value that results from encoding the string as a sequence of octets in the * given encoding. */ public static HexBinaryValue stringToHexBinary(String in, String encoding) throws Exception { if (in == null) { return null; } if (encoding == null) { encoding = "UTF-8"; } ByteArrayOutputStream stream = new ByteArrayOutputStream(in.length()); OutputStreamWriter writer = new OutputStreamWriter(stream, encoding); writer.write(in); writer.close(); byte[] bytes = stream.toByteArray(); return octetsToHexBinary(bytes); } /** * Test whether a given integer is the codepoint of a valid XML character * * @param c the XPath dynamic context * @param in the character to be tested * @return true if and only if the character is valid in (the relevant version of) XML */ public static boolean validCharacter(XPathContext c, int in) { return c.getConfiguration().getNameChecker().isValidChar(in); } /** * Create a parentless namespace node. This function is useful in XQuery when namespaces need to be created * dynamically. The effect is the same as that of the xsl:namespace instruction in XSLT. * * @param context the dynamic evaluation context * @param prefix the name of the namespace node * @param uri the string value of the namespace node * @return the newly constructed namespace node */ public static NodeInfo namespaceNode(XPathContext context, String prefix, String uri) throws XPathException { if (prefix == null) { prefix = ""; } else if (!(prefix.length() == 0 || context.getConfiguration().getNameChecker().isValidNCName(prefix))) { throw new XPathException("Namespace prefix " + Err.wrap(prefix) + " is not a valid NCName"); } if (uri == null || uri.length() == 0) { throw new XPathException("URI of namespace node must not be empty"); } final NamePool namePool = context.getNamePool(); Orphan node = new Orphan(context.getConfiguration()); node.setNodeKind(Type.NAMESPACE); node.setNameCode(namePool.allocate("", "", prefix)); node.setStringValue(uri); return node; } /** * Get a list of the names of the unparsed entities in a document * @param doc the document node of the document whose unparsed entities are required * @return an iterator over a sequence of strings containing the names of the unparsed entities */ public static String[] unparsedEntities(DocumentInfo doc) throws XPathException { Iterator names = doc.getUnparsedEntityNames(); int count = 0; while (names.hasNext()) { names.next(); count++; } String[] ss = new String[count]; names = doc.getUnparsedEntityNames(); count = 0; while (names.hasNext()) { ss[count++] = (String)names.next(); } return ss; } /** * Perform a parameterized deep-equals() test * * @param context The evaluation context * @param arg1 The first sequence to be compared * @param arg2 The second sequence to be compared * @param collation The collation to be used (null if the default collation is to be used) * @param flags A string whose characters select options that cause the comparison to vary from the * standard fn:deep-equals() function. The flags are: *

    *
  • N - take namespace nodes into account
  • *
  • J - join adjacent text nodes (e.g, nodes either side of a comment) *
  • A - compare type annotations
  • *
  • C - take comments into account
  • *
  • F - take namespace prefixes into account
  • *
  • P - take processing instructions into account
  • *
  • S - compare string values, not typed values
  • *
  • w - don't take whitespace-only text nodes into account
  • *
* @return true if the sequences are deep equal, otherwise false */ public static boolean deepEqual(XPathContext context, SequenceIterator arg1, SequenceIterator arg2, String collation, String flags) throws XPathException { if (flags.indexOf('!') >= 0) { // undocumented diagnostic option Properties indent = new Properties(); indent.setProperty(OutputKeys.INDENT, "yes"); System.err.println("DeepEqual: first argument:"); QueryResult.serialize(QueryResult.wrap(arg1.getAnother(), context.getConfiguration()), new StreamResult(System.err), indent); System.err.println("DeepEqual: second argument:"); QueryResult.serialize(QueryResult.wrap(arg2.getAnother(), context.getConfiguration()), new StreamResult(System.err), indent); } GenericAtomicComparer comparer; if (collation == null) { comparer = new GenericAtomicComparer(context.getDefaultCollation(), context); } else { comparer = new GenericAtomicComparer(context.getCollation(collation), context); } int flag = 0; if (flags.indexOf("N") >= 0) { flag |= DeepEqual.INCLUDE_NAMESPACES; } if (flags.indexOf("J") >= 0) { flag |= DeepEqual.JOIN_ADJACENT_TEXT_NODES; } if (flags.indexOf("C") >= 0) { flag |= DeepEqual.INCLUDE_COMMENTS; } if (flags.indexOf("P") >= 0) { flag |= DeepEqual.INCLUDE_PROCESSING_INSTRUCTIONS; } if (flags.indexOf("F") >= 0) { flag |= DeepEqual.INCLUDE_PREFIXES; } if (flags.indexOf("S") >= 0) { flag |= DeepEqual.COMPARE_STRING_VALUES; } if (flags.indexOf("A") >= 0) { flag |= DeepEqual.COMPARE_ANNOTATIONS; } if (flags.indexOf("w") >= 0) { flag |= DeepEqual.EXCLUDE_WHITESPACE_TEXT_NODES; } if (flags.indexOf("?") >= 0) { flag |= DeepEqual.WARNING_IF_FALSE; } return DeepEqual.deepEquals(arg1, arg2, comparer, context.getConfiguration(), flag); } /** * This function implements the last-modified() function without any argument. It returns * the modification time of the file containing the context node. * * @param c the dynamic evaluation context supplied by Saxon * @return file modification time as an xs:dateTime value, or an empty sequence if the context item is * not a node or if the context node is not present in a local file * @throws XPathException XPath dynamic error reported back to Saxon */ public static DateTimeValue lastModified(XPathContext c) throws XPathException { // Original author Zdenek Wagner [zdenek.wagner@gmail.com] contributed 2007-10-22 Item item = c.getContextItem(); if (item == null) { XPathException e = new XPathException("The context item for lastModified() is not set"); e.setXPathContext(c); throw e; } if (item instanceof NodeInfo) { return lastModified(c, (NodeInfo)item); } else { return null; } } /** * This function implements the last-modified(node) function with one argument which * must be a node. It returns the modification time of the file containing the context node. * * @param node the node supplied by a user * @return file modification time as an xs:dateTime value, or an empty sequence if the supplied * node is not present in a local file * @throws XPathException if an error occurs and the configuration option TRACE_EXTERNAL_FUNCTIONS is true */ public static DateTimeValue lastModified(XPathContext context, NodeInfo node) throws XPathException { // Original author Zdenek Wagner [zdenek.wagner@gmail.com] contributed 2007-10-22 // Rewritten by Michael Kay to use URL checking and connection code from UnparsedText.java return fileLastModified(context, node.getSystemId()); } /** * This function determines the file modification time. It can be called from the stylesheet as file-timestamp(fn). * @param context the XPath dynamic evaluation context * @param fileURI the URI of a file. This must be an absolute URI to which Saxon can connect * @return file modification time as an xs:dateTime value or an empty sequence if the file is * not found * @throws XPathException if an error occurs and the configuration option TRACE_EXTERNAL_FUNCTIONS is true */ public static DateTimeValue fileLastModified(XPathContext context, String fileURI) throws XPathException { // Original author Zdenek Wagner [zdenek.wagner@gmail.com] contributed 2007-10-22 // Rewritten by Michael Kay to take a URI and to use URL connection code from UnparsedText.java boolean debug = context.getConfiguration().isTraceExternalFunctions(); URI absoluteURI; try { absoluteURI = new URI(fileURI); } catch (URISyntaxException e) { if (debug) { throw new XPathException(e); } return null; } if (!absoluteURI.isAbsolute()) { if (debug) { throw new XPathException("Supplied URI " + fileURI + " is not a valid absolute URI"); } return null; } // The URL dereferencing classes throw all kinds of strange exceptions if given // ill-formed sequences of %hh escape characters. So we do a sanity check that the // escaping is well-formed according to UTF-8 rules try { EscapeURI.checkPercentEncoding(absoluteURI.toString()); } catch (XPathException e) { if (debug) { throw e; } return null; } URL absoluteURL; try { absoluteURL = absoluteURI.toURL(); } catch (MalformedURLException err) { if (debug) { throw new XPathException(err); } return null; } long lastMod; try { URLConnection connection = absoluteURL.openConnection(); connection.setRequestProperty("Accept-Encoding","gzip"); connection.connect(); lastMod = connection.getLastModified(); } catch (IOException e) { if (debug) { throw new XPathException(e); } return null; } if (lastMod == 0) { return null; } Calendar c = Calendar.getInstance(); c.setTimeInMillis(lastMod); return new DateTimeValue(c, true); } /** * Determine whether a given date/time is in summer time (daylight savings time) * in a given region. This relies on the Java database of changes to daylight savings time. * Since summer time changes are set by civil authorities the information is not necessarily * reliable when applied to dates in the future. * @param context used to get the implicit timezone in the event that the supplied date/time * has no timezone * @param date the date/time in question. This should preferably include a timezone. * @param region either the two-letter ISO country code, or an Olsen timezone name such as * "America/New_York" or "Europe/Lisbon". If the country code denotes a country spanning several * timezones, such as the US, then one of them is chosen arbitrarily. * @return true if the date/time is known to be in summer time in the relevant country; * false if it is known not to be in summer time; null if there is no timezone or if no * information is available. */ public static BooleanValue inSummerTime(XPathContext context, DateTimeValue date, String region) { if (!date.hasTimezone()) { try { date = (DateTimeValue)date.adjustTimezone(context.getImplicitTimezone()); } catch (NoDynamicContextException err) { date = (DateTimeValue)date.adjustTimezone(0); } } Boolean b = NamedTimeZone.inSummerTime(date, region); return (b == null ? null : BooleanValue.get(b.booleanValue())); } /** * Compile a document containing a stylesheet module into a stylesheet that can be used to perform * transformations * * @param context the XPath dynamic evaluation context * @param doc the document containing the stylesheet to be compiled * @return the compiled stylesheet */ public static Templates compileStylesheet(XPathContext context, DocumentInfo doc) throws XPathException { if (doc == null) { return null; } try { TransformerFactoryImpl factory = new TransformerFactoryImpl(context.getConfiguration()); return factory.newTemplates(doc); } catch (TransformerConfigurationException e) { throw XPathException.makeXPathException(e); } } /** * Run a transformation to convert an input tree to an output document * * @param context The dynamic context * @param templates The compiled stylesheet * @param source The initial context node representing the document to be transformed * @return the document that results from the transformation */ public static DocumentInfo transform(XPathContext context, Templates templates, NodeInfo source) throws XPathException { if (templates == null) { return null; } if (source == null) { return null; } try { Transformer transformer = templates.newTransformer(); TinyBuilder builder = new TinyBuilder(); builder.setPipelineConfiguration(context.getController().makePipelineConfiguration()); transformer.transform(source, builder); return (DocumentInfo)builder.getCurrentRoot(); } catch (TransformerException e) { throw XPathException.makeXPathException(e); } } /** * Run a transformation to convert an input tree to an output document, supplying parameters to the * transformation. * * @param context The dynamic context * @param templates The compiled stylesheet * @param source The initial context node representing the document to be transformed * @param params A sequence of nodes (typically element nodes) supplying values of parameters. * The name of the node should match the name of the parameter, the typed value of the node is * used as the value of the parameter. * @return the document that results from the transformation */ public static DocumentInfo transform(XPathContext context, Templates templates, NodeInfo source, SequenceIterator params) throws XPathException { if (templates == null) { return null; } if (source == null) { return null; } try { Transformer transformer = templates.newTransformer(); TinyBuilder builder = new TinyBuilder(); builder.setPipelineConfiguration(context.getController().makePipelineConfiguration()); while (true) { Item param = params.next(); if (param == null) { break; } if (param instanceof NodeInfo) { switch (((NodeInfo)param).getNodeKind()) { case Type.ELEMENT: case Type.ATTRIBUTE: setTransformerParameter(param, transformer, source); break; case Type.DOCUMENT: AxisIterator kids = ((NodeInfo)param).iterateAxis(Axis.CHILD, NodeKindTest.ELEMENT); while (true) { NodeInfo kid = (NodeInfo)kids.next(); if (kid == null) { break; } setTransformerParameter(kid, transformer, source); } break; default: throw new XPathException( "Parameters passed to saxon:transform() must be element, attribute, or document nodes"); } } else { throw new XPathException("Parameters passed to saxon:transform() must be nodes"); } } transformer.transform(source, builder); return (DocumentInfo)builder.getCurrentRoot(); } catch (TransformerException e) { throw XPathException.makeXPathException(e); } } private static void setTransformerParameter(Item param, Transformer transformer, NodeInfo source) throws XPathException { int fp = ((NodeInfo)param).getFingerprint(); if (fp != -1) { Value val = ((NodeInfo)param).atomize(); ((Controller)transformer).setParameter( new StructuredQName(source.getNamePool(), fp), val); } } /** * Compile a string containing a source query * transformations * * @param context the XPath dynamic evaluation context * @param query a string containing the query to be compiled * @return the compiled query */ public static XQueryExpression compileQuery(XPathContext context, String query) throws XPathException { if (query == null) { return null; } StaticQueryContext sqc = new StaticQueryContext(context.getConfiguration()); return sqc.compileQuery(query); } /** * Run a previously-compiled query. The initial context item for the query is taken from the context * in which the query is called (if there is one); no parameters are supplied * * @param context The dynamic context * @param query The compiled query * @return the sequence representing the result of the query */ public static SequenceIterator query(XPathContext context, XQueryExpression query) throws XPathException { if (query == null) { return null; } DynamicQueryContext dqc = new DynamicQueryContext(context.getConfiguration()); Item c = context.getContextItem(); if (c != null) { dqc.setContextItem(c); } return query.iterator(dqc); } /** * Run a previously-compiled query * * @param context The dynamic context * @param query The compiled query * @param source The initial context item for the query (may be null) * @return the sequence representing the result of the query */ public static SequenceIterator query(XPathContext context, XQueryExpression query, Item source) throws XPathException { if (query == null) { return null; } DynamicQueryContext dqc = new DynamicQueryContext(context.getConfiguration()); if (source != null) { dqc.setContextItem(source); } return query.iterator(dqc); } /** * Run a previously-compiled query, supplying parameters to the * transformation. * * @param context The dynamic context * @param query The compiled query * @param source The initial context node for the query (may be null) * @param params A sequence of nodes (typically element nodes) supplying values of parameters. * The name of the node should match the name of the parameter, the typed value of the node is * used as the value of the parameter. * @return the results of the query (a sequence of items) */ public static SequenceIterator query(XPathContext context, XQueryExpression query, Item source, SequenceIterator params) throws XPathException { if (query == null) { return null; } DynamicQueryContext dqc = new DynamicQueryContext(context.getConfiguration()); if (source != null) { dqc.setContextItem(source); } NamePool pool = context.getConfiguration().getNamePool(); while (true) { Item param = params.next(); if (param == null) { break; } if (param instanceof NodeInfo) { switch (((NodeInfo)param).getNodeKind()) { case Type.ELEMENT: case Type.ATTRIBUTE: Value val = ((NodeInfo)param).atomize(); dqc.setParameter(pool.getClarkName(((NodeInfo)param).getNameCode()), val); break; case Type.DOCUMENT: AxisIterator kids = ((NodeInfo)param).iterateAxis(Axis.CHILD, NodeKindTest.ELEMENT); while (true) { NodeInfo kid = (NodeInfo)kids.next(); if (kid == null) { break; } Value val2 = ((NodeInfo)param).atomize(); dqc.setParameter(pool.getClarkName(kid.getNameCode()), val2); } break; default: throw new XPathException( "Parameters passed to saxon:query() must be element, attribute, or document nodes"); } } else { throw new XPathException("Parameters passed to saxon:query() must be nodes"); } } return query.iterator(dqc); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by Zdenek Wagner [zdenek.wagner@gmail.com] are Copyright (C) Zdenek Wagner. // All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/functions/StringLength.java0000644000175000017500000001141611033112257022665 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.expr.*; import net.sf.saxon.om.Item; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ItemType; import net.sf.saxon.value.AtomicValue; import net.sf.saxon.value.Int64Value; import net.sf.saxon.value.StringValue; import net.sf.saxon.value.Value; /** * Implement the XPath string-length() function */ public class StringLength extends SystemFunction { //private boolean shortcut = false; // if this is set we return 0 for a zero length string, // 1 for any other. Used by the optimizer. /** * Simplify and validate. * This is a pure function so it can be simplified in advance if the arguments are known * @param visitor an expression visitor */ public Expression simplify(ExpressionVisitor visitor) throws XPathException { //useContextItemAsDefault(); return simplifyArguments(visitor); } /** * Determine the intrinsic dependencies of an expression, that is, those which are not derived * from the dependencies of its subexpressions. For example, position() has an intrinsic dependency * on the context position, while (position()+1) does not. The default implementation * of the method returns 0, indicating "no dependencies". * * @return a set of bit-significant flags identifying the "intrinsic" * dependencies. The flags are documented in class net.sf.saxon.value.StaticProperty */ public int getIntrinsicDependencies() { int d = super.getIntrinsicDependencies(); if (argument.length == 0) { d |= StaticProperty.DEPENDS_ON_CONTEXT_ITEM; } return d; } /** * Pre-evaluate a function at compile time. Functions that do not allow * pre-evaluation, or that need access to context information, can override this method. * @param visitor an expression visitor * @return the expression, either unchanged, or pre-evaluated */ public Expression preEvaluate(ExpressionVisitor visitor) throws XPathException { if (argument.length == 0) { return this; } else { return Literal.makeLiteral( (Value)evaluateItem(visitor.getStaticContext().makeEarlyEvaluationContext())); } } public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { if (argument.length == 0 && contextItemType == null) { XPathException err = new XPathException("The context item for string-length() is undefined"); err.setErrorCode("XPDY0002"); err.setIsTypeError(true); err.setLocator(this); throw err; } return super.typeCheck(visitor, contextItemType); } /** * setShortCut() - used by optimizer when we only need to know if the length is non-zero */ // public void setShortcut() { // shortcut = true; // } /** * Evaluate in a general context */ public Item evaluateItem(XPathContext c) throws XPathException { AtomicValue sv; if (argument.length == 0) { final Item contextItem = c.getContextItem(); if (contextItem == null) { dynamicError("The context item for string-length() is not set", "XPDY0002", c); return null; } sv = StringValue.makeStringValue(contextItem.getStringValueCS()); } else { sv = (AtomicValue)argument[0].evaluateItem(c); } if (sv==null) { return Int64Value.ZERO; } // if (shortcut) { // CharSequence s = sv.getStringValueCS(); // return (s.length()>0 ? Int64Value.PLUS_ONE : Int64Value.ZERO); // } else if (sv instanceof StringValue) { return Int64Value.makeIntegerValue(((StringValue)sv).getStringLength()); } else { CharSequence s = sv.getStringValueCS(); return Int64Value.makeIntegerValue(StringValue.getStringLength(s)); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/functions/Existence.java0000644000175000017500000001336411033112257022210 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.expr.*; import net.sf.saxon.om.Item; import net.sf.saxon.om.LookaheadIterator; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ItemType; import net.sf.saxon.value.BooleanValue; /** Implement the exists() and empty() functions **/ public class Existence extends SystemFunction implements Negatable { public static final int EXISTS = 0; public static final int EMPTY = 1; /** * Static analysis: prevent sorting of the argument */ public void checkArguments(ExpressionVisitor visitor) throws XPathException { super.checkArguments(visitor); Optimizer opt = visitor.getConfiguration().getOptimizer(); argument[0] = ExpressionTool.unsorted(opt, argument[0], false); } // public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { // return super.typeCheck(visitor, contextItemType); //AUTO // } /** * Perform optimisation of an expression and its subexpressions. *

*

This method is called after all references to functions and variables have been resolved * to the declaration of the function or variable, and after all type checking has been done.

* * @param visitor an expression visitor * @param contextItemType the static type of "." at the point where this expression is invoked. * The parameter is set to null if it is known statically that the context item will be undefined. * If the type of the context item is not known statically, the argument is set to * {@link net.sf.saxon.type.Type#ITEM_TYPE} * @return the original expression, rewritten if appropriate to optimize execution * @throws net.sf.saxon.trans.XPathException * if an error is discovered during this phase * (typically a type error) */ public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { Expression e2 = super.optimize(visitor, contextItemType); if (e2 != this) { return e2; } // See if we can deduce the answer from the cardinality int c = argument[0].getCardinality(); if (c == StaticProperty.ALLOWS_ONE_OR_MORE) { return new Literal(BooleanValue.get(operation == EXISTS)); } else if (c == StaticProperty.ALLOWS_ZERO) { return new Literal(BooleanValue.get(operation == EMPTY)); } // Rewrite // exists(A|B) => exists(A) or exists(B) // empty(A|B) => empty(A) and empty(B) if (argument[0] instanceof VennExpression) { VennExpression v = (VennExpression)argument[0]; if (v.getOperator() == Token.UNION) { int newop = (operation == EXISTS ? Token.OR : Token.AND); FunctionCall e0 = SystemFunction.makeSystemFunction( getFunctionName().getLocalName(), new Expression[]{v.getOperands()[0]}); FunctionCall e1 = SystemFunction.makeSystemFunction( getFunctionName().getLocalName(), new Expression[]{v.getOperands()[1]}); return new BooleanExpression(e0, newop, e1).optimize(visitor, contextItemType); } } return this; } /** * Check whether this specific instance of the expression is negatable * * @return true if it is */ public boolean isNegatable(ExpressionVisitor visitor) { return true; } /** * Return the negation of the expression * @return the negation of the expression */ public Expression negate() { FunctionCall fc = SystemFunction.makeSystemFunction( (operation == EXISTS ? "empty" : "exists"), getArguments()); fc.setLocationId(getLocationId()); return fc; } /** * Evaluate the function in a boolean context */ public boolean effectiveBooleanValue(XPathContext c) throws XPathException { SequenceIterator iter = argument[0].iterate(c); boolean result = false; if ((iter.getProperties() & SequenceIterator.LOOKAHEAD) != 0) { switch (operation) { case EXISTS: result = ((LookaheadIterator)iter).hasNext(); break; case EMPTY: result = !((LookaheadIterator)iter).hasNext(); break; } } else { switch (operation) { case EXISTS: result = iter.next() != null; break; case EMPTY: result = iter.next() == null; break; } } iter.close(); return result; } /** * Evaluate in a general context */ public Item evaluateItem(XPathContext c) throws XPathException { return BooleanValue.get(effectiveBooleanValue(c)); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/functions/Lang.java0000644000175000017500000001046311033112257021137 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.expr.Expression; import net.sf.saxon.expr.ExpressionVisitor; import net.sf.saxon.expr.StaticProperty; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.Item; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.om.StandardNames; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.AtomicType; import net.sf.saxon.type.ItemType; import net.sf.saxon.value.BooleanValue; public class Lang extends SystemFunction { /** * preEvaluate: this method suppresses compile-time evaluation by doing nothing * @param visitor an expression visitor */ public Expression preEvaluate(ExpressionVisitor visitor) { return this; } public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { if (argument.length==1) { if (contextItemType == null) { XPathException err = new XPathException("The context item for lang() is undefined"); err.setErrorCode("XPDY0002"); err.setIsTypeError(true); err.setLocator(this); throw err; } else if (contextItemType instanceof AtomicType) { XPathException err = new XPathException("The context item for lang() is not a node"); err.setErrorCode("XPTY0004"); err.setIsTypeError(true); err.setLocator(this); throw err; } } return super.typeCheck(visitor, contextItemType); } /** * Evaluate in a general context */ public Item evaluateItem(XPathContext c) throws XPathException { NodeInfo target; if (argument.length > 1) { target = (NodeInfo)argument[1].evaluateItem(c); } else { Item current = c.getContextItem(); if (current==null) { XPathException err = new XPathException("The context item is undefined"); err.setErrorCode("XPDY0002"); err.setXPathContext(c); throw err; } if (!(current instanceof NodeInfo)) { XPathException err = new XPathException("The context item is not a node"); err.setErrorCode("XPTY0004"); err.setXPathContext(c); throw err; } target = (NodeInfo)current; } final Item arg0Val = argument[0].evaluateItem(c); final String testLang = (arg0Val==null ? "" : arg0Val.getStringValue()); boolean b = isLang(testLang, target); return BooleanValue.get(b); } /** * Determine the dependencies */ public int getIntrinsicDependencies() { return StaticProperty.DEPENDS_ON_CONTEXT_ITEM; } /** * Test whether the context node has the given language attribute * @param arglang the language being tested * @param target the target node */ public static boolean isLang(String arglang, NodeInfo target) { String doclang = null; NodeInfo node = target; while(node!=null) { doclang = node.getAttributeValue(StandardNames.XML_LANG); if (doclang!=null) break; node = node.getParent(); if (node==null) return false; } if (doclang==null) return false; if (arglang.equalsIgnoreCase(doclang)) return true; int hyphen = doclang.indexOf("-"); if (hyphen<0) return false; doclang = doclang.substring(0, hyphen); if (arglang.equalsIgnoreCase(doclang)) return true; return false; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/functions/BooleanFn.java0000644000175000017500000001762511033112257022130 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.expr.*; import net.sf.saxon.om.Item; import net.sf.saxon.pattern.NodeTest; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.BuiltInAtomicType; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.TypeHierarchy; import net.sf.saxon.value.BooleanValue; import net.sf.saxon.Configuration; /** * This class supports the XPath functions boolean(), not(), true(), and false() */ public class BooleanFn extends SystemFunction implements Negatable { public static final int BOOLEAN = 0; public static final int NOT = 1; public static final int TRUE = 2; public static final int FALSE = 3; /** * Simplify the function call. Default method is to simplify each of the supplied arguments and * evaluate the function if all are now known. * @param visitor an expression visitor */ public Expression simplify(ExpressionVisitor visitor) throws XPathException { switch (operation) { case BOOLEAN: case NOT: return super.simplify(visitor); case TRUE: return Literal.makeLiteral(BooleanValue.TRUE); case FALSE: return Literal.makeLiteral(BooleanValue.FALSE); default: throw new UnsupportedOperationException("Unknown boolean operation"); } } /** * Static analysis: prevent sorting of the argument */ public void checkArguments(ExpressionVisitor visitor) throws XPathException { super.checkArguments(visitor); if (operation==BOOLEAN || operation==NOT) { XPathException err = TypeChecker.ebvError(argument[0], visitor.getConfiguration().getTypeHierarchy()); if (err != null) { err.setLocator(this); throw err; } Optimizer opt = visitor.getConfiguration().getOptimizer(); argument[0] = ExpressionTool.unsortedIfHomogeneous(opt, argument[0]); } } /** * Perform optimisation of an expression and its subexpressions. *

*

This method is called after all references to functions and variables have been resolved * to the declaration of the function or variable, and after all type checking has been done.

* * @param visitor an expression visitor * @param contextItemType the static type of "." at the point where this expression is invoked. * The parameter is set to null if it is known statically that the context item will be undefined. * If the type of the context item is not known statically, the argument is set to * {@link net.sf.saxon.type.Type#ITEM_TYPE} * @return the original expression, rewritten if appropriate to optimize execution * @throws XPathException if an error is discovered during this phase * (typically a type error) */ public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { Expression e = super.optimize(visitor, contextItemType); if (e == this) { if (operation == BOOLEAN) { Expression ebv = rewriteEffectiveBooleanValue(argument[0], visitor, contextItemType); return (ebv == null ? this : ebv.optimize(visitor, contextItemType)); } else if (operation == NOT) { Expression ebv = rewriteEffectiveBooleanValue(argument[0], visitor, contextItemType); if (ebv != null) { argument[0] = ebv; } if (argument[0] instanceof Negatable && ((Negatable)argument[0]).isNegatable(visitor)) { return ((Negatable)argument[0]).negate(); } else { return this; } } } return e; } /** * Check whether this specific instance of the expression is negatable * * @return true if it is */ public boolean isNegatable(ExpressionVisitor visitor) { return true; } /** * Create an expression that returns the negation of this expression * @return the negated expression */ public Expression negate() { switch (operation) { case BOOLEAN: return SystemFunction.makeSystemFunction("not", getArguments()); case NOT: return SystemFunction.makeSystemFunction("boolean", getArguments()); case TRUE: return new Literal(BooleanValue.FALSE); case FALSE: default: return new Literal(BooleanValue.TRUE); } } /** * Optimize an expression whose effective boolean value is required * @param exp the expression whose EBV is to be evaluated * @param visitor an expression visitor * @param contextItemType the type of the context item for this expression * @return an expression that returns the EBV of exp, or null if no optimization was possible * @throws XPathException if static errors are found */ public static Expression rewriteEffectiveBooleanValue( Expression exp, ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { Configuration config = visitor.getConfiguration(); TypeHierarchy th = config.getTypeHierarchy(); exp = ExpressionTool.unsortedIfHomogeneous(config.getOptimizer(), exp); if (exp instanceof ValueComparison) { ValueComparison vc = (ValueComparison)exp; if (vc.getResultWhenEmpty() == null) { vc.setResultWhenEmpty(BooleanValue.FALSE); } return exp; } else if (th.isSubType(exp.getItemType(th), BuiltInAtomicType.BOOLEAN) && exp.getCardinality() == StaticProperty.EXACTLY_ONE) { return exp; } else if (exp.getItemType(th) instanceof NodeTest) { // rewrite boolean(x) => exists(x) FunctionCall exists = SystemFunction.makeSystemFunction("exists", new Expression[]{exp}); exists.setLocationId(exp.getLocationId()); return exists.optimize(visitor, contextItemType); } else { return null; } } /** * Evaluate the function */ public Item evaluateItem(XPathContext context) throws XPathException { return BooleanValue.get(effectiveBooleanValue(context)); } /** * Evaluate the effective boolean value */ public boolean effectiveBooleanValue(XPathContext c) throws XPathException { try { switch (operation) { case BOOLEAN: return argument[0].effectiveBooleanValue(c); case NOT: return !argument[0].effectiveBooleanValue(c); case TRUE: return true; case FALSE: return false; default: throw new UnsupportedOperationException("Unknown boolean operation"); } } catch (XPathException e) { e.maybeSetLocation(this); e.maybeSetContext(c); throw e; } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/functions/Substring.java0000644000175000017500000002042611033112257022236 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.expr.ArithmeticExpression; import net.sf.saxon.expr.Calculator; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.Item; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.AtomicValue; import net.sf.saxon.value.Int64Value; import net.sf.saxon.value.NumericValue; import net.sf.saxon.value.StringValue; /** * This class implements the XPath substring() function */ public class Substring extends SystemFunction { /** * Evaluate the function */ public Item evaluateItem(XPathContext context) throws XPathException { AtomicValue av = (AtomicValue)argument[0].evaluateItem(context); if (av==null) { return StringValue.EMPTY_STRING; } StringValue sv = (StringValue)av; if (sv.isZeroLength()) { return StringValue.EMPTY_STRING; } AtomicValue a1 = (AtomicValue)argument[1].evaluateItem(context); NumericValue a = (NumericValue)a1; if (argument.length==2) { return StringValue.makeStringValue(substring(sv, a)); } else { AtomicValue b2 = (AtomicValue)argument[2].evaluateItem(context); NumericValue b = (NumericValue)b2; return StringValue.makeStringValue(substring(sv, a, b, context)); } } /** * Implement the substring function with two arguments. * @param sv the string value * @param start the numeric offset (1-based) of the first character to be included in the result * (if not an integer, the XPath rules apply) * @return the substring starting at this position. */ public static CharSequence substring(StringValue sv, NumericValue start) { CharSequence s = sv.getStringValueCS(); int slength = s.length(); long lstart; if (start instanceof Int64Value) { //noinspection RedundantCast lstart = ((Int64Value)start).longValue(); if (lstart > slength) { return ""; } else if (lstart <= 0) { lstart = 1; } } else { NumericValue rstart = start.round(); // We need to be careful to handle cases such as plus/minus infinity if (rstart.isNaN()) { return ""; } else if (rstart.signum() <= 0) { return s; } else if (rstart.compareTo(slength) > 0) { // this works even where the string contains surrogate pairs, // because the Java length is always >= the XPath length return ""; } else { try { lstart = rstart.longValue(); } catch (XPathException err) { // this shouldn't happen unless the string length exceeds the bounds // of a long throw new AssertionError("string length out of permissible range"); } } } if (!sv.containsSurrogatePairs()) { return s.subSequence((int)lstart-1, s.length()); } int pos=1; int cpos=0; while (cpos= lstart) { return s.subSequence(cpos, s.length()); } int ch = (int)s.charAt(cpos++); if (ch<55296 || ch>56319) { pos++; // don't count high surrogates, i.e. D800 to DBFF } } return ""; } /** * Implement the substring function with three arguments. * @param sv the string value * @param start the numeric offset (1-based) of the first character to be included in the result * (if not an integer, the XPath rules apply) * @param len the length of the required substring (again, XPath rules apply) * @param context the XPath dynamic context. Provided because some arithmetic computations require it * @return the substring starting at this position. */ public static CharSequence substring(StringValue sv, NumericValue start, NumericValue len, XPathContext context) { CharSequence s = sv.getStringValueCS(); int slength = s.length(); long lstart; if (start instanceof Int64Value) { //noinspection RedundantCast lstart = ((Int64Value)start).longValue(); if (lstart > slength) { return ""; } } else { start = start.round(); // We need to be careful to handle cases such as plus/minus infinity and NaN if (start.isNaN()) { return ""; } else if (start.signum() <= 0) { lstart = 0; } else if (start.compareTo(slength) > 0) { // this works even where the string contains surrogate pairs, // because the Java length is always >= the XPath length return ""; } else { try { lstart = start.longValue(); } catch (XPathException err) { // this shouldn't happen unless the string length exceeds the bounds // of a long throw new AssertionError("string length out of permissible range"); } } } NumericValue end; try { //end = start.arithmetic(Token.PLUS, len.round(), context); end = (NumericValue)ArithmeticExpression.compute(start, Calculator.PLUS, len.round(), context); } catch (XPathException e) { throw new AssertionError("Unexpected arithmetic failure in substring"); } long lend; if (end instanceof Int64Value) { //noinspection RedundantCast lend = ((Int64Value)end).longValue(); } else { // We need to be careful to handle cases such as plus/minus infinity and NaN if (end.isNaN()) { return ""; } else if (end.signum() <= 0) { return ""; } else if (end.compareTo(slength) > 0) { // this works even where the string contains surrogate pairs, // because the Java length is always >= the XPath length lend = slength+1; } else { try { lend = end.ceiling().longValue(); } catch (XPathException err) { // this shouldn't happen unless the string length exceeds the bounds // of a long throw new AssertionError("string length out of permissible range"); } } } if (lend < lstart) { return ""; } if (!sv.containsSurrogatePairs()) { return s.subSequence(Math.max((int)lstart-1, 0), Math.min(slength, (int)lend-1)); } int jstart=-1; int jend=-1; int pos=1; int cpos=0; while (cpos= lstart) { if (pos < lend) { if (jstart<0) { jstart = cpos; } } else { jend = cpos; break; } } int ch = (int)s.charAt(cpos++); if (ch<55296 || ch>56319) pos++; // don't count high surrogates, i.e. D800 to DBFF } if (jstart<0 || jstart==jend) { return ""; } else if (jend<0) { return s.subSequence(jstart, s.length()); } else { return s.subSequence(jstart, jend); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/functions/SystemFunction.java0000644000175000017500000002745311033112257023257 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.expr.*; import net.sf.saxon.om.NamespaceConstant; import net.sf.saxon.om.StructuredQName; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.AnyItemType; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.TypeHierarchy; import net.sf.saxon.value.SequenceType; /** * Abstract superclass for system-defined and user-defined functions */ public abstract class SystemFunction extends FunctionCall { /** * Make a system function call (one in the standard function namespace). * @param name The local name of the function. * @param arguments the arguments to the function call * @return a FunctionCall that implements this function, if it * exists, or null if the function is unknown. */ public static FunctionCall makeSystemFunction(String name, Expression[] arguments) { StandardFunction.Entry entry = StandardFunction.getFunction(name, arguments.length); if (entry==null) { return null; } Class functionClass = entry.implementationClass; try { SystemFunction f = (SystemFunction)functionClass.newInstance(); f.setDetails(entry); f.setFunctionName(new StructuredQName("", NamespaceConstant.FN, name)); f.setArguments(arguments); return f; } catch (IllegalAccessException err) { return null; } catch (InstantiationException err) { return null; } } private StandardFunction.Entry details; protected int operation; /** * Set the details of this type of function * @param entry information giving details of the function signature */ public void setDetails(StandardFunction.Entry entry) { details = entry; operation = details.opcode; } /** * Get the details of the function signature * @return information about the function signature */ public StandardFunction.Entry getDetails() { return details; } /** * Method called during static type checking */ public void checkArguments(ExpressionVisitor visitor) throws XPathException { checkArgumentCount(details.minArguments, details.maxArguments, visitor); for (int i=0; i *

This method is called after all references to functions and variables have been resolved * to the declaration of the function or variable, and after all type checking has been done.

* * @param visitor an expression visitor * @param contextItemType the static type of "." at the point where this expression is invoked. * The parameter is set to null if it is known statically that the context item will be undefined. * If the type of the context item is not known statically, the argument is set to * {@link net.sf.saxon.type.Type#ITEM_TYPE} * @return the original expression, rewritten if appropriate to optimize execution * @throws XPathException if an error is discovered during this phase * (typically a type error) */ public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { Expression sf = super.optimize(visitor, contextItemType); if (sf == this && argument.length <= details.resultIfEmpty.length) { // the condition eliminates concat, which is a special case. for (int i=0; i 0) { return argument[0].getItemType(th); } else { return AnyItemType.getInstance(); // if there is no first argument, an error will be reported } } else { return type; } } /** * Determine the cardinality of the function. */ public int computeCardinality() { if (details==null) { //System.err.println("**** No details for " + getClass() + " at " + this); return StaticProperty.ALLOWS_ZERO_OR_MORE; } return details.cardinality; } /** * Determine the special properties of this expression. The general rule * is that a system function call is non-creative if its return type is * atomic, or if all its arguments are non-creative. This is overridden * for the generate-id() function, which is considered creative if * its operand is creative (because the result depends on the * identity of the operand) */ public int computeSpecialProperties() { int p = super.computeSpecialProperties(); if (details == null) { return p; } if (details.itemType.isAtomicType()) { return p | StaticProperty.NON_CREATIVE; } for (int i=0; i pos) { return; // this can happen during optimization, if the extra argument is already present } if (argument.length != pos) { throw new XPathException("Too few arguments in call to " + augmentedName + "() function"); } Expression[] newArgs = new Expression[pos+1]; System.arraycopy(argument, 0, newArgs, 0, argument.length); RootExpression rootExpression = new RootExpression(); ExpressionTool.copyLocationInfo(this, rootExpression); newArgs[pos] = rootExpression; argument = newArgs; setDetails(StandardFunction.getFunction(augmentedName, newArgs.length)); } /** * Add a representation of a doc() call or similar function to a PathMap. * This is a convenience method called by the addToPathMap() methods for doc(), document(), collection() * and similar functions. These all create a new root expression in the path map. * * @param pathMap the PathMap to which the expression should be added * @param pathMapNodes the node in the PathMap representing the focus at the point where this expression * is called. Set to null if this expression appears at the top level. * @return the pathMapNode representing the focus established by this expression, in the case where this * expression is the first operand of a path expression or filter expression */ public PathMap.PathMapNodeSet addDocToPathMap(PathMap pathMap, PathMap.PathMapNodeSet pathMapNodes) { argument[0].addToPathMap(pathMap, pathMapNodes); return new PathMap.PathMapNodeSet(pathMap.makeNewRoot(this)); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/functions/BaseURI.java0000644000175000017500000000352111033112257021505 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.expr.Expression; import net.sf.saxon.expr.ExpressionVisitor; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.Item; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.AnyURIValue; /** * This class supports the base-uri() functions in XPath 2.0 */ public class BaseURI extends SystemFunction { /** * Simplify and validate. * This is a pure function so it can be simplified in advance if the arguments are known * @param visitor an expression visitor */ public Expression simplify(ExpressionVisitor visitor) throws XPathException { useContextItemAsDefault(); return simplifyArguments(visitor); } /** * Evaluate the function at run-time */ public Item evaluateItem(XPathContext c) throws XPathException { NodeInfo node = (NodeInfo)argument[0].evaluateItem(c); if (node==null) { return null; } String s = node.getBaseURI(); if (s == null) { return null; } return new AnyURIValue(s); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/functions/IndexOf.java0000644000175000017500000001106311033112257021607 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.Item; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.sort.GenericAtomicComparer; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.TypeHierarchy; import net.sf.saxon.type.Type; import net.sf.saxon.type.BuiltInAtomicType; import net.sf.saxon.value.AtomicValue; import net.sf.saxon.value.Int64Value; /** * The XPath 2.0 index-of() function */ public class IndexOf extends CollatingFunction { /** * Evaluate the function to return an iteration of selected nodes. */ public SequenceIterator iterate(XPathContext context) throws XPathException { GenericAtomicComparer comparer = getAtomicComparer(2, context); SequenceIterator seq = argument[0].iterate(context); AtomicValue val = (AtomicValue)argument[1].evaluateItem(context); return new IndexIterator(seq, val, comparer); } /** * Iterator to return the index positions of selected items in a sequence */ public static class IndexIterator implements SequenceIterator { SequenceIterator base; AtomicValue value; GenericAtomicComparer comparer; int index = 0; int position = 0; Item current = null; BuiltInAtomicType primitiveTypeRequired; TypeHierarchy typeHierarchy; /** * Get an iterator returning the index positions of selected items in a sequence * @param base The sequence to be searched * @param value The value being sought * @param comparer Comparer used to determine whether values match */ public IndexIterator(SequenceIterator base, AtomicValue value, GenericAtomicComparer comparer) { this.base = base; this.value = value; this.comparer = comparer; primitiveTypeRequired = value.getPrimitiveType(); } public Item next() throws XPathException { while (true) { AtomicValue i = (AtomicValue)base.next(); if (i==null) break; index++; if (Type.isComparable(primitiveTypeRequired, i.getPrimitiveType(), false)) { try { if (comparer.comparesEqual(i, value)) { current = Int64Value.makeIntegerValue(index); position++; return current; } } catch (ClassCastException err) { // non-comparable values are treated as not equal // Exception shouldn't happen but we catch it anyway } } } current = null; position = -1; return null; } public Item current() { return current; } public int position() { return position; } public void close() { base.close(); } public SequenceIterator getAnother() throws XPathException { return new IndexIterator(base.getAnother(), value, comparer); } /** * Get properties of this iterator, as a bit-significant integer. * * @return the properties of this iterator. This will be some combination of * properties such as {@link SequenceIterator#GROUNDED}, {@link SequenceIterator#LAST_POSITION_FINDER}, * and {@link SequenceIterator#LOOKAHEAD}. It is always * acceptable to return the value zero, indicating that there are no known special properties. * It is acceptable for the properties of the iterator to change depending on its state. */ public int getProperties() { return 0; } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/functions/SystemFunctionLibrary.java0000644000175000017500000002400211033112257024567 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.trans.Err; import net.sf.saxon.expr.Expression; import net.sf.saxon.expr.StaticContext; import net.sf.saxon.om.NamespaceConstant; import net.sf.saxon.om.StructuredQName; import net.sf.saxon.trans.XPathException; /** * The SystemFunctionLibrary represents the collection of functions in the fn: namespace. That is, the * functions defined in the "Functions and Operators" specification, optionally augmented by the additional * functions defined in XSLT. */ public class SystemFunctionLibrary implements FunctionLibrary { private int functionSet; public static final int XPATH_ONLY = 0; public static final int FULL_XSLT = 1; public static final int USE_WHEN = 2; private static SystemFunctionLibrary[] THE_INSTANCES = new SystemFunctionLibrary[3]; /** * Factory method to create or get a SystemFunctionLibrary * @param functionSet determines the set of functions allowed. One of * {@link #XPATH_ONLY}, {@link #FULL_XSLT}, {@link #USE_WHEN} * @return the appropriate SystemFunctionLibrary */ public static SystemFunctionLibrary getSystemFunctionLibrary(int functionSet) { if (THE_INSTANCES[functionSet] == null) { THE_INSTANCES[functionSet] = new SystemFunctionLibrary(functionSet); } return THE_INSTANCES[functionSet]; } /** * Create a SystemFunctionLibrary * @param functionSet determines the set of functions allowed. One of * {@link #XPATH_ONLY}, {@link #FULL_XSLT}, {@link #USE_WHEN} */ private SystemFunctionLibrary(int functionSet) { this.functionSet = functionSet; } /** * Test whether a system function with a given name and arity is available. This supports * the function-available() function in XSLT. This method may be called either at compile time * or at run time. * @param functionName the name of the function being tested * @param arity The number of arguments. This is set to -1 in the case of the single-argument * function-available() function; in this case the method should return true if there is some */ public boolean isAvailable(StructuredQName functionName, int arity) { String uri = functionName.getNamespaceURI(); String local = functionName.getLocalName(); if (uri.equals(NamespaceConstant.FN)) { StandardFunction.Entry entry = StandardFunction.getFunction(local, arity); if (entry == null) { return false; } if (!(arity == -1 || (arity >= entry.minArguments && arity <= entry.maxArguments))) { return false; } //noinspection RedundantIfStatement if (functionSet == USE_WHEN && ( local.equals("current") || local.equals("current-group") || local.equals("current-grouping-key") || local.equals("document") || local.equals("format-date") || local.equals("format-dateTime") || local.equals("format-time") || local.equals("generate-id") || local.equals("key") || local.equals("regex-group") || local.equals("unparsed-entity-uri") || local.equals("unparsed-entity-public-id") || local.equals("unparsed-text"))) { return false; } return true; } else { return false; } } /** * Bind an extension function, given the URI and local parts of the function name, * and the list of expressions supplied as arguments. This method is called at compile * time. * @param functionName the name of the function to be bound * @param staticArgs The expressions supplied statically in the function call. The intention is * that the static type of the arguments (obtainable via getItemType() and getCardinality() may * be used as part of the binding algorithm. * @param env * @return An object representing the extension function to be called, if one is found; * null if no extension function was found matching the required name and arity. * @throws net.sf.saxon.trans.XPathException if a function is found with the required name and arity, but * the implementation of the function cannot be loaded or used; or if an error occurs * while searching for the function; or if this function library "owns" the namespace containing * the function call, but no function was found. */ public Expression bind(StructuredQName functionName, Expression[] staticArgs, StaticContext env) throws XPathException { String uri = functionName.getNamespaceURI(); String local = functionName.getLocalName(); if (uri.equals(NamespaceConstant.FN)) { StandardFunction.Entry entry = StandardFunction.getFunction(local, staticArgs.length); if (entry == null) { if (StandardFunction.getFunction(local, -1) == null) { XPathException err = new XPathException("Unknown system function " + local + "()"); err.setErrorCode("XPST0017"); err.setIsStaticError(true); throw err; } else { XPathException err = new XPathException("System function " + local + "() cannot be called with " + pluralArguments(staticArgs.length)); err.setErrorCode("XPST0017"); err.setIsStaticError(true); throw err; } } Class functionClass = entry.implementationClass; SystemFunction f; try { f = (SystemFunction)functionClass.newInstance(); } catch (Exception err) { throw new AssertionError("Failed to load system function: " + err.getMessage()); } f.setDetails(entry); f.setFunctionName(functionName); if (functionSet != FULL_XSLT) { if (f instanceof XSLTFunction || (f instanceof NamePart && entry.opcode==NamePart.GENERATE_ID)) { if (functionSet == XPATH_ONLY) { XPathException err = new XPathException("Cannot use the " + local + "() function in a non-XSLT context"); err.setErrorCode("XPST0017"); err.setIsStaticError(true); throw err; } else if (functionSet == USE_WHEN && !(f instanceof Available || f instanceof SystemProperty)) { XPathException err = new XPathException("Cannot use the " + local + "() function in a use-when expression"); err.setErrorCode("XPST0017"); err.setIsStaticError(true); throw err; } } } f.setArguments(staticArgs); checkArgumentCount(staticArgs.length, entry.minArguments, entry.maxArguments, local); return f; } else { return null; } } /** * Check number of arguments.
* A convenience routine for use in subclasses. * @param numArgs the actual number of arguments (arity) * @param min the minimum number of arguments allowed * @param max the maximum number of arguments allowed * @param local the local name of the function (for diagnostics) * @return the actual number of arguments * @throws net.sf.saxon.trans.XPathException if the number of arguments is out of range */ private int checkArgumentCount(int numArgs, int min, int max, String local) throws XPathException { if (min==max && numArgs != min) { throw new XPathException("Function " + Err.wrap(local, Err.FUNCTION) + " must have " + min + pluralArguments(min)); } if (numArgs < min) { throw new XPathException("Function " + Err.wrap(local, Err.FUNCTION) + " must have at least " + min + pluralArguments(min)); } if (numArgs > max) { throw new XPathException("Function " + Err.wrap(local, Err.FUNCTION) + " must have no more than " + max + pluralArguments(max)); } return numArgs; } /** * Utility routine used in constructing error messages * @param num the number of arguments * @return the string " argument" or "arguments" depending whether num is plural */ private static String pluralArguments(int num) { if (num==1) return " argument"; return " arguments"; } /** * This method creates a copy of a FunctionLibrary: if the original FunctionLibrary allows * new functions to be added, then additions to this copy will not affect the original, or * vice versa. * * @return a copy of this function library. This must be an instance of the original class. */ public FunctionLibrary copy() { return this; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. //saxonb-9.1.0.8/bj/net/sf/saxon/functions/JavaExtensionFunctionFactory.java0000644000175000017500000000674211033112257026077 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.Configuration; import net.sf.saxon.om.StructuredQName; import net.sf.saxon.expr.Expression; import java.io.Serializable; import java.lang.reflect.AccessibleObject; /** * This class acts as a factory for creating expressions that call Java extension functions. * A different factory may be registered with the Configuration in order to customize the * behaviour. Alternatively, this factory class can be customized by calling setExtensionFunctionClass * to nominate a subclass of ExtensionFunctionCall to be used to implement calls on extension functions. *

Note that this class handles Java extension functions only; a different class, * DotNetExtensionFunctionFactory, is used for .NET extensions. */ public class JavaExtensionFunctionFactory implements ExtensionFunctionFactory, Serializable { public JavaExtensionFunctionFactory(Configuration config) { this.config = config; } private Class extensionFunctionCallClass = ExtensionFunctionCall.class; private Configuration config; /** * Set the class to be used to represent extension function calls. This must be a subclass * of {@link ExtensionFunctionCall} * @param subclass the subclass of ExtensionFunctionCall to be used */ public void setExtensionFunctionClass(Class subclass) { extensionFunctionCallClass = subclass; } /** * Factory method to create an expression that calls a Java extension function. * This is always called at XPath compile time. * @param functionName the name of the function * @param theClass the Java class containing the extension function * @param method The "accessibleObject" representing a constructor, method, or field corresponding * to the extension function * @param arguments Array containing the expressions supplied as arguments to the function call. * @return the constructed ExtensionFunctionCall object (a subclass might return any expression * representing the extension function call). */ public Expression makeExtensionFunctionCall( StructuredQName functionName, Class theClass, AccessibleObject method, Expression[] arguments) { ExtensionFunctionCall fn; try { fn = (ExtensionFunctionCall)(extensionFunctionCallClass.newInstance()); } catch (InstantiationException e) { throw new IllegalArgumentException(e.getMessage()); } catch (IllegalAccessException e) { throw new IllegalArgumentException(e.getMessage()); } fn.init(functionName, theClass, method, config); fn.setArguments(arguments); return fn; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): Gunther Schadow (changes to allow access to public fields; also wrapping // of extensions and mapping of null to empty sequence). // saxonb-9.1.0.8/bj/net/sf/saxon/functions/ExtensionFunctionCall.java0000644000175000017500000010762311160723424024546 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.Configuration; import net.sf.saxon.expr.*; import net.sf.saxon.om.*; import net.sf.saxon.pattern.NodeTest; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.AnyItemType; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.TypeHierarchy; import net.sf.saxon.value.SequenceType; import net.sf.saxon.value.Value; import java.io.*; import java.lang.reflect.*; /** * This class acts as a container for an extension function defined to call a method * in a user-defined class. * *

Note that the binding of an XPath function call to a Java method is done in * class {@link net.sf.saxon.functions.JavaExtensionLibrary}

*/ public class ExtensionFunctionCall extends FunctionCall { private transient AccessibleObject theMethod; // declared transient because AccessibleObject is not serializable private MethodRepresentation persistentMethod; // a serializable representation of the method, constructor, or field to be called private transient Class[] theParameterTypes; private PJConverter[] argumentConverters; private JPConverter resultConverter; private boolean checkForNodes; private Class theClass; /** * Default constructor */ public ExtensionFunctionCall() {} /** * Initialization: creates an ExtensionFunctionCall * @param functionName the name of the function, for display purposes * @param theClass the Java class containing the method to be called * @param object the method, field, or constructor of the Java class to be called * @param config the Saxon configuration */ public void init(StructuredQName functionName, Class theClass, AccessibleObject object, Configuration config) { setFunctionName(functionName); this.theClass = theClass; theMethod = object; theParameterTypes = null; } /** * preEvaluate: this method suppresses compile-time evaluation by doing nothing * (because the external function might have side-effects and might use the context) * @param visitor an expression visitor */ public Expression preEvaluate(ExpressionVisitor visitor) { return this; } public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { Expression tc = super.typeCheck(visitor, contextItemType); if (tc != this) { return tc; } Configuration config = visitor.getConfiguration(); TypeHierarchy th = config.getTypeHierarchy(); int firstParam = 0; int firstArg = 0; if (theMethod instanceof Constructor) { if (theParameterTypes == null) { theParameterTypes = ((Constructor)theMethod).getParameterTypes(); } } if (theMethod instanceof Method) { if (theParameterTypes == null) { theParameterTypes = ((Method)theMethod).getParameterTypes(); } boolean isStatic = Modifier.isStatic(((Method)theMethod).getModifiers()); firstArg = (isStatic ? 0 : 1); boolean usesContext = theParameterTypes.length > 0 && (theParameterTypes[0] == XPathContext.class); firstParam = (usesContext ? 1 : 0); } argumentConverters = new PJConverter[argument.length]; if (firstArg != 0) { SequenceType st = PJConverter.getEquivalentItemType(theClass); if (st != null) { RoleLocator role = new RoleLocator( RoleLocator.FUNCTION, getFunctionName(), 0); argument[0] = TypeChecker.staticTypeCheck( argument[0], st, false, role, visitor); } argumentConverters[0] = PJConverter.allocate( config, argument[0].getItemType(th), argument[0].getCardinality(), theClass); } int j = firstParam; for (int i = firstArg; i < argument.length; i++) { SequenceType st = PJConverter.getEquivalentItemType(theParameterTypes[j]); if (st != null) { RoleLocator role = new RoleLocator( RoleLocator.FUNCTION, getFunctionName(), i); argument[i] = TypeChecker.staticTypeCheck( argument[i], st, false, role, visitor); } argumentConverters[i] = PJConverter.allocate( config, argument[i].getItemType(th), argument[i].getCardinality(), theParameterTypes[j]); j++; } if (theMethod instanceof Constructor) { // Constructors always return wrapped external objects, even if the Java class // is one known to Saxon such as java.util.Date //ItemType resultType = new ExternalObjectType(theClass, config); //resultConverter = new JPConverter.WrapExternalObject(resultType); resultConverter = JPConverter.allocate(theClass, config); } else if (theMethod instanceof Method) { Class resultClass = ((Method)theMethod).getReturnType(); resultConverter = JPConverter.allocate(resultClass, config); } else if (theMethod instanceof Field) { Class resultClass = ((Field)theMethod).getType(); resultConverter = JPConverter.allocate(resultClass, config); } else { throw new AssertionError("Unknown component type"); } ItemType resultType = resultConverter.getItemType(); checkForNodes = resultType == AnyItemType.getInstance() || resultType instanceof NodeTest; resetLocalStaticProperties(); return this; } /** * Method called by the expression parser when all arguments have been supplied */ public void checkArguments(ExpressionVisitor visitor) throws XPathException { } /** * Copy an expression. This makes a deep copy. * * @return the copy of the original expression */ public Expression copy() { throw new UnsupportedOperationException(); } /** * Determine which aspects of the context the expression depends on. The result is * a bitwise-or'ed value composed from constants such as XPathContext.VARIABLES and * XPathContext.CURRENT_NODE */ public int getIntrinsicDependencies() { int depend = StaticProperty.HAS_SIDE_EFFECTS; if (theMethod instanceof Method) { Class[] theParameterTypes = ((Method)theMethod).getParameterTypes(); if (theParameterTypes.length > 0 && theParameterTypes[0] == XPathContext.class) { depend |= ( StaticProperty.DEPENDS_ON_CONTEXT_ITEM | StaticProperty.DEPENDS_ON_POSITION | StaticProperty.DEPENDS_ON_LAST ); } } return depend; } /** * Add a representation of this expression to a PathMap. The PathMap captures a map of the nodes visited * by an expression in a source tree. *

*

The default implementation of this method assumes that an expression does no navigation other than * the navigation done by evaluating its subexpressions, and that the subexpressions are evaluated in the * same context as the containing expression. The method must be overridden for any expression * where these assumptions do not hold. For example, implementations exist for AxisExpression, ParentExpression, * and RootExpression (because they perform navigation), and for the doc(), document(), and collection() * functions because they create a new navigation root. Implementations also exist for PathExpression and * FilterExpression because they have subexpressions that are evaluated in a different context from the * calling expression.

* * @param pathMap the PathMap to which the expression should be added * @param pathMapNodeSet the PathMapNodeSet to which the paths embodied in this expression should be added * @return the pathMapNode representing the focus established by this expression, in the case where this * expression is the first operand of a path expression or filter expression. For an expression that does * navigation, it represents the end of the arc in the path map that describes the navigation route. For other * expressions, it is the same as the input pathMapNode. */ public PathMap.PathMapNodeSet addToPathMap(PathMap pathMap, PathMap.PathMapNodeSet pathMapNodeSet) { return addExternalFunctionCallToPathMap(pathMap, pathMapNodeSet); } /** * Evaluate the function.
* @param context The context in which the function is to be evaluated * @return a Value representing the result of the function. * @throws net.sf.saxon.trans.XPathException if the function cannot be evaluated. */ public SequenceIterator iterate(XPathContext context) throws XPathException { ValueRepresentation[] argValues = new ValueRepresentation[argument.length]; for (int i=0; i 0 && (theParameterTypes[0] == XPathContext.class); if (isStatic) { theInstance = null; } else { if (argValues.length == 0) { throw new XPathException("Must supply an argument for a non-static extension function"); } theInstance = getTargetInstance(argValues[0], context); // this fails if the first argument is not of a suitable class } Object[] params = new Object[theParameterTypes.length]; if (usesContext) { params[0] = context; } setupParams(argValues, params, theParameterTypes, (usesContext ? 1 : 0), (isStatic ? 0 : 1), context ); try { Object result = invokeMethod(method, theInstance, params); //Object result = method.invoke(theInstance, params); //if (method.getReturnType().toString().equals("void")) { if (method.getReturnType() == Void.TYPE) { // WH // method returns void: // tried (method.getReturnType()==Void.class) unsuccessfully return EmptyIterator.getInstance(); } return asIterator(result, context); } catch (IllegalAccessException err1) { throw new XPathException("Method access is illegal", err1); } catch (IllegalArgumentException err2) { throw new XPathException("Argument is of wrong type", err2); } catch (NullPointerException err2) { throw new XPathException("Object is null", err2); } catch (InvocationTargetException err3) { Throwable ex = err3.getTargetException(); if (ex instanceof XPathException) { throw (XPathException) ex; } else { if (context.getController().isTracing() || context.getConfiguration().isTraceExternalFunctions()) { err3.getTargetException().printStackTrace(); } throw new XPathException("Exception in extension function " + err3.getTargetException().toString(), ex); } } } else if (theMethod instanceof Field) { // Start of code added by GS Field field = (Field) theMethod; boolean isStatic = Modifier.isStatic(field.getModifiers()); Object theInstance; if (isStatic) { theInstance = null; } else { if (argValues.length == 0) { throw new XPathException("Must supply an argument for a non-static extension function"); } theInstance = getTargetInstance(argValues[0], context); //Value arg0 = Value.asValue(argValues[0]); //theInstance = arg0.convertToJava(theClass, context); // this fails if the first argument is not of a suitable class } try { Object result = getField(field, theInstance); return asIterator(result, context); } catch (IllegalAccessException err1) { throw new XPathException("Field access is illegal", err1); } catch (IllegalArgumentException err2) { throw new XPathException("Argument is of wrong type", err2); } } else { throw new AssertionError("property " + theMethod + " is neither constructor, method, nor field"); } } private Object getTargetInstance(ValueRepresentation arg0, XPathContext context) throws XPathException { Value val = Value.asValue(arg0).reduce(); // Configuration config = context.getConfiguration(); // PJConverter converter = PJConverter.allocate( // config, val.getItemType(config.getTypeHierarchy()), val.getCardinality(), theClass); PJConverter converter = argumentConverters[0]; return converter.convert(val, theClass, context); //return arg0.convertToJava(theClass, context); } /** * Convert the extension function result to an XPath value (a sequence) and return a * SequenceIterator over that sequence * @param result the result returned by the Java extension function * @param context the dynamic context * @return an iterator over the items in the result * @throws net.sf.saxon.trans.XPathException */ private SequenceIterator asIterator(Object result, XPathContext context) throws XPathException { if (result == null) { return EmptyIterator.getInstance(); } SequenceIterator resultIterator; if (result instanceof SequenceIterator) { resultIterator = (SequenceIterator)result; } else { resultIterator = Value.asIterator(resultConverter.convert(result, context)); } if (checkForNodes) { return new ItemMappingIterator(resultIterator, new ConfigurationCheckingFunction(context.getConfiguration())); } else { return resultIterator; } // if (result instanceof Value) { // return new ItemMappingIterator(((Value) result).iterate(), // new ConfigurationCheckingFunction(context.getConfiguration())); // } // if (result instanceof NodeInfo) { // if (!((NodeInfo)result).getConfiguration().isCompatible(context.getConfiguration())) { // XPathException err = new XPathException( // "NodeInfo returned by extension function was created with an incompatible Configuration"); // err.setLocator(this); // err.setXPathContext(context); // throw err; // } // return SingletonIterator.makeIterator(((NodeInfo) result)); // } // Value actual = Value.convertJavaObjectToXPath( // result, SequenceType.ANY_SEQUENCE, context); // return actual.iterate(); } /** * Set up parameters for the Java method call * @param argValues the supplied XPath argument values * @param params the result of converting the XPath argument values to Java objects * @param paramTypes the Java classes defining the types of the arguments in the method signature * @param firstParam normally 0, but 1 if the first parameter to the Java method is an XPathContext object * @param firstArg normally 0, but 1 if the first argument in the XPath call is the instance object whose method * is to be called * @param context The dynamic context, giving access to a NamePool and to schema information * @throws net.sf.saxon.trans.XPathException */ private void setupParams(ValueRepresentation[] argValues, Object[] params, Class[] paramTypes, int firstParam, int firstArg, XPathContext context) throws XPathException { int j = firstParam; for (int i = firstArg; i < argValues.length; i++) { ValueRepresentation val = argValues[i]; if (val instanceof Value) { val = ((Value)val).reduce(); } params[j] = argumentConverters[i].convert(val, paramTypes[j], context); j++; } } /** * Determine the data type of the expression, if possible. All expressions return * sequences, in general; this method determines the type of the items within the * sequence, assuming that (a) this is known in advance, and (b) it is the same for * all items in the sequence. * *

This method will always return a result, though it may be the best approximation * that is available at the time.

* * @return the item type * @param th the type hierarchy cache */ public ItemType getItemType(TypeHierarchy th) { //return convertClassToType(getReturnClass()); if (resultConverter == null) { return AnyItemType.getInstance(); } else { return resultConverter.getItemType(); } } // /** // * Given the return class of the Java method, determine the return type of the XPath function // * @param resultClass the Java return class of the method // * @return the XPath return type of the extension function // */ // private ItemType convertClassToType(Class resultClass) { // if (resultClass==null || resultClass==Value.class) { // return AnyItemType.getInstance(); // } else if (resultClass.toString().equals("void")) { // return AnyItemType.getInstance(); // } else if (resultClass==String.class || resultClass==StringValue.class) { // return BuiltInAtomicType.STRING; // } else if (resultClass==Boolean.class || resultClass==boolean.class || resultClass == BooleanValue.class) { // return BuiltInAtomicType.BOOLEAN; // } else if (resultClass==Double.class || resultClass==double.class || resultClass==DoubleValue.class) { // return BuiltInAtomicType.DOUBLE; // } else if (resultClass==Float.class || resultClass==float.class || resultClass==FloatValue.class) { // return BuiltInAtomicType.FLOAT; // } else if (resultClass==Long.class || resultClass==long.class || // resultClass==Int64Value.class || resultClass==BigIntegerValue.class || // resultClass==Integer.class || resultClass==int.class || // resultClass==Short.class || resultClass==short.class || // resultClass==Byte.class || resultClass==byte.class ) { // return BuiltInAtomicType.INTEGER; // } else if (resultClass == BigDecimal.class) { // return BuiltInAtomicType.DECIMAL; // } else if (resultClass == Date.class) { // return BuiltInAtomicType.DATE_TIME; // } else if (Value.class.isAssignableFrom(resultClass) || // SequenceIterator.class.isAssignableFrom(resultClass)) { // return AnyItemType.getInstance(); // // } else { // // Offer the object to all the registered external object models // List externalObjectModels = config.getExternalObjectModels(); // for (int m=0; m= 0) { FastStringBuffer buff = new FastStringBuffer(name.length()); boolean afterHyphen = false; for (int n = 0; n < name.length(); n++) { char c = name.charAt(n); if (c == '-') { afterHyphen = true; } else { if (afterHyphen) { buff.append(Character.toUpperCase(c)); } else { buff.append(c); } afterHyphen = false; } } name = buff.toString(); if (debug) { diag.println("Seeking a method with adjusted name " + name); } } return name; } /** * A Java AccessibleObject is not serializable. When compiling a stylesheet that contains extension * functions, we therefore need to create a serializable representation of the method (or constructor * or field) to be called. This is provided by the class MethodRepresentation. */ private static class MethodRepresentation implements Serializable { private Class theClass; private byte category; // one of Method, Constructor, Field private String name; // the name of the method or field private Class[] params; // the types of the parameters to a method or constructor public MethodRepresentation(Class theClass, AccessibleObject obj) { this.theClass = theClass; if (obj instanceof Method) { category = 0; name = ((Method)obj).getName(); params = ((Method)obj).getParameterTypes(); } else if (obj instanceof Constructor) { category = 1; params = ((Constructor)obj).getParameterTypes(); } else { category = 2; name = ((Field)obj).getName(); } } public AccessibleObject recoverAccessibleObject() throws NoSuchMethodException, NoSuchFieldException { switch (category) { case 0: return theClass.getMethod(name, params); case 1: return theClass.getConstructor(params); case 2: return theClass.getField(name); default: return null; } } } /** * This class checks that NodeInfo objects returned by an extension function were created * under the right Configuration */ private static class ConfigurationCheckingFunction implements ItemMappingFunction { private Configuration config; public ConfigurationCheckingFunction(Configuration config) { this.config = config; } /** * Map one item to another item. * * @param item The input item to be mapped. * @return either the output item, or null. */ public Item map(Item item) throws XPathException { if (item instanceof NodeInfo && !config.isCompatible(((NodeInfo)item).getConfiguration())) { throw new XPathException( "NodeInfo returned by extension function was created with an incompatible Configuration"); } return item; } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): Gunther Schadow (changes to allow access to public fields; also wrapping // of extensions and mapping of null to empty sequence). // Contributor(s): Wolfgang Hoschek (performance improvement by not recomputing theParameterTypes). // saxonb-9.1.0.8/bj/net/sf/saxon/functions/FormatNumber.java0000644000175000017500000010014411033112257022653 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.Controller; import net.sf.saxon.expr.*; import net.sf.saxon.om.*; import net.sf.saxon.style.ExpressionContext; import net.sf.saxon.tinytree.CharSlice; import net.sf.saxon.trans.*; import net.sf.saxon.value.*; import java.io.Serializable; import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; /** * XSLT 2.0 implementation of format-number() function - removes the dependence on the JDK. */ public class FormatNumber extends SystemFunction implements XSLTFunction { private NamespaceResolver nsContext = null; // held only if the third argument is present, and its value is not known statically private DecimalSymbols decimalFormatSymbols = null; // held only if the decimal format to use can be determined statically private transient String picture = null; // held transiently at compile time if the picture is known statically private SubPicture[] subPictures = null; // held if the picture is known statically private boolean requireFixup = false; // used to detect when an unknown decimal-format name is used private transient boolean checked = false; // the second time checkArguments is called, it's a global check so the static context is inaccurate public void checkArguments(ExpressionVisitor visitor) throws XPathException { StaticContext env = visitor.getStaticContext(); if (checked) return; checked = true; super.checkArguments(visitor); if (argument[1] instanceof StringLiteral) { // picture is known statically - optimize for this common case picture = ((StringLiteral)argument[1]).getStringValue(); } if (argument.length==3) { if (argument[2] instanceof StringLiteral) { // common case, decimal format name is supplied as a string literal String lexicalName = ((StringLiteral)argument[2]).getStringValue(); StructuredQName qName; try { qName = StructuredQName.fromLexicalQName(lexicalName, false, visitor.getConfiguration().getNameChecker(), env.getNamespaceResolver()); } catch (XPathException e) { XPathException se = new XPathException("Invalid decimal format name. " + e.getMessage()); se.setErrorCode("XTDE1280"); throw se; } DecimalFormatManager dfm = ((ExpressionContext)env).getXSLStylesheet().getDecimalFormatManager(); requireFixup = true; dfm.registerUsage(qName, this); // this causes a callback to the fixup() method, either now, or later if it's a forwards reference } else { // we need to save the namespace context nsContext = env.getNamespaceResolver(); } } else { // two arguments only: it uses the default decimal format if (env instanceof ExpressionContext) { // this is XSLT DecimalFormatManager dfm = ((ExpressionContext)env).getXSLStylesheet().getDecimalFormatManager(); dfm.registerUsage(DecimalFormatManager.DEFAULT_NAME, this); // Note: if using the "default default", there will be no fixup call. } else { // using saxon:decimal-format in some other environment } } } /** * Fixup: this is a callback from the DecimalFormatManager used once the xsl:decimal-format * element is identified * @param dfs the decimal symbols to be used */ public void fixup(DecimalSymbols dfs) { // System.err.println("Fixed up format-number, picture=" + picture); requireFixup = false; decimalFormatSymbols = dfs; if (picture != null) { try { subPictures = getSubPictures(picture, dfs); } catch (XPathException err) { subPictures = null; // we'll report the error at run-time } } } /** * Analyze a picture string into two sub-pictures. * @param picture the picture as written (possibly two subpictures separated by a semicolon) * @param dfs the decimal format symbols * @return an array of two sub-pictures, the positive and the negative sub-pictures respectively. * If there is only one sub-picture, the second one is null. */ private SubPicture[] getSubPictures(String picture, DecimalSymbols dfs) throws XPathException { int[] picture4 = StringValue.expand(picture); SubPicture[] pics = new SubPicture[2]; if (picture4.length==0) { XPathException err = new XPathException("format-number() picture is zero-length"); err.setErrorCode("XTDE1310"); throw err; } int sep = -1; for (int c=0; c= 0) { grumble("more than one pattern separator"); } else if (sep == picture4.length-1) { grumble("second subpicture is zero-length"); } sep = c; } } if (sep<0) { pics[0] = new SubPicture(picture4, dfs); pics[1] = null; } else { int[] pic0 = new int[sep]; System.arraycopy(picture4, 0, pic0, 0, sep); int[] pic1 = new int[picture4.length - sep - 1]; System.arraycopy(picture4, sep+1, pic1, 0, picture4.length - sep - 1); pics[0] = new SubPicture(pic0, dfs); pics[1] = new SubPicture(pic1, dfs); } return pics; } /** * preEvaluate: this method suppresses compile-time evaluation by doing nothing. * We can't evaluate early because we don't have access to the DecimalFormatManager. * @param visitor the expression visitor */ public Expression preEvaluate(ExpressionVisitor visitor) throws XPathException { return this; } /** * Evaluate in a context where a string is wanted */ public CharSequence evaluateAsString(XPathContext context) throws XPathException { int numArgs = argument.length; Controller ctrl = context.getController(); DecimalSymbols dfs = decimalFormatSymbols; AtomicValue av0 = (AtomicValue)argument[0].evaluateItem(context); if (av0 == null) { av0 = DoubleValue.NaN; } NumericValue number = (NumericValue)av0; if (dfs == null) { // the decimal-format name was not resolved statically if (requireFixup) { // we registered for a fixup, but none came dynamicError("Unknown decimal format name", "XTDE1280", context); return null; } DecimalFormatManager dfm = ctrl.getExecutable().getDecimalFormatManager(); if (numArgs==2) { dfs = dfm.getDefaultDecimalFormat(); } else { // the decimal-format name was given as a run-time expression String lexicalName = argument[2].evaluateItem(context).getStringValue(); StructuredQName qName = null; try { qName = StructuredQName.fromLexicalQName(lexicalName, false, context.getConfiguration().getNameChecker(), nsContext); } catch (XPathException e) { dynamicError("Invalid decimal format name. " + e.getMessage(), "XTDE1280", context); } dfs = dfm.getNamedDecimalFormat(qName); if (dfs==null) { dynamicError( "format-number function: decimal-format '" + lexicalName + "' is not defined", "XTDE1280", context); return null; } } } SubPicture[] pics = subPictures; if (pics == null) { String format = argument[1].evaluateItem(context).getStringValue(); pics = getSubPictures(format, dfs); } return formatNumber(number, pics, dfs).toString(); } /** * Evaluate in a general context */ public Item evaluateItem(XPathContext c) throws XPathException { return new StringValue(evaluateAsString(c)); } /** * Format a number, given the two subpictures and the decimal format symbols * @param number the number to be formatted * @param subPictures the negative and positive subPictures * @param dfs the decimal format symbols to be used * @return the formatted number */ private CharSequence formatNumber(NumericValue number, SubPicture[] subPictures, DecimalSymbols dfs) { NumericValue absN = number; SubPicture pic; String minusSign = ""; if (number.signum() < 0) { absN = number.negate(); if (subPictures[1]==null) { pic = subPictures[0]; minusSign = "" + unicodeChar(dfs.minusSign); } else { pic = subPictures[1]; } } else { pic = subPictures[0]; } return pic.format(absN, dfs, minusSign); } private void grumble(String s) throws XPathException { dynamicError("format-number picture: " + s, "XTDE1310", null); } /** * Convert a double to a BigDecimal. In general there will be several BigDecimal values that * are equal to the supplied value, and the one we want to choose is the one with fewest non-zero * digits. The algorithm used is rather pragmatic: look for a string of zeroes or nines, try rounding * the number down or up as approriate, then convert the adjusted value to a double to see if it's * equal to the original: if not, use the original value unchanged. * @param value the double to be converted * @param precision 2 for a double, 1 for a float * @return the result of conversion to a double */ public static BigDecimal adjustToDecimal(double value, int precision) { final String zeros = (precision == 1 ? "00000" : "000000000"); final String nines = (precision == 1 ? "99999" : "999999999"); BigDecimal initial = new BigDecimal(value); BigDecimal trial = null; FastStringBuffer fsb = new FastStringBuffer(20); DecimalValue.decimalToString(initial, fsb); String s = fsb.toString(); int start = (s.charAt(0) == '-' ? 1 : 0); int p = s.indexOf("."); int i = s.lastIndexOf(zeros); if (i > 0) { if (p < 0 || i < p) { // we're in the integer part // try replacing all following digits with zeros and seeing if we get the same double back FastStringBuffer sb = new FastStringBuffer(s.length()); sb.append(s.substring(0, i)); for (int n=i; n= 0) { if (i == start) { // number starts with 99999... or -99999. Try rounding up to 100000.. or -100000... FastStringBuffer sb = new FastStringBuffer(s.length() + 1); if (start == 1) { sb.append('-'); } sb.append('1'); for (int n=start; n= 0 && (s.charAt(i) == '9' || s.charAt(i) == '.')) { i--; } if (i < 0 || s.charAt(i) == '-') { return initial; // can't happen: we've already handled numbers starting 99999.. } else if (p < 0 || i < p) { // we're in the integer part FastStringBuffer sb = new FastStringBuffer(s.length()); sb.append(s.substring(0, i)); sb.append((char)((int)s.charAt(i) + 1)); for (int n=i; n='0' && c<='9') { ib[i] = (c-'0'+newZero); } } } // Add the whole-part grouping separators if (wholePartGroupingPositions != null) { if (wholePartGroupingPositions.length == 1) { // grouping separators are at regular positions int g = wholePartGroupingPositions[0]; int p = point - g; while (p > 0) { ib = insert(ib, ibused++, dfs.groupingSeparator, p); //sb.insert(p, unicodeChar(dfs.groupingSeparator)); p -= g; } } else { // grouping separators are at irregular positions for (int i=0; i 0) { ib = insert(ib, ibused++, dfs.groupingSeparator, p); //sb.insert(p, unicodeChar(dfs.groupingSeparator)); } } } } // Add the fractional-part grouping separators if (fractionalPartGroupingPositions != null) { // grouping separators are at irregular positions. for (int i=0; i= 0) { int zz = maxFractionPartSize - minFractionPartSize; while (zz>0) { if (fsb.charAt(fsb.length()-1) == '0') { fsb.setLength(fsb.length()-1); zz--; } else { break; } } intDigits = point; if (fsb.charAt(fsb.length()-1) == '.') { fsb.setLength(fsb.length()-1); } } else { intDigits = fsb.length(); if (minFractionPartSize > 0) { fsb.append('.'); for (int i=0; i65536) to a String, using a surrogate pair if necessary * @param ch the Unicode codepoint value * @return a string representing the Unicode codepoint, either a string of one character or a surrogate pair */ private static CharSequence unicodeChar(int ch) { if (ch<65536) { return "" + (char)ch; } else { // output a surrogate pair //To compute the numeric value of the character corresponding to a surrogate //pair, use this formula (all numbers are hex): //(FirstChar - D800) * 400 + (SecondChar - DC00) + 10000 ch -= 65536; char[] sb = new char[2]; sb[0] = ((char)((ch / 1024) + 55296)); sb[1] = ((char)((ch % 1024) + 56320)); return new CharSlice(sb, 0, 2); } } /** * Insert an integer into an array of integers. This may or may not modify the supplied array. * @param array the initial array * @param used the number of items in the initial array that are used * @param value the integer to be inserted * @param position the position of the new integer in the final array * @return the new array, with the new integer inserted */ private static int[] insert(int[] array, int used, int value, int position) { if (used+1 > array.length) { int[] a2 = new int[used+10]; System.arraycopy(array, 0, a2, 0, used); array = a2; } for (int i=used-1; i>=position; i--) { array[i+1] = array[i]; } array[position] = value; return array; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/functions/Adjust.java0000644000175000017500000000570711033112257021515 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.expr.Expression; import net.sf.saxon.expr.ExpressionVisitor; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.Item; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.AtomicValue; import net.sf.saxon.value.CalendarValue; import net.sf.saxon.value.DayTimeDurationValue; /** * This class implements the XPath 2.0 functions * adjust-date-to-timezone(), adjust-time-timezone(), and adjust-dateTime-timezone(). */ public class Adjust extends SystemFunction { /** * Simplify and validate. * @param visitor an expression visitor */ public Expression simplify(ExpressionVisitor visitor) throws XPathException { return super.simplify(visitor); } /** * Evaluate in a general context */ public Item evaluateItem(XPathContext context) throws XPathException { AtomicValue av1 = (AtomicValue)argument[0].evaluateItem(context); if (av1==null) { return null; } CalendarValue in = (CalendarValue)av1; int nargs = argument.length; DayTimeDurationValue tz; if (nargs==1) { return in.adjustTimezone(context.getImplicitTimezone()); } else { AtomicValue av2 = (AtomicValue)argument[1].evaluateItem(context); if (av2==null) { return in.removeTimezone(); } tz = (DayTimeDurationValue)av2; long microseconds = tz.getLengthInMicroseconds(); if (microseconds%60000000 != 0) { XPathException err = new XPathException("Timezone is not an integral number of minutes"); err.setErrorCode("FODT0003"); err.setLocator(this); err.setXPathContext(context); throw err; } int tzminutes = (int)(microseconds / 60000000); if (Math.abs(tzminutes) > 14*60) { XPathException err = new XPathException("Timezone out of range (-14:00 to +14:00)"); err.setErrorCode("FODT0003"); err.setLocator(this); err.setXPathContext(context); throw err; } return in.adjustTimezone(tzminutes); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/functions/StringToCodepoints.java0000644000175000017500000000255011033112257024055 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.EmptyIterator; import net.sf.saxon.om.Item; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.StringValue; /** * This class supports the function string-to-codepoints() */ public class StringToCodepoints extends SystemFunction { public SequenceIterator iterate(XPathContext c) throws XPathException { Item item = argument[0].evaluateItem(c); if (item==null) { return EmptyIterator.getInstance(); } return ((StringValue)item).iterateCharacters(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/functions/Reverse.java0000644000175000017500000000562411033112257021674 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.expr.*; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.AnyItemType; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.TypeHierarchy; import net.sf.saxon.value.SequenceExtent; /** * Implement XPath function fn:reverse() */ public class Reverse extends SystemFunction { /** * Determine the item type of the value returned by the function * * @param th the type hierarchy cache */ public ItemType getItemType(TypeHierarchy th) { return argument[0].getItemType(th); //AUTO } public int computeSpecialProperties() { int baseProps = argument[0].getSpecialProperties(); if ((baseProps & StaticProperty.REVERSE_DOCUMENT_ORDER) != 0) { return (baseProps & (~StaticProperty.REVERSE_DOCUMENT_ORDER)) | StaticProperty.ORDERED_NODESET; } else if ((baseProps & StaticProperty.ORDERED_NODESET) != 0) { return (baseProps & (~StaticProperty.ORDERED_NODESET)) | StaticProperty.REVERSE_DOCUMENT_ORDER; } else { return baseProps; } } public SequenceIterator iterate(XPathContext context) throws XPathException { SequenceIterator forwards = argument[0].iterate(context); if (forwards instanceof ReversibleIterator) { return ((ReversibleIterator)forwards).getReverseIterator(); } else { SequenceExtent extent = new SequenceExtent(forwards); return extent.reverseIterate(); } } public boolean effectiveBooleanValue(XPathContext context) throws XPathException { // EBV is independent of sequence order unless the sequence mixes atomic values and nodes // Note, calls to get the EBV of reverse() should normally have been rewritten at compile time ItemType type = argument[0].getItemType(context.getConfiguration().getTypeHierarchy()); if (type == AnyItemType.getInstance()) { return super.effectiveBooleanValue(context); } else { return argument[0].effectiveBooleanValue(context); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/functions/Remove.java0000644000175000017500000001642311033112257021515 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.expr.*; import net.sf.saxon.om.Item; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.TypeHierarchy; import net.sf.saxon.value.AtomicValue; import net.sf.saxon.value.NumericValue; import net.sf.saxon.value.IntegerValue; /** * The XPath 2.0 remove() function */ public class Remove extends SystemFunction { /** * Simplify. Recognize remove(seq, 1) as a TailExpression. * @param visitor an expression visitor */ public Expression simplify(ExpressionVisitor visitor) throws XPathException { Expression exp = super.simplify(visitor); if (exp instanceof Remove) { return ((Remove)exp).simplifyAsTailExpression(); } else { return exp; } } /** * Simplify. Recognize remove(seq, 1) as a TailExpression. This * is worth doing because tail expressions used in a recursive call * are handled specially. */ private Expression simplifyAsTailExpression() { if (Literal.isAtomic(argument[1])) { try { long value = ((IntegerValue)((Literal)argument[1]).getValue()).longValue(); if (value <= 0) { return argument[0]; } else if (value == 1) { TailExpression t = new TailExpression(argument[0], 2); ExpressionTool.copyLocationInfo(this, t); return t; } } catch (XPathException err) { return this; } } return this; } /** * Perform optimisation of an expression and its subexpressions. *

*

This method is called after all references to functions and variables have been resolved * to the declaration of the function or variable, and after all type checking has been done.

* * @param visitor an expression visitor * @param contextItemType the static type of "." at the point where this expression is invoked. * The parameter is set to null if it is known statically that the context item will be undefined. * If the type of the context item is not known statically, the argument is set to * {@link net.sf.saxon.type.Type#ITEM_TYPE} * @return the original expression, rewritten if appropriate to optimize execution * @throws net.sf.saxon.trans.XPathException * if an error is discovered during this phase * (typically a type error) */ public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { Expression e = super.optimize(visitor, contextItemType); if (e == this) { return simplifyAsTailExpression(); } return e; } /** * Determine the data type of the items in the sequence * @return the type of the input sequence * @param th the type hierarchy cache */ public ItemType getItemType(TypeHierarchy th) { return argument[0].getItemType(th); } /** * Evaluate the function to return an iteration of selected nodes. */ public SequenceIterator iterate(XPathContext context) throws XPathException { SequenceIterator seq = argument[0].iterate(context); AtomicValue n0 = (AtomicValue)argument[1].evaluateItem(context); NumericValue n = (NumericValue)n0; int pos = (int)n.longValue(); if (pos < 1) { return seq; } return new RemoveIterator(seq, pos); } /** * An implementation of SequenceIterator that returns all items except the one * at a specified position. */ public static class RemoveIterator implements SequenceIterator, LastPositionFinder { SequenceIterator base; int removePosition; int position = 0; Item current = null; public RemoveIterator(SequenceIterator base, int removePosition) { this.base = base; this.removePosition = removePosition; } public Item next() throws XPathException { current = base.next(); if (current != null && base.position() == removePosition) { current = base.next(); } if (current == null) { position = -1; } else { position++; } return current; } public Item current() { return current; } public int position() { return position; } public void close() { base.close(); } /** * Get the last position (that is, the number of items in the sequence). This method is * non-destructive: it does not change the state of the iterator. * The result is undefined if the next() method of the iterator has already returned null. */ public int getLastPosition() throws XPathException { if (base instanceof LastPositionFinder) { int x = ((LastPositionFinder)base).getLastPosition(); if (removePosition >= 1 && removePosition <= x) { return x - 1; } else { return x; } } else { // This shouldn't happen, because this iterator only has the LAST_POSITION_FINDER property // if the base iterator has the LAST_POSITION_FINDER property throw new AssertionError("base of removeIterator is not a LastPositionFinder"); } } public SequenceIterator getAnother() throws XPathException { return new RemoveIterator( base.getAnother(), removePosition); } /** * Get properties of this iterator, as a bit-significant integer. * * @return the properties of this iterator. This will be some combination of * properties such as {@link SequenceIterator#GROUNDED}, {@link SequenceIterator#LAST_POSITION_FINDER}, * and {@link SequenceIterator#LOOKAHEAD}. It is always * acceptable to return the value zero, indicating that there are no known special properties. * It is acceptable for the properties of the iterator to change depending on its state. */ public int getProperties() { return base.getProperties() & LAST_POSITION_FINDER; } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/functions/Trace.java0000644000175000017500000001561111033112257021314 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.expr.*; import net.sf.saxon.instruct.InstructionDetails; import net.sf.saxon.om.*; import net.sf.saxon.trace.Location; import net.sf.saxon.trace.TraceListener; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.Type; import net.sf.saxon.value.Value; import net.sf.saxon.Controller; import java.io.PrintStream; /** * This class supports the XPath 2.0 function trace(). * The value is traced to the registered output stream (defaulting to System.err), * unless a TraceListener is in use, in which case the information is sent to the TraceListener */ public class Trace extends SystemFunction { NamespaceResolver resolver; // This is retained so that the static namespace context is available if required by the TraceListener /** * Simplify the function call. This implementation saves the static namespace context, in case it is * needed by the TraceListener. * @param visitor an expression visitor */ public Expression simplify(ExpressionVisitor visitor) throws XPathException { resolver = visitor.getStaticContext().getNamespaceResolver(); return super.simplify(visitor); } /** * preEvaluate: this method suppresses compile-time evaluation by doing nothing * @param visitor an expression visitor */ public Expression preEvaluate(ExpressionVisitor visitor) { return this; } /** * Get the static properties of this expression (other than its type). The result is * bit-significant. These properties are used for optimizations. In general, if * property bit is set, it is true, but if it is unset, the value is unknown. */ public int computeSpecialProperties() { return argument[0].getSpecialProperties(); } /** * Get the static cardinality */ public int computeCardinality() { return argument[0].getCardinality(); } /** * Evaluate the function */ public Item evaluateItem(XPathContext context) throws XPathException { Item val = argument[0].evaluateItem(context); String label = argument[1].evaluateAsString(context).toString(); Controller controller = context.getController(); if (controller.isTracing()) { notifyListener(label, Value.asValue(val), context); } else { PrintStream out = controller.getTraceFunctionDestination(); if (out != null) { traceItem(val, label, out); } } return val; } private void notifyListener(String label, Value val, XPathContext context) { InstructionDetails info = new InstructionDetails(); info.setConstructType(Location.TRACE_CALL); info.setLineNumber(getLineNumber()); info.setSystemId(getSystemId()); info.setProperty("label", label); info.setProperty("value", val); TraceListener listener = context.getController().getTraceListener(); listener.enter(info, context); listener.leave(info); } private void traceItem(Item val, String label, PrintStream out) { if (val==null) { out.println(label + ": empty sequence"); } else { if (val instanceof NodeInfo) { out.println(label + ": " + Type.displayTypeName(val) + ": " + Navigator.getPath((NodeInfo)val)); } else { out.println(label + ": " + Type.displayTypeName(val) + ": " + val.getStringValue()); } } } /** * Iterate over the results of the function */ public SequenceIterator iterate(XPathContext context) throws XPathException { Controller controller = context.getController(); if (controller.isTracing()) { String label = argument[1].evaluateAsString(context).toString(); Value value = Value.asValue(ExpressionTool.eagerEvaluate(argument[0], context)); notifyListener(label, value, context); return value.iterate(); } else { PrintStream out = controller.getTraceFunctionDestination(); if (out == null) { return argument[0].iterate(context); } else { return new TracingIterator(argument[0].iterate(context), argument[1].evaluateAsString(context).toString(), out); } } } /** * Tracing Iterator class */ private class TracingIterator implements SequenceIterator { SequenceIterator base; String label; PrintStream out; boolean empty = true; public TracingIterator(SequenceIterator base, String label, PrintStream out) { this.base = base; this.label = label; this.out = out; } public Item next() throws XPathException { Item n = base.next(); if (n==null) { if (empty) { traceItem(null, label, out); } } else { traceItem(n, label + " [" + position() + ']', out); empty = false; } return n; } public Item current() { return base.current(); } public int position() { return base.position(); } public void close() { base.close(); } public SequenceIterator getAnother() throws XPathException { return new TracingIterator(base.getAnother(), label, out); } /** * Get properties of this iterator, as a bit-significant integer. * * @return the properties of this iterator. This will be some combination of * properties such as {@link #GROUNDED}, {@link #LAST_POSITION_FINDER}, * and {@link #LOOKAHEAD}. It is always * acceptable to return the value zero, indicating that there are no known special properties. * It is acceptable for the properties of the iterator to change depending on its state. */ public int getProperties() { return 0; } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/functions/Idref.java0000644000175000017500000001775511033112257021322 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.Controller; import net.sf.saxon.expr.*; import net.sf.saxon.om.*; import net.sf.saxon.pattern.AnyNodeTest; import net.sf.saxon.sort.DocumentOrderIterator; import net.sf.saxon.sort.LocalOrderComparer; import net.sf.saxon.trans.KeyDefinitionSet; import net.sf.saxon.trans.KeyManager; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.Type; import net.sf.saxon.value.AtomicValue; import net.sf.saxon.value.Cardinality; import net.sf.saxon.value.StringValue; public class Idref extends SystemFunction { private KeyDefinitionSet idRefKey; /** * Simplify: add a second implicit argument, the context document * @param visitor an expression visitor */ public Expression simplify(ExpressionVisitor visitor) throws XPathException { Idref f = (Idref)super.simplify(visitor); f.addContextDocumentArgument(1, "idref"); return f; } /** * Type-check the expression. This also calls preEvaluate() to evaluate the function * if all the arguments are constant; functions that do not require this behavior * can override the preEvaluate method. */ public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { Expression e = super.typeCheck(visitor, contextItemType); idRefKey = visitor.getExecutable().getKeyManager().getKeyDefinitionSet( StandardNames.getStructuredQName(StandardNames.XS_IDREFS)); return e; } public void checkArguments(ExpressionVisitor visitor) throws XPathException { super.checkArguments(visitor); Optimizer opt = visitor.getConfiguration().getOptimizer(); argument[0] = ExpressionTool.unsorted(opt, argument[0], false); } /** * Get the static properties of this expression (other than its type). The result is * bit-signficant. These properties are used for optimizations. In general, if * property bit is set, it is true, but if it is unset, the value is unknown. */ public int computeSpecialProperties() { int prop = StaticProperty.ORDERED_NODESET | StaticProperty.SINGLE_DOCUMENT_NODESET | StaticProperty.NON_CREATIVE; if ((getNumberOfArguments() == 1) || (argument[1].getSpecialProperties() & StaticProperty.CONTEXT_DOCUMENT_NODESET) != 0) { prop |= StaticProperty.CONTEXT_DOCUMENT_NODESET; } return prop; } /** * preEvaluate: this method suppresses compile-time evaluation by doing nothing * @param visitor an expression visitor */ public Expression preEvaluate(ExpressionVisitor visitor) { return this; } /** * Copy an expression. This makes a deep copy. * * @return the copy of the original expression */ public Expression copy() { Idref i2 = (Idref)super.copy(); i2.idRefKey = idRefKey; return i2; } /** * Add a representation of a doc() call or similar function to a PathMap. * This is a convenience method called by the addToPathMap() methods for doc(), document(), collection() * and similar functions. These all create a new root expression in the path map. * * @param pathMap the PathMap to which the expression should be added * @param pathMapNodeSet * @return the pathMapNode representing the focus established by this expression, in the case where this * expression is the first operand of a path expression or filter expression */ public PathMap.PathMapNodeSet addToPathMap(PathMap pathMap, PathMap.PathMapNodeSet pathMapNodeSet) { argument[0].addToPathMap(pathMap, pathMapNodeSet); PathMap.PathMapNodeSet target = argument[1].addToPathMap(pathMap, pathMapNodeSet); // indicate that the function navigates to all nodes in the document AxisExpression allElements = new AxisExpression(Axis.DESCENDANT, AnyNodeTest.getInstance()); allElements.setContainer(getContainer()); target = target.createArc(allElements); // if (isStringValueUsed()) { // target.setAtomized(); // } return target; } /** * Enumerate the results of the expression */ public SequenceIterator iterate(XPathContext context) throws XPathException { Controller controller = context.getController(); NodeInfo arg2 = (NodeInfo)argument[1].evaluateItem(context); arg2 = arg2.getRoot(); if (arg2.getNodeKind() != Type.DOCUMENT) { dynamicError("In the idref() function," + " the tree being searched must be one whose root is a document node", "FODC0001", context); return null; } DocumentInfo doc = (DocumentInfo)arg2; // If the argument is a singleton, we evaluate the function // directly; otherwise we recurse to evaluate it once for each Item // in the sequence. Expression expression = argument[0]; if (Cardinality.allowsMany(expression.getCardinality())) { SequenceIterator keys = argument[0].iterate(context); return getIdrefMultiple(doc, keys, context); } else { AtomicValue keyValue = (AtomicValue)argument[0].evaluateItem(context); if (keyValue == null) { return EmptyIterator.getInstance(); } KeyManager keyManager = controller.getKeyManager(); return keyManager.selectByKey(idRefKey, doc, keyValue, context); } } /** * Get the result when multiple idref values are supplied. Note this is also called from * compiled XQuery code. * @param doc the document to be searched * @param keys the idref values supplied * @param context the dynamic execution context * @return iterator over the result of the function * @throws XPathException */ public static SequenceIterator getIdrefMultiple(DocumentInfo doc, SequenceIterator keys, XPathContext context) throws XPathException { IdrefMappingFunction map = new IdrefMappingFunction(); map.document = doc; map.keyContext = context; map.keyManager = context.getController().getKeyManager(); map.keySet = map.keyManager.getKeyDefinitionSet(StandardNames.getStructuredQName(StandardNames.XS_IDREFS)); SequenceIterator allValues = new MappingIterator(keys, map); return new DocumentOrderIterator(allValues, LocalOrderComparer.getInstance()); } private static class IdrefMappingFunction implements MappingFunction { public DocumentInfo document; public XPathContext keyContext; public KeyManager keyManager; public KeyDefinitionSet keySet; /** * Implement the MappingFunction interface */ public SequenceIterator map(Item item) throws XPathException { KeyManager keyManager = keyContext.getController().getKeyManager(); AtomicValue keyValue; if (item instanceof AtomicValue) { keyValue = (AtomicValue)item; } else { keyValue = new StringValue(item.getStringValue()); } return keyManager.selectByKey(keySet, document, keyValue, keyContext); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/functions/IsWholeNumber.java0000644000175000017500000000427711033112257023007 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.Item; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.BooleanValue; import net.sf.saxon.value.NumericValue; /** * This class implements the saxon:is-whole-number() extension function, * which is specially-recognized by the system because calls are generated by the optimizer. * *

The function signature is saxon:is-whole-number($arg as numeric?) as boolean

* *

The result is true if $arg is not empty and is equal to some integer.

*/ public class IsWholeNumber extends SystemFunction { /** * Get the effective boolean value of the expression. This returns false if the value * is the empty sequence, a zero-length string, a number equal to zero, or the boolean * false. Otherwise it returns true. * * @param context The context in which the expression is to be evaluated * @return the effective boolean value * @throws net.sf.saxon.trans.XPathException * if any dynamic error occurs evaluating the * expression */ public boolean effectiveBooleanValue(XPathContext context) throws XPathException { NumericValue val = (NumericValue)argument[0].evaluateItem(context); return val != null && val.isWholeNumber(); } /** * Evaluate in a general context */ public Item evaluateItem(XPathContext context) throws XPathException { return BooleanValue.get(effectiveBooleanValue(context)); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/functions/UnparsedEntity.java0000644000175000017500000001254311033112257023235 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.expr.Expression; import net.sf.saxon.expr.ExpressionVisitor; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.DocumentInfo; import net.sf.saxon.om.Item; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.Type; import net.sf.saxon.value.StringValue; /** * Implements the unparsed-entity-uri() function defined in XSLT 1.0 * and the unparsed-entity-public-id() function defined in XSLT 2.0 */ public class UnparsedEntity extends SystemFunction implements XSLTFunction { public static int URI = 0; public static int PUBLIC_ID = 1; /** * Simplify: add a second implicit argument, the context document * @param visitor an expression visitor */ public Expression simplify(ExpressionVisitor visitor) throws XPathException { UnparsedEntity f = (UnparsedEntity)super.simplify(visitor); f.addContextDocumentArgument(1, (operation==URI ? "unparsed-entity-uri_9999_": "unparsed-entity-public-id_9999_")); return f; } /** * Type-check the expression. This also calls preEvaluate() to evaluate the function * if all the arguments are constant; functions that do not require this behavior * can override the preEvaluate method. */ public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { try { return super.typeCheck(visitor, contextItemType); } catch (XPathException err) { if ("XPDY0002".equals(err.getErrorCodeLocalPart())) { if (operation == URI) { XPathException e = new XPathException("Cannot call the unparsed-entity-uri()" + " function when there is no context node"); e.setErrorCode("XTDE1370"); throw e; } else { XPathException e = new XPathException("Cannot call the unparsed-entity-public-id()" + " function when there is no context node"); e.setErrorCode("XTDE1380"); throw e; } } throw err; } } /** * preEvaluate: this method suppresses compile-time evaluation by doing nothing * @param visitor an expression visitor */ public Expression preEvaluate(ExpressionVisitor visitor) { return this; } /** * Evaluate the expression */ public Item evaluateItem(XPathContext context) throws XPathException { String arg0 = argument[0].evaluateItem(context).getStringValue(); NodeInfo doc = null; try { doc = (NodeInfo)argument[1].evaluateItem(context); } catch (XPathException err) { if ("XPDY0002".equals(err.getErrorCodeLocalPart())) { if (operation == URI) { XPathException e = new XPathException("Cannot call the unparsed-entity-uri()" + " function when there is no context node"); e.setErrorCode("XTDE1370"); throw e; } else { XPathException e = new XPathException("Cannot call the unparsed-entity-public-id()" + " function when there is no context node"); e.setErrorCode("XTDE1380"); throw e; } } else if ("XPDY0050".equals(err.getErrorCodeLocalPart())) { if (operation == URI) { XPathException e = new XPathException("Can only call the unparsed-entity-uri()" + " function when the context node is in a tree rooted at a document node"); e.setErrorCode("XTDE1370"); throw e; } else { XPathException e = new XPathException("Can only call the unparsed-entity-public-id()" + " function when the context node is in a tree rooted at a document node"); e.setErrorCode("XTDE1380"); throw e; } } } if (doc.getNodeKind() != Type.DOCUMENT) { String code = (operation==URI ? "XTDE1370" : "XTDE1380"); dynamicError("In function " + getDisplayName() + ", the context node must be in a tree whose root is a document node", code, context); } String[] ids = ((DocumentInfo)doc).getUnparsedEntity(arg0); if (ids==null) return StringValue.EMPTY_STRING; return new StringValue(ids[operation]); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/functions/FunctionLibrary.java0000644000175000017500000001100411033112257023360 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.expr.Expression; import net.sf.saxon.expr.StaticContext; import net.sf.saxon.trans.XPathException; import net.sf.saxon.om.StructuredQName; import java.io.Serializable; /** * A FunctionLibrary handles the binding of function calls in XPath (or XQuery) expressions. * There are a number of implementations of this * class to handle different kinds of function: system functions, constructor functions, vendor-defined * functions, Java extension functions, stylesheet functions, and so on. There is also an implementation * {@link net.sf.saxon.functions.FunctionLibraryList} that allows a FunctionLibrary * to be constructed by combining other FunctionLibrary objects. */ public interface FunctionLibrary extends Serializable { /** * Test whether an extension function with a given name and arity is available. This supports * the function-available() function in XSLT. This method may be called either at compile time * or at run time. If the function library is to be used only in an XQuery or free-standing XPath * environment, this method may throw an UnsupportedOperationException. * @param functionName the qualified name of the function being called * @param arity The number of arguments. This is set to -1 in the case of the single-argument * function-available() function; in this case the method should return true if there is some * @return true if a function of this name and arity is available for calling. */ public boolean isAvailable(StructuredQName functionName, int arity); /** * Bind an extension function, given the URI and local parts of the function name, * and the list of expressions supplied as arguments. This method is called at compile * time. * @param functionName the QName of the function being called * @param staticArgs The expressions supplied statically in arguments to the function call. * The length of this array represents the arity of the function. The intention is * that the static type of the arguments (obtainable via getItemType() and getCardinality()) may * be used as part of the binding algorithm. In some cases it may be possible for the function * to be pre-evaluated at compile time, for example if these expressions are all constant values. *

* The conventions of the XPath language demand that the results of a function depend only on the * values of the expressions supplied as arguments, and not on the form of those expressions. For * example, the result of f(4) is expected to be the same as f(2+2). The actual expression is supplied * here to enable the binding mechanism to select the most efficient possible implementation (including * compile-time pre-evaluation where appropriate). * @param env The static context of the function call * @return An object representing the function to be called, if one is found; * null if no function was found matching the required name and arity. * @throws net.sf.saxon.trans.XPathException if a function is found with the required name and arity, but * the implementation of the function cannot be loaded or used; or if an error occurs * while searching for the function. */ public Expression bind(StructuredQName functionName, Expression[] staticArgs, StaticContext env) throws XPathException; /** * This method creates a copy of a FunctionLibrary: if the original FunctionLibrary allows * new functions to be added, then additions to this copy will not affect the original, or * vice versa. * @return a copy of this function library. This must be an instance of the original class. */ public FunctionLibrary copy(); } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. //saxonb-9.1.0.8/bj/net/sf/saxon/functions/NumberFn.java0000644000175000017500000001206311033112257021770 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.expr.*; import net.sf.saxon.om.Item; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.BuiltInAtomicType; import net.sf.saxon.type.ConversionResult; import net.sf.saxon.type.ValidationFailure; import net.sf.saxon.value.*; /** * Implements the XPath number() function. This can also be used as a mapping function * in a MappingIterator to map a sequence of values to numbers. */ public class NumberFn extends SystemFunction implements ItemMappingFunction { /** * Simplify and validate. * This is a pure function so it can be simplified in advance if the arguments are known * @param visitor an expression visitor */ public Expression simplify(ExpressionVisitor visitor) throws XPathException { useContextItemAsDefault(); argument[0].setFlattened(true); return simplifyArguments(visitor); } /** * Add a representation of a doc() call or similar function to a PathMap. * This is a convenience method called by the addToPathMap() methods for doc(), document(), collection() * and similar functions. These all create a new root expression in the path map. * * @param pathMap the PathMap to which the expression should be added * @param pathMapNodes the node in the PathMap representing the focus at the point where this expression * is called. Set to null if this expression appears at the top level. * @return the pathMapNode representing the focus established by this expression, in the case where this * expression is the first operand of a path expression or filter expression */ public PathMap.PathMapNodeSet addDocToPathMap(PathMap pathMap, PathMap.PathMapNodeSet pathMapNodes) { PathMap.PathMapNodeSet result = argument[0].addToPathMap(pathMap, pathMapNodes); if (result != null) { result.setAtomized(); } return null; } /** * Evaluate in a general context */ public Item evaluateItem(XPathContext context) throws XPathException { Item arg0 = argument[0].evaluateItem(context); if (arg0==null) { return DoubleValue.NaN; } if (arg0 instanceof BooleanValue || arg0 instanceof NumericValue) { ConversionResult result = ((AtomicValue)arg0).convert(BuiltInAtomicType.DOUBLE, true, context); if (result instanceof ValidationFailure) { return DoubleValue.NaN; } else { return (AtomicValue)result; } } if (arg0 instanceof StringValue && !(arg0 instanceof AnyURIValue)) { CharSequence s = arg0.getStringValueCS(); try { return new DoubleValue(Value.stringToNumber(s)); } catch (NumberFormatException e) { return DoubleValue.NaN; } } return DoubleValue.NaN; } /** * Static method to perform the same conversion as the number() function. This is different from the * convert(Type.DOUBLE) in that it produces NaN rather than an error for non-numeric operands. * @param value the value to be converted * @return the result of the conversion */ public static DoubleValue convert(AtomicValue value) { try { if (value==null) { return DoubleValue.NaN; } if (value instanceof BooleanValue || value instanceof NumericValue) { ConversionResult result = value.convert(BuiltInAtomicType.DOUBLE, true, null); if (result instanceof ValidationFailure) { return DoubleValue.NaN; } else { return (DoubleValue)result; } } if (value instanceof StringValue && !(value instanceof AnyURIValue)) { CharSequence s = value.getStringValueCS(); return new DoubleValue(Value.stringToNumber(s)); } return DoubleValue.NaN; } catch (NumberFormatException e) { return DoubleValue.NaN; } } /** * Mapping function for use when converting a sequence of atomic values to doubles * using the rules of the number() function */ public Item map(Item item) throws XPathException { return convert((AtomicValue)item); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/functions/EscapeURI.java0000644000175000017500000002245611033112257022043 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.trans.Err; import net.sf.saxon.charcode.UnicodeCharacterSet; import net.sf.saxon.event.HTMLURIEscaper; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.FastStringBuffer; import net.sf.saxon.om.Item; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.StringValue; import java.util.Arrays; /** * This class supports the functions encode-for-uri() and iri-to-uri() */ public class EscapeURI extends SystemFunction { public static final int ENCODE_FOR_URI = 1; public static final int IRI_TO_URI = 2; public static final int HTML_URI = 3; public static boolean[] allowedASCII = new boolean[128]; static { Arrays.fill(allowedASCII, 0, 32, false); Arrays.fill(allowedASCII, 33, 127, true); allowedASCII[(int)'"'] = false; allowedASCII[(int)'<'] = false; allowedASCII[(int)'>'] = false; allowedASCII[(int)'\\'] = false; allowedASCII[(int)'^'] = false; allowedASCII[(int)'`'] = false; allowedASCII[(int)'{'] = false; allowedASCII[(int)'|'] = false; allowedASCII[(int)'}'] = false; } /** * Evaluate the function */ public Item evaluateItem(XPathContext c) throws XPathException { Item item = argument[0].evaluateItem(c); if (item == null) { return StringValue.EMPTY_STRING; } final CharSequence s = item.getStringValueCS(); switch (operation) { case ENCODE_FOR_URI: return StringValue.makeStringValue(escape(s, "-_.~")); case IRI_TO_URI: return StringValue.makeStringValue(iriToUri(s)); case HTML_URI: return StringValue.makeStringValue(HTMLURIEscaper.escapeURL(s, false)); default: throw new UnsupportedOperationException("Unknown escape operation"); } } /** * Escape special characters in a URI. The characters that are %HH-encoded are * all non-ASCII characters * @param s the URI to be escaped * @return the %HH-encoded string */ public static CharSequence iriToUri(CharSequence s) { // NOTE: implements a late spec change which says that characters that are illegal in an IRI, // for example "\", must be %-encoded. if (allAllowedAscii(s)) { // it's worth doing a prescan to avoid the cost of copying in the common all-ASCII case return s; } FastStringBuffer sb = new FastStringBuffer(s.length()+20); for (int i=0; i=0x7f || !allowedASCII[(int)c]) { escapeChar(c, ((i+1)=0x7f || !allowedASCII[(int)c]) { return false; } } return true; } /** * Escape special characters in a URI. The characters that are %HH-encoded are * all non-ASCII characters, plus all ASCII characters except (a) letter A-Z * and a-z, (b) digits 0-9, and (c) characters listed in the allowedPunctuation * argument * @param s the URI to be escaped * @param allowedPunctuation ASCII characters other than letters and digits that * should NOT be %HH-encoded * @return the %HH-encoded string */ public static CharSequence escape(CharSequence s, String allowedPunctuation) { FastStringBuffer sb = new FastStringBuffer(s.length()); for (int i=0; i='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9')) { sb.append(c); } else if (c<=0x20 || c>=0x7f) { escapeChar(c, ((i+1)= 0) { sb.append(c); } else { escapeChar(c, ' ', sb); } } return sb; } private static final String hex = "0123456789ABCDEF"; /** * Escape a single character in %HH representation, or a pair of two chars representing * a surrogate pair * @param c the character to be escaped, or the first character of a surrogate pair * @param c2 the second character of a surrogate pair * @param sb the buffer to contain the escaped result */ private static void escapeChar(char c, char c2, FastStringBuffer sb) { byte[] array = new byte[4]; int used = UnicodeCharacterSet.getUTF8Encoding(c, c2, array); for (int b=0; b= uri.length()) { throw new XPathException("% sign in URI must be followed by two hex digits" + Err.wrap(uri)); } int h1 = hexDigits.indexOf(uri.charAt(i+1)); if (h1 > 15) { h1 -= 6; } int h2 = hexDigits.indexOf(uri.charAt(i+2)); if (h2 > 15) { h2 -= 6; } if (h1 >= 0 && h2 >= 0) { int b = h1<<4 | h2; expectedOctets = UTF8RepresentationLength[h1]; if (expectedOctets == -1) { throw new XPathException("First %-encoded octet in URI is not valid as the start of a UTF-8 " + "character: first two bits must not be '10'" + Err.wrap(uri)); } bytes = new byte[expectedOctets]; bytes[0] = (byte)b; i+=3; for (int q=1; q uri.length() || uri.charAt(i) != '%') { throw new XPathException("Incomplete %-encoded UTF-8 octet sequence in URI " + Err.wrap(uri)); } h1 = hexDigits.indexOf(uri.charAt(i+1)); if (h1 > 15) { h1 -= 6; } h2 = hexDigits.indexOf(uri.charAt(i+2)); if (h2 > 15) { h2 -= 6; } if (h1 < 0 || h2 < 0) { throw new XPathException("Invalid %-encoded UTF-8 octet sequence in URI" + Err.wrap(uri)); } if (UTF8RepresentationLength[h1] != -1) { throw new XPathException("In a URI, a %-encoded UTF-8 octet after the first " + "must have '10' as the first two bits" + Err.wrap(uri)); } b = h1<<4 | h2; bytes[q] = (byte)b; i += 3; } } else { throw new XPathException("% sign in URI must be followed by two hex digits" + Err.wrap(uri)); } } else { i++; } } } private static String hexDigits = "0123456789abcdefABCDEF"; // Length of a UTF8 byte sequence, as a function of the first nibble private static int[] UTF8RepresentationLength = {1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, 2, 2, 3, 4}; } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/functions/DeepEqual.java0000644000175000017500000004612711033112257022131 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.Configuration; import net.sf.saxon.expr.Expression; import net.sf.saxon.expr.ExpressionVisitor; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.*; import net.sf.saxon.pattern.NameTest; import net.sf.saxon.sort.GenericAtomicComparer; import net.sf.saxon.sort.IntHashSet; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ComplexType; import net.sf.saxon.type.SchemaType; import net.sf.saxon.type.Type; import net.sf.saxon.value.*; import javax.xml.transform.TransformerException; import java.util.ArrayList; import java.util.List; /** * XSLT 2.0 deep-equal() function. * Supports deep comparison of two sequences (of nodes and/or atomic values) * optionally using a collation */ public class DeepEqual extends CollatingFunction { /** * Flag indicating that two elements should only be considered equal if they have the same * in-scope namespaces */ public static final int INCLUDE_NAMESPACES = 1<<0; /** * Flag indicating that two element or attribute nodes are considered equal only if their * names use the same namespace prefix */ public static final int INCLUDE_PREFIXES = 1<<1; /** * Flag indicating that comment children are taken into account when comparing element or document nodes */ public static final int INCLUDE_COMMENTS = 1<<2; /** * Flag indicating that processing instruction nodes are taken into account when comparing element or document nodes */ public static final int INCLUDE_PROCESSING_INSTRUCTIONS = 1<<3; /** * Flag indicating that whitespace text nodes are ignored when comparing element nodes */ public static final int EXCLUDE_WHITESPACE_TEXT_NODES = 1<<4; /** * Flag indicating that elements and attributes should always be compared according to their string * value, not their typed value */ public static final int COMPARE_STRING_VALUES = 1<<5; /** * Flag indicating that elements and attributes must have the same type annotation to be considered * deep-equal */ public static final int COMPARE_ANNOTATIONS = 1<<6; /** * Flag indicating that a warning message explaining the reason why the sequences were deemed non-equal * should be sent to the ErrorListener */ public static final int WARNING_IF_FALSE = 1<<7; /** * Flag indicating that adjacent text nodes in the top-level sequence are to be merged */ public static final int JOIN_ADJACENT_TEXT_NODES = 1<<8; private transient Configuration config = null; /** * preEvaluate: if all arguments are known statically, evaluate early * @param visitor an expression visitor */ public Expression preEvaluate(ExpressionVisitor visitor) throws XPathException { config = visitor.getConfiguration(); return super.preEvaluate(visitor); } /** * Evaluate the expression */ public Item evaluateItem(XPathContext context) throws XPathException { GenericAtomicComparer collator = getAtomicComparer(2, context); SequenceIterator op1 = argument[0].iterate(context); SequenceIterator op2 = argument[1].iterate(context); Configuration config = (this.config!=null ? this.config : context.getConfiguration()); return BooleanValue.get(deepEquals(op1, op2, collator, config, 0)); } /** * Determine when two sequences are deep-equal * @param op1 the first sequence * @param op2 the second sequence * @param collator the collator to be used * @param config the configuration (gives access to the NamePool) * @param flags bit-significant integer giving comparison options. Always zero for standard * F+O deep-equals comparison. * @return true if the sequences are deep-equal */ public static boolean deepEquals(SequenceIterator op1, SequenceIterator op2, GenericAtomicComparer collator, Configuration config, int flags) { boolean result = true; String reason = null; try { if ((flags & JOIN_ADJACENT_TEXT_NODES) != 0) { op1 = mergeAdjacentTextNodes(op1); op2 = mergeAdjacentTextNodes(op2); } while (true) { Item item1 = op1.next(); Item item2 = op2.next(); if (item1 == null && item2 == null) { break; } if (item1 == null || item2 == null) { result = false; reason = "sequences have different lengths"; break; } if (item1 instanceof NodeInfo) { if (item2 instanceof NodeInfo) { if (!deepEquals((NodeInfo)item1, (NodeInfo)item2, collator, config, flags)) { result = false; reason = "nodes at position " + op1.position() + " differ"; break; } } else { result = false; reason = "comparing a node to an atomic value at position " + op1.position(); break; } } else { if (item2 instanceof NodeInfo) { result = false; reason = "comparing an atomic value to a node at position " + op1.position(); break; } else { AtomicValue av1 = ((AtomicValue)item1); AtomicValue av2 = ((AtomicValue)item2); if (av1.isNaN() && av2.isNaN()) { // treat as equal, no action } else if (!collator.comparesEqual(av1, av2)) { result = false; reason = "atomic values at position " + op1.position() + " differ"; break; } } } } // end while } catch (ClassCastException err) { // this will happen if the sequences contain non-comparable values // comparison errors are masked result = false; reason = "sequences contain non-comparable values"; } catch (XPathException err) { // comparison errors are masked result = false; reason = "error occurred while comparing two values (" + err.getMessage() + ')'; } if (!result) { explain(config, reason, flags); // config.getErrorListener().warning( // new XPathException("deep-equal(): " + reason) // ); } return result; } /** * Determine whether two nodes are deep-equal */ private static boolean deepEquals(NodeInfo n1, NodeInfo n2, GenericAtomicComparer collator, Configuration config, int flags) throws XPathException { // shortcut: a node is always deep-equal to itself if (n1.isSameNodeInfo(n2)) return true; if (n1.getNodeKind() != n2.getNodeKind()) { explain(config, "node kinds differ: comparing " + Type.displayTypeName(n1) + " to " + Type.displayTypeName(n2), flags); return false; } final NamePool pool = config.getNamePool(); switch (n1.getNodeKind()) { case Type.ELEMENT: if (n1.getFingerprint() != n2.getFingerprint()) { explain(config, "element names differ: " + config.getNamePool().getClarkName(n1.getFingerprint()) + " != " + config.getNamePool().getClarkName(n2.getFingerprint()), flags); return false; } if (((flags & INCLUDE_PREFIXES) != 0) && (n1.getNameCode() != n2.getNameCode())) { explain(config, "element prefixes differ: " + n1.getPrefix() + " != " + n2.getPrefix(), flags); return false; } AxisIterator a1 = n1.iterateAxis(Axis.ATTRIBUTE); AxisIterator a2 = n2.iterateAxis(Axis.ATTRIBUTE); if (Aggregate.count(a1.getAnother()) != Aggregate.count(a2)) { explain(config, "elements have different number of attributes", flags); return false; } while (true) { NodeInfo att1 = (NodeInfo)a1.next(); if (att1 == null) break; AxisIterator a2iter = n2.iterateAxis(Axis.ATTRIBUTE, new NameTest(Type.ATTRIBUTE, att1.getFingerprint(), pool)); NodeInfo att2 = (NodeInfo)a2iter.next(); if (att2==null) { explain(config, "one element has an attribute " + config.getNamePool().getClarkName(att1.getFingerprint()) + ", the other does not", flags); return false; } if (!deepEquals(att1, att2, collator, config, flags)) { explain(config, "elements have different values for the attribute " + config.getNamePool().getClarkName(att1.getFingerprint()), flags); return false; } } if ((flags & INCLUDE_NAMESPACES) != 0) { IntHashSet ns1 = new IntHashSet(10); IntHashSet ns2 = new IntHashSet(10); AxisIterator it1 = n1.iterateAxis(Axis.NAMESPACE); while (true) { NodeInfo nn1 = (NodeInfo)it1.next(); if (nn1 == null) { break; } int nscode1 = pool.getNamespaceCode(nn1.getLocalPart(), nn1.getStringValue()); ns1.add(nscode1); } AxisIterator it2 = n2.iterateAxis(Axis.NAMESPACE); while (true) { NodeInfo nn2 = (NodeInfo)it2.next(); if (nn2 == null) { break; } int nscode2 = pool.getNamespaceCode(nn2.getLocalPart(), nn2.getStringValue()); ns2.add(nscode2); } if (!ns1.equals(ns2)) { explain(config, "elements have different in-scope namespaces", flags); return false; } } if ((flags & COMPARE_ANNOTATIONS) != 0) { if (n1.getTypeAnnotation() != n2.getTypeAnnotation()) { explain(config, "elements have different type annotation", flags); return false; } } if ((flags & COMPARE_STRING_VALUES) == 0) { int ann1 = n1.getTypeAnnotation(); int ann2 = n2.getTypeAnnotation(); if (ann1 == -1) { // defensive programming ann1 = StandardNames.XS_UNTYPED; } if (ann2 == -1) { // defensive programming ann2 = StandardNames.XS_UNTYPED; } final SchemaType type1 = config.getSchemaType(ann1); final SchemaType type2 = config.getSchemaType(ann2); final boolean isSimple1 = type1.isSimpleType() || ((ComplexType)type1).isSimpleContent(); final boolean isSimple2 = type2.isSimpleType() || ((ComplexType)type2).isSimpleContent(); if (isSimple1 != isSimple2) { explain(config, "one element has a simple type, the other does not", flags); return false; } if (isSimple1 && isSimple2) { final SequenceIterator v1 = n1.getTypedValue(); final SequenceIterator v2 = n2.getTypedValue(); return deepEquals(v1, v2, collator, config, flags); } } // fall through case Type.DOCUMENT: AxisIterator c1 = n1.iterateAxis(Axis.CHILD); AxisIterator c2 = n2.iterateAxis(Axis.CHILD); while (true) { NodeInfo d1 = (NodeInfo)c1.next(); while (d1 != null && isIgnorable(d1, flags)) { d1 = (NodeInfo)c1.next(); } NodeInfo d2 = (NodeInfo)c2.next(); while (d2 != null && isIgnorable(d2, flags)) { d2 = (NodeInfo)c2.next(); } if (d1 == null || d2 == null) { boolean r = (d1 == d2); if (!r) { explain(config, "nodes have different numbers of children", flags); } return r; } if (!deepEquals(d1, d2, collator, config, flags)) { return false; } } case Type.ATTRIBUTE: if (n1.getFingerprint() != n2.getFingerprint()) { explain(config, "attribute names differ: " + config.getNamePool().getClarkName(n1.getFingerprint()) + " != " + config.getNamePool().getClarkName(n2.getFingerprint()), flags); return false; } if (((flags & INCLUDE_PREFIXES) != 0) && (n1.getNameCode() != n2.getNameCode())) { explain(config, "attribute prefixes differ: " + n1.getPrefix() + " != " + n2.getPrefix(), flags); return false; } if ((flags & COMPARE_ANNOTATIONS) != 0) { if (n1.getTypeAnnotation() != n2.getTypeAnnotation()) { explain(config, "attributes have different type annotations", flags); return false; } } boolean ar; if ((flags & COMPARE_STRING_VALUES) == 0) { ar = deepEquals(n1.getTypedValue(), n2.getTypedValue(), collator, config, 0); } else { ar = collator.comparesEqual( new StringValue(n1.getStringValueCS()), new StringValue(n2.getStringValueCS())); } if (!ar) { explain(config, "attribute values differ", flags); } return ar; case Type.PROCESSING_INSTRUCTION: case Type.NAMESPACE: if (n1.getFingerprint() != n2.getFingerprint()) { explain(config, Type.displayTypeName(n1) + " names differ", flags); return false; } // drop through case Type.TEXT: case Type.COMMENT: boolean vr = (collator.comparesEqual((AtomicValue)n1.atomize(), (AtomicValue)n2.atomize())); if (!vr) { AtomicValue av1 = (AtomicValue)n1.atomize(); AtomicValue av2 = (AtomicValue)n2.atomize(); explain(config, Type.displayTypeName(n1) + " values differ (\"" + Navigator.getPath(n1) + ", " + Navigator.getPath(n2) + ": " + StringValue.diagnosticDisplay(av1.getStringValue()) + "\", \"" + StringValue.diagnosticDisplay(av2.getStringValue()) + "\")", flags); } return vr; default: throw new IllegalArgumentException("Unknown node type"); } } private static boolean isIgnorable(NodeInfo node, int flags) { final int kind = node.getNodeKind(); if (kind == Type.COMMENT) { return (flags & INCLUDE_COMMENTS)==0; } else if (kind == Type.PROCESSING_INSTRUCTION) { return (flags & INCLUDE_PROCESSING_INSTRUCTIONS)==0; } else if (kind == Type.TEXT) { return ((flags & EXCLUDE_WHITESPACE_TEXT_NODES)!=0) && Whitespace.isWhite(node.getStringValueCS()); } return false; } private static void explain(Configuration config, String message, int flags) { try { if ((flags & WARNING_IF_FALSE) != 0) { config.getErrorListener().warning(new XPathException("deep-equal(): " + message)); } } catch (TransformerException e) { // } } private static SequenceIterator mergeAdjacentTextNodes(SequenceIterator in) throws XPathException { Configuration config = null; List items = new ArrayList(20); boolean prevIsText = false; FastStringBuffer textBuffer = new FastStringBuffer(100); while (true) { Item next = in.next(); if (next == null) { break; } if (next instanceof NodeInfo && ((NodeInfo)next).getNodeKind() == Type.TEXT) { textBuffer.append(next.getStringValueCS()); prevIsText = true; config = ((NodeInfo)next).getConfiguration(); } else { if (prevIsText) { Orphan textNode = new Orphan(config); textNode.setNodeKind(Type.TEXT); textNode.setStringValue(textBuffer.toString()); // must copy the buffer before reusing it items.add(textNode); textBuffer.setLength(0); } prevIsText = false; items.add(next); } } if (prevIsText) { Orphan textNode = new Orphan(config); textNode.setNodeKind(Type.TEXT); textNode.setStringValue(textBuffer.toString()); // must copy the buffer before reusing it items.add(textNode); } SequenceExtent extent = new SequenceExtent(items); return extent.iterate(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/functions/Document.java0000644000175000017500000006724711033112257022050 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.*; import net.sf.saxon.event.Builder; import net.sf.saxon.event.PipelineConfiguration; import net.sf.saxon.event.Receiver; import net.sf.saxon.event.Sender; import net.sf.saxon.expr.*; import net.sf.saxon.om.DocumentInfo; import net.sf.saxon.om.Item; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.sort.DocumentOrderIterator; import net.sf.saxon.sort.GlobalOrderComparer; import net.sf.saxon.trans.XPathException; import net.sf.saxon.trans.Err; import net.sf.saxon.value.Cardinality; import net.sf.saxon.value.Whitespace; import net.sf.saxon.value.AtomicValue; import net.sf.saxon.value.SingletonNode; import javax.xml.transform.Source; import javax.xml.transform.SourceLocator; import javax.xml.transform.TransformerException; import javax.xml.transform.URIResolver; import javax.xml.transform.dom.DOMSource; import java.net.URI; import java.net.URISyntaxException; /** * Implements the XSLT document() function */ public class Document extends SystemFunction implements XSLTFunction { private String expressionBaseURI = null; private boolean readOnce = false; // TODO: implement this. The idea is that if streaming copy cannot be // used, then document projection will be used instead, for this specific call on the document() function. /** * Indicate that the document(s) will be read once only (or that they should be treated as if they * are read once only. This means (a) the document will not be held in memory after all references * to it go out of scope, and (b) if the query or transformation tries to read it again, it will get a new * copy, with different node identities, and potentially with different content. It also means that the * document is eligible for document projection. * @param once true if this document is to be treated as being read once only */ public void setReadOnce(boolean once) { readOnce = once; } /** * Ask whether this document has been marked as being read once only. * @return true if the document has been marked as being read once only */ public boolean isReadOnce() { return readOnce; } public void checkArguments(ExpressionVisitor visitor) throws XPathException { if (expressionBaseURI == null) { // only do this once. The second call supplies an env pointing to the containing // xsl:template, which has a different base URI (and in a simplified stylesheet, has no base URI) super.checkArguments(visitor); expressionBaseURI = visitor.getStaticContext().getBaseURI(); Optimizer opt = visitor.getConfiguration().getOptimizer(); argument[0] = ExpressionTool.unsorted(opt, argument[0], false); } } /** * Determine the static cardinality */ public int computeCardinality() { Expression expression = argument[0]; if (Cardinality.allowsMany(expression.getCardinality())) { return StaticProperty.ALLOWS_ZERO_OR_MORE; } else { return StaticProperty.ALLOWS_ZERO_OR_ONE; } // may have to revise this if the argument can be a list-valued element or attribute } /** * Get the base URI from the static context * @return the base URI */ public String getStaticBaseURI() { return expressionBaseURI; } /** * Get the static properties of this expression (other than its type). The result is * bit-signficant. These properties are used for optimizations. In general, if * property bit is set, it is true, but if it is unset, the value is unknown. */ public int computeSpecialProperties() { return StaticProperty.ORDERED_NODESET | StaticProperty.PEER_NODESET | StaticProperty.NON_CREATIVE; // Declaring it as a peer node-set expression avoids sorting of expressions such as // document(XXX)/a/b/c // The document() function might appear to be creative: but it isn't, because multiple calls // with the same arguments will produce identical results. } /** * preEvaluate: the document() function can be evaluated at compile time if (a) the argument * is a string literal, and (b) the option {@link FeatureKeys#PRE_EVALUATE_DOC_FUNCTION} is set. * @param visitor an expression visitor */ public Expression preEvaluate(ExpressionVisitor visitor) { Configuration config = visitor.getConfiguration(); if (getNumberOfArguments() == 1 && ((Boolean)config.getConfigurationProperty(FeatureKeys.PRE_EVALUATE_DOC_FUNCTION)).booleanValue()) { try { AtomicValue hrefVal = (AtomicValue)argument[0].evaluateItem(null); if (hrefVal==null) { return null; } String href = hrefVal.getStringValue(); if (href.indexOf('#') >= 0) { return this; } NodeInfo item = Document.preLoadDoc(href, expressionBaseURI, config, this); if (item!=null) { return new Literal(new SingletonNode(item)); } } catch (Exception err) { // ignore the exception and try again at run-time return this; } } return this; } /** * Add a representation of this expression to a PathMap. The PathMap captures a map of the nodes visited * by an expression in a source tree. * * @param pathMap the PathMap to which the expression should be added * @param pathMapNodeSet the set of nodes in the path map that are affected * @return the pathMapNode representing the focus established by this expression, in the case where this * expression is the first operand of a path expression or filter expression */ public PathMap.PathMapNodeSet addToPathMap(PathMap pathMap, PathMap.PathMapNodeSet pathMapNodeSet) { return addDocToPathMap(pathMap, pathMapNodeSet); } /** * Copy an expression. This makes a deep copy. * @return the copy of the original expression */ public Expression copy() { Document d = (Document)super.copy(); d.expressionBaseURI = expressionBaseURI; d.readOnce = readOnce; return d; } /** * iterate() handles evaluation of the function: * it returns a sequence of Document nodes */ public SequenceIterator iterate(XPathContext context) throws XPathException { int numArgs = argument.length; SequenceIterator hrefSequence = argument[0].iterate(context); String baseURI = null; if (numArgs==2) { // we can trust the type checking: it must be a node NodeInfo base = (NodeInfo)argument[1].evaluateItem(context); baseURI = base.getBaseURI(); } DocumentMappingFunction map = new DocumentMappingFunction(context); map.baseURI = baseURI; map.stylesheetURI = expressionBaseURI; map.locator = this; ItemMappingIterator iter = new ItemMappingIterator(hrefSequence, map); Expression expression = argument[0]; if (Cardinality.allowsMany(expression.getCardinality())) { return new DocumentOrderIterator(iter, GlobalOrderComparer.getInstance()); // this is to make sure we eliminate duplicates: two href's might be the same } else { return iter; } } private static class DocumentMappingFunction implements ItemMappingFunction { public String baseURI; public String stylesheetURI; public SourceLocator locator; public XPathContext context; public DocumentMappingFunction(XPathContext context) { this.context = context; } public Item map(Item item) throws XPathException { String b = baseURI; if (b==null) { if (item instanceof NodeInfo) { b = ((NodeInfo)item).getBaseURI(); } else { b = stylesheetURI; } } return makeDoc(item.getStringValue(), b, context, locator); } } /** * Supporting routine to load one external document given a URI (href) and a baseURI. This is used * in the normal case when a document is loaded at run-time (that is, when a Controller is available) * @param href the relative URI * @param baseURI the base URI * @param c the dynamic XPath context * @param locator used to identify the location of the instruction in event of error * @return the root of the constructed document, or the selected element within the document * if a fragment identifier was supplied */ public static NodeInfo makeDoc(String href, String baseURI, XPathContext c, SourceLocator locator) throws XPathException { Configuration config = c.getConfiguration(); // If the href contains a fragment identifier, strip it out now //System.err.println("Entering makeDoc " + href); int hash = href.indexOf('#'); String fragmentId = null; if (hash>=0) { if (hash==href.length()-1) { // # sign at end - just ignore it href = href.substring(0, hash); } else { fragmentId = href.substring(hash+1); href = href.substring(0, hash); if (!config.getNameChecker().isValidNCName(fragmentId)) { XPathException de = new XPathException("The fragment identifier " + Err.wrap(fragmentId) + " is not a valid NCName"); de.setErrorCode("XTRE1160"); de.setXPathContext(c); throw de; } } } Controller controller = c.getController(); // Resolve relative URI String documentKey; URIResolver resolver = controller.getURIResolver(); if (resolver == null) { resolver = controller.getStandardURIResolver(); } if (resolver instanceof RelativeURIResolver) { // If this is the case, the URIResolver is responsible for absolutization as well as dereferencing try { documentKey = ((RelativeURIResolver)resolver).makeAbsolute(href, baseURI); } catch (TransformerException e) { documentKey = '/' + href; baseURI = ""; } } else { // Saxon takes charge of absolutization, leaving the user URIResolver to handle dereferencing only if (baseURI==null) { // no base URI available try { // the href might be an absolute URL documentKey = (new URI(href)).toString(); } catch (URISyntaxException err) { // it isn't; but the URI resolver might know how to cope documentKey = '/' + href; baseURI = ""; } } else if (href.length() == 0) { // common case in XSLT, which java.net.URI#resolve() does not handle correctly documentKey = baseURI; } else { try { URI uri = new URI(baseURI).resolve(href); documentKey = uri.toString(); } catch (URISyntaxException err) { documentKey = baseURI + "/../" + href; } catch (IllegalArgumentException err) { documentKey = baseURI + "/../" + href; } } } // see if the document is already loaded DocumentInfo doc = config.getGlobalDocumentPool().find(documentKey); if (doc != null) { return doc; } doc = controller.getDocumentPool().find(documentKey); if (doc != null) { return getFragment(doc, fragmentId, c); } // check that the document was not written by this transformation if (!controller.checkUniqueOutputDestination(documentKey)) { XPathException err = new XPathException( "Cannot read a document that was written during the same transformation: " + documentKey); err.setXPathContext(c); err.setErrorCode("XTRE1500"); throw err; } try { // Get a Source from the URIResolver Source source; if (resolver instanceof RelativeURIResolver) { try { source = ((RelativeURIResolver)resolver).dereference(documentKey); } catch (Exception ex) { XPathException de = new XPathException("Exception thrown by URIResolver", ex); if (controller.getConfiguration().isTraceExternalFunctions()) { ex.printStackTrace(); } de.setLocator(locator); throw de; } } else { try { source = resolver.resolve(href, baseURI); } catch (Exception ex) { XPathException de = new XPathException("Exception thrown by URIResolver", ex); if (controller.getConfiguration().isTraceExternalFunctions()) { ex.printStackTrace(); } de.setLocator(locator); throw de; } } // if a user URI resolver returns null, try the standard one // (Note, the standard URI resolver never returns null) if (source==null && !(resolver instanceof NonDelegatingURIResolver)) { resolver = controller.getStandardURIResolver(); if (resolver instanceof RelativeURIResolver) { source = ((RelativeURIResolver)resolver).dereference(documentKey); } else { source = resolver.resolve(href, baseURI); } } //System.err.println("URI resolver returned " + source.getClass() + " " + source.getSystemId()); source = config.getSourceResolver().resolveSource(source, config); //System.err.println("Resolved source " + source.getClass() + " " + source.getSystemId()); DocumentInfo newdoc; if (source instanceof NodeInfo || source instanceof DOMSource) { NodeInfo startNode = controller.prepareInputTree(source); newdoc = startNode.getDocumentRoot(); } else { Builder b = controller.makeBuilder(); Receiver s = b; source = AugmentedSource.makeAugmentedSource(source); ((AugmentedSource)source).setStripSpace(Whitespace.XSLT); if (controller.getExecutable().stripsInputTypeAnnotations()) { s = controller.getConfiguration().getAnnotationStripper(s); } PathMap map = controller.getPathMapForDocumentProjection(); if (map != null) { PathMap.PathMapRoot pathRoot = map.getRootForDocument(documentKey); if (pathRoot != null && !pathRoot.isReturnable() && !pathRoot.hasUnknownDependencies()) { ((AugmentedSource)source).addFilter(config.makeDocumentProjector(pathRoot)); } } new Sender(b.getPipelineConfiguration()).send(source, s); newdoc = (DocumentInfo)b.getCurrentRoot(); b.reset(); if (source instanceof AugmentedSource && ((AugmentedSource)source).isPleaseCloseAfterUse()) { ((AugmentedSource)source).close(); } } controller.registerDocument(newdoc, documentKey); controller.addUnavailableOutputDestination(documentKey); return getFragment(newdoc, fragmentId, c); } catch (TransformerException err) { XPathException xerr = XPathException.makeXPathException(err); xerr.setLocator(locator); xerr.setErrorCode("FODC0002"); try { controller.recoverableError(xerr); } catch (XPathException err2) { throw xerr; } return null; } } /** * Supporting routine to load one external document given a URI (href) and a baseURI. This is used * when the document is pre-loaded at compile time. * @param href the relative URI. This must not contain a fragment identifier * @param baseURI the base URI * @param config the Saxon configuration * @param locator used to identify the location of the instruction in event of error. May be null. * @return the root of the constructed document, or the selected element within the document * if a fragment identifier was supplied */ public static NodeInfo preLoadDoc(String href, String baseURI, Configuration config, SourceLocator locator) throws XPathException { int hash = href.indexOf('#'); if (hash>=0) { throw new XPathException("Fragment identifier not supported for preloaded documents"); } // Resolve relative URI String documentKey; URIResolver resolver = config.getURIResolver(); if (resolver instanceof RelativeURIResolver) { try { documentKey = ((RelativeURIResolver)resolver).makeAbsolute(href, baseURI); } catch (TransformerException e) { documentKey = '/' + href; baseURI = ""; } } else { if (baseURI==null) { // no base URI available try { // the href might be an absolute URL documentKey = (new URI(href)).toString(); } catch (URISyntaxException err) { // it isn't; but the URI resolver might know how to cope documentKey = '/' + href; baseURI = ""; } } else if (href.length() == 0) { // common case in XSLT, which java.net.URI#resolve() does not handle correctly documentKey = baseURI; } else { try { URI uri = new URI(baseURI).resolve(href); documentKey = uri.toString(); } catch (URISyntaxException err) { documentKey = baseURI + "/../" + href; } catch (IllegalArgumentException err) { documentKey = baseURI + "/../" + href; } } } // see if the document is already loaded DocumentInfo doc = config.getGlobalDocumentPool().find(documentKey); if (doc != null) { return doc; } try { // Get a Source from the URIResolver URIResolver r = resolver; Source source = null; if (r != null) { try { source = r.resolve(href, baseURI); } catch (Exception ex) { XPathException de = new XPathException("Exception thrown by URIResolver", ex); if (config.isTraceExternalFunctions()) { ex.printStackTrace(); } de.setLocator(locator); throw de; } } // if a user URI resolver returns null, try the standard one // (Note, the standard URI resolver never returns null) if (source==null && !(r instanceof NonDelegatingURIResolver)) { r = config.getSystemURIResolver(); source = r.resolve(href, baseURI); } //System.err.println("URI resolver returned " + source.getClass() + " " + source.getSystemId()); source = config.getSourceResolver().resolveSource(source, config); //System.err.println("Resolved source " + source.getClass() + " " + source.getSystemId()); DocumentInfo newdoc = config.buildDocument(source); config.getGlobalDocumentPool().add(newdoc, documentKey); return newdoc; } catch (TransformerException err) { XPathException xerr = XPathException.makeXPathException(err); xerr.setLocator(locator); xerr.setErrorCode("FODC0002"); throw new XPathException(err); } } /** * Copy the documents identified by this expression to a given Receiver. This method is used only when it is * known that the documents are being copied, because there is then no problem about node identity. * @param context the XPath dynamic context * @param out the destination to which the documents will be sent */ public void sendDocuments(XPathContext context, Receiver out) throws XPathException { SequenceIterator hrefSequence = argument[0].iterate(context); String explicitBaseURI = null; if (argument.length==2) { // we can trust the type checking: it must be a node NodeInfo base = (NodeInfo)argument[1].evaluateItem(context); explicitBaseURI = base.getBaseURI(); } while (true) { Item href = hrefSequence.next(); if (href == null) { break; } String base; if (explicitBaseURI == null) { if (href instanceof NodeInfo) { base = ((NodeInfo)href).getBaseURI(); } else { base = expressionBaseURI; } } else { base = explicitBaseURI; } sendDoc(href.getStringValue(), base, context, this, out); } } /** * Supporting routine to push one external document given a URI (href) and a baseURI to a given Receiver. * This method cannot handle fragment identifiers * @param href the relative URI * @param baseURL the base URI * @param c the XPath dynamic context * @param locator used to identify the lcoation of the instruction in case of error * @param out the destination where the document is to be sent */ public static void sendDoc(String href, String baseURL, XPathContext c, SourceLocator locator, Receiver out) throws XPathException { PipelineConfiguration pipe = out.getPipelineConfiguration(); if (pipe == null) { pipe = c.getController().makePipelineConfiguration(); out.setPipelineConfiguration(pipe); } // Resolve relative URI String documentKey; if (baseURL==null) { // no base URI available try { // the href might be an absolute URL documentKey = (new URI(href)).toString(); } catch (URISyntaxException err) { // it isn't; but the URI resolver might know how to cope documentKey = '/' + href; baseURL = ""; } } else if (href.length() == 0) { // common case in XSLT, which java.net.URI#resolve() does not handle correctly documentKey = baseURL; } else { try { URI url = new URI(baseURL).resolve(href); documentKey = url.toString(); } catch (URISyntaxException err) { documentKey = baseURL + "/../" + href; } catch (IllegalArgumentException err) { documentKey = baseURL + "/../" + href; } } Controller controller = c.getController(); // see if the document is already loaded DocumentInfo doc = controller.getDocumentPool().find(documentKey); Source source = null; if (doc != null) { source = doc; } else { try { // Get a Source from the URIResolver URIResolver r = controller.getURIResolver(); if (r != null) { source = r.resolve(href, baseURL); } // if a user URI resolver returns null, try the standard one // (Note, the standard URI resolver never returns null) if (source==null) { r = controller.getStandardURIResolver(); source = r.resolve(href, baseURL); } if (source instanceof NodeInfo || source instanceof DOMSource) { NodeInfo startNode = controller.prepareInputTree(source); source = startNode.getDocumentRoot(); } } catch (TransformerException err) { XPathException xerr = XPathException.makeXPathException(err); xerr.setLocator(locator); if (xerr.getErrorCodeLocalPart() == null) { xerr.setErrorCode("FODC0005"); } throw xerr; } } //out = controller.makeStripper(out); source = AugmentedSource.makeAugmentedSource(source); ((AugmentedSource)source).setStripSpace(Whitespace.XSLT); if (controller.getExecutable().stripsInputTypeAnnotations()) { out = controller.getConfiguration().getAnnotationStripper(out); } try { new Sender(pipe).send(source, out); } catch (XPathException e) { e.maybeSetLocation(locator); if (e.getErrorCodeLocalPart() == null) { e.setErrorCode("FODC0005"); } throw e; } } /** * Resolve the fragment identifier within a URI Reference. * Only "bare names" XPointers are recognized, that is, a fragment identifier * that matches an ID attribute value within the target document. * @param doc the document node * @param fragmentId the fragment identifier (an ID value within the document) * @param context the XPath dynamic context * @return the element within the supplied document that matches the * given id value; or null if no such element is found. */ private static NodeInfo getFragment(DocumentInfo doc, String fragmentId, XPathContext context) throws XPathException { // TODO: we only support one kind of fragment identifier. The rules say // that the interpretation of the fragment identifier depends on media type, // but we aren't getting the media type from the URIResolver. if (fragmentId==null) { return doc; } if (!context.getConfiguration().getNameChecker().isValidNCName(fragmentId)) { XPathException err = new XPathException("Invalid fragment identifier in URI"); err.setXPathContext(context); err.setErrorCode("XTRE1160"); try { context.getController().recoverableError(err); } catch (XPathException dynamicError) { throw err; } return doc; } return doc.selectID(fragmentId); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/functions/StandardFunction.java0000644000175000017500000013164711033112257023534 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.expr.StaticProperty; import net.sf.saxon.pattern.NodeKindTest; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.Type; import net.sf.saxon.type.BuiltInAtomicType; import net.sf.saxon.type.AnyItemType; import net.sf.saxon.value.*; import net.sf.saxon.om.StandardNames; import java.util.HashMap; /** * This class contains static data tables defining the properties of standard functions. "Standard functions" * here means the XPath 2.0 functions, the XSLT 2.0 functions, and a few selected extension functions * which need special recognition. */ public abstract class StandardFunction { private static Value EMPTY = EmptySequence.getInstance(); /** * This class is never instantiated */ private StandardFunction() { } /** * Register a system function in the table of function details. * @param name the function name * @param implementationClass the class used to implement the function * @param opcode identifies the function when a single class implements several functions * @param minArguments the minimum number of arguments required * @param maxArguments the maximum number of arguments allowed * @param itemType the item type of the result of the function * @param cardinality the cardinality of the result of the function * @return the entry describing the function. The entry is incomplete, it does not yet contain information * about the function arguments. */ private static Entry register( String name, Class implementationClass, int opcode, int minArguments, int maxArguments, ItemType itemType, int cardinality ) { Entry e = makeEntry(name, implementationClass, opcode, minArguments, maxArguments, itemType, cardinality); functionTable.put(name, e); return e; } /** * Make a table entry describing the signature of a function, with a reference to the implementation class. * @param name the function name * @param implementationClass the class used to implement the function * @param opcode identifies the function when a single class implements several functions * @param minArguments the minimum number of arguments required * @param maxArguments the maximum number of arguments allowed * @param itemType the item type of the result of the function * @param cardinality the cardinality of the result of the function * @return the entry describing the function. The entry is incomplete, it does not yet contain information * about the function arguments. */ public static Entry makeEntry(String name, Class implementationClass, int opcode, int minArguments, int maxArguments, ItemType itemType, int cardinality) { Entry e = new Entry(); int hash = name.indexOf('#'); if (hash < 0) { e.name = name; } else { e.name = name.substring(0, hash); } e.implementationClass = implementationClass; e.opcode = opcode; e.minArguments = minArguments; e.maxArguments = maxArguments; e.itemType = itemType; e.cardinality = cardinality; if (maxArguments > 100) { // special case for concat() e.argumentTypes = new SequenceType[1]; e.resultIfEmpty = new Value[1]; } else { e.argumentTypes = new SequenceType[maxArguments]; e.resultIfEmpty = new Value[maxArguments]; } return e; } /** * Add information to a function entry about the argument types of the function * @param e the entry for the function * @param a the position of the argument, counting from zero * @param type the item type of the argument * @param cardinality the cardinality of the argument * @param resultIfEmpty the value returned by the function if an empty sequence appears as the value, * when this result is unaffected by any other arguments */ public static void arg(Entry e, int a, ItemType type, int cardinality, Value resultIfEmpty) { try { e.argumentTypes[a] = SequenceType.makeSequenceType(type, cardinality); e.resultIfEmpty[a] = resultIfEmpty; } catch (ArrayIndexOutOfBoundsException err) { System.err.println("Internal Saxon error: Can't set argument " + a + " of " + e.name); } } private static HashMap functionTable = new HashMap(200); protected static ItemType SAME_AS_FIRST_ARGUMENT = NodeKindTest.NAMESPACE; // this could be any item type that is used only for this purpose static { Entry e; e = register("abs", Rounding.class, Rounding.ABS, 1, 1, SAME_AS_FIRST_ARGUMENT, StaticProperty.ALLOWS_ZERO_OR_ONE); arg(e, 0, BuiltInAtomicType.NUMERIC, StaticProperty.ALLOWS_ZERO_OR_ONE, EMPTY); e = register("adjust-date-to-timezone", Adjust.class, 0, 1, 2, BuiltInAtomicType.DATE, StaticProperty.ALLOWS_ZERO_OR_ONE); arg(e, 0, BuiltInAtomicType.DATE, StaticProperty.ALLOWS_ZERO_OR_ONE, EMPTY); arg(e, 1, BuiltInAtomicType.DAY_TIME_DURATION, StaticProperty.ALLOWS_ZERO_OR_ONE, null); e = register("adjust-dateTime-to-timezone", Adjust.class, 0, 1, 2, BuiltInAtomicType.DATE_TIME, StaticProperty.ALLOWS_ZERO_OR_ONE); arg(e, 0, BuiltInAtomicType.DATE_TIME, StaticProperty.ALLOWS_ZERO_OR_ONE, EMPTY); arg(e, 1, BuiltInAtomicType.DAY_TIME_DURATION, StaticProperty.ALLOWS_ZERO_OR_ONE, null); e = register("adjust-time-to-timezone", Adjust.class, 0, 1, 2, BuiltInAtomicType.TIME, StaticProperty.ALLOWS_ZERO_OR_ONE); arg(e, 0, BuiltInAtomicType.TIME, StaticProperty.ALLOWS_ZERO_OR_ONE, EMPTY); arg(e, 1, BuiltInAtomicType.DAY_TIME_DURATION, StaticProperty.ALLOWS_ZERO_OR_ONE, null); e = register("avg", Aggregate.class, Aggregate.AVG, 1, 1, BuiltInAtomicType.ANY_ATOMIC, StaticProperty.ALLOWS_ZERO_OR_ONE); // can't say "same as first argument" because the avg of a set of integers is decimal arg(e, 0, BuiltInAtomicType.ANY_ATOMIC, StaticProperty.ALLOWS_ZERO_OR_MORE, EMPTY); e = register("base-uri", BaseURI.class, 0, 0, 1, BuiltInAtomicType.ANY_URI, StaticProperty.ALLOWS_ZERO_OR_ONE); arg(e, 0, Type.NODE_TYPE, StaticProperty.ALLOWS_ZERO_OR_ONE, EMPTY); e = register("boolean", BooleanFn.class, BooleanFn.BOOLEAN, 1, 1, BuiltInAtomicType.BOOLEAN, StaticProperty.EXACTLY_ONE); arg(e, 0, Type.ITEM_TYPE, StaticProperty.ALLOWS_ZERO_OR_MORE, null); e = register("ceiling", Rounding.class, Rounding.CEILING, 1, 1, SAME_AS_FIRST_ARGUMENT, StaticProperty.ALLOWS_ZERO_OR_ONE); arg(e, 0, BuiltInAtomicType.NUMERIC, StaticProperty.ALLOWS_ZERO_OR_ONE, EMPTY); e = register("codepoint-equal", CodepointEqual.class, 0, 2, 2, BuiltInAtomicType.BOOLEAN, StaticProperty.ALLOWS_ZERO_OR_ONE); arg(e, 0, BuiltInAtomicType.STRING, StaticProperty.ALLOWS_ZERO_OR_ONE, EMPTY); arg(e, 1, BuiltInAtomicType.STRING, StaticProperty.ALLOWS_ZERO_OR_ONE, EMPTY); e = register("codepoints-to-string", CodepointsToString.class, 0, 1, 1, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE); arg(e, 0, BuiltInAtomicType.INTEGER, StaticProperty.ALLOWS_ZERO_OR_MORE, null); e = register("collection", Collection.class, 0, 0, 1, Type.NODE_TYPE, StaticProperty.ALLOWS_ZERO_OR_MORE); arg(e, 0, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE, null); e = register("compare", Compare.class, 0, 2, 3, BuiltInAtomicType.INTEGER, StaticProperty.ALLOWS_ZERO_OR_ONE); arg(e, 0, BuiltInAtomicType.STRING, StaticProperty.ALLOWS_ZERO_OR_ONE, EMPTY); arg(e, 1, BuiltInAtomicType.STRING, StaticProperty.ALLOWS_ZERO_OR_ONE, EMPTY); arg(e, 2, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE, null); e = register("concat", Concat.class, 0, 2, Integer.MAX_VALUE, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE); arg(e, 0, BuiltInAtomicType.ANY_ATOMIC, StaticProperty.ALLOWS_ZERO_OR_ONE, null); // Note, this has a variable number of arguments so it is treated specially e = register("contains", Contains.class, Contains.CONTAINS, 2, 3, BuiltInAtomicType.BOOLEAN, StaticProperty.EXACTLY_ONE); arg(e, 0, BuiltInAtomicType.STRING, StaticProperty.ALLOWS_ZERO_OR_ONE, null); arg(e, 1, BuiltInAtomicType.STRING, StaticProperty.ALLOWS_ZERO_OR_ONE, BooleanValue.TRUE); arg(e, 2, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE, null); e = register("count", Aggregate.class, Aggregate.COUNT, 1, 1, BuiltInAtomicType.INTEGER, StaticProperty.EXACTLY_ONE); arg(e, 0, Type.ITEM_TYPE, StaticProperty.ALLOWS_ZERO_OR_MORE, Int64Value.ZERO); register("current", Current.class, 0, 0, 0, Type.ITEM_TYPE, StaticProperty.EXACTLY_ONE); register("current-date", CurrentDateTime.class, 0, 0, 0, BuiltInAtomicType.DATE, StaticProperty.EXACTLY_ONE); register("current-dateTime", CurrentDateTime.class, 0, 0, 0, BuiltInAtomicType.DATE_TIME, StaticProperty.EXACTLY_ONE); register("current-time", CurrentDateTime.class, 0, 0, 0, BuiltInAtomicType.TIME, StaticProperty.EXACTLY_ONE); register("current-group", CurrentGroup.class, CurrentGroup.CURRENT_GROUP, 0, 0, Type.ITEM_TYPE, StaticProperty.ALLOWS_ZERO_OR_MORE); register("current-grouping-key", CurrentGroup.class, CurrentGroup.CURRENT_GROUPING_KEY, 0, 0, BuiltInAtomicType.ANY_ATOMIC, StaticProperty.ALLOWS_ZERO_OR_ONE); e = register("data", Data.class, 0, 1, 1, BuiltInAtomicType.ANY_ATOMIC, StaticProperty.ALLOWS_ZERO_OR_MORE); arg(e, 0, Type.ITEM_TYPE, StaticProperty.ALLOWS_ZERO_OR_MORE, EMPTY); e = register("dateTime", DateTimeConstructor.class, 0, 2, 2, BuiltInAtomicType.DATE_TIME, StaticProperty.ALLOWS_ZERO_OR_ONE); arg(e, 0, BuiltInAtomicType.DATE, StaticProperty.ALLOWS_ZERO_OR_ONE, EMPTY); arg(e, 1, BuiltInAtomicType.TIME, StaticProperty.ALLOWS_ZERO_OR_ONE, EMPTY); e = register("day-from-date", Component.class, (Component.DAY<<16) + StandardNames.XS_DATE, 1, 1, BuiltInAtomicType.INTEGER, StaticProperty.ALLOWS_ZERO_OR_ONE); arg(e, 0, BuiltInAtomicType.DATE, StaticProperty.ALLOWS_ZERO_OR_ONE, EMPTY); e = register("day-from-dateTime", Component.class, (Component.DAY<<16) + StandardNames.XS_DATE_TIME, 1, 1, BuiltInAtomicType.INTEGER, StaticProperty.ALLOWS_ZERO_OR_ONE); arg(e, 0, BuiltInAtomicType.DATE_TIME, StaticProperty.ALLOWS_ZERO_OR_ONE, EMPTY); e = register("days-from-duration", Component.class, (Component.DAY<<16) + StandardNames.XS_DURATION, 1, 1, BuiltInAtomicType.INTEGER, StaticProperty.ALLOWS_ZERO_OR_ONE); arg(e, 0, BuiltInAtomicType.DURATION, StaticProperty.ALLOWS_ZERO_OR_ONE, EMPTY); e = register("deep-equal", DeepEqual.class, 0, 2, 3, BuiltInAtomicType.BOOLEAN, StaticProperty.EXACTLY_ONE); arg(e, 0, Type.ITEM_TYPE, StaticProperty.ALLOWS_ZERO_OR_MORE, null); arg(e, 1, Type.ITEM_TYPE, StaticProperty.ALLOWS_ZERO_OR_MORE, null); arg(e, 2, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE, null); register("default-collation", DefaultCollation.class, 0, 0, 0, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE); e = register("distinct-values", DistinctValues.class, 0, 1, 2, BuiltInAtomicType.ANY_ATOMIC, StaticProperty.ALLOWS_ZERO_OR_MORE); arg(e, 0, BuiltInAtomicType.ANY_ATOMIC, StaticProperty.ALLOWS_ZERO_OR_MORE, EMPTY); arg(e, 1, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE, null); e = register("doc", Doc.class, 0, 1, 1, NodeKindTest.DOCUMENT, StaticProperty.ALLOWS_ZERO_OR_ONE); arg(e, 0, BuiltInAtomicType.STRING, StaticProperty.ALLOWS_ZERO_OR_ONE, EMPTY); e = register("doc-available", DocAvailable.class, 0, 1, 1, BuiltInAtomicType.BOOLEAN, StaticProperty.EXACTLY_ONE); arg(e, 0, BuiltInAtomicType.STRING, StaticProperty.ALLOWS_ZERO_OR_ONE, BooleanValue.FALSE); e = register("document", Document.class, 0, 1, 2, Type.NODE_TYPE, StaticProperty.ALLOWS_ZERO_OR_MORE); arg(e, 0, Type.ITEM_TYPE, StaticProperty.ALLOWS_ZERO_OR_MORE, null); arg(e, 1, Type.NODE_TYPE, StaticProperty.EXACTLY_ONE, null); e = register("document-uri", NamePart.class, NamePart.DOCUMENT_URI, 1, 1, BuiltInAtomicType.ANY_URI, StaticProperty.ALLOWS_ZERO_OR_ONE); arg(e, 0, Type.NODE_TYPE, StaticProperty.ALLOWS_ZERO_OR_MORE, EMPTY); e = register("empty", Existence.class, Existence.EMPTY, 1, 1, BuiltInAtomicType.BOOLEAN, StaticProperty.EXACTLY_ONE); arg(e, 0, Type.ITEM_TYPE, StaticProperty.ALLOWS_ZERO_OR_MORE, BooleanValue.TRUE); e = register("ends-with", Contains.class, Contains.ENDSWITH, 2, 3, BuiltInAtomicType.BOOLEAN, StaticProperty.EXACTLY_ONE); arg(e, 0, BuiltInAtomicType.STRING, StaticProperty.ALLOWS_ZERO_OR_ONE, null); arg(e, 1, BuiltInAtomicType.STRING, StaticProperty.ALLOWS_ZERO_OR_ONE, BooleanValue.TRUE); arg(e, 2, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE, null); e = register("element-available", Available.class, Available.ELEMENT_AVAILABLE, 1, 1, BuiltInAtomicType.BOOLEAN, StaticProperty.EXACTLY_ONE); arg(e, 0, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE, null); e = register("encode-for-uri", EscapeURI.class, EscapeURI.ENCODE_FOR_URI, 1, 1, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE); arg(e, 0, BuiltInAtomicType.STRING, StaticProperty.ALLOWS_ZERO_OR_ONE, StringValue.EMPTY_STRING); e = register("escape-html-uri", EscapeURI.class, EscapeURI.HTML_URI, 1, 1, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE); arg(e, 0, BuiltInAtomicType.STRING, StaticProperty.ALLOWS_ZERO_OR_ONE, StringValue.EMPTY_STRING); e = register("error", Error.class, 0, 0, 3, Type.ITEM_TYPE, StaticProperty.ALLOWS_ZERO_OR_ONE); // The return type is chosen so that use of the error() function will never give a static type error, // on the basis that item()? overlaps every other type, and it's almost impossible to make any // unwarranted inferences from it, except perhaps count(error()) lt 2. arg(e, 0, BuiltInAtomicType.QNAME, StaticProperty.ALLOWS_ZERO_OR_ONE, null); arg(e, 1, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE, null); arg(e, 2, Type.ITEM_TYPE, StaticProperty.ALLOWS_ZERO_OR_MORE, null); e = register("exactly-one", TreatFn.class, StaticProperty.EXACTLY_ONE, 1, 1, SAME_AS_FIRST_ARGUMENT, StaticProperty.EXACTLY_ONE); arg(e, 0, Type.ITEM_TYPE, StaticProperty.EXACTLY_ONE, null); // because we don't do draconian static type checking, we can do the work in the argument type checking code e = register("exists", Existence.class, Existence.EXISTS, 1, 1, BuiltInAtomicType.BOOLEAN, StaticProperty.EXACTLY_ONE); arg(e, 0, Type.ITEM_TYPE, StaticProperty.ALLOWS_ZERO_OR_MORE, BooleanValue.FALSE); register("false", BooleanFn.class, BooleanFn.FALSE, 0, 0, BuiltInAtomicType.BOOLEAN, StaticProperty.EXACTLY_ONE); e = register("floor", Rounding.class, Rounding.FLOOR, 1, 1, SAME_AS_FIRST_ARGUMENT, StaticProperty.ALLOWS_ZERO_OR_ONE); arg(e, 0, BuiltInAtomicType.NUMERIC, StaticProperty.ALLOWS_ZERO_OR_ONE, EMPTY); e = register("format-date", FormatDate.class, StandardNames.XS_DATE, 2, 5, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE); arg(e, 0, BuiltInAtomicType.DATE, StaticProperty.ALLOWS_ZERO_OR_ONE, null); arg(e, 1, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE, null); arg(e, 2, BuiltInAtomicType.STRING, StaticProperty.ALLOWS_ZERO_OR_ONE, null); arg(e, 3, BuiltInAtomicType.STRING, StaticProperty.ALLOWS_ZERO_OR_ONE, null); arg(e, 4, BuiltInAtomicType.STRING, StaticProperty.ALLOWS_ZERO_OR_ONE, null); e = register("format-dateTime", FormatDate.class, StandardNames.XS_DATE_TIME, 2, 5, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE); arg(e, 0, BuiltInAtomicType.DATE_TIME, StaticProperty.ALLOWS_ZERO_OR_ONE, null); arg(e, 1, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE, null); arg(e, 2, BuiltInAtomicType.STRING, StaticProperty.ALLOWS_ZERO_OR_ONE, null); arg(e, 3, BuiltInAtomicType.STRING, StaticProperty.ALLOWS_ZERO_OR_ONE, null); arg(e, 4, BuiltInAtomicType.STRING, StaticProperty.ALLOWS_ZERO_OR_ONE, null); e = register("format-number", FormatNumber.class, 0, 2, 3, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE); arg(e, 0, BuiltInAtomicType.NUMERIC, StaticProperty.ALLOWS_ZERO_OR_ONE, null); arg(e, 1, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE, null); arg(e, 2, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE, null); e = register("format-time", FormatDate.class, StandardNames.XS_TIME, 2, 5, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE); arg(e, 0, BuiltInAtomicType.TIME, StaticProperty.ALLOWS_ZERO_OR_ONE, null); arg(e, 1, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE, null); arg(e, 2, BuiltInAtomicType.STRING, StaticProperty.ALLOWS_ZERO_OR_ONE, null); arg(e, 3, BuiltInAtomicType.STRING, StaticProperty.ALLOWS_ZERO_OR_ONE, null); arg(e, 4, BuiltInAtomicType.STRING, StaticProperty.ALLOWS_ZERO_OR_ONE, null); e = register("function-available", Available.class, Available.FUNCTION_AVAILABLE, 1, 2, BuiltInAtomicType.BOOLEAN, StaticProperty.EXACTLY_ONE); arg(e, 0, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE, null); arg(e, 1, BuiltInAtomicType.INTEGER, StaticProperty.EXACTLY_ONE, null); e = register("generate-id", NamePart.class, NamePart.GENERATE_ID, 0, 1, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE); arg(e, 0, Type.NODE_TYPE, StaticProperty.ALLOWS_ZERO_OR_ONE, StringValue.EMPTY_STRING); e = register("hours-from-dateTime", Component.class, (Component.HOURS<<16) + StandardNames.XS_DATE_TIME, 1, 1, BuiltInAtomicType.INTEGER, StaticProperty.ALLOWS_ZERO_OR_ONE); arg(e, 0, BuiltInAtomicType.DATE_TIME, StaticProperty.ALLOWS_ZERO_OR_ONE, EMPTY); e = register("hours-from-duration", Component.class, (Component.HOURS<<16) + StandardNames.XS_DURATION, 1, 1, BuiltInAtomicType.INTEGER, StaticProperty.ALLOWS_ZERO_OR_ONE); arg(e, 0, BuiltInAtomicType.DURATION, StaticProperty.ALLOWS_ZERO_OR_ONE, EMPTY); e = register("hours-from-time", Component.class, (Component.HOURS<<16) + StandardNames.XS_TIME, 1, 1, BuiltInAtomicType.INTEGER, StaticProperty.ALLOWS_ZERO_OR_ONE); arg(e, 0, BuiltInAtomicType.TIME, StaticProperty.ALLOWS_ZERO_OR_ONE, EMPTY); e = register("id", Id.class, 0, 1, 2, NodeKindTest.ELEMENT, StaticProperty.ALLOWS_ZERO_OR_MORE); arg(e, 0, BuiltInAtomicType.STRING, StaticProperty.ALLOWS_ZERO_OR_MORE, EMPTY); arg(e, 1, Type.NODE_TYPE, StaticProperty.EXACTLY_ONE, null); e = register("idref", Idref.class, 0, 1, 2, Type.NODE_TYPE, StaticProperty.ALLOWS_ZERO_OR_MORE); arg(e, 0, BuiltInAtomicType.STRING, StaticProperty.ALLOWS_ZERO_OR_MORE, EMPTY); arg(e, 1, Type.NODE_TYPE, StaticProperty.EXACTLY_ONE, null); register("implicit-timezone", CurrentDateTime.class, 0, 0, 0, BuiltInAtomicType.DAY_TIME_DURATION, StaticProperty.EXACTLY_ONE); e = register("in-scope-prefixes", InScopePrefixes.class, 0, 1, 1, BuiltInAtomicType.STRING, StaticProperty.ALLOWS_ZERO_OR_MORE); arg(e, 0, NodeKindTest.ELEMENT, StaticProperty.EXACTLY_ONE, null); e = register("index-of", IndexOf.class, 0, 2, 3, BuiltInAtomicType.INTEGER, StaticProperty.ALLOWS_ZERO_OR_MORE); arg(e, 0, BuiltInAtomicType.ANY_ATOMIC, StaticProperty.ALLOWS_ZERO_OR_MORE, EMPTY); arg(e, 1, BuiltInAtomicType.ANY_ATOMIC, StaticProperty.EXACTLY_ONE, null); arg(e, 2, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE, null); e = register("insert-before", Insert.class, 0, 3, 3, Type.ITEM_TYPE, StaticProperty.ALLOWS_ZERO_OR_MORE); arg(e, 0, Type.ITEM_TYPE, StaticProperty.ALLOWS_ZERO_OR_MORE, null); arg(e, 1, BuiltInAtomicType.INTEGER, StaticProperty.EXACTLY_ONE, null); arg(e, 2, Type.ITEM_TYPE, StaticProperty.ALLOWS_ZERO_OR_MORE, null); e = register("iri-to-uri", EscapeURI.class, EscapeURI.IRI_TO_URI, 1, 1, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE); arg(e, 0, BuiltInAtomicType.STRING, StaticProperty.ALLOWS_ZERO_OR_ONE, StringValue.EMPTY_STRING); e = register("key", KeyFn.class, 0, 2, 3, Type.NODE_TYPE, StaticProperty.ALLOWS_ZERO_OR_MORE); arg(e, 0, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE, null); arg(e, 1, BuiltInAtomicType.ANY_ATOMIC, StaticProperty.ALLOWS_ZERO_OR_MORE, EMPTY); arg(e, 2, Type.NODE_TYPE, StaticProperty.EXACTLY_ONE, null); e = register("lang", Lang.class, 0, 1, 2, BuiltInAtomicType.BOOLEAN, StaticProperty.EXACTLY_ONE); arg(e, 0, BuiltInAtomicType.STRING, StaticProperty.ALLOWS_ZERO_OR_ONE, null); arg(e, 1, Type.NODE_TYPE, StaticProperty.EXACTLY_ONE, null); register("last", Last.class, 0, 0, 0, BuiltInAtomicType.INTEGER, StaticProperty.EXACTLY_ONE); e = register("local-name", NamePart.class, NamePart.LOCAL_NAME, 0, 1, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE); arg(e, 0, Type.NODE_TYPE, StaticProperty.ALLOWS_ZERO_OR_ONE, StringValue.EMPTY_STRING); e = register("local-name-from-QName", Component.class, (Component.LOCALNAME<<16) + StandardNames.XS_QNAME, 1, 1, BuiltInAtomicType.NCNAME, StaticProperty.ALLOWS_ZERO_OR_ONE); arg(e, 0, BuiltInAtomicType.QNAME, StaticProperty.ALLOWS_ZERO_OR_ONE, EMPTY); e = register("lower-case", ForceCase.class, ForceCase.LOWERCASE, 1, 1, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE); arg(e, 0, BuiltInAtomicType.STRING, StaticProperty.ALLOWS_ZERO_OR_ONE, StringValue.EMPTY_STRING); e = register("matches", Matches.class, 0, 2, 3, BuiltInAtomicType.BOOLEAN, StaticProperty.EXACTLY_ONE); arg(e, 0, BuiltInAtomicType.STRING, StaticProperty.ALLOWS_ZERO_OR_ONE, null); arg(e, 1, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE, null); arg(e, 2, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE, null); e = register("max", Minimax.class, Minimax.MAX, 1, 2, BuiltInAtomicType.ANY_ATOMIC, StaticProperty.ALLOWS_ZERO_OR_ONE); arg(e, 0, BuiltInAtomicType.ANY_ATOMIC, StaticProperty.ALLOWS_ZERO_OR_MORE, EMPTY); arg(e, 1, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE, null); e = register("min", Minimax.class, Minimax.MIN, 1, 2, BuiltInAtomicType.ANY_ATOMIC, StaticProperty.ALLOWS_ZERO_OR_ONE); arg(e, 0, BuiltInAtomicType.ANY_ATOMIC, StaticProperty.ALLOWS_ZERO_OR_MORE, EMPTY); arg(e, 1, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE, null); e = register("minutes-from-dateTime", Component.class, (Component.MINUTES<<16) + StandardNames.XS_DATE_TIME, 1, 1, BuiltInAtomicType.INTEGER, StaticProperty.ALLOWS_ZERO_OR_ONE); arg(e, 0, BuiltInAtomicType.DATE_TIME, StaticProperty.ALLOWS_ZERO_OR_ONE, EMPTY); e = register("minutes-from-duration", Component.class, (Component.MINUTES<<16) + StandardNames.XS_DURATION, 1, 1, BuiltInAtomicType.INTEGER, StaticProperty.ALLOWS_ZERO_OR_ONE); arg(e, 0, BuiltInAtomicType.DURATION, StaticProperty.ALLOWS_ZERO_OR_ONE, EMPTY); e = register("minutes-from-time", Component.class, (Component.MINUTES<<16) + StandardNames.XS_TIME, 1, 1, BuiltInAtomicType.INTEGER, StaticProperty.ALLOWS_ZERO_OR_ONE); arg(e, 0, BuiltInAtomicType.TIME, StaticProperty.ALLOWS_ZERO_OR_ONE, EMPTY); e = register("month-from-date", Component.class, (Component.MONTH<<16) + StandardNames.XS_DATE, 1, 1, BuiltInAtomicType.INTEGER, StaticProperty.ALLOWS_ZERO_OR_ONE); arg(e, 0, BuiltInAtomicType.DATE, StaticProperty.ALLOWS_ZERO_OR_ONE, EMPTY); e = register("month-from-dateTime", Component.class, (Component.MONTH<<16) + StandardNames.XS_DATE_TIME, 1, 1, BuiltInAtomicType.INTEGER, StaticProperty.ALLOWS_ZERO_OR_ONE); arg(e, 0, BuiltInAtomicType.DATE_TIME, StaticProperty.ALLOWS_ZERO_OR_ONE, EMPTY); e = register("months-from-duration", Component.class, (Component.MONTH<<16) + StandardNames.XS_DURATION, 1, 1, BuiltInAtomicType.INTEGER, StaticProperty.ALLOWS_ZERO_OR_ONE); arg(e, 0, BuiltInAtomicType.DURATION, StaticProperty.ALLOWS_ZERO_OR_ONE, EMPTY); e = register("name", NamePart.class, NamePart.NAME, 0, 1, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE); arg(e, 0, Type.NODE_TYPE, StaticProperty.ALLOWS_ZERO_OR_ONE, StringValue.EMPTY_STRING); e = register("namespace-uri", NamePart.class, NamePart.NAMESPACE_URI, 0, 1, BuiltInAtomicType.ANY_URI, StaticProperty.EXACTLY_ONE); arg(e, 0, Type.NODE_TYPE, StaticProperty.ALLOWS_ZERO_OR_ONE, StringValue.EMPTY_STRING); e = register("namespace-uri-for-prefix", NamespaceForPrefix.class, 0, 2, 2, BuiltInAtomicType.ANY_URI, StaticProperty.ALLOWS_ZERO_OR_ONE); arg(e, 0, BuiltInAtomicType.STRING, StaticProperty.ALLOWS_ZERO_OR_ONE, null); arg(e, 1, NodeKindTest.ELEMENT, StaticProperty.EXACTLY_ONE, null); e = register("namespace-uri-from-QName", Component.class, (Component.NAMESPACE<<16) + StandardNames.XS_QNAME, 1, 1, BuiltInAtomicType.ANY_URI, StaticProperty.ALLOWS_ZERO_OR_ONE); arg(e, 0, BuiltInAtomicType.QNAME, StaticProperty.ALLOWS_ZERO_OR_ONE, EMPTY); e = register("nilled", Nilled.class, 0, 1, 1, BuiltInAtomicType.BOOLEAN, StaticProperty.ALLOWS_ZERO_OR_ONE); arg(e, 0, Type.NODE_TYPE, StaticProperty.ALLOWS_ZERO_OR_ONE, EMPTY); e = register("node-name", NamePart.class, NamePart.NODE_NAME, 1, 1, BuiltInAtomicType.QNAME, StaticProperty.ALLOWS_ZERO_OR_ONE); arg(e, 0, Type.NODE_TYPE, StaticProperty.ALLOWS_ZERO_OR_ONE, EMPTY); e = register("not", BooleanFn.class, BooleanFn.NOT, 1, 1, BuiltInAtomicType.BOOLEAN, StaticProperty.EXACTLY_ONE); arg(e, 0, Type.ITEM_TYPE, StaticProperty.ALLOWS_ZERO_OR_MORE, BooleanValue.TRUE); register("normalize-space", NormalizeSpace.class, 0, 0, 1, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE); register("normalize-space#0", NormalizeSpace.class, 0, 0, 0, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE); e = register("normalize-space#1", NormalizeSpace.class, 0, 1, 1, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE); arg(e, 0, BuiltInAtomicType.STRING, StaticProperty.ALLOWS_ZERO_OR_ONE, null); e = register("normalize-unicode", NormalizeUnicode.class, 0, 1, 2, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE); arg(e, 0, BuiltInAtomicType.STRING, StaticProperty.ALLOWS_ZERO_OR_ONE, StringValue.EMPTY_STRING); arg(e, 1, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE, null); e = register("number", NumberFn.class, 0, 0, 1, BuiltInAtomicType.DOUBLE, StaticProperty.EXACTLY_ONE); arg(e, 0, BuiltInAtomicType.ANY_ATOMIC, StaticProperty.ALLOWS_ZERO_OR_ONE, DoubleValue.NaN); e = register("one-or-more", TreatFn.class, StaticProperty.ALLOWS_ONE_OR_MORE, 1, 1, SAME_AS_FIRST_ARGUMENT, StaticProperty.ALLOWS_ONE_OR_MORE); arg(e, 0, Type.ITEM_TYPE, StaticProperty.ALLOWS_ONE_OR_MORE, null); // because we don't do draconian static type checking, we can do the work in the argument type checking code register("position", Position.class, 0, 0, 0, BuiltInAtomicType.INTEGER, StaticProperty.EXACTLY_ONE); e = register("prefix-from-QName", Component.class, (Component.PREFIX<<16) + StandardNames.XS_QNAME, 1, 1, BuiltInAtomicType.NCNAME, StaticProperty.ALLOWS_ZERO_OR_ONE); arg(e, 0, BuiltInAtomicType.QNAME, StaticProperty.ALLOWS_ZERO_OR_ONE, EMPTY); e = register("put", Put.class, 0, 2, 2, AnyItemType.getInstance(), StaticProperty.ALLOWS_ZERO_OR_ONE); arg(e, 0, Type.NODE_TYPE, StaticProperty.EXACTLY_ONE, null); arg(e, 1, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE, null); e = register("QName", QNameFn.class, 0, 2, 2, BuiltInAtomicType.QNAME, StaticProperty.EXACTLY_ONE); arg(e, 0, BuiltInAtomicType.STRING, StaticProperty.ALLOWS_ZERO_OR_ONE, null); arg(e, 1, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE, null); e = register("regex-group", RegexGroup.class, 0, 1, 1, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE); arg(e, 0, BuiltInAtomicType.INTEGER, StaticProperty.EXACTLY_ONE, null); e = register("remove", Remove.class, 0, 2, 2, SAME_AS_FIRST_ARGUMENT, StaticProperty.ALLOWS_ZERO_OR_MORE); arg(e, 0, Type.ITEM_TYPE, StaticProperty.ALLOWS_ZERO_OR_MORE, EMPTY); arg(e, 1, BuiltInAtomicType.INTEGER, StaticProperty.EXACTLY_ONE, null); e = register("replace", Replace.class, 0, 3, 4, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE); arg(e, 0, BuiltInAtomicType.STRING, StaticProperty.ALLOWS_ZERO_OR_ONE, StringValue.EMPTY_STRING); arg(e, 1, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE, null); arg(e, 2, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE, null); arg(e, 3, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE, null); e = register("resolve-QName", ResolveQName.class, 0, 2, 2, BuiltInAtomicType.QNAME, StaticProperty.ALLOWS_ZERO_OR_ONE); arg(e, 0, BuiltInAtomicType.STRING, StaticProperty.ALLOWS_ZERO_OR_ONE, EMPTY); arg(e, 1, NodeKindTest.ELEMENT, StaticProperty.EXACTLY_ONE, null); e = register("resolve-uri", ResolveURI.class, 0, 1, 2, BuiltInAtomicType.ANY_URI, StaticProperty.ALLOWS_ZERO_OR_ONE); arg(e, 0, BuiltInAtomicType.STRING, StaticProperty.ALLOWS_ZERO_OR_ONE, null); arg(e, 1, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE, null); e = register("reverse", Reverse.class, 0, 1, 1, Type.ITEM_TYPE, StaticProperty.ALLOWS_ZERO_OR_MORE); arg(e, 0, Type.ITEM_TYPE, StaticProperty.ALLOWS_ZERO_OR_MORE, EMPTY); e = register("root", Root.class, 0, 0, 1, Type.NODE_TYPE, StaticProperty.ALLOWS_ZERO_OR_ONE); arg(e, 0, Type.NODE_TYPE, StaticProperty.ALLOWS_ZERO_OR_ONE, EMPTY); e = register("round", Rounding.class, Rounding.ROUND, 1, 1, SAME_AS_FIRST_ARGUMENT, StaticProperty.ALLOWS_ZERO_OR_ONE); arg(e, 0, BuiltInAtomicType.NUMERIC, StaticProperty.ALLOWS_ZERO_OR_ONE, EMPTY); e = register("round-half-to-even", Rounding.class, Rounding.HALF_EVEN, 1, 2, SAME_AS_FIRST_ARGUMENT, StaticProperty.ALLOWS_ZERO_OR_ONE); arg(e, 0, BuiltInAtomicType.NUMERIC, StaticProperty.ALLOWS_ZERO_OR_ONE, EMPTY); arg(e, 1, BuiltInAtomicType.INTEGER, StaticProperty.EXACTLY_ONE, null); e = register("seconds-from-dateTime", Component.class, (Component.SECONDS<<16) + StandardNames.XS_DATE_TIME, 1, 1, BuiltInAtomicType.DECIMAL, StaticProperty.ALLOWS_ZERO_OR_ONE); arg(e, 0, BuiltInAtomicType.DATE_TIME, StaticProperty.ALLOWS_ZERO_OR_ONE, EMPTY); e = register("seconds-from-duration", Component.class, (Component.SECONDS<<16) + StandardNames.XS_DURATION, 1, 1, BuiltInAtomicType.DECIMAL, StaticProperty.ALLOWS_ZERO_OR_ONE); arg(e, 0, BuiltInAtomicType.DURATION, StaticProperty.ALLOWS_ZERO_OR_ONE, EMPTY); e = register("seconds-from-time", Component.class, (Component.SECONDS<<16) + StandardNames.XS_TIME, 1, 1, BuiltInAtomicType.DECIMAL, StaticProperty.ALLOWS_ZERO_OR_ONE); arg(e, 0, BuiltInAtomicType.TIME, StaticProperty.ALLOWS_ZERO_OR_ONE, EMPTY); e = register("starts-with", Contains.class, Contains.STARTSWITH, 2, 3, BuiltInAtomicType.BOOLEAN, StaticProperty.EXACTLY_ONE); arg(e, 0, BuiltInAtomicType.STRING, StaticProperty.ALLOWS_ZERO_OR_ONE, null); arg(e, 1, BuiltInAtomicType.STRING, StaticProperty.ALLOWS_ZERO_OR_ONE, BooleanValue.TRUE); arg(e, 2, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE, null); register("static-base-uri", StaticBaseURI.class, 0, 0, 0, BuiltInAtomicType.ANY_URI, StaticProperty.ALLOWS_ZERO_OR_ONE); e = register("string", StringFn.class, 0, 0, 1, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE); arg(e, 0, Type.ITEM_TYPE, StaticProperty.ALLOWS_ZERO_OR_ONE, StringValue.EMPTY_STRING); register("string-length", StringLength.class, 0, 0, 1, BuiltInAtomicType.INTEGER, StaticProperty.EXACTLY_ONE); register("string-length#0", StringLength.class, 0, 0, 0, BuiltInAtomicType.INTEGER, StaticProperty.EXACTLY_ONE); e = register("string-length#1", StringLength.class, 0, 1, 1, BuiltInAtomicType.INTEGER, StaticProperty.EXACTLY_ONE); arg(e, 0, BuiltInAtomicType.STRING, StaticProperty.ALLOWS_ZERO_OR_ONE, null); e = register("string-join", StringJoin.class, 0, 2, 2, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE); arg(e, 0, BuiltInAtomicType.STRING, StaticProperty.ALLOWS_ZERO_OR_MORE, StringValue.EMPTY_STRING); arg(e, 1, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE, null); e = register("string-to-codepoints", StringToCodepoints.class, 0, 1, 1, BuiltInAtomicType.INTEGER, StaticProperty.ALLOWS_ZERO_OR_MORE); arg(e, 0, BuiltInAtomicType.STRING, StaticProperty.ALLOWS_ZERO_OR_ONE, EMPTY); e = register("subsequence", Subsequence.class, 0, 2, 3, SAME_AS_FIRST_ARGUMENT, StaticProperty.ALLOWS_ZERO_OR_MORE); arg(e, 0, Type.ITEM_TYPE, StaticProperty.ALLOWS_ZERO_OR_MORE, EMPTY); arg(e, 1, BuiltInAtomicType.NUMERIC, StaticProperty.EXACTLY_ONE, null); arg(e, 2, BuiltInAtomicType.NUMERIC, StaticProperty.EXACTLY_ONE, null); e = register("substring", Substring.class, 0, 2, 3, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE); arg(e, 0, BuiltInAtomicType.STRING, StaticProperty.ALLOWS_ZERO_OR_ONE, StringValue.EMPTY_STRING); arg(e, 1, BuiltInAtomicType.NUMERIC, StaticProperty.EXACTLY_ONE, null); arg(e, 2, BuiltInAtomicType.NUMERIC, StaticProperty.EXACTLY_ONE, null); e = register("substring-after", Contains.class, Contains.AFTER, 2, 3, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE); arg(e, 0, BuiltInAtomicType.STRING, StaticProperty.ALLOWS_ZERO_OR_ONE, null); arg(e, 1, BuiltInAtomicType.STRING, StaticProperty.ALLOWS_ZERO_OR_ONE, null); arg(e, 2, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE, null); e = register("substring-before", Contains.class, Contains.BEFORE, 2, 3, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE); arg(e, 0, BuiltInAtomicType.STRING, StaticProperty.ALLOWS_ZERO_OR_ONE, null); arg(e, 1, BuiltInAtomicType.STRING, StaticProperty.ALLOWS_ZERO_OR_ONE, StringValue.EMPTY_STRING); arg(e, 2, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE, null); e = register("sum", Aggregate.class, Aggregate.SUM, 1, 2, BuiltInAtomicType.ANY_ATOMIC, StaticProperty.ALLOWS_ZERO_OR_ONE); arg(e, 0, BuiltInAtomicType.ANY_ATOMIC, StaticProperty.ALLOWS_ZERO_OR_MORE, null); arg(e, 1, BuiltInAtomicType.ANY_ATOMIC, StaticProperty.ALLOWS_ZERO_OR_ONE, null); e = register("system-property", SystemProperty.class, 0, 1, 1, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE); arg(e, 0, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE, null); e = register("timezone-from-date", Component.class, (Component.TIMEZONE<<16) + StandardNames.XS_DATE, 1, 1, BuiltInAtomicType.DAY_TIME_DURATION, StaticProperty.ALLOWS_ZERO_OR_ONE); arg(e, 0, BuiltInAtomicType.DATE, StaticProperty.ALLOWS_ZERO_OR_ONE, EMPTY); e = register("timezone-from-dateTime", Component.class, (Component.TIMEZONE<<16) + StandardNames.XS_DATE_TIME, 1, 1, BuiltInAtomicType.DAY_TIME_DURATION, StaticProperty.ALLOWS_ZERO_OR_ONE); arg(e, 0, BuiltInAtomicType.DATE_TIME, StaticProperty.ALLOWS_ZERO_OR_ONE, EMPTY); e = register("timezone-from-time", Component.class, (Component.TIMEZONE<<16) + StandardNames.XS_TIME, 1, 1, BuiltInAtomicType.DAY_TIME_DURATION, StaticProperty.ALLOWS_ZERO_OR_ONE); arg(e, 0, BuiltInAtomicType.TIME, StaticProperty.ALLOWS_ZERO_OR_ONE, EMPTY); e = register("trace", Trace.class, 0, 2, 2, SAME_AS_FIRST_ARGUMENT, StaticProperty.ALLOWS_ZERO_OR_MORE); arg(e, 0, Type.ITEM_TYPE, StaticProperty.ALLOWS_ZERO_OR_MORE, null); arg(e, 1, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE, null); register("true", BooleanFn.class, BooleanFn.TRUE, 0, 0, BuiltInAtomicType.BOOLEAN, StaticProperty.EXACTLY_ONE); e = register("translate", Translate.class, 0, 3, 3, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE); arg(e, 0, BuiltInAtomicType.STRING, StaticProperty.ALLOWS_ZERO_OR_ONE, StringValue.EMPTY_STRING); arg(e, 1, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE, null); arg(e, 2, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE, null); e = register("tokenize", Tokenize.class, 0, 2, 3, BuiltInAtomicType.STRING, StaticProperty.ALLOWS_ZERO_OR_MORE); arg(e, 0, BuiltInAtomicType.STRING, StaticProperty.ALLOWS_ZERO_OR_ONE, EMPTY); arg(e, 1, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE, null); arg(e, 2, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE, null); e = register("type-available", Available.class, Available.TYPE_AVAILABLE, 1, 1, BuiltInAtomicType.BOOLEAN, StaticProperty.EXACTLY_ONE); arg(e, 0, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE, null); e = register("unordered", Unordered.class, 0, 1, 1, SAME_AS_FIRST_ARGUMENT, StaticProperty.ALLOWS_ZERO_OR_MORE); arg(e, 0, Type.ITEM_TYPE, StaticProperty.ALLOWS_ZERO_OR_MORE, EMPTY); e = register("upper-case", ForceCase.class, ForceCase.UPPERCASE, 1, 1, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE); arg(e, 0, BuiltInAtomicType.STRING, StaticProperty.ALLOWS_ZERO_OR_ONE, StringValue.EMPTY_STRING); e = register("unparsed-entity-uri", UnparsedEntity.class, UnparsedEntity.URI, 1, 1, BuiltInAtomicType.ANY_URI, StaticProperty.EXACTLY_ONE); arg(e, 0, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE, null); // internal version of unparsed-entity-uri with second argument representing the current document e = register("unparsed-entity-uri_9999_", UnparsedEntity.class, UnparsedEntity.URI, 2, 2, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE); arg(e, 0, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE, null); arg(e, 1, Type.NODE_TYPE, StaticProperty.EXACTLY_ONE, null); // it must actually be a document node, but there's a non-standard error code e = register("unparsed-entity-public-id", UnparsedEntity.class, UnparsedEntity.PUBLIC_ID, 1, 1, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE); arg(e, 0, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE, null); // internal version of unparsed-entity-public-id with second argument representing the current document e = register("unparsed-entity-public-id_9999_", UnparsedEntity.class, UnparsedEntity.PUBLIC_ID, 2, 2, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE); arg(e, 0, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE, null); arg(e, 1, Type.NODE_TYPE, StaticProperty.EXACTLY_ONE, null); // it must actually be a document node, but there's a non-standard error code e = register("unparsed-text", UnparsedText.class, UnparsedText.UNPARSED_TEXT, 1, 2, BuiltInAtomicType.STRING, StaticProperty.ALLOWS_ZERO_OR_ONE); arg(e, 0, BuiltInAtomicType.STRING, StaticProperty.ALLOWS_ZERO_OR_ONE, null); arg(e, 1, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE, null); e = register("unparsed-text-available", UnparsedText.class, UnparsedText.UNPARSED_TEXT_AVAILABLE, 1, 2, BuiltInAtomicType.BOOLEAN, StaticProperty.EXACTLY_ONE); arg(e, 0, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE, null); arg(e, 1, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE, null); e = register("year-from-date", Component.class, (Component.YEAR<<16) + StandardNames.XS_DATE, 1, 1, BuiltInAtomicType.INTEGER, StaticProperty.ALLOWS_ZERO_OR_ONE); arg(e, 0, BuiltInAtomicType.DATE, StaticProperty.ALLOWS_ZERO_OR_ONE, EMPTY); e = register("year-from-dateTime", Component.class, (Component.YEAR<<16) + StandardNames.XS_DATE_TIME, 1, 1, BuiltInAtomicType.INTEGER, StaticProperty.ALLOWS_ZERO_OR_ONE); arg(e, 0, BuiltInAtomicType.DATE_TIME, StaticProperty.ALLOWS_ZERO_OR_ONE, EMPTY); e = register("years-from-duration", Component.class, (Component.YEAR<<16) + StandardNames.XS_DURATION, 1, 1, BuiltInAtomicType.INTEGER, StaticProperty.ALLOWS_ZERO_OR_ONE); arg(e, 0, BuiltInAtomicType.DURATION, StaticProperty.ALLOWS_ZERO_OR_ONE, EMPTY); e = register("zero-or-one", TreatFn.class, StaticProperty.ALLOWS_ZERO_OR_ONE, 1, 1, SAME_AS_FIRST_ARGUMENT, StaticProperty.ALLOWS_ZERO_OR_ONE); arg(e, 0, Type.ITEM_TYPE, StaticProperty.ALLOWS_ZERO_OR_ONE, null); // because we don't do draconian static type checking, we can do the work in the argument type checking code } /** * Get the table entry for the function with a given name * @param name the name of the function. This may be an unprefixed local-name for functions in the * system namespace, or may use the conventional prefix "saxon:" in the case of Saxon extension functions * that are specially recognized * @return if the function name is known, an Entry containing information about the function. Otherwise, * null */ public static Entry getFunction(String name, int arity) { // try first for an entry of the form name#arity Entry e = (Entry)functionTable.get(name + '#' + arity); if (e != null) { return e; } // try for a generic entry return (Entry)functionTable.get(name); } /** * An entry in the table describing the properties of a function */ public static class Entry implements java.io.Serializable { /** * The name of the function: a local name in the case of functions in the standard library, or a * name with the conventional prefix "saxon:" in the case of Saxon extension functions */ public String name; /** * The class containing the implementation of this function (always a subclass of SystemFunction) */ public Class implementationClass; /** * Some classes support more than one function. In these cases the particular function is defined * by an integer opcode, whose meaning is local to the implementation class. */ public int opcode; /** * The minimum number of arguments required */ public int minArguments; /** * The maximum number of arguments permitted */ public int maxArguments; /** * The item type of the result of the function */ public ItemType itemType; /** * The cardinality of the result of the function */ public int cardinality; /** * An array holding the types of the arguments to the function */ public SequenceType[] argumentTypes; /** * An array holding, for each declared argument, the value that is to be returned if an empty sequence * as the value of this argument allows the result to be determined irrespective of the values of the * other arguments; null if there is no such calculation possible */ public Value[] resultIfEmpty; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License]; // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/functions/FormatDate.java0000644000175000017500000006461611033112257022315 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.expr.ExpressionVisitor; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.instruct.NumberInstruction; import net.sf.saxon.number.NamedTimeZone; import net.sf.saxon.number.Numberer; import net.sf.saxon.om.FastStringBuffer; import net.sf.saxon.om.Item; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.*; import java.math.BigDecimal; import java.util.Locale; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Implement the format-date() function in XSLT 2.0 */ public class FormatDate extends SystemFunction implements XSLTFunction { public void checkArguments(ExpressionVisitor visitor) throws XPathException { int numArgs = argument.length; if (numArgs != 2 && numArgs != 5) { throw new XPathException("Function " + getDisplayName() + " must have either two or five arguments", this); } super.checkArguments(visitor); } /** * Evaluate in a general context */ public Item evaluateItem(XPathContext context) throws XPathException { CalendarValue value = (CalendarValue)argument[0].evaluateItem(context); if (value==null) { return null; } String format = argument[1].evaluateItem(context).getStringValue(); String language; StringValue calendarVal = null; StringValue countryVal = null; if (argument.length > 2) { AtomicValue languageVal = (AtomicValue)argument[2].evaluateItem(context); calendarVal = (StringValue)argument[3].evaluateItem(context); countryVal = (StringValue)argument[4].evaluateItem(context); if (languageVal==null) { language = getDefaultLanguage(context); } else { language = languageVal.getStringValue(); if (language.length() >= 2) { language = language.substring(0, 2); } else { language = Locale.getDefault().getLanguage(); } } } else { language = getDefaultLanguage(context); } String country = (countryVal == null ? null : countryVal.getStringValue()); CharSequence result = formatDate(value, format, language, country, context); if (calendarVal != null) { String cal = calendarVal.getStringValue(); if (!cal.equals("AD") && !cal.equals("ISO")) { result = "[Calendar: AD]" + result.toString(); } } return new StringValue(result); } /** * Default language is "en", unless (a) the Java default locale is some other language, and * (b) there is a loadable Numberer for that language. * @param context the XPath dynamic context * @return the default language */ private static String getDefaultLanguage(XPathContext context) { String language = Locale.getDefault().getLanguage(); if (!language.equals("en")) { Numberer numberer = NumberInstruction.makeNumberer(language, "us", context); if (!numberer.getClass().getName().endsWith("Numberer_" + language)) { language = "en"; } } return language; } /** * This method analyzes the formatting picture and delegates the work of formatting * individual parts of the date. * @param value the value to be formatted * @param format the supplied format picture * @param language the chosen language * @param country the chosen country * @param context the XPath dynamic evaluation context * @return the formatted date/time */ private static CharSequence formatDate(CalendarValue value, String format, String language, String country, XPathContext context) throws XPathException { Numberer numberer = NumberInstruction.makeNumberer(language, country, context); FastStringBuffer sb = new FastStringBuffer(32); if (!numberer.getClass().getName().endsWith("Numberer_" + language)) { sb.append("[Language: en]"); } int i = 0; while (true) { while (i < format.length() && format.charAt(i) != '[') { sb.append(format.charAt(i)); if (format.charAt(i) == ']') { i++; if (i == format.length() || format.charAt(i) != ']') { XPathException e = new XPathException("Closing ']' in date picture must be written as ']]'"); e.setErrorCode("XTDE1340"); e.setXPathContext(context); throw e; } } i++; } if (i == format.length()) { break; } // look for '[[' i++; if (i < format.length() && format.charAt(i) == '[') { sb.append('['); i++; } else { int close = (i < format.length() ? format.indexOf("]", i) : -1); if (close == -1) { XPathException e = new XPathException("Date format contains a '[' with no matching ']'"); e.setErrorCode("XTDE1340"); e.setXPathContext(context); throw e; } String componentFormat = format.substring(i, close); sb.append(formatComponent(value, Whitespace.removeAllWhitespace(componentFormat), numberer, context)); i = close+1; } } return sb; } private static Pattern componentPattern = Pattern.compile("([YMDdWwFHhmsfZzPCE])\\s*(.*)"); private static CharSequence formatComponent(CalendarValue value, CharSequence specifier, Numberer numberer, XPathContext context) throws XPathException { boolean ignoreDate = (value instanceof TimeValue); boolean ignoreTime = (value instanceof DateValue); DateTimeValue dtvalue = value.toDateTime(); Matcher matcher = componentPattern.matcher(specifier); if (!matcher.matches()) { XPathException error = new XPathException("Unrecognized date/time component [" + specifier + ']'); error.setErrorCode("XTDE1340"); error.setXPathContext(context); throw error; } String component = matcher.group(1); String format = matcher.group(2); if (format==null) { format = ""; } boolean defaultFormat = false; if ("".equals(format) || format.startsWith(",")) { defaultFormat = true; switch (component.charAt(0) ) { case 'F': format = "Nn" + format; break; case 'P': format = 'n' + format; break; case 'C': case 'E': format = 'N' + format; break; case 'm': case 's': format = "01" + format; break; default: format = '1' + format; } } switch (component.charAt(0)) { case'Y': // year if (ignoreDate) { XPathException error = new XPathException("In formatTime(): an xs:time value does not contain a year component"); error.setErrorCode("XTDE1350"); error.setXPathContext(context); throw error; } else { int year = dtvalue.getYear(); if (year < 0) { year = 1 - year; } return formatNumber(component, year, format, defaultFormat, numberer, context); } case'M': // month if (ignoreDate) { XPathException error = new XPathException("In formatTime(): an xs:time value does not contain a month component"); error.setErrorCode("XTDE1350"); error.setXPathContext(context); throw error; } else { int month = dtvalue.getMonth(); return formatNumber(component, month, format, defaultFormat, numberer, context); } case'D': // day in month if (ignoreDate) { XPathException error = new XPathException("In formatTime(): an xs:time value does not contain a day component"); error.setErrorCode("XTDE1350"); error.setXPathContext(context); throw error; } else { int day = dtvalue.getDay(); return formatNumber(component, day, format, defaultFormat, numberer, context); } case'd': // day in year if (ignoreDate) { XPathException error = new XPathException("In formatTime(): an xs:time value does not contain a day component"); error.setErrorCode("XTDE1350"); error.setXPathContext(context); throw error; } else { int day = DateValue.getDayWithinYear(dtvalue.getYear(), dtvalue.getMonth(), dtvalue.getDay()); return formatNumber(component, day, format, defaultFormat, numberer, context); } case'W': // week of year if (ignoreDate) { XPathException error = new XPathException("In formatTime(): cannot obtain the week number from an xs:time value"); error.setErrorCode("XTDE1350"); error.setXPathContext(context); throw error; } else { int week = DateValue.getWeekNumber(dtvalue.getYear(), dtvalue.getMonth(), dtvalue.getDay()); return formatNumber(component, week, format, defaultFormat, numberer, context); } case'w': // week in month if (ignoreDate) { XPathException error = new XPathException("In formatTime(): cannot obtain the week number from an xs:time value"); error.setErrorCode("XTDE1350"); error.setXPathContext(context); throw error; } else { int week = DateValue.getWeekNumberWithinMonth(dtvalue.getYear(), dtvalue.getMonth(), dtvalue.getDay()); return formatNumber(component, week, format, defaultFormat, numberer, context); } case'H': // hour in day if (ignoreTime) { XPathException error = new XPathException("In formatDate(): an xs:date value does not contain an hour component"); error.setErrorCode("XTDE1350"); error.setXPathContext(context); throw error; } else { Int64Value hour = (Int64Value)value.getComponent(Component.HOURS); return formatNumber(component, (int)hour.longValue(), format, defaultFormat, numberer, context); } case'h': // hour in half-day (12 hour clock) if (ignoreTime) { XPathException error = new XPathException("In formatDate(): an xs:date value does not contain an hour component"); error.setErrorCode("XTDE1350"); error.setXPathContext(context); throw error; } else { Int64Value hour = (Int64Value)value.getComponent(Component.HOURS); int hr = (int)hour.longValue(); if (hr > 12) { hr = hr - 12; } if (hr == 0) { hr = 12; } return formatNumber(component, hr, format, defaultFormat, numberer, context); } case'm': // minutes if (ignoreTime) { XPathException error = new XPathException("In formatDate(): an xs:date value does not contain a minutes component"); error.setErrorCode("XTDE1350"); error.setXPathContext(context); throw error; } else { Int64Value min = (Int64Value)value.getComponent(Component.MINUTES); return formatNumber(component, (int)min.longValue(), format, defaultFormat, numberer, context); } case's': // seconds if (ignoreTime) { XPathException error = new XPathException("In formatDate(): an xs:date value does not contain a seconds component"); error.setErrorCode("XTDE1350"); error.setXPathContext(context); throw error; } else { IntegerValue sec = (IntegerValue)value.getComponent(Component.WHOLE_SECONDS); return formatNumber(component, (int)sec.longValue(), format, defaultFormat, numberer, context); } case'f': // fractional seconds // ignore the format if (ignoreTime) { XPathException error = new XPathException("In formatDate(): an xs:date value does not contain a fractional seconds component"); error.setErrorCode("XTDE1350"); error.setXPathContext(context); throw error; } else { int micros = (int)((Int64Value)value.getComponent(Component.MICROSECONDS)).longValue(); return formatNumber(component, micros, format, defaultFormat, numberer, context); } case'Z': // timezone in +hh:mm format, unless format=N in which case use timezone name if (value.hasTimezone()) { return getNamedTimeZone(value.toDateTime(), numberer.getCountry(), format); } else { return ""; } case'z': // timezone if (value.hasTimezone()) { int tz = value.getTimezoneInMinutes(); return "GMT" + (tz == 0 ? "" : ((tz > 0 ? "+" : "-") + Math.abs(tz / 60) + (tz % 60 == 0 ? "" : ".5"))); } else { return ""; } case'F': // day of week if (ignoreDate) { XPathException error = new XPathException("In formatTime(): an xs:time value does not contain day-of-week component"); error.setErrorCode("XTDE1350"); error.setXPathContext(context); throw error; } else { int day = DateValue.getDayOfWeek(dtvalue.getYear(), dtvalue.getMonth(), dtvalue.getDay()); return formatNumber(component, day, format, defaultFormat, numberer, context); } case'P': // am/pm marker if (ignoreTime) { XPathException error = new XPathException("In formatDate(): an xs:date value does not contain an am/pm component"); error.setErrorCode("XTDE1350"); error.setXPathContext(context); throw error; } else { int minuteOfDay = dtvalue.getHour() * 60 + dtvalue.getMinute(); return formatNumber(component, minuteOfDay, format, defaultFormat, numberer, context); } case'C': // calendar return numberer.getCalendarName("AD"); case'E': // era if (ignoreDate) { XPathException error = new XPathException("In formatTime(): an xs:time value does not contain an AD/BC component"); error.setErrorCode("XTDE1350"); error.setXPathContext(context); throw error; } else { int year = dtvalue.getYear(); return numberer.getEraName(year); } default: XPathException e = new XPathException("Unknown formatDate/time component specifier '" + format.charAt(0) + '\''); e.setErrorCode("XTDE1340"); e.setXPathContext(context); throw e; } } private static Pattern formatPattern = //Pattern.compile("([^ot,]*?)([ot]?)(,.*)?"); // GNU Classpath has problems with this one Pattern.compile("([^,]*)(,.*)?"); // Note, the group numbers are different from above private static Pattern widthPattern = Pattern.compile(",(\\*|[0-9]+)(\\-(\\*|[0-9]+))?"); private static Pattern alphanumericPattern = Pattern.compile("([A-Za-z0-9]|\\p{L}|\\p{N})*"); // the first term is redundant, but GNU Classpath can't cope with the others... private static Pattern digitsPattern = Pattern.compile("\\p{Nd}*"); private static CharSequence formatNumber(String component, int value, String format, boolean defaultFormat, Numberer numberer, XPathContext context) throws XPathException { Matcher matcher = formatPattern.matcher(format); if (!matcher.matches()) { XPathException error = new XPathException("Unrecognized format picture [" + component + format + ']'); error.setErrorCode("XTDE1340"); error.setXPathContext(context); throw error; } //String primary = matcher.group(1); //String modifier = matcher.group(2); String primary = matcher.group(1); String modifier = null; if (primary.endsWith("t")) { primary = primary.substring(0, primary.length()-1); modifier = "t"; } else if (primary.endsWith("o")) { primary = primary.substring(0, primary.length()-1); modifier = "o"; } String letterValue = ("t".equals(modifier) ? "traditional" : null); String ordinal = ("o".equals(modifier) ? numberer.getOrdinalSuffixForDateTime(component) : null); String widths = matcher.group(2); // was 3 if (!alphanumericPattern.matcher(primary).matches()) { XPathException error = new XPathException("In format picture at '" + primary + "', primary format must be alphanumeric"); error.setErrorCode("XTDE1340"); error.setXPathContext(context); throw error; } int min = 1; int max = Integer.MAX_VALUE; if (widths==null || "".equals(widths)) { if (digitsPattern.matcher(primary).matches()) { int len = StringValue.getStringLength(primary); if (len > 1) { // "A format token containing leading zeroes, such as 001, sets the minimum and maximum width..." // We interpret this literally: a format token of "1" does not set a maximum, because it would // cause the year 2006 to be formatted as "6". min = len; max = len; } } } else if (primary.equals("I") || primary.equals("i")) { // for roman numerals, ignore the width specifier min = 1; max = Integer.MAX_VALUE; } else { int[] range = getWidths(widths); min = range[0]; max = range[1]; if (defaultFormat) { // if format was defaulted, the explicit widths override the implicit format if (primary.endsWith("1") && min != primary.length()) { FastStringBuffer sb = new FastStringBuffer(min+1); for (int i=1; i max) { DecimalValue dec = new DecimalValue(new BigDecimal("0." + s)); dec = (DecimalValue)dec.roundHalfToEven(max); s = dec.getStringValue(); if (s.length() > 2) { // strip the ".0" s = s.substring(2); } else { // fractional seconds value was 0 s = ""; } } } while (s.length() < min) { s = s + '0'; } while (s.length() > min && s.charAt(s.length()-1) == '0') { s = s.substring(0, s.length()-1); } return s; } if ("N".equals(primary) || "n".equals(primary) || "Nn".equals(primary)) { String s = ""; if ("M".equals(component)) { s = numberer.monthName(value, min, max); } else if ("F".equals(component)) { s = numberer.dayName(value, min, max); } else if ("P".equals(component)) { s = numberer.halfDayName(value, min, max); } else { primary = "1"; } if ("N".equals(primary)) { return s.toUpperCase(); } else if ("n".equals(primary)) { return s.toLowerCase(); } else { return s; } } String s = numberer.format(value, primary, 0, ",", letterValue, ordinal); int len = StringValue.getStringLength(s); while (len < min) { // assert: this can only happen as a result of width specifiers, in which case we're using ASCII digits s = ("00000000"+s).substring(s.length()+8-min); len = StringValue.getStringLength(s); } if (len > max) { // the year is the only field we allow to be truncated if (component.charAt(0) == 'Y') { if (len == s.length()) { // no wide characters s = s.substring(s.length() - max); } else { // assert: each character must be two bytes long s = s.substring(s.length() - 2*max); } } } return s; } private static int[] getWidths(String widths) throws XPathException { try { int min = -1; int max = -1; if (!"".equals(widths)) { Matcher widthMatcher = widthPattern.matcher(widths); if (widthMatcher.matches()) { String smin = widthMatcher.group(1); if (smin==null || "".equals(smin) || "*".equals(smin)) { min = 1; } else { min = Integer.parseInt(smin); } String smax = widthMatcher.group(3); if (smax==null || "".equals(smax) || "*".equals(smax)) { max = Integer.MAX_VALUE; } else { max = Integer.parseInt(smax); } } else { XPathException error = new XPathException("Unrecognized width specifier"); error.setErrorCode("XTDE1340"); throw error; } } if (min>max && max!=-1) { XPathException e = new XPathException("Minimum width in date/time picture exceeds maximum width"); e.setErrorCode("XTDE1340"); throw e; } int[] result = new int[2]; result[0] = min; result[1] = max; return result; } catch (NumberFormatException err) { XPathException e = new XPathException("Invalid integer used as width in date/time picture"); e.setErrorCode("XTDE1340"); throw e; } } private static String getNamedTimeZone(DateTimeValue value, String country, String format) throws XPathException { int min = 1; int comma = format.indexOf(','); if (comma > 0) { String widths = format.substring(comma); int[] range = getWidths(widths); min = range[0]; } if (format.charAt(0) == 'N' || format.charAt(0) == 'n') { if (min <= 5) { String tzname = NamedTimeZone.getTimeZoneNameForDate(value, country); if (format.charAt(0) == 'n') { tzname = tzname.toLowerCase(); } return tzname; } else { return NamedTimeZone.getOlsenTimeZoneName(value, country); } } FastStringBuffer sbz = new FastStringBuffer(8); value.appendTimezone(sbz); return sbz.toString(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/functions/ForceCase.java0000644000175000017500000000341011033112257022102 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.Item; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.AtomicValue; import net.sf.saxon.value.StringValue; /** * This class implements the upper-case() and lower-case() functions */ public class ForceCase extends SystemFunction { public static final int UPPERCASE = 0; public static final int LOWERCASE = 1; /** * Evaluate in a general context */ public Item evaluateItem(XPathContext c) throws XPathException { AtomicValue sv = (AtomicValue)argument[0].evaluateItem(c); if (sv==null) { return StringValue.EMPTY_STRING; } switch(operation) { case UPPERCASE: return StringValue.makeStringValue(sv.getStringValue().toUpperCase()); case LOWERCASE: return StringValue.makeStringValue(sv.getStringValue().toLowerCase()); default: throw new UnsupportedOperationException("Unknown function"); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/functions/CodepointsToString.java0000644000175000017500000000711611033112257024060 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.charcode.UTF16; import net.sf.saxon.expr.Expression; import net.sf.saxon.expr.ExpressionVisitor; import net.sf.saxon.expr.StringLiteral; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.FastStringBuffer; import net.sf.saxon.om.Item; import net.sf.saxon.om.NameChecker; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.NumericValue; import net.sf.saxon.value.StringValue; /** * This class supports the function codepoints-to-string */ public class CodepointsToString extends SystemFunction { /** * Pre-evaluate a function at compile time. Functions that do not allow * pre-evaluation, or that need access to context information, can override this method. * @param visitor an expression visitor */ public Expression preEvaluate(ExpressionVisitor visitor) throws XPathException { final XPathContext context = visitor.getStaticContext().makeEarlyEvaluationContext(); return new StringLiteral( unicodeToString(argument[0].iterate(context), context)); } /** * Evaluate */ public Item evaluateItem(XPathContext c) throws XPathException { return StringValue.makeStringValue(unicodeToString(argument[0].iterate(c), c)); } /** * Return the Unicode string corresponding to a given sequence of Unicode code values * @param chars iterator delivering the characters as integer values * @param context the evaluation context * @throws net.sf.saxon.trans.XPathException if any of the integers is not the codepoint of a valid XML character */ public static CharSequence unicodeToString(SequenceIterator chars, XPathContext context) throws XPathException { FastStringBuffer sb = new FastStringBuffer(256); NameChecker checker = context.getConfiguration().getNameChecker(); while (true) { NumericValue nextInt = (NumericValue)chars.next(); if (nextInt == null) { return sb.condense(); } long next = nextInt.longValue(); if (next < 0 || next > Integer.MAX_VALUE || !checker.isValidChar((int)next)) { XPathException e = new XPathException("Invalid XML character [x " + Integer.toHexString((int)next) + ']'); e.setErrorCode("FOCH0001"); if (context instanceof XPathContext) { e.setXPathContext((XPathContext)context); } throw e; } if (next<65536) { sb.append((char)next); } else { // output a surrogate pair sb.append(UTF16.highSurrogate((int)next)); sb.append(UTF16.lowSurrogate((int)next)); } } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/functions/TreatFn.java0000644000175000017500000000410511033112257021615 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.expr.StaticProperty; import net.sf.saxon.om.Item; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.trans.XPathException; /** * This class supports the XPath 2.0 functions exactly-one(), one-or-more(), zero-or-one(). * Because Saxon doesn't do strict static type checking, these are essentially identity * functions; the run-time type checking is done as part of the function call mechanism */ public class TreatFn extends SystemFunction { /** * Return the error code to be used for type errors */ public String getErrorCodeForTypeErrors() { switch (operation) { case StaticProperty.ALLOWS_ZERO_OR_ONE: return "FORG0003"; case StaticProperty.ALLOWS_ONE_OR_MORE: return "FORG0004"; case StaticProperty.EXACTLY_ONE: return "FORG0005"; default: return "XPTY0004"; } } /** * Evaluate the function */ public Item evaluateItem(XPathContext context) throws XPathException { return argument[0].evaluateItem(context); } /** * Iterate over the results of the function */ public SequenceIterator iterate(XPathContext context) throws XPathException { return argument[0].iterate(context); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/functions/JavaExtensionLibrary.java0000644000175000017500000012035211254131444024364 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.Configuration; import net.sf.saxon.expr.*; import net.sf.saxon.om.*; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ExternalObjectType; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.Type; import net.sf.saxon.type.TypeHierarchy; import net.sf.saxon.value.*; import java.io.PrintStream; import java.lang.reflect.*; import java.math.BigDecimal; import java.math.BigInteger; import java.net.URI; import java.net.URL; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; /** * The JavaExtensionLibrary is a FunctionLibrary that binds XPath function calls to * calls on Java methods (or constructors, or fields). It performs a mapping from * the namespace URI of the function to the Java class (the mapping is partly table * driven and partly algorithmic), and maps the local name of the function to the * Java method, constructor, or field within the class. If the Java methods are * polymorphic, then it tries to select the appropriate method based on the static types * of the supplied arguments. Binding is done entirely at XPath compilation time. */ public class JavaExtensionLibrary implements FunctionLibrary { private Configuration config; // HashMap containing URI->Class mappings. This includes conventional // URIs such as the Saxon and EXSLT namespaces, and mapping defined by // the user using saxon:script private HashMap explicitMappings = new HashMap(10); // Output destination for debug messages. At present this cannot be configured. private transient PrintStream diag = System.err; // flag to indicate that only the "java:" URI format is recognized private boolean strictUriFormat = false; /** * Construct a JavaExtensionLibrary and establish the default uri->class mappings. * @param config The Saxon configuration */ public JavaExtensionLibrary(Configuration config) { this.config = config; setDefaultURIMappings(); } /** * Define initial mappings of "well known" namespace URIs to Java classes (this covers * the Saxon and EXSLT extensions). The method is protected so it can be overridden in * a subclass. */ protected void setDefaultURIMappings() { declareJavaClass(NamespaceConstant.SAXON, net.sf.saxon.functions.Extensions.class); declareJavaClass(NamespaceConstant.EXSLT_COMMON, net.sf.saxon.exslt.Common.class); declareJavaClass(NamespaceConstant.EXSLT_SETS, net.sf.saxon.exslt.Sets.class); declareJavaClass(NamespaceConstant.EXSLT_MATH, net.sf.saxon.exslt.Math.class); declareJavaClass(NamespaceConstant.EXSLT_DATES_AND_TIMES, net.sf.saxon.exslt.Date.class); declareJavaClass(NamespaceConstant.EXSLT_RANDOM, net.sf.saxon.exslt.Random.class); } /** * Indicate that only the strict "java:" URI format is to be recognized * @param strict true if only the strict format is recognized */ public void setStrictJavaUriFormat(boolean strict) { strictUriFormat = strict; } /** * Declare a mapping from a specific namespace URI to a Java class * @param uri the namespace URI of the function name * @param theClass the Java class that implements the functions in this namespace */ public void declareJavaClass(String uri, Class theClass) { explicitMappings.put(uri, theClass); } /** * Test whether an extension function with a given name and arity is available. This supports * the function-available() function in XSLT. This method may be called either at compile time * or at run time. * @param functionName The qualified name of the extension function * @param arity The number of arguments. This is set to -1 in the case of the single-argument * function-available() function; in this case the method should return true if there is some */ public boolean isAvailable(StructuredQName functionName, int arity) { if (!config.isAllowExternalFunctions()) { return false; } Class reqClass; try { reqClass = getExternalJavaClass(functionName.getNamespaceURI()); if (reqClass == null) { return false; } } catch (Exception err) { return false; } int significantArgs; Class theClass = reqClass; // if the method name is "new", look for a matching constructor String local = functionName.getLocalName(); if ("new".equals(local)) { int mod = theClass.getModifiers(); if (Modifier.isAbstract(mod)) { return false; } else if (Modifier.isInterface(mod)) { return false; } else if (Modifier.isPrivate(mod)) { return false; } else if (Modifier.isProtected(mod)) { return false; } if (arity == -1) return true; Constructor[] constructors = theClass.getConstructors(); for (int c = 0; c < constructors.length; c++) { Constructor theConstructor = constructors[c]; if (theConstructor.getParameterTypes().length == arity) { return true; } } return false; } else { // convert any hyphens in the name, camelCasing the following character String name = ExtensionFunctionCall.toCamelCase(local, false, diag); // look through the methods of this class to find one that matches the local name Method[] methods = theClass.getMethods(); for (int m = 0; m < methods.length; m++) { Method theMethod = methods[m]; if (theMethod.getName().equals(name) && Modifier.isPublic(theMethod.getModifiers())) { if (arity == -1) return true; Class[] theParameterTypes = theMethod.getParameterTypes(); boolean isStatic = Modifier.isStatic(theMethod.getModifiers()); // if the method is not static, the first supplied argument is the instance, so // discount it significantArgs = (isStatic ? arity : arity - 1); if (significantArgs >= 0) { if (theParameterTypes.length == significantArgs && (significantArgs == 0 || theParameterTypes[0] != XPathContext.class)) { return true; } // we allow the method to have an extra parameter if the first parameter is XPathContext if (theParameterTypes.length == significantArgs + 1 && theParameterTypes[0] == XPathContext.class) { return true; } } } } // look through the fields of this class to find those that matches the local name Field[] fields = theClass.getFields(); for (int m = 0; m < fields.length; m++) { Field theField = fields[m]; if (theField.getName().equals(name) && Modifier.isPublic(theField.getModifiers())) { if (arity == -1) return true; boolean isStatic = Modifier.isStatic(theField.getModifiers()); // if the field is not static, the first supplied argument is the instance, so // discount it significantArgs = (isStatic ? arity : arity - 1); if (significantArgs == 0) { return true; } } } return false; } } /** * Bind an extension function, given the URI and local parts of the function name, * and the list of expressions supplied as arguments. This method is called at compile * time. * @param functionName the qualified name of the function being called * @param staticArgs The expressions supplied statically in the function call. The intention is * that the static type of the arguments (obtainable via getItemType() and getCardinality()) may * be used as part of the binding algorithm. * @param env the static context * @return An object representing the extension function to be called, if one is found; * null if no extension function was found matching the required name, arity, or signature. */ public Expression bind(StructuredQName functionName, Expression[] staticArgs, StaticContext env) throws XPathException { boolean debug = config.isTraceExternalFunctions(); if (!config.isAllowExternalFunctions()) { if (debug) { diag.println("Calls to extension functions have been disabled"); } return null; } Class reqClass; Exception theException = null; ArrayList candidateMethods = new ArrayList(10); Class resultClass = null; try { reqClass = getExternalJavaClass(functionName.getNamespaceURI()); if (reqClass == null) { return null; } } catch (Exception err) { throw new XPathException("Cannot load external Java class", err); } if (debug) { diag.println("Looking for method " + functionName.getLocalName() + " in Java class " + reqClass); diag.println("Number of actual arguments = " + staticArgs.length); } int numArgs = staticArgs.length; int significantArgs; Class theClass = reqClass; // if the method name is "new", look for a matching constructor if ("new".equals(functionName.getLocalName())) { if (debug) { diag.println("Looking for a constructor"); } int mod = theClass.getModifiers(); if (Modifier.isAbstract(mod)) { theException = new XPathException("Class " + theClass + " is abstract"); } else if (Modifier.isInterface(mod)) { theException = new XPathException(theClass + " is an interface"); } else if (Modifier.isPrivate(mod)) { theException = new XPathException("Class " + theClass + " is private"); } else if (Modifier.isProtected(mod)) { theException = new XPathException("Class " + theClass + " is protected"); } if (theException != null) { if (debug) { diag.println("Cannot construct an instance: " + theException.getMessage()); } return null; } Constructor[] constructors = theClass.getConstructors(); for (int c = 0; c < constructors.length; c++) { Constructor theConstructor = constructors[c]; if (debug) { diag.println("Found a constructor with " + theConstructor.getParameterTypes().length + " arguments"); } if (theConstructor.getParameterTypes().length == numArgs) { candidateMethods.add(theConstructor); } } if (candidateMethods.isEmpty()) { theException = new XPathException("No constructor with " + numArgs + (numArgs == 1 ? " parameter" : " parameters") + " found in class " + theClass.getName()); if (debug) { diag.println(theException.getMessage()); } return null; } } else { // convert any hyphens in the name, camelCasing the following character String name = ExtensionFunctionCall.toCamelCase(functionName.getLocalName(), debug, diag); // look through the methods of this class to find one that matches the local name Method[] methods = theClass.getMethods(); boolean consistentReturnType = true; for (int m = 0; m < methods.length; m++) { Method theMethod = methods[m]; if (debug) { if (theMethod.getName().equals(name)) { diag.println("Trying method " + theMethod.getName() + ": name matches"); if (!Modifier.isPublic(theMethod.getModifiers())) { diag.println(" -- but the method is not public"); } } else { diag.println("Trying method " + theMethod.getName() + ": name does not match"); } } if (theMethod.getName().equals(name) && Modifier.isPublic(theMethod.getModifiers())) { if (consistentReturnType) { if (resultClass == null) { resultClass = theMethod.getReturnType(); } else { consistentReturnType = (theMethod.getReturnType() == resultClass); } } Class[] theParameterTypes = theMethod.getParameterTypes(); boolean isStatic = Modifier.isStatic(theMethod.getModifiers()); // if the method is not static, the first supplied argument is the instance, so // discount it if (debug) { diag.println("Method is " + (isStatic ? "" : "not ") + "static"); } significantArgs = (isStatic ? numArgs : numArgs - 1); if (significantArgs >= 0) { if (debug) { if (isStatic) { diag.println("Method has " + theParameterTypes.length + " argument" + (theParameterTypes.length == 1 ? "" : "s") + "; expecting " + significantArgs); } else { diag.println("Method has " + theParameterTypes.length + " argument" + (theParameterTypes.length == 1 ? "" : "s") + "; expecting " + numArgs + " plus one for the target object"); } } if (theParameterTypes.length == significantArgs && (significantArgs == 0 || theParameterTypes[0] != XPathContext.class)) { if (debug) { diag.println("Found a candidate method:"); diag.println(" " + theMethod); } candidateMethods.add(theMethod); } // we allow the method to have an extra parameter if the first parameter is XPathContext if (theParameterTypes.length == significantArgs + 1 && theParameterTypes[0] == XPathContext.class) { if (debug) { diag.println("Method is a candidate because first argument is XPathContext"); } candidateMethods.add(theMethod); } } } } // Code added by GS -- start // look through the fields of this class to find those that matches the local name Field[] fields = theClass.getFields(); for (int m = 0; m < fields.length; m++) { Field theField = fields[m]; if (debug) { if (theField.getName().equals(name)) { diag.println("Trying field " + theField.getName() + ": name matches"); if (!Modifier.isPublic(theField.getModifiers())) { diag.println(" -- but the field is not public"); } } else { diag.println("Trying field " + theField.getName() + ": name does not match"); } } if (theField.getName().equals(name) && Modifier.isPublic(theField.getModifiers())) { if (consistentReturnType) { if (resultClass == null) { resultClass = theField.getType(); } else { consistentReturnType = (theField.getType() == resultClass); } } boolean isStatic = Modifier.isStatic(theField.getModifiers()); // if the field is not static, the first supplied argument is the instance, so // discount it if (debug) { diag.println("Field is " + (isStatic ? "" : "not ") + "static"); } significantArgs = (isStatic ? numArgs : numArgs - 1); if (significantArgs == 0) { if (debug) { diag.println("Found a candidate field:"); diag.println(" " + theField); } candidateMethods.add(theField); } } } // End of code added by GS // No method found? if (candidateMethods.isEmpty()) { theException = new XPathException("No method or field matching " + name + " with " + numArgs + (numArgs == 1 ? " parameter" : " parameters") + " found in class " + theClass.getName()); if (debug) { diag.println(theException.getMessage()); } return null; } } if (candidateMethods.isEmpty()) { if (debug) { diag.println("There is no suitable method matching the arguments of function " + functionName.getLocalName()); } return null; } AccessibleObject method = getBestFit(candidateMethods, staticArgs, theClass); if (method == null) { if (candidateMethods.size() > 1) { // There was more than one candidate method, and we can't decide which to use. // This may be because insufficient type information is available at this stage. // Return an UnresolvedExtensionFunction, and try to resolve it later when more // type information is known. return new UnresolvedExtensionFunction(functionName, theClass, candidateMethods, staticArgs); } return null; } else { JavaExtensionFunctionFactory factory = (JavaExtensionFunctionFactory)config.getExtensionFunctionFactory("java"); return factory.makeExtensionFunctionCall(functionName, theClass, method, staticArgs); } } /** * Get the best fit amongst all the candidate methods, constructors, or fields, based on the static types * of the supplied arguments * @param candidateMethods a list of all the methods, fields, and constructors that match the extension * function call in name and arity (but not necessarily in the types of the arguments) * @param args the expressions supplied as arguments. * @param theClass the class that implements the extension function * @return the result is either a Method or a Constructor or a Field, or null if no unique best fit * method could be found. */ private AccessibleObject getBestFit(List candidateMethods, Expression[] args, Class theClass) { boolean debug = config.isTraceExternalFunctions(); int candidates = candidateMethods.size(); if (candidates == 1) { // short cut: there is only one candidate method return (AccessibleObject) candidateMethods.get(0); } else { // choose the best fit method or constructor or field // for each pair of candidate methods, eliminate either or both of the pair // if one argument is less-preferred if (debug) { diag.println("Finding best fit method for arguments"); } boolean eliminated[] = new boolean[candidates]; for (int i = 0; i < candidates; i++) { eliminated[i] = false; } if (debug) { for (int i = 0; i < candidates; i++) { int[] pref_i = getConversionPreferences( args, (AccessibleObject)candidateMethods.get(i), theClass); diag.println("Trying option " + i + ": " + candidateMethods.get(i).toString()); if (pref_i == null) { diag.println("Arguments cannot be converted to required types"); } else { String prefs = "["; for (int p = 0; p < pref_i.length; p++) { if (p != 0) prefs += ", "; prefs += pref_i[p]; } prefs += "]"; diag.println("Conversion preferences are " + prefs); } } } for (int i = 0; i < candidates; i++) { int[] pref_i = getConversionPreferences( args, (AccessibleObject) candidateMethods.get(i), theClass); if (pref_i == null) { eliminated[i] = true; } if (!eliminated[i]) { for (int j = i + 1; j < candidates; j++) { if (!eliminated[j]) { int[] pref_j = getConversionPreferences( args, (AccessibleObject) candidateMethods.get(j), theClass); if (pref_j == null) { eliminated[j] = true; } else { for (int k = 0; k < pref_j.length; k++) { if (pref_i[k] > pref_j[k] && !eliminated[i]) { // high number means less preferred eliminated[i] = true; if (debug) { diag.println("Eliminating option " + i); } } if (pref_i[k] < pref_j[k] && !eliminated[j]) { eliminated[j] = true; if (debug) { diag.println("Eliminating option " + j); } } } } } } } } int remaining = 0; AccessibleObject theMethod = null; for (int r = 0; r < candidates; r++) { if (!eliminated[r]) { theMethod = (AccessibleObject) candidateMethods.get(r); remaining++; } } if (debug) { diag.println("Number of candidate methods remaining: " + remaining); } if (remaining == 0) { if (debug) { diag.println("There are " + candidates + " candidate Java methods matching the function name, but none is a unique best match"); } return null; } if (remaining > 1) { if (debug) { diag.println("There are several Java methods that match the function name equally well"); } return null; } return theMethod; } } /** * Get an array of integers representing the conversion distances of each "real" argument * to a given method * @param args the actual expressions supplied in the function call * @param method the method or constructor. * @param theClass the class that implements the extension function * @return an array of integers, one for each argument, indicating the conversion * distances. A high number indicates low preference. If any of the arguments cannot * be converted to the corresponding type defined in the method signature, return null. */ private int[] getConversionPreferences(Expression[] args, AccessibleObject method, Class theClass) { Class[] params; int firstArg; TypeHierarchy th = config.getTypeHierarchy(); if (method instanceof Constructor) { firstArg = 0; params = ((Constructor) method).getParameterTypes(); } else if (method instanceof Method) { boolean isStatic = Modifier.isStatic(((Method) method).getModifiers()); firstArg = (isStatic ? 0 : 1); params = ((Method) method).getParameterTypes(); } else if (method instanceof Field) { boolean isStatic = Modifier.isStatic(((Field) method).getModifiers()); firstArg = (isStatic ? 0 : 1); params = NO_PARAMS; } else { throw new AssertionError("property " + method + " was neither constructor, method, nor field"); } int noOfArgs = args.length; int preferences[] = new int[noOfArgs]; int firstParam = 0; if (params.length > 0 && params[0] == XPathContext.class) { firstParam = 1; } for (int i = firstArg; i < noOfArgs; i++) { preferences[i] = getConversionPreference(th, args[i], params[i + firstParam - firstArg]); if (preferences[i] == -1) { return null; } } if (firstArg == 1) { preferences[0] = getConversionPreference(th, args[0], theClass); if (preferences[0] == -1) { return null; } } return preferences; } /** * Get the conversion preference from a given XPath type to a given Java class * @param th the type hierarchy cache * @param arg the supplied XPath expression (the static type of this expression * is used as input to the algorithm) * @param required the Java class of the relevant argument of the Java method * @return the conversion preference. A high number indicates a low preference; * -1 indicates that conversion is not possible. */ private int getConversionPreference(TypeHierarchy th, Expression arg, Class required) { ItemType itemType = arg.getItemType(th); int cardinality = arg.getCardinality(); if (required == Object.class) { return 100; } else if (Cardinality.allowsMany(cardinality)) { if (required.isAssignableFrom(SequenceIterator.class)) { return 20; } else if (required.isAssignableFrom(Value.class)) { return 21; } else if (Collection.class.isAssignableFrom(required)) { return 22; } else if (required.isArray()) { return 24; // sort out at run-time whether the component type of the array is actually suitable } else { return 80; // conversion possible only if external object model supports it } } else { if (Type.isNodeType(itemType)) { if (required.isAssignableFrom(NodeInfo.class)) { return 20; } else if (required.isAssignableFrom(DocumentInfo.class)) { return 21; } else { return 80; } } else if (itemType instanceof ExternalObjectType) { Class ext = ((ExternalObjectType)itemType).getJavaClass(); if (required.isAssignableFrom(ext)) { return 10; } else { return -1; } } else { int primitiveType = itemType.getPrimitiveType(); return atomicConversionPreference(primitiveType, required); } } } private static final Class[] NO_PARAMS = new Class[0]; /** * Get the conversion preference from an XPath primitive atomic type to a Java class * @param primitiveType integer code identifying the XPath primitive type, for example * {@link StandardNames#XS_STRING} or {@link StandardNames#XS_STRING} * @param required The Java Class named in the method signature * @return an integer indicating the relative preference for converting this primitive type * to this Java class. A high number indicates a low preference. All values are in the range * 50 to 100. For example, the conversion of an XPath String to {@link net.sf.saxon.value.StringValue} is 50, while * XPath String to {@link java.lang.String} is 51. The value -1 indicates that the conversion is not allowed. */ protected int atomicConversionPreference(int primitiveType, Class required) { if (required == Object.class) return 100; switch (primitiveType) { case StandardNames.XS_STRING: if (required.isAssignableFrom(StringValue.class)) return 50; if (required == String.class) return 51; if (required == CharSequence.class) return 51; return -1; case StandardNames.XS_DOUBLE: if (required.isAssignableFrom(DoubleValue.class)) return 50; if (required == double.class) return 50; if (required == Double.class) return 51; return -1; case StandardNames.XS_FLOAT: if (required.isAssignableFrom(FloatValue.class)) return 50; if (required == float.class) return 50; if (required == Float.class) return 51; if (required == double.class) return 52; if (required == Double.class) return 53; return -1; case StandardNames.XS_DECIMAL: if (required.isAssignableFrom(DecimalValue.class)) return 50; if (required == BigDecimal.class) return 50; if (required == double.class) return 51; if (required == Double.class) return 52; if (required == float.class) return 53; if (required == Float.class) return 54; return -1; case StandardNames.XS_INTEGER: if (required.isAssignableFrom(Int64Value.class)) return 50; if (required == BigInteger.class) return 51; if (required == BigDecimal.class) return 52; if (required == long.class) return 53; if (required == Long.class) return 54; if (required == int.class) return 55; if (required == Integer.class) return 56; if (required == short.class) return 57; if (required == Short.class) return 58; if (required == byte.class) return 59; if (required == Byte.class) return 60; if (required == double.class) return 61; if (required == Double.class) return 62; if (required == float.class) return 63; if (required == Float.class) return 64; return -1; case StandardNames.XS_BOOLEAN: if (required.isAssignableFrom(BooleanValue.class)) return 50; if (required == boolean.class) return 51; if (required == Boolean.class) return 52; return -1; case StandardNames.XS_DATE: case StandardNames.XS_G_DAY: case StandardNames.XS_G_MONTH_DAY: case StandardNames.XS_G_MONTH: case StandardNames.XS_G_YEAR_MONTH: case StandardNames.XS_G_YEAR: if (required.isAssignableFrom(DateValue.class)) return 50; if (required.isAssignableFrom(Date.class)) return 51; return -1; case StandardNames.XS_DATE_TIME: if (required.isAssignableFrom(DateTimeValue.class)) return 50; if (required.isAssignableFrom(Date.class)) return 51; return -1; case StandardNames.XS_TIME: if (required.isAssignableFrom(TimeValue.class)) return 50; return -1; case StandardNames.XS_DURATION: case StandardNames.XS_YEAR_MONTH_DURATION: case StandardNames.XS_DAY_TIME_DURATION: if (required.isAssignableFrom(DurationValue.class)) return 50; return -1; case StandardNames.XS_ANY_URI: if (required.isAssignableFrom(AnyURIValue.class)) return 50; if (required == URI.class) return 51; if (required == URL.class) return 52; if (required == String.class) return 53; if (required == CharSequence.class) return 53; return -1; case StandardNames.XS_QNAME: if (required.isAssignableFrom(QualifiedNameValue.class)) return 50; //if (required.isAssignableFrom(QName.class)) return 51; // TODO: reinstate above line under JDK 1.5 if (required.getClass().getName().equals("javax.xml.namespace.QName")) return 51; return -1; case StandardNames.XS_BASE64_BINARY: if (required.isAssignableFrom(Base64BinaryValue.class)) return 50; return -1; case StandardNames.XS_HEX_BINARY: if (required.isAssignableFrom(HexBinaryValue.class)) return 50; return -1; case StandardNames.XS_UNTYPED_ATOMIC: return 50; default: return -1; } } /** * Get an external Java class corresponding to a given namespace prefix, if there is * one. * @param uri The namespace URI corresponding to the prefix used in the function call. * @return the Java class name if a suitable class exists, otherwise return null. */ private Class getExternalJavaClass(String uri) { // First see if an explicit mapping has been registered for this URI Class c = (Class) explicitMappings.get(uri); if (c != null) { return c; } // Failing that, try to identify a class directly from the URI try { // support the URN format java:full.class.Name if (uri.startsWith("java:")) { return config.getClass(uri.substring(5), config.isTraceExternalFunctions(), null); } if (strictUriFormat) { return null; } else { // extract the class name as anything in the URI after the last "/" // if there is one, or the whole class name otherwise int slash = uri.lastIndexOf('/'); if (slash < 0) { return config.getClass(uri, config.isTraceExternalFunctions(), null); } else if (slash == uri.length() - 1) { return null; } else { return config.getClass(uri.substring(slash + 1), config.isTraceExternalFunctions(), null); } } } catch (XPathException err) { return null; } } /** * Inner class representing an unresolved extension function call. This arises when there is insufficient * static type information available at the time the function call is parsed to determine which of several * candidate Java methods to invoke. The function call cannot be executed; it must be resolved to an * actual Java method during the analysis phase. */ private class UnresolvedExtensionFunction extends CompileTimeFunction { private List candidateMethods; private Class theClass; public UnresolvedExtensionFunction(StructuredQName functionName, Class theClass, List candidateMethods, Expression[] staticArgs) { setArguments(staticArgs); setFunctionName(functionName); this.theClass = theClass; this.candidateMethods = candidateMethods; } /** * Type-check the expression. */ public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { for (int i=0; i *

The difference between this method and {@link #getCollator} is that a * GenericAtomicComparer is capable of comparing values of any atomic type, not only * strings. It is therefore called by functions such as compare, deep-equal, index-of, and * min() and max() where the operands may include a mixture of strings and other types.

* * @param arg the position of the argument (starting at 0) containing the collation name. * If this argument was not supplied, the default collation is used * @param context The dynamic evaluation context. * @return a GenericAtomicComparer that can be used to compare atomic values. */ protected GenericAtomicComparer getAtomicComparer(int arg, XPathContext context) throws XPathException { // TODO:PERF avoid creating a new object on each call when the collation is specified dynamically return new GenericAtomicComparer(getCollator(arg, context), context); } /** * Get a collator suitable for comparing strings. Returns the collator specified in the * given function argument if present, otherwise returns the default collator. This method is * called by subclasses at run time. It is used (in contrast to {@link #getAtomicComparer}) * when it is known that the values to be compared are always strings. * * @param arg The argument position (counting from zero) that holds the collation * URI if present * @param context The dynamic context * @return a StringCollator */ protected StringCollator getCollator(int arg, XPathContext context) throws XPathException { if (stringCollator != null) { // the collation was determined statically return stringCollator; } else { int numargs = argument.length; if (numargs > arg) { AtomicValue av = (AtomicValue) argument[arg].evaluateItem(context); StringValue collationValue = (StringValue) av; String collationName = collationValue.getStringValue(); URI collationURI; try { collationURI = new URI(collationName); if (!collationURI.isAbsolute()) { if (expressionBaseURI == null) { XPathException err = new XPathException("Cannot resolve relative collation URI '" + collationName + "': unknown or invalid base URI"); err.setErrorCode("FOCH0002"); err.setXPathContext(context); err.setLocator(this); throw err; } collationURI = expressionBaseURI.resolve(collationURI); collationName = collationURI.toString(); } } catch (URISyntaxException e) { XPathException err = new XPathException("Collation name '" + collationName + "' is not a valid URI"); err.setErrorCode("FOCH0002"); err.setXPathContext(context); err.setLocator(this); throw err; } return context.getCollation(collationName); } else { StringCollator collator = context.getDefaultCollation(); return (collator == null ? CodepointCollator.getInstance() : collator); } } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/functions/Position.java0000644000175000017500000000427311033112257022064 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.expr.Expression; import net.sf.saxon.expr.ExpressionVisitor; import net.sf.saxon.expr.StaticProperty; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.Item; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ItemType; import net.sf.saxon.value.Int64Value; public class Position extends SystemFunction { /** * preEvaluate: this method suppresses compile-time evaluation by doing nothing * (because the value of the expression depends on the runtime context) * @param visitor an expression visitor */ public Expression preEvaluate(ExpressionVisitor visitor) { return this; } public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { if (contextItemType == null) { XPathException err = new XPathException("The context for position() is undefined"); err.setErrorCode("XPDY0002"); err.setIsTypeError(true); err.setLocator(this); throw err; } return super.typeCheck(visitor, contextItemType); } /** * Evaluate in a general context */ public Item evaluateItem(XPathContext c) throws XPathException { return Int64Value.makeIntegerValue(c.getContextPosition()); } /** * Determine the intrinsic dependencies */ public int getIntrinsicDependencies() { return StaticProperty.DEPENDS_ON_POSITION; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/functions/VendorFunctionLibrary.java0000644000175000017500000002553311033112257024552 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.trans.Err; import net.sf.saxon.expr.Expression; import net.sf.saxon.expr.StaticContext; import net.sf.saxon.expr.StaticProperty; import net.sf.saxon.om.NamespaceConstant; import net.sf.saxon.om.StructuredQName; import net.sf.saxon.pattern.NodeKindTest; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.BuiltInAtomicType; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.Type; import java.util.HashMap; /** * The VendorFunctionLibrary represents specially-recognized functions in the Saxon namespace. It doesn't * handle Saxon extension functions that are implemented as normal extension functions, which are bound using * the {@link net.sf.saxon.functions.JavaExtensionLibrary}. */ public class VendorFunctionLibrary implements FunctionLibrary { private HashMap functionTable; /** * Create the Vendor Function Library for Saxon */ public VendorFunctionLibrary() { init(); } /** * Register an extension function in the table of function details. * @param name the function name * @param implementationClass the class used to implement the function * @param opcode identifies the function when a single class implements several functions * @param minArguments the minimum number of arguments required * @param maxArguments the maximum number of arguments allowed * @param itemType the item type of the result of the function * @param cardinality the cardinality of the result of the function * @return the entry describing the function. The entry is incomplete, it does not yet contain information * about the function arguments. */ protected StandardFunction.Entry register( String name, Class implementationClass, int opcode, int minArguments, int maxArguments, ItemType itemType, int cardinality ) { StandardFunction.Entry e = StandardFunction.makeEntry( name, implementationClass, opcode, minArguments, maxArguments, itemType, cardinality); functionTable.put(name, e); return e; } protected void init() { functionTable = new HashMap(30); StandardFunction.Entry e; e = register("evaluate", Evaluate.class, Evaluate.EVALUATE, 1, 10, Type.ITEM_TYPE, StaticProperty.ALLOWS_ZERO_OR_MORE); StandardFunction.arg(e, 0, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE, null); e = register("evaluate-node", Evaluate.class, Evaluate.EVALUATE_NODE, 1, 1, Type.ITEM_TYPE, StaticProperty.ALLOWS_ZERO_OR_MORE); StandardFunction.arg(e, 0, Type.NODE_TYPE, StaticProperty.EXACTLY_ONE, null); e = register("eval", Evaluate.class, Evaluate.EVAL, 1, 10, Type.ITEM_TYPE, StaticProperty.ALLOWS_ZERO_OR_MORE); StandardFunction.arg(e, 0, BuiltInAtomicType.ANY_ATOMIC, StaticProperty.EXACTLY_ONE, null); e = register("expression", Evaluate.class, Evaluate.EXPRESSION, 1, 2, BuiltInAtomicType.ANY_ATOMIC, StaticProperty.EXACTLY_ONE); StandardFunction.arg(e, 0, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE, null); StandardFunction.arg(e, 1, NodeKindTest.ELEMENT, StaticProperty.EXACTLY_ONE, null); e = register("is-whole-number", IsWholeNumber.class, 1, 1, 1, BuiltInAtomicType.BOOLEAN, StaticProperty.EXACTLY_ONE); StandardFunction.arg(e, 0, BuiltInAtomicType.NUMERIC, StaticProperty.ALLOWS_ZERO_OR_ONE, null); e = register("item-at", ItemAt.class, 1, 2, 2, StandardFunction.SAME_AS_FIRST_ARGUMENT, StaticProperty.ALLOWS_ZERO_OR_ONE); StandardFunction.arg(e, 0, Type.ITEM_TYPE, StaticProperty.ALLOWS_ZERO_OR_MORE, null); StandardFunction.arg(e, 1, BuiltInAtomicType.NUMERIC, StaticProperty.ALLOWS_ZERO_OR_ONE, null); e = register("parse", Parse.class, 0, 1, 1, NodeKindTest.DOCUMENT, StaticProperty.EXACTLY_ONE); StandardFunction.arg(e, 0, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE, null); e = register("serialize", Serialize.class, 0, 2, 2, BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE); StandardFunction.arg(e, 0, Type.NODE_TYPE, StaticProperty.ALLOWS_ZERO_OR_ONE, null); StandardFunction.arg(e, 1, Type.ITEM_TYPE, StaticProperty.EXACTLY_ONE, null); } /** * Test whether a Saxon function with a given name and arity is available. This supports * the function-available() function in XSLT. This method may be called either at compile time * or at run time. * @param functionName the name of the function * @param arity The number of arguments. This is set to -1 in the case of the single-argument * function-available() function; in this case the method should return true if there is some */ public boolean isAvailable(StructuredQName functionName, int arity) { if (functionName.getNamespaceURI().equals(NamespaceConstant.SAXON)) { StandardFunction.Entry entry = (StandardFunction.Entry)functionTable.get(functionName.getLocalName()); return entry != null && (arity == -1 || (arity >= entry.minArguments && arity <= entry.maxArguments)); } else { return false; } } /** * Bind an extension function, given the URI and local parts of the function name, * and the list of expressions supplied as arguments. This method is called at compile * time. * @param functionName the name of the function * @param staticArgs The expressions supplied statically in the function call. The intention is * that the static type of the arguments (obtainable via getItemType() and getCardinality() may * be used as part of the binding algorithm. * @param env * @return An object representing the extension function to be called, if one is found; * null if no extension function was found matching the required name and arity. * @throws net.sf.saxon.trans.XPathException if a function is found with the required name and arity, but * the implementation of the function cannot be loaded or used; or if an error occurs * while searching for the function; or if this function library "owns" the namespace containing * the function call, but no function was found. */ public Expression bind(StructuredQName functionName, Expression[] staticArgs, StaticContext env) throws XPathException { String uri = functionName.getNamespaceURI(); String local = functionName.getLocalName(); if (uri.equals(NamespaceConstant.SAXON)) { StandardFunction.Entry entry = (StandardFunction.Entry)functionTable.get(local); if (entry == null) { return null; } Class functionClass = entry.implementationClass; SystemFunction f; try { f = (SystemFunction)functionClass.newInstance(); } catch (Exception err) { throw new AssertionError("Failed to load Saxon extension function: " + err.getMessage()); } f.setDetails(entry); f.setFunctionName(functionName); f.setArguments(staticArgs); checkArgumentCount(staticArgs.length, entry.minArguments, entry.maxArguments, local); return f; } else { return null; } } /** * Make a Saxon function with a given name * @param localName the local name of the function * @param env the static context * @param arguments the arguments of the function * @return an exprssion representing a call on the given function */ public Expression makeSaxonFunction(String localName, StaticContext env, Expression[] arguments) throws XPathException { String uri = NamespaceConstant.SAXON; StructuredQName functionName = new StructuredQName("saxon", uri, localName); return bind(functionName, arguments, env); } /** * Check number of arguments.
* A convenience routine for use in subclasses. * @param numArgs the actual number of arguments * @param min the minimum number of arguments allowed * @param max the maximum number of arguments allowed * @param local the local name of the function, used for diagnostics * @return the actual number of arguments * @throws net.sf.saxon.trans.XPathException if the number of arguments is out of range */ private int checkArgumentCount(int numArgs, int min, int max, String local) throws XPathException { if (min==max && numArgs != min) { throw new XPathException("Function " + Err.wrap("saxon:"+local, Err.FUNCTION) + " must have " + min + pluralArguments(min)); } if (numArgs < min) { throw new XPathException("Function " + Err.wrap("saxon:"+local, Err.FUNCTION) + " must have at least " + min + pluralArguments(min)); } if (numArgs > max) { throw new XPathException("Function " + Err.wrap("saxon:"+local, Err.FUNCTION) + " must have no more than " + max + pluralArguments(max)); } return numArgs; } /** * Utility routine used in constructing error messages * @param num a number * @return the string " argument" or " arguments" if num is plural */ public static String pluralArguments(int num) { if (num==1) return " argument"; return " arguments"; } /** * This method creates a copy of a FunctionLibrary: if the original FunctionLibrary allows * new functions to be added, then additions to this copy will not affect the original, or * vice versa. * * @return a copy of this function library. This must be an instance of the original class. */ public FunctionLibrary copy() { return this; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. //saxonb-9.1.0.8/bj/net/sf/saxon/functions/Id.java0000644000175000017500000002147611033112257020620 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.expr.*; import net.sf.saxon.om.*; import net.sf.saxon.sort.DocumentOrderIterator; import net.sf.saxon.sort.LocalOrderComparer; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.AtomicValue; import net.sf.saxon.value.Cardinality; import net.sf.saxon.value.Whitespace; import net.sf.saxon.type.Type; import net.sf.saxon.pattern.NodeKindTest; /** * The XPath id() function * XPath 2.0 version: accepts any sequence as the first parameter; each item in the sequence * is taken as an IDREFS value, that is, a space-separated list of ID values. * Also accepts an optional second argument to identify the target document, this * defaults to the context node. */ public class Id extends SystemFunction { private boolean isSingletonId = false; /** * Simplify: add a second implicit argument, the context document * @param visitor an expression visitor */ public Expression simplify(ExpressionVisitor visitor) throws XPathException { Id id = (Id)super.simplify(visitor); if (argument.length == 1) { id.addContextDocumentArgument(1, "id"); } return id; } /** * Static analysis: prevent sorting of the argument */ public void checkArguments(ExpressionVisitor visitor) throws XPathException { super.checkArguments(visitor); Optimizer opt = visitor.getConfiguration().getOptimizer(); argument[0] = ExpressionTool.unsorted(opt, argument[0], false); isSingletonId = !Cardinality.allowsMany(argument[0].getCardinality()); } /** * preEvaluate: this method suppresses compile-time evaluation by doing nothing * @param visitor an expression visitor */ public Expression preEvaluate(ExpressionVisitor visitor) { return this; } /** * Get the static properties of this expression (other than its type). The result is * bit-signficant. These properties are used for optimizations. In general, if * property bit is set, it is true, but if it is unset, the value is unknown. */ public int computeSpecialProperties() { int prop = StaticProperty.ORDERED_NODESET | StaticProperty.SINGLE_DOCUMENT_NODESET | StaticProperty.NON_CREATIVE; if ((getNumberOfArguments() == 1) || (argument[1].getSpecialProperties() & StaticProperty.CONTEXT_DOCUMENT_NODESET) != 0) { prop |= StaticProperty.CONTEXT_DOCUMENT_NODESET; } return prop; } /** * Add a representation of a doc() call or similar function to a PathMap. * This is a convenience method called by the addToPathMap() methods for doc(), document(), collection() * and similar functions. These all create a new root expression in the path map. * * @param pathMap the PathMap to which the expression should be added * @param pathMapNodeSet * @return the pathMapNode representing the focus established by this expression, in the case where this * expression is the first operand of a path expression or filter expression */ public PathMap.PathMapNodeSet addToPathMap(PathMap pathMap, PathMap.PathMapNodeSet pathMapNodeSet) { argument[0].addToPathMap(pathMap, pathMapNodeSet); PathMap.PathMapNodeSet target = argument[1].addToPathMap(pathMap, pathMapNodeSet); // indicate that the function navigates to all elements in the document AxisExpression allElements = new AxisExpression(Axis.DESCENDANT, NodeKindTest.ELEMENT); allElements.setContainer(getContainer()); target = target.createArc(allElements); // if (isStringValueUsed()) { // target.setAtomized(); // } return target; } /** * Evaluate the function to return an iteration of selected nodes. */ public SequenceIterator iterate(XPathContext context) throws XPathException { NodeInfo arg1 = (NodeInfo)argument[1].evaluateItem(context); // TODO: test K2-SeqIDFunc-3: we are getting XPTY0020 instead of XPTY0004 when the context item is not a node arg1 = arg1.getRoot(); if (arg1.getNodeKind() != Type.DOCUMENT) { dynamicError("In the id() function," + " the tree being searched must be one whose root is a document node", "FODC0001", context); return null; } DocumentInfo doc = (DocumentInfo)arg1; if (isSingletonId) { AtomicValue arg = (AtomicValue)argument[0].evaluateItem(context); if (arg==null) { return EmptyIterator.getInstance(); } String idrefs = arg.getStringValue(); return getIdSingle(doc, idrefs); } else { SequenceIterator idrefs = argument[0].iterate(context); return getIdMultiple(doc, idrefs); } } /** * Get an iterator over the nodes that have an id equal to one of the values is a whitespace separated * string * @param doc The document to be searched * @param idrefs a string containing zero or more whitespace-separated ID values to be found in the document * @return an iterator over the nodes whose ID is one of the specified values * @throws XPathException */ public static SequenceIterator getIdSingle(DocumentInfo doc, String idrefs) throws XPathException { boolean white = false; for (int i=idrefs.length()-1; i>=0; i--) { char c = idrefs.charAt(i); if (c <= 0x20 && (c == 0x20 || c == 0x09 || c == 0x0a || c == 0x0d)) { white = true; break; } } if (white) { StringTokenIterator tokens = new StringTokenIterator(idrefs); IdMappingFunction map = new IdMappingFunction(); map.document = doc; SequenceIterator result = new MappingIterator(tokens, map); return new DocumentOrderIterator(result, LocalOrderComparer.getInstance()); } else { return SingletonIterator.makeIterator(doc.selectID(idrefs)); } } /** * Get an iterator over the nodes that have an id equal to one of the values is a set of whitespace separated * strings * @param doc The document to be searched * @param idrefs an iterator over a set of strings each of which is a string containing * zero or more whitespace-separated ID values to be found in the document * @return an iterator over the nodes whose ID is one of the specified values * @throws XPathException */ public static SequenceIterator getIdMultiple(DocumentInfo doc, SequenceIterator idrefs) throws XPathException { IdMappingFunction map = new IdMappingFunction(); map.document = doc; SequenceIterator result = new MappingIterator(idrefs, map); return new DocumentOrderIterator(result, LocalOrderComparer.getInstance()); } private static class IdMappingFunction implements MappingFunction { public DocumentInfo document; /** * Evaluate the function for a single string value * (implements the MappingFunction interface) */ public SequenceIterator map(Item item) throws XPathException { String idrefs = Whitespace.trim(item.getStringValueCS()); // If this value contains a space, we need to break it up into its // separate tokens; if not, we can process it directly boolean white = false; for (int i=idrefs.length()-1; i>=0; i--) { char c = idrefs.charAt(i); if (c <= 0x20 && (c == 0x20 || c == 0x09 || c == 0x0a || c == 0x0d)) { white = true; break; } } if (white) { StringTokenIterator tokens = new StringTokenIterator(idrefs); IdMappingFunction submap = new IdMappingFunction(); submap.document = document; return new MappingIterator(tokens, submap); } else { return SingletonIterator.makeIterator(document.selectID(idrefs)); } } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/functions/KeyFn.java0000644000175000017500000003272411033112257021276 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.Controller; import net.sf.saxon.pattern.NodeKindTest; import net.sf.saxon.pattern.AnyNodeTest; import net.sf.saxon.expr.*; import net.sf.saxon.om.*; import net.sf.saxon.sort.DocumentOrderIterator; import net.sf.saxon.sort.LocalOrderComparer; import net.sf.saxon.style.ExpressionContext; import net.sf.saxon.trans.*; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.Type; import net.sf.saxon.value.AtomicValue; import net.sf.saxon.value.Cardinality; public class KeyFn extends SystemFunction implements XSLTFunction { private NamespaceResolver nsContext = null; private KeyDefinitionSet staticKeySet = null; // null if name resolution is done at run-time private transient boolean checked = false; private transient boolean internal = false; // the second time checkArguments is called, it's a global check so the static context is inaccurate /** * Get the key name, if known statically. If not known statically, return null. * @return the key name if known, otherwise null */ public StructuredQName getStaticKeyName() { return (staticKeySet == null ? null : staticKeySet.getKeyName()); } /** * Type-check the expression. This also calls preEvaluate() to evaluate the function * if all the arguments are constant; functions that do not require this behavior * can override the preEvaluate method. */ public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { try { return super.typeCheck(visitor, contextItemType); } catch (XPathException err) { if ("XPDY0002".equals(err.getErrorCodeLocalPart())) { XPathException e = new XPathException("Cannot call the key() function when there is no context node"); e.setErrorCode("XTDE1270"); e.maybeSetLocation(this); throw e; } throw err; } } /** * Non-standard constructor to create an internal call on key() with a known key definition * @param keySet the set of KeyDefinitions (always a single KeyDefinition) * @param name the name allocated to the key (first argument of the function) * @param value the value being searched for (second argument of the function) * @param doc the document being searched (third argument) * @return a call on the key() function */ public static KeyFn internalKeyCall(KeyDefinitionSet keySet, String name, Expression value, Expression doc) { KeyFn k = new KeyFn(); k.argument = new Expression[] {new StringLiteral(name), value, doc}; k.staticKeySet = keySet; k.checked = true; k.internal = true; k.setDetails(StandardFunction.getFunction("key", 3)); k.setFunctionName(FN_KEY); k.adoptChildExpression(value); k.adoptChildExpression(doc); return k; } private final static StructuredQName FN_KEY = new StructuredQName("fn", NamespaceConstant.FN, "key"); /** * Simplify: add a third implicit argument, the context document * @param visitor the expression visitor */ public Expression simplify(ExpressionVisitor visitor) throws XPathException { if (!internal && !(visitor.getStaticContext() instanceof ExpressionContext)) { throw new XPathException("The key() function is available only in XPath expressions within an XSLT stylesheet"); } KeyFn f = (KeyFn)super.simplify(visitor); if (argument.length == 2) { f.addContextDocumentArgument(2, "key"); } return f; } public void checkArguments(ExpressionVisitor visitor) throws XPathException { if (checked) return; checked = true; super.checkArguments(visitor); Optimizer opt = visitor.getConfiguration().getOptimizer(); argument[1] = ExpressionTool.unsorted(opt, argument[1], false); if (argument[0] instanceof StringLiteral) { // common case, key name is supplied as a constant StructuredQName keyName; try { keyName = ((ExpressionContext)visitor.getStaticContext()).getStructuredQName( ((StringLiteral)argument[0]).getStringValue(), false); } catch (XPathException e) { XPathException err = new XPathException("Error in key name " + ((StringLiteral)argument[0]).getStringValue() + ": " + e.getMessage()); err.setLocator(this); err.setErrorCode("XTDE1260"); throw err; } staticKeySet = visitor.getExecutable().getKeyManager().getKeyDefinitionSet(keyName); if (staticKeySet == null) { XPathException err = new XPathException("Key " + ((StringLiteral)argument[0]).getStringValue() + " has not been defined"); err.setLocator(this); err.setErrorCode("XTDE1260"); throw err; } } else { // we need to save the namespace context nsContext = visitor.getStaticContext().getNamespaceResolver(); } } /** * Get the static properties of this expression (other than its type). The result is * bit-signficant. These properties are used for optimizations. In general, if * a property bit is set, it is true, but if it is unset, the value is unknown. */ public int computeSpecialProperties() { int prop = StaticProperty.ORDERED_NODESET | StaticProperty.SINGLE_DOCUMENT_NODESET | StaticProperty.NON_CREATIVE; if ((getNumberOfArguments() == 2) || (argument[2].getSpecialProperties() & StaticProperty.CONTEXT_DOCUMENT_NODESET) != 0) { prop |= StaticProperty.CONTEXT_DOCUMENT_NODESET; } return prop; } /** * preEvaluate: this method suppresses compile-time evaluation by doing nothing * @param visitor the expression visitor */ public Expression preEvaluate(ExpressionVisitor visitor) { return this; } /** * Add a representation of a doc() call or similar function to a PathMap. * This is a convenience method called by the addToPathMap() methods for doc(), document(), collection() * and similar functions. These all create a new root expression in the path map. * * @param pathMap the PathMap to which the expression should be added * @param pathMapNodeSet * @return the pathMapNode representing the focus established by this expression, in the case where this * expression is the first operand of a path expression or filter expression */ public PathMap.PathMapNodeSet addToPathMap(PathMap pathMap, PathMap.PathMapNodeSet pathMapNodeSet) { argument[0].addToPathMap(pathMap, pathMapNodeSet); argument[1].addToPathMap(pathMap, pathMapNodeSet); PathMap.PathMapNodeSet target = argument[2].addToPathMap(pathMap, pathMapNodeSet); // indicate that the function navigates to all nodes in the containing document AxisExpression root = new AxisExpression(Axis.ANCESTOR_OR_SELF, NodeKindTest.DOCUMENT); root.setContainer(getContainer()); target = target.createArc(root); AxisExpression allElements = new AxisExpression(Axis.DESCENDANT, AnyNodeTest.getInstance()); allElements.setContainer(getContainer()); return target.createArc(allElements); } /** * Copy an expression. This makes a deep copy. * * @return the copy of the original expression */ public Expression copy() { KeyFn k = (KeyFn)super.copy(); k.nsContext = nsContext; k.staticKeySet = staticKeySet; k.internal = internal; k.checked = checked; return k; } /** * Enumerate the results of the expression */ public SequenceIterator iterate(XPathContext context) throws XPathException { Controller controller = context.getController(); Item arg2; try { arg2 = argument[2].evaluateItem(context); } catch (XPathException e) { if ("XPDY0002".equals(e.getErrorCodeLocalPart())) { dynamicError("Cannot call the key() function when there is no context item", "XTDE1270", context); return null; } else if ("XPDY0050".equals(e.getErrorCodeLocalPart())) { dynamicError("In the key() function," + " the node supplied in the third argument (or the context node if absent)" + " must be in a tree whose root is a document node", "XTDE1270", context); return null; } else if ("XPTY0020".equals(e.getErrorCodeLocalPart())) { dynamicError("Cannot call the key() function when the context item is an atomic value", "XTDE1270", context); return null; } throw e; } NodeInfo origin = (NodeInfo)arg2; NodeInfo root = origin.getRoot(); if (root.getNodeKind() != Type.DOCUMENT) { dynamicError("In the key() function," + " the node supplied in the third argument (or the context node if absent)" + " must be in a tree whose root is a document node", "XTDE1270", context); return null; } DocumentInfo doc = (DocumentInfo)root; KeyDefinitionSet selectedKeySet = staticKeySet; if (selectedKeySet == null) { String givenkeyname = argument[0].evaluateItem(context).getStringValue(); StructuredQName qName = null; try { qName = StructuredQName.fromLexicalQName( givenkeyname, false, controller.getConfiguration().getNameChecker(), nsContext); } catch (XPathException err) { dynamicError("Invalid key name: " + err.getMessage(), "XTDE1260", context); } selectedKeySet = controller.getKeyManager().getKeyDefinitionSet(qName); if (selectedKeySet == null) { dynamicError("Key '" + givenkeyname + "' has not been defined", "XTDE1260", context); return null; } } // if (internal) { // System.err.println("Using key " + fprint + " on doc " + doc); // } // If the second argument is a singleton, we evaluate the function // directly; otherwise we recurse to evaluate it once for each Item // in the sequence. Expression expression = argument[1]; SequenceIterator allResults; if (Cardinality.allowsMany(expression.getCardinality())) { final XPathContext keyContext = context; final DocumentInfo document = doc; final KeyManager keyManager = controller.getKeyManager(); final KeyDefinitionSet keySet = selectedKeySet; MappingFunction map = new MappingFunction() { // Map a value to the sequence of nodes having that value as a key value public SequenceIterator map(Item item) throws XPathException { return keyManager.selectByKey( keySet, document, (AtomicValue)item, keyContext); } }; SequenceIterator keys = argument[1].iterate(context); SequenceIterator allValues = new MappingIterator(keys, map); allResults = new DocumentOrderIterator(allValues, LocalOrderComparer.getInstance()); } else { try { AtomicValue keyValue = (AtomicValue)argument[1].evaluateItem(context); if (keyValue == null) { return EmptyIterator.getInstance(); } KeyManager keyManager = controller.getKeyManager(); allResults = keyManager.selectByKey(selectedKeySet, doc, keyValue, context); } catch (XPathException e) { e.maybeSetLocation(this); throw e; } } if (origin == doc) { return allResults; } SubtreeFilter filter = new SubtreeFilter(); filter.origin = origin; return new ItemMappingIterator(allResults, filter); } /** * Mapping class to filter nodes that have the origin node as an ancestor-or-self */ private static class SubtreeFilter implements ItemMappingFunction { public NodeInfo origin; public Item map(Item item) throws XPathException { if (Navigator.isAncestorOrSelf(origin, (NodeInfo)item)) { return item; } else { return null; } } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/functions/Serialize.java0000644000175000017500000001441711033112257022210 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.event.SequenceReceiver; import net.sf.saxon.expr.ExpressionVisitor; import net.sf.saxon.expr.StaticContext; import net.sf.saxon.expr.StringLiteral; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.instruct.ResultDocument; import net.sf.saxon.om.*; import net.sf.saxon.style.ExpressionContext; import net.sf.saxon.trace.Location; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.Type; import net.sf.saxon.value.StringValue; import net.sf.saxon.value.Whitespace; import javax.xml.transform.OutputKeys; import javax.xml.transform.stream.StreamResult; import java.io.StringWriter; import java.util.Properties; /** * This class implements the saxon:serialize() extension function, * which is specially-recognized by the system because it needs access * to parts of the static context */ public class Serialize extends SystemFunction implements XSLTFunction { Properties outputProperties; private transient boolean checked = false; // the second time checkArguments is called, it's a global check so the static context is inaccurate /** * Method supplied by each class of function to check arguments during parsing, when all * the argument expressions have been read */ public void checkArguments(ExpressionVisitor visitor) throws XPathException { if (checked) return; checked = true; super.checkArguments(visitor); if (argument[1] instanceof StringLiteral) { StaticContext env = visitor.getStaticContext(); if (env instanceof ExpressionContext) { // We're in XSLT String formatString = ((StringLiteral)argument[1]).getStringValue(); StructuredQName formatQName = null; if (formatString.length() != 0) { formatQName = ((ExpressionContext)env).getStructuredQName(formatString, false); // if (fingerprint==-1) { // throw new XPathException("Output format '" + format + "' has not been defined"); // } } outputProperties = ((ExpressionContext)env).getXSLStylesheet().gatherOutputProperties(formatQName); } else { // we're not in XSLT: treat the second argument as the method property, default the rest // See https://sourceforge.net/forum/message.php?msg_id=3780729 outputProperties = new Properties(); outputProperties.setProperty(OutputKeys.METHOD, ((StringLiteral)argument[1]).getStringValue()); } } } /** * Evaluate the function */ public Item evaluateItem(XPathContext c) throws XPathException { NodeInfo node = (NodeInfo)argument[0].evaluateItem(c); if (node==null) { return StringValue.EMPTY_STRING; } Properties props = outputProperties; if (props == null) { // the second argument was not a literal string: in this case it must be an xsl:output element Item secondArg = argument[1].evaluateItem(c); if (!(secondArg instanceof NodeInfo && ((NodeInfo)secondArg).getNodeKind() == Type.ELEMENT && ((NodeInfo)secondArg).getFingerprint() == StandardNames.XSL_OUTPUT)) { XPathException err = new XPathException("The second argument of saxon:serialize must either be " + "a string literal, or an xsl:output element"); err.setXPathContext(c); throw err; } props = new Properties(); processXslOutputElement((NodeInfo)secondArg, props, c); } try { StringWriter result = new StringWriter(); XPathContext c2 = c.newMinorContext(); c.setOriginatingConstructType(Location.SAXON_SERIALIZE); c2.changeOutputDestination(props, new StreamResult(result), false, getHostLanguage(), Validation.PRESERVE, null); SequenceReceiver out = c2.getReceiver(); out.open(); node.copy(out, NodeInfo.ALL_NAMESPACES, true, locationId); out.close(); return new StringValue(result.toString()); } catch (XPathException err) { throw new XPathException(err); } } /** * Construct a set of output properties from an xsl:output element supplied at run-time * @param element an xsl:output element * @param props Properties object to which will be added the values of those serialization properties * that were specified * @param c the XPath dynamic context */ public static void processXslOutputElement(NodeInfo element, Properties props, XPathContext c) throws XPathException { SequenceIterator iter = element.iterateAxis(Axis.ATTRIBUTE); NameChecker nc = c.getConfiguration().getNameChecker(); NamespaceResolver resolver = new InscopeNamespaceResolver(element); while (true) { NodeInfo att = (NodeInfo)iter.next(); if (att == null) { break; } String uri = att.getURI(); String local = att.getLocalPart(); String val = Whitespace.trim(att.getStringValueCS()); ResultDocument.setSerializationProperty(props, uri, local, val, resolver, false, nc); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/functions/StringJoin.java0000644000175000017500000000604111033112257022341 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.expr.*; import net.sf.saxon.om.Item; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.om.FastStringBuffer; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ItemType; import net.sf.saxon.value.Cardinality; import net.sf.saxon.value.StringValue; /** * xf:string-join(string* $sequence, string $separator) */ public class StringJoin extends SystemFunction { public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { Expression exp = super.optimize(visitor, contextItemType); if (exp instanceof StringJoin) { return ((StringJoin)exp).simplifySingleton(); } else { return exp; } } private Expression simplifySingleton() { int card = argument[0].getCardinality(); if (!Cardinality.allowsMany(card)) { if (Cardinality.allowsZero(card)) { return SystemFunction.makeSystemFunction("string", new Expression[]{argument[0]}); } else { return argument[0]; } } return this; } public Item evaluateItem(XPathContext c) throws XPathException { // This rather tortuous code is designed to ensure that we don't evaluate the // separator argument unless there are at least two items in the sequence. SequenceIterator iter = argument[0].iterate(c); Item it = iter.next(); if (it==null) { return StringValue.EMPTY_STRING; } CharSequence first = it.getStringValueCS(); it = iter.next(); if (it==null) { return StringValue.makeStringValue(first); } FastStringBuffer sb = new FastStringBuffer(1024); sb.append(first); // Type checking ensures that the separator is not an empty sequence CharSequence sep = argument[1].evaluateItem(c).getStringValueCS(); sb.append(sep); sb.append(it.getStringValueCS()); while (true) { it = iter.next(); if (it == null) { return StringValue.makeStringValue(sb.condense()); } sb.append(sep); sb.append(it.getStringValueCS()); } } // TODO: allow the output of string-join to be streamed to the serializer } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/functions/Replace.java0000644000175000017500000001730011033112257021626 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.Configuration; import net.sf.saxon.Platform; import net.sf.saxon.type.ItemType; import net.sf.saxon.expr.Expression; import net.sf.saxon.expr.ExpressionVisitor; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.Item; import net.sf.saxon.regex.RegularExpression; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.AtomicValue; import net.sf.saxon.value.StringValue; import java.util.regex.PatternSyntaxException; /** * This class implements the replace() function for replacing * substrings that match a regular expression */ public class Replace extends SystemFunction { private RegularExpression regexp; /** * Simplify and validate. * This is a pure function so it can be simplified in advance if the arguments are known * @param visitor an expression visitor */ public Expression simplify(ExpressionVisitor visitor) throws XPathException { Expression e = simplifyArguments(visitor); if (e == this) { maybePrecompile(visitor); } return e; } private void maybePrecompile(ExpressionVisitor visitor) throws XPathException { // compile the regular expression once if possible if (regexp == null) { try { regexp = Matches.tryToCompile(argument, 1, 3, visitor.getStaticContext()); } catch (XPathException err) { err.setLocator(this); throw err; } // check that it's not a pattern that matches "" if (regexp != null && regexp.matches("")) { XPathException err = new XPathException("The regular expression in replace() must not be one that matches a zero-length string"); err.setErrorCode("FORX0003"); err.setLocator(this); throw err; } } } /** * Perform optimisation of an expression and its subexpressions. *

*

This method is called after all references to functions and variables have been resolved * to the declaration of the function or variable, and after all type checking has been done.

* * @param visitor an expression visitor * @param contextItemType the static type of "." at the point where this expression is invoked. * The parameter is set to null if it is known statically that the context item will be undefined. * If the type of the context item is not known statically, the argument is set to * {@link net.sf.saxon.type.Type#ITEM_TYPE} * @return the original expression, rewritten if appropriate to optimize execution * @throws net.sf.saxon.trans.XPathException * if an error is discovered during this phase * (typically a type error) */ public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { Expression e = super.optimize(visitor, contextItemType); // try once again to compile the regular expression once if possible // (used when the regex has been identified as a constant as a result of earlier rewrites) if (e == this) { maybePrecompile(visitor); } return e; } /** * Get the compiled regular expression if available, otherwise return null * @return the compiled regex, or null */ public RegularExpression getCompiledRegularExpression() { return regexp; } /** * Evaluate the function in a string context */ public Item evaluateItem(XPathContext c) throws XPathException { AtomicValue arg0 = (AtomicValue)argument[0].evaluateItem(c); if (arg0==null) { arg0 = StringValue.EMPTY_STRING; } AtomicValue arg2 = (AtomicValue)argument[2].evaluateItem(c); CharSequence replacement = arg2.getStringValueCS(); String msg = checkReplacement(replacement); if (msg != null) { dynamicError(msg, "FORX0004", c); } RegularExpression re = regexp; if (re == null) { AtomicValue arg1 = (AtomicValue)argument[1].evaluateItem(c); CharSequence flags; if (argument.length == 3) { flags = ""; } else { AtomicValue arg3 = (AtomicValue)argument[3].evaluateItem(c); flags = arg3.getStringValueCS(); } try { final Platform platform = Configuration.getPlatform(); final int xmlVersion = c.getConfiguration().getXMLVersion(); re = platform.compileRegularExpression( arg1.getStringValueCS(), xmlVersion, RegularExpression.XPATH_SYNTAX, flags); } catch (XPathException err) { XPathException de = new XPathException(err); de.setErrorCode("FORX0002"); de.setXPathContext(c); de.setLocator(this); throw de; } catch (PatternSyntaxException err) { XPathException de = new XPathException(err); de.setErrorCode("FORX0002"); de.setXPathContext(c); de.setLocator(this); throw de; } // check that it's not a pattern that matches "" if (re.matches("")) { dynamicError( "The regular expression in replace() must not be one that matches a zero-length string", "FORX0003", c); } } String input = arg0.getStringValue(); CharSequence res = re.replace(input, replacement); return StringValue.makeStringValue(res); } /** * Check the contents of the replacement string * @param rep the replacement string * @return null if the string is OK, or an error message if not */ public static String checkReplacement(CharSequence rep) { for (int i=0; i '9') { return "Invalid replacement string in replace(): $ sign must be followed by digit 0-9"; } } else { return "Invalid replacement string in replace(): $ sign at end of string"; } } else if (c == '\\') { if (i+1 < rep.length()) { char next = rep.charAt(++i); if (next != '\\' && next != '$') { return "Invalid replacement string in replace(): \\ character must be followed by \\ or $"; } } else { return "Invalid replacement string in replace(): \\ character at end of string"; } } } return null; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/functions/ResolveQName.java0000644000175000017500000000366411033112257022624 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.*; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.AtomicValue; import net.sf.saxon.value.QNameValue; import net.sf.saxon.type.BuiltInAtomicType; /** * This class supports the resolve-QName function in XPath 2.0 */ public class ResolveQName extends SystemFunction { /** * Evaluate the expression */ public Item evaluateItem(XPathContext context) throws XPathException { AtomicValue arg0 = (AtomicValue)argument[0].evaluateItem(context); if (arg0 == null) { return null; } CharSequence lexicalQName = arg0.getStringValueCS(); final NameChecker checker = context.getConfiguration().getNameChecker(); NodeInfo element = (NodeInfo)argument[1].evaluateItem(context); NamespaceResolver resolver = new InscopeNamespaceResolver(element); StructuredQName qName; try { qName= StructuredQName.fromLexicalQName(lexicalQName, true, checker, resolver); } catch (XPathException e) { e.maybeSetLocation(this); throw e; } return new QNameValue(qName, BuiltInAtomicType.QNAME); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/functions/Available.java0000644000175000017500000002435511157310114022142 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.Configuration; import net.sf.saxon.expr.*; import net.sf.saxon.om.*; import net.sf.saxon.style.StyleNodeFactory; import net.sf.saxon.style.XSLTStaticContext; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.BuiltInAtomicType; import net.sf.saxon.type.SchemaType; import net.sf.saxon.type.BuiltInListType; import net.sf.saxon.value.AtomicValue; import net.sf.saxon.value.BooleanValue; import net.sf.saxon.value.NumericValue; import net.sf.saxon.value.StringValue; import java.util.Set; /** * This class supports the XSLT element-available and function-available functions. */ public class Available extends SystemFunction implements XSLTFunction { public static final int ELEMENT_AVAILABLE = 0; public static final int FUNCTION_AVAILABLE = 1; public static final int TYPE_AVAILABLE = 2; private NamespaceResolver nsContext; private transient StyleNodeFactory styleNodeFactory; private transient boolean checked = false; private Set importedSchemaNamespaces; public void checkArguments(ExpressionVisitor visitor) throws XPathException { // the second time checkArguments is called, it's a global check so the static context is inaccurate if (checked) { return; } checked = true; super.checkArguments(visitor); if (!(argument[0] instanceof Literal && (argument.length==1 || argument[1] instanceof Literal))) { // we need to save the namespace context nsContext = visitor.getStaticContext().getNamespaceResolver(); // for type-available, we need to save the set of imported namespaces if (operation == TYPE_AVAILABLE) { importedSchemaNamespaces = visitor.getStaticContext().getImportedSchemaNamespaces(); } } } /** * preEvaluate: this method uses the static context to do early evaluation of the function * if the argument is known (which is the normal case) * @param visitor the expression visitor */ public Expression preEvaluate(ExpressionVisitor visitor) throws XPathException { String lexicalQName = ((Literal)argument[0]).getValue().getStringValue(); StaticContext env = visitor.getStaticContext(); boolean b = false; Configuration config = visitor.getConfiguration(); switch(operation) { case ELEMENT_AVAILABLE: b = ((XSLTStaticContext)env).isElementAvailable(lexicalQName); break; case FUNCTION_AVAILABLE: long arity = -1; if (argument.length == 2) { arity = ((NumericValue)argument[1].evaluateItem(env.makeEarlyEvaluationContext())).longValue(); } try { String[] parts = config.getNameChecker().getQNameParts(lexicalQName); String prefix = parts[0]; String uri; if (prefix.length() == 0) { uri = env.getDefaultFunctionNamespace(); } else { uri = env.getURIForPrefix(prefix); } StructuredQName functionName = new StructuredQName(prefix, uri, parts[1]); b = env.getFunctionLibrary().isAvailable(functionName, (int)arity); } catch (QNameException e) { XPathException err = new XPathException(e.getMessage()); err.setErrorCode("XTDE1400"); throw err; } break; case TYPE_AVAILABLE: try { String[] parts = config.getNameChecker().getQNameParts(lexicalQName); String prefix = parts[0]; String uri; if (prefix.length() == 0) { uri = env.getDefaultElementNamespace(); } else { uri = env.getURIForPrefix(prefix); } if (uri.equals(NamespaceConstant.JAVA_TYPE)) { try { config.getClass(parts[1], false, null); b = true; } catch (XPathException err) { b = false; } } else { int fingerprint = config.getNamePool().allocate(prefix, uri, parts[1]) & 0xfffff; SchemaType type = config.getSchemaType(fingerprint); if (type instanceof BuiltInAtomicType) { b = env.isAllowedBuiltInType((BuiltInAtomicType)type); } else if (type instanceof BuiltInListType) { b = config.isSchemaAware(Configuration.XSLT); } else { b = (type != null && (uri.equals(NamespaceConstant.SCHEMA) || env.isImportedSchema(uri))); } } } catch (QNameException e) { XPathException err = new XPathException(e.getMessage()); err.setErrorCode("XTDE1425"); throw err; } } return Literal.makeLiteral(BooleanValue.get(b)); } /** * Run-time evaluation. This is the only thing in the spec that requires information * about in-scope functions to be available at run-time. However, we keep it because * it's handy for some other things such as saxon:evaluate(). */ public Item evaluateItem(XPathContext context) throws XPathException { AtomicValue av1 = (AtomicValue)argument[0].evaluateItem(context); long arity = -1; if (argument.length == 2) { arity = ((NumericValue)argument[1].evaluateItem(context)).longValue(); } StringValue nameValue = (StringValue)av1; String lexicalName = nameValue.getStringValue(); StructuredQName qName; try { if (lexicalName.indexOf(':') < 0) { // we're in XSLT, where the default namespace for functions can't be changed String uri = (operation == FUNCTION_AVAILABLE ? NamespaceConstant.FN : nsContext.getURIForPrefix("", true)); qName = new StructuredQName("", uri, lexicalName); } else { qName = StructuredQName.fromLexicalQName(lexicalName, false, context.getConfiguration().getNameChecker(), nsContext); } } catch (XPathException e) { dynamicError(e.getMessage(), badQNameCode(), context); return null; } boolean b = false; switch(operation) { case ELEMENT_AVAILABLE: b = isElementAvailable(qName.getNamespaceURI(), qName.getLocalName(), context); break; case FUNCTION_AVAILABLE: final FunctionLibrary lib = context.getController().getExecutable().getFunctionLibrary(); b = lib.isAvailable(qName, (int)arity); break; case TYPE_AVAILABLE: String uri = qName.getNamespaceURI(); if (uri.equals(NamespaceConstant.SCHEMA) || importedSchemaNamespaces.contains(uri)) { final int fp = context.getNamePool().allocate( qName.getPrefix(), uri, qName.getLocalName()) & 0xfffff; SchemaType type = context.getConfiguration().getSchemaType(fp); b = (type != null); } else { return BooleanValue.FALSE; } } return BooleanValue.get(b); } private String badQNameCode() { switch (operation) { case FUNCTION_AVAILABLE: return "XTDE1400"; case TYPE_AVAILABLE: return "XTDE1428"; case ELEMENT_AVAILABLE: return "XTDE1440"; default: return null; } } /** * Determine at run-time whether a particular instruction is available. Returns true * only in the case of XSLT instructions and Saxon extension instructions; returns false * for user-defined extension instructions * @param uri the namespace URI of the element * @param localname the local part of the element name * @param context the XPath evaluation context * @return true if the instruction is available, in the sense of the XSLT element-available() function */ private boolean isElementAvailable(String uri, String localname, XPathContext context) { // This is horribly inefficient. But hopefully it's hardly ever executed, because there // is very little point calling element-available() with a dynamically-constructed argument. // And the inefficiency is only incurred once, on the first call. // Note: this requires the compile-time classes to be available at run-time; it will need // changing if we ever want to build a run-time JAR file. try { if (styleNodeFactory==null) { Configuration config = context.getConfiguration(); styleNodeFactory = new StyleNodeFactory(config, context.getController().getErrorListener()); } return styleNodeFactory.isElementAvailable(uri, localname); } catch (Exception err) { //err.printStackTrace(); return false; } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/functions/Error.java0000644000175000017500000001061111033112257021342 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.expr.*; import net.sf.saxon.om.Item; import net.sf.saxon.om.NamespaceConstant; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.sxpath.XPathEvaluator; import net.sf.saxon.sxpath.XPathExpression; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.BuiltInAtomicType; import net.sf.saxon.type.Type; import net.sf.saxon.value.*; /** * Implement XPath function fn:error() */ public class Error extends SystemFunction { /** * preEvaluate: this method suppresses compile-time evaluation by doing nothing * @param visitor an expression visitor */ public Expression preEvaluate(ExpressionVisitor visitor) { return this; } /** * Evaluation of the expression always throws an error */ public Item evaluateItem(XPathContext context) throws XPathException { QualifiedNameValue qname = null; if (argument.length > 0) { qname = (QualifiedNameValue)argument[0].evaluateItem(context); } if (qname == null) { qname = new QNameValue("err", NamespaceConstant.ERR, (argument.length == 1 ? "FOTY0004" : "FOER0000"), BuiltInAtomicType.QNAME, null); } String description; if (argument.length > 1) { description = argument[1].evaluateItem(context).getStringValue(); } else { description = "Error signalled by application call on error()"; } XPathException e = new XPathException(description); e.setErrorCode(qname.getNamespaceURI(), qname.getLocalName()); e.setXPathContext(context); e.setLocator(this); if (argument.length > 2) { Value errorObject = ((Value)SequenceExtent.makeSequenceExtent(argument[2].iterate(context))).reduce(); if (errorObject instanceof SingletonNode) { NodeInfo root = ((SingletonNode)errorObject).getNode(); if (root.getNodeKind() == Type.DOCUMENT) { XPathEvaluator xpath = new XPathEvaluator(); XPathExpression exp = xpath.createExpression("/error/@module"); NodeInfo moduleAtt = (NodeInfo)exp.evaluateSingle(root); String module = (moduleAtt == null ? null : moduleAtt.getStringValue()); exp = xpath.createExpression("/error/@line"); NodeInfo lineAtt = (NodeInfo)exp.evaluateSingle(root); int line = (lineAtt == null ? -1 : Integer.parseInt(lineAtt.getStringValue())); exp = xpath.createExpression("/error/@column"); NodeInfo columnAtt = (NodeInfo)exp.evaluateSingle(root); int column = (columnAtt == null ? -1 : Integer.parseInt(columnAtt.getStringValue())); ExpressionLocation locator = new ExpressionLocation(); locator.setSystemId(module); locator.setLineNumber(line); locator.setColumnNumber(column); e.setLocator(locator); } } e.setErrorObject(errorObject); } throw e; } /** * Evaluate an updating expression, adding the results to a Pending Update List. * The default implementation of this method, which is used for non-updating expressions, * throws an UnsupportedOperationException * * @param context the XPath dynamic evaluation context * @param pul the pending update list to which the results should be written */ public void evaluatePendingUpdates(XPathContext context, PendingUpdateList pul) throws XPathException { evaluateItem(context); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/functions/Subsequence.java0000644000175000017500000001755611033112257022552 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.expr.*; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.om.EmptyIterator; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.TypeHierarchy; import net.sf.saxon.value.AtomicValue; import net.sf.saxon.value.NumericValue; import net.sf.saxon.value.Int64Value; import net.sf.saxon.value.EmptySequence; /** * Implements the XPath 2.0 subsequence() function */ public class Subsequence extends SystemFunction { /** * Determine the data type of the items in the sequence * @return the type of the argument * @param th the type hierarchy cache */ public ItemType getItemType(TypeHierarchy th) { return argument[0].getItemType(th); } /** * Get the static properties of this expression (other than its type). The result is * bit-significant. These properties are used for optimizations. In general, if * property bit is set, it is true, but if it is unset, the value is unknown. */ public int computeSpecialProperties() { return argument[0].getSpecialProperties(); } /** * Determine the cardinality of the function. */ public int computeCardinality() { if (getNumberOfArguments() == 3 && Literal.isConstantOne(argument[2])) { return StaticProperty.ALLOWS_ZERO_OR_ONE; } return argument[0].getCardinality() | StaticProperty.ALLOWS_ZERO; } /** * Perform optimisation of an expression and its subexpressions. *

*

This method is called after all references to functions and variables have been resolved * to the declaration of the function or variable, and after all type checking has been done.

* * @param visitor an expression visitor * @param contextItemType the static type of "." at the point where this expression is invoked. * The parameter is set to null if it is known statically that the context item will be undefined. * If the type of the context item is not known statically, the argument is set to * {@link net.sf.saxon.type.Type#ITEM_TYPE} * @return the original expression, rewritten if appropriate to optimize execution * @throws net.sf.saxon.trans.XPathException * if an error is discovered during this phase * (typically a type error) */ public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { Expression e = super.optimize(visitor, contextItemType); if (e != this) { return e; } if (getNumberOfArguments() == 2 && Literal.isAtomic(argument[1])) { NumericValue start = (NumericValue)((Literal)argument[1]).getValue(); start = start.round(); long intstart = start.longValue(); if (intstart > Integer.MAX_VALUE) { return new Literal(EmptySequence.getInstance()); } return new TailExpression(argument[0], (int)intstart); } return this; } /** * Evaluate the function to return an iteration of selected nodes. */ public SequenceIterator iterate(XPathContext context) throws XPathException { SequenceIterator seq = argument[0].iterate(context); AtomicValue startVal0 = (AtomicValue)argument[1].evaluateItem(context); NumericValue startVal = (NumericValue)startVal0; if (argument.length == 2) { long lstart; if (startVal instanceof Int64Value) { lstart = startVal.longValue(); if (lstart <= 1) { return seq; } } else { startVal = startVal.round(); if (startVal.compareTo(Int64Value.PLUS_ONE) <= 0) { return seq; } else if (startVal.compareTo(Int64Value.MAX_LONG) > 0) { return EmptyIterator.getInstance(); } else if (startVal.isNaN()) { return EmptyIterator.getInstance(); } else { lstart = startVal.longValue(); } } if (lstart > Integer.MAX_VALUE) { // we don't allow sequences longer than an this return EmptyIterator.getInstance(); } return TailIterator.make(seq, (int)lstart); } else { // There are three arguments AtomicValue lengthVal0 = (AtomicValue)argument[2].evaluateItem(context); NumericValue lengthVal = (NumericValue)lengthVal0; if (startVal instanceof Int64Value && lengthVal instanceof Int64Value) { long lstart = startVal.longValue(); if (lstart > Integer.MAX_VALUE) { return EmptyIterator.getInstance(); } long llength = lengthVal.longValue(); if (llength > Integer.MAX_VALUE) { llength = Integer.MAX_VALUE; } if (llength < 1) { return EmptyIterator.getInstance(); } long lend = lstart + llength - 1; if (lend < 1) { return EmptyIterator.getInstance(); } int start = (lstart < 1 ? 1 : (int)lstart); return SubsequenceIterator.make(seq, start, (int)lend); } else { if (startVal.isNaN()) { return EmptyIterator.getInstance(); } if (startVal.compareTo(Int64Value.MAX_LONG) > 0) { return EmptyIterator.getInstance(); } startVal = startVal.round(); if (lengthVal.isNaN()) { return EmptyIterator.getInstance(); } lengthVal = lengthVal.round(); if (lengthVal.compareTo(Int64Value.ZERO) <= 0) { return EmptyIterator.getInstance(); } NumericValue rend = (NumericValue)ArithmeticExpression.compute( startVal, Calculator.PLUS, lengthVal, context); rend = (NumericValue)ArithmeticExpression.compute( rend, Calculator.MINUS, Int64Value.PLUS_ONE, context); if (rend.compareTo(Int64Value.ZERO) <= 0) { return EmptyIterator.getInstance(); } long lstart; if (startVal.compareTo(Int64Value.PLUS_ONE) <= 0) { lstart = 1; } else { lstart = startVal.longValue(); } if (lstart > Integer.MAX_VALUE) { return EmptyIterator.getInstance(); } long lend; if (rend.compareTo(Int64Value.MAX_LONG) >= 0) { lend = Integer.MAX_VALUE; } else { lend = rend.longValue(); } return SubsequenceIterator.make(seq, (int)lstart, (int)lend); } } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/functions/CurrentGroup.java0000644000175000017500000000501611033112257022713 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.expr.*; import net.sf.saxon.om.EmptyIterator; import net.sf.saxon.om.Item; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.sort.GroupIterator; import net.sf.saxon.trans.XPathException; /** * Implements the XSLT functions current-group() and current-grouping-key() */ public class CurrentGroup extends SystemFunction implements XSLTFunction { public static final int CURRENT_GROUP = 0; public static final int CURRENT_GROUPING_KEY = 1; /** * preEvaluate: this method suppresses compile-time evaluation by doing nothing * (because the value of the expression depends on the runtime context) * @param visitor an expression visitor */ public Expression preEvaluate(ExpressionVisitor visitor) { return this; } /** * Evaluate the expression */ public Item evaluateItem(XPathContext c) throws XPathException { if (operation==CURRENT_GROUPING_KEY) { GroupIterator gi = c.getCurrentGroupIterator(); if (gi==null) { return null; } return gi.getCurrentGroupingKey(); } else { return super.evaluateItem(c); } } /** * Return an iteration over the result sequence */ public SequenceIterator iterate(XPathContext c) throws XPathException { if (operation==CURRENT_GROUP) { GroupIterator gi = c.getCurrentGroupIterator(); if (gi==null) { return EmptyIterator.getInstance(); } return gi.iterateCurrentGroup(); } else { return super.iterate(c); } } /** * Determine the dependencies */ public int getIntrinsicDependencies() { return StaticProperty.DEPENDS_ON_CURRENT_GROUP; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/functions/UnparsedText.java0000644000175000017500000002242611033112257022706 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.Configuration; import net.sf.saxon.trans.Err; import net.sf.saxon.Platform; import net.sf.saxon.charcode.UTF16; import net.sf.saxon.expr.Expression; import net.sf.saxon.expr.ExpressionVisitor; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.FastStringBuffer; import net.sf.saxon.om.Item; import net.sf.saxon.om.NameChecker; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.BooleanValue; import net.sf.saxon.value.StringValue; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.io.Reader; import java.net.URI; import java.nio.charset.CharacterCodingException; import java.nio.charset.MalformedInputException; import java.nio.charset.UnmappableCharacterException; public class UnparsedText extends SystemFunction implements XSLTFunction { // TODO: There is now a requirement that the results should be stable // TODO: Consider supporting a query parameter ?substitute-character=xFFDE String expressionBaseURI = null; public static final int UNPARSED_TEXT = 0; public static final int UNPARSED_TEXT_AVAILABLE = 1; public void checkArguments(ExpressionVisitor visitor) throws XPathException { if (expressionBaseURI == null) { super.checkArguments(visitor); expressionBaseURI = visitor.getStaticContext().getBaseURI(); } } /** * preEvaluate: this method suppresses compile-time evaluation by doing nothing * @param visitor an expression visitor */ public Expression preEvaluate(ExpressionVisitor visitor) { return this; // in principle we could pre-evaluate any call of unparsed-text() with // constant arguments. But we don't, because the file contents might // change before the stylesheet executes. } /** * This method handles evaluation of the function: * it returns a StringValue in the case of unparsed-text(), or a BooleanValue * in the case of unparsed-text-available() */ public Item evaluateItem(XPathContext context) throws XPathException { StringValue result; try { StringValue hrefVal = (StringValue)argument[0].evaluateItem(context); if (hrefVal == null) { return null; } String href = hrefVal.getStringValue(); String encoding = null; if (getNumberOfArguments() == 2) { encoding = argument[1].evaluateItem(context).getStringValue(); } result = new StringValue( readFile(href, expressionBaseURI, encoding, context)); } catch (XPathException err) { if (operation == UNPARSED_TEXT_AVAILABLE) { return BooleanValue.FALSE; } else { throw err; } } if (operation == UNPARSED_TEXT_AVAILABLE) { return BooleanValue.TRUE; } else { return result; } } /** * Supporting routine to load one external file given a URI (href) and a baseURI */ private CharSequence readFile(String href, String baseURI, String encoding, XPathContext context) throws XPathException { final Configuration config = context.getConfiguration(); NameChecker checker = config.getNameChecker(); // Use the URI machinery to validate and resolve the URIs Platform platform = Configuration.getPlatform(); URI absoluteURI; try { absoluteURI = platform.makeAbsolute(href, baseURI); } catch (java.net.URISyntaxException err) { XPathException e = new XPathException(err.getReason() + ": " + err.getInput(), err); e.setErrorCode("XTDE1170"); throw e; } if (absoluteURI.getFragment() != null) { XPathException e = new XPathException("URI for unparsed-text() must not contain a fragment identifier"); e.setErrorCode("XTDE1170"); throw e; } // The URL dereferencing classes throw all kinds of strange exceptions if given // ill-formed sequences of %hh escape characters. So we do a sanity check that the // escaping is well-formed according to UTF-8 rules EscapeURI.checkPercentEncoding(absoluteURI.toString()); Reader reader = context.getController().getUnparsedTextURIResolver().resolve(absoluteURI, encoding, config); try { FastStringBuffer sb = new FastStringBuffer(2048); char[] buffer = new char[2048]; boolean first = true; int actual; int line = 1; int column = 1; while (true) { actual = reader.read(buffer, 0, 2048); if (actual < 0) { break; } for (int c=0; c 80) { System.out.println(sb1.toString()); System.out.println(sb2.toString()); sb1 = new FastStringBuffer(100); sb2 = new FastStringBuffer(100); } } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. The detectEncoding() method includes // code fragments taken from the AElfred XML Parser developed by David Megginson. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/functions/NormalizeSpace.java0000644000175000017500000001222511033112257023170 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.expr.*; import net.sf.saxon.om.Item; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ItemType; import net.sf.saxon.value.AtomicValue; import net.sf.saxon.value.StringValue; import net.sf.saxon.value.Value; import net.sf.saxon.value.Whitespace; /** * Implement the XPath normalize-space() function */ public class NormalizeSpace extends SystemFunction { /** * Determine the intrinsic dependencies of an expression, that is, those which are not derived * from the dependencies of its subexpressions. For example, position() has an intrinsic dependency * on the context position, while (position()+1) does not. The default implementation * of the method returns 0, indicating "no dependencies". * * @return a set of bit-significant flags identifying the "intrinsic" * dependencies. The flags are documented in class net.sf.saxon.value.StaticProperty */ public int getIntrinsicDependencies() { int d = super.getIntrinsicDependencies(); if (argument.length == 0) { d |= StaticProperty.DEPENDS_ON_CONTEXT_ITEM; } return d; } public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { if (argument.length == 0 && contextItemType == null) { XPathException err = new XPathException("The context item for normalize-space() is undefined"); err.setErrorCode("XPDY0002"); err.setIsTypeError(true); err.setLocator(this); throw err; } return super.typeCheck(visitor, contextItemType); } /** * Pre-evaluate a function at compile time. Functions that do not allow * pre-evaluation, or that need access to context information, can override this method. * @param visitor an expression visitor */ public Expression preEvaluate(ExpressionVisitor visitor) throws XPathException { if (argument.length == 0) { return this; } else { return Literal.makeLiteral((Value)evaluateItem( visitor.getStaticContext().makeEarlyEvaluationContext())); } } /** * Evaluate in a general context */ public Item evaluateItem(XPathContext c) throws XPathException { if (argument.length == 0) { Item item = c.getContextItem(); if (item == null) { dynamicError("Context item for normalize-space() is undefined", "FONC0001", c); return null; } return StringValue.makeStringValue( Whitespace.collapseWhitespace(item.getStringValueCS())); } else { AtomicValue sv = (AtomicValue)argument[0].evaluateItem(c); if (sv==null) { return StringValue.EMPTY_STRING; } return StringValue.makeStringValue( Whitespace.collapseWhitespace(sv.getStringValueCS())); } } /** * Get the effective boolean value of the expression. This returns false if the value * is the empty sequence, a zero-length string, a number equal to zero, or the boolean * false. Otherwise it returns true. * *

This method is implemented for normalize-space() because it is quite often used in a * boolean context to test whether a value exists and is non-white, and because testing for the * presence of non-white characters is a lot more efficient than constructing the normalized * string, especially because of early-exit.

* * @param c The context in which the expression is to be evaluated * @return the effective boolean value * @throws net.sf.saxon.trans.XPathException * if any dynamic error occurs evaluating the expression */ public boolean effectiveBooleanValue(XPathContext c) throws XPathException { CharSequence cs; if (argument.length == 0) { Item item = c.getContextItem(); if (item == null) { dynamicError("Context item for normalize-space() is undefined", "FONC0001", c); return false; } cs = item.getStringValueCS(); } else { AtomicValue sv = (AtomicValue)argument[0].evaluateItem(c); if (sv==null) { return false; } cs = sv.getStringValueCS(); } return !Whitespace.isWhite(cs); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/functions/Matches.java0000644000175000017500000002312011033112257021634 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.Configuration; import net.sf.saxon.Platform; import net.sf.saxon.expr.*; import net.sf.saxon.om.Item; import net.sf.saxon.regex.RegularExpression; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ItemType; import net.sf.saxon.value.AtomicValue; import net.sf.saxon.value.BooleanValue; import net.sf.saxon.value.StringValue; /** * This class implements the matches() function for regular expression matching */ public class Matches extends SystemFunction { private RegularExpression regexp; /** * Simplify and validate. * This is a pure function so it can be simplified in advance if the arguments are known * @return the simplified expression * @throws XPathException if any error is found (e.g. invalid regular expression) * @param visitor an expression visitor */ public Expression simplify(ExpressionVisitor visitor) throws XPathException { Expression e = simplifyArguments(visitor); // compile the regular expression once if possible if (e == this) { maybePrecompile(visitor); } return e; } /** * Precompile the regular expression if possible * @param visitor an expression visitor */ private void maybePrecompile(ExpressionVisitor visitor) throws XPathException { if (regexp == null) { try { regexp = tryToCompile(argument, 1, 2, visitor.getStaticContext()); } catch (XPathException err) { err.setLocator(this); throw err; } } } /** * Perform optimisation of an expression and its subexpressions. *

*

This method is called after all references to functions and variables have been resolved * to the declaration of the function or variable, and after all type checking has been done.

* * @param visitor an expression visitor * @param contextItemType the static type of "." at the point where this expression is invoked. * The parameter is set to null if it is known statically that the context item will be undefined. * If the type of the context item is not known statically, the argument is set to * {@link net.sf.saxon.type.Type#ITEM_TYPE} * @return the original expression, rewritten if appropriate to optimize execution * @throws net.sf.saxon.trans.XPathException * if an error is discovered during this phase * (typically a type error) */ public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { Expression e = super.optimize(visitor, contextItemType); // try once again to compile the regular expression once if possible // (used when the regex has been identified as a constant as a result of earlier rewrites) if (e == this) { maybePrecompile(visitor); } return e; } /** * Get the compiled regular expression, returning null if the regex has not been compiled * @return the compiled regular expression, or null */ public RegularExpression getCompiledRegularExpression() { return regexp; } /** * Evaluate the matches() function to give a Boolean value. * @param c The dynamic evaluation context * @return the result as a BooleanValue, or null to indicate the empty sequence * @throws XPathException on an error */ public Item evaluateItem(XPathContext c) throws XPathException { AtomicValue sv0 = (AtomicValue)argument[0].evaluateItem(c); if (sv0==null) { sv0 = StringValue.EMPTY_STRING; } RegularExpression re = regexp; if (re == null) { AtomicValue pat = (AtomicValue)argument[1].evaluateItem(c); if (pat==null) return null; CharSequence flags; if (argument.length==2) { flags = ""; } else { AtomicValue sv2 = (AtomicValue)argument[2].evaluateItem(c); if (sv2==null) return null; flags = sv2.getStringValueCS(); } try { final Platform platform = Configuration.getPlatform(); final int xmlVersion = c.getConfiguration().getXMLVersion(); re = platform.compileRegularExpression( pat.getStringValueCS(), xmlVersion, RegularExpression.XPATH_SYNTAX, flags); } catch (XPathException err) { XPathException de = new XPathException(err); if (de.getErrorCodeLocalPart() == null) { de.setErrorCode("FORX0002"); } de.setXPathContext(c); throw de; } } return BooleanValue.get(re.containsMatch(sv0.getStringValueCS())); } /** * Temporary test rig, used to submit bug report to Sun */ // public static void main(String[] args) throws Exception { // // matches("\u212a", "K"); // matches("\u212a", "[A-Z]"); // matches("\u212a", "I|J|K|L"); // matches("\u212a", "[IJKL]"); // matches("\u212a", "k"); // matches("\u212a", "[a-z]"); // matches("\u212a", "i|j|k|l"); // matches("\u212a", "[ijkl]"); // } // // private static void matches(String in, String pattern) { // System.err.println("Java version " + System.getProperty("java.version")); // int flags = Pattern.UNIX_LINES; // flags |= Pattern.CASE_INSENSITIVE; // flags |= Pattern.UNICODE_CASE; // Pattern p = Pattern.compile(pattern, flags); // boolean b = p.matcher(in).find(); // System.err.println("Pattern " + pattern + ": " + (b ? " match" : "no match")); // } // Results of this test with JDK 1.5.0_05: // // Pattern K: match // Java version 1.5.0_05 // Pattern [A-Z]: no match // Java version 1.5.0_05 // Pattern I|J|K|L: match // Java version 1.5.0_05 // Pattern [IJKL]: no match // Java version 1.5.0_05 // Pattern k: match // Java version 1.5.0_05 // Pattern [a-z]: match // Java version 1.5.0_05 // Pattern i|j|k|l: match // Java version 1.5.0_05 // Pattern [ijkl]: no match /** * Try to precompile the arguments to the function. This method is shared by * the implementations of the three XPath functions matches(), replace(), and * tokenize(). * @param args the supplied arguments to the function, as an array * @param patternArg the position of the argument containing the regular expression * @param flagsArg the position of the argument containing the flags * @param env the static context * @return the compiled regular expression, or null indicating that the information * is not available statically so it cannot be precompiled * @throws XPathException if any failure occurs, in particular, if the regular * expression is invalid */ public static RegularExpression tryToCompile(Expression[] args, int patternArg, int flagsArg, StaticContext env) throws XPathException { if (patternArg > args.length - 1) { // too few arguments were supplied; the error will be reported in due course return null; } CharSequence flagstr = null; if (args.length-1 < flagsArg) { flagstr = ""; } else if (args[flagsArg] instanceof StringLiteral) { flagstr = ((StringLiteral)args[flagsArg]).getStringValue(); } if (args[patternArg] instanceof StringLiteral && flagstr != null) { try { Platform platform = Configuration.getPlatform(); String in = ((StringLiteral)args[patternArg]).getStringValue(); final int xmlVersion = env.getConfiguration().getXMLVersion(); int syntax = RegularExpression.XPATH_SYNTAX; // TODO: Find a better (conformant) way of switching this option on if (flagstr.length() > 0 && flagstr.charAt(0) == '!') { flagstr = flagstr.subSequence(1, flagstr.length()); syntax = RegularExpression.NATIVE_SYNTAX; } return platform.compileRegularExpression(in, xmlVersion, syntax, flagstr); } catch (XPathException err) { if (err.getErrorCodeLocalPart() == null) { err.setErrorCode("FORX0002"); } throw err; } } else { return null; } } // public static void main(String[] args) { // System.out.println(Pattern.matches("(X)(2)?(3)?(4)?(5)?(6)?(7)?(8)?(9)?(10)?((Y)(\\12))", "XYY")); //// String pat = "(X)(2)(3)(4)(5)(6)(7)(8)(9)(10)(11(12)(13)\\11)"; //// System.out.println(Pattern.matches(pat, "X2345678910111213X1")); // } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/functions/Nilled.java0000644000175000017500000000602411033112257021463 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.Item; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.Type; import net.sf.saxon.value.BooleanValue; /** * This class supports the nilled() function */ public class Nilled extends SystemFunction { /** * Evaluate the function */ public Item evaluateItem(XPathContext c) throws XPathException { NodeInfo node = (NodeInfo)argument[0].evaluateItem(c); return getNilledProperty(node); } /** * Determine whether a node has the nilled property * @param node the node in question (if null, the function returns null) * @return the value of the nilled accessor. Returns null for any node other than an * element node. For an element node, returns true if the element has been validated and * has an xsi:nil attribute whose value is true. */ public static BooleanValue getNilledProperty(NodeInfo node) { // TODO: if the type annotation is ANYTYPE, we need to keep an extra bit to represent the nilled // property: it will be set only if validation has been performed. A newly-constructed element using // validation="preserve" has nilled=false even if xsi:nil = true if (node==null || node.getNodeKind() != Type.ELEMENT) { return null; } return BooleanValue.get(node.isNilled()); // int typeAnnotation = node.getTypeAnnotation(); // if (typeAnnotation == -1 || typeAnnotation == StandardNames.XDT_UNTYPED) { // return BooleanValue.FALSE; // } // String val = node.getAttributeValue(StandardNames.XSI_NIL); // if (val == null) { // return BooleanValue.FALSE; // } // if (val.trim().equals("1") || val.trim().equals("true")) { // return BooleanValue.TRUE; // } // return BooleanValue.FALSE; } /** * Determine whether a node is nilled. Returns true if the value * of the nilled property is true; false if the value is false or absent */ public static boolean isNilled(NodeInfo node) { BooleanValue b = getNilledProperty(node); return b != null && b.getBooleanValue(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/functions/NormalizeUnicode.java0000644000175000017500000000577511033112257023537 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.codenorm.Normalizer; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.Item; import net.sf.saxon.tinytree.CompressedWhitespace; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.StringValue; import net.sf.saxon.value.Whitespace; /** * Implement the XPath normalize-unicode() function */ public class NormalizeUnicode extends SystemFunction { /** * Evaluate in a general context */ public Item evaluateItem(XPathContext c) throws XPathException { StringValue sv = (StringValue)argument[0].evaluateItem(c); if (sv==null) { return StringValue.EMPTY_STRING; } byte fb = Normalizer.C; if (argument.length == 2) { String form = Whitespace.trim(argument[1].evaluateAsString(c)); if (form.equalsIgnoreCase("NFC")) { fb = Normalizer.C; } else if (form.equalsIgnoreCase("NFD")) { fb = Normalizer.D; } else if (form.equalsIgnoreCase("NFKC")) { fb = Normalizer.KC; } else if (form.equalsIgnoreCase("NFKD")) { fb = Normalizer.KD; } else if (form.length() == 0) { return sv; } else { String msg = "Normalization form " + form + " is not supported"; XPathException err = new XPathException(msg); err.setErrorCode("FOCH0003"); err.setXPathContext(c); err.setLocator(this); throw err; } } // fast path for ASCII strings: normalization is a no-op boolean allASCII = true; CharSequence chars = sv.getStringValueCS(); if (chars instanceof CompressedWhitespace) { return sv; } for (int i=chars.length()-1; i>=0; i--) { if (chars.charAt(i) > 127) { allASCII = false; break; } } if (allASCII) { return sv; } Normalizer norm = new Normalizer(fb); CharSequence result = norm.normalize(sv.getStringValueCS()); return StringValue.makeStringValue(result); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/functions/ItemAt.java0000644000175000017500000001013411033112257021434 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.expr.*; import net.sf.saxon.om.GroundedIterator; import net.sf.saxon.om.GroundedValue; import net.sf.saxon.om.Item; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.NumericValue; import net.sf.saxon.value.EmptySequence; import net.sf.saxon.type.ItemType; /** * Implements the saxon:item-at() function. This is handled specially because it is generated * by the optimizer. * *

The function takes two arguments: the first is an arbitrary sequence, the second is optional numeric. * The function returns the same result as let $N := NUMBER return SEQUENCE[$N], including cases where the * numeric argument is not a whole number.

*/ public class ItemAt extends SystemFunction { /** * Perform optimisation of an expression and its subexpressions. *

*

This method is called after all references to functions and variables have been resolved * to the declaration of the function or variable, and after all type checking has been done.

* * @param visitor an expression visitor * @param contextItemType the static type of "." at the point where this expression is invoked. * The parameter is set to null if it is known statically that the context item will be undefined. * If the type of the context item is not known statically, the argument is set to * {@link net.sf.saxon.type.Type#ITEM_TYPE} * @return the original expression, rewritten if appropriate to optimize execution * @throws net.sf.saxon.trans.XPathException * if an error is discovered during this phase * (typically a type error) */ public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { Expression e = super.optimize(visitor, contextItemType); if (e != this) { return e; } if (argument[1] instanceof Literal) { NumericValue val = (NumericValue)((Literal)argument[1]).getValue(); if (val.compareTo(1) < 0 || val.compareTo(Integer.MAX_VALUE) > 0 || !val.isWholeNumber()) { return new Literal(EmptySequence.getInstance()); } } return this; } /** * Evaluate the function to return the selected item. */ public Item evaluateItem(XPathContext context) throws XPathException { NumericValue index = (NumericValue)argument[1].evaluateItem(context); if (index == null) { return null; } if (index.compareTo(Integer.MAX_VALUE) <= 0 && index.isWholeNumber()) { int intindex = (int)index.longValue(); if (intindex < 1) { return null; } SequenceIterator base = argument[0].iterate(context); if (intindex == 1) { return base.next(); } else if (base instanceof GroundedIterator) { GroundedValue value = ((GroundedIterator)base).materialize(); return value.itemAt(intindex-1); } else { SequenceIterator tail = TailIterator.make(base, intindex); return tail.next(); } } else { // there is no item at the required position return null; } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/functions/CurrentDateTime.java0000644000175000017500000000605611033112257023320 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.expr.Expression; import net.sf.saxon.expr.ExpressionVisitor; import net.sf.saxon.expr.StaticProperty; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.Item; import net.sf.saxon.om.StandardNames; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.BuiltInAtomicType; import net.sf.saxon.type.TypeHierarchy; import net.sf.saxon.value.DateTimeValue; /** * This class implements the XPath 2.0 functions * current-date(), current-time(), and current-dateTime(), as * well as the function implicit-timezone(). The value that is required * is inferred from the type of result required. */ public class CurrentDateTime extends SystemFunction { /** * preEvaluate: this method suppresses compile-time evaluation by doing nothing * (because the value of the expression depends on the runtime context) * @param visitor an expression visitor */ public Expression preEvaluate(ExpressionVisitor visitor) { return this; } /** * Determine the dependencies */ public int getIntrinsicDependencies() { // current date/time is part of the context, but it is fixed for a transformation, so // we don't need to manage it as a dependency: expressions using it can be freely // rearranged return StaticProperty.DEPENDS_ON_RUNTIME_ENVIRONMENT; } /** * Evaluate in a general context */ public Item evaluateItem(XPathContext context) throws XPathException { final DateTimeValue dt = DateTimeValue.getCurrentDateTime(context); final TypeHierarchy th = context.getConfiguration().getTypeHierarchy(); final int targetType = getItemType(th).getPrimitiveType(); switch (targetType) { case StandardNames.XS_DATE_TIME: return dt; case StandardNames.XS_DATE: return dt.convert(BuiltInAtomicType.DATE, true, context).asAtomic(); case StandardNames.XS_TIME: return dt.convert(BuiltInAtomicType.TIME, true, context).asAtomic(); case StandardNames.XS_DAY_TIME_DURATION: case StandardNames.XS_DURATION: return dt.getComponent(Component.TIMEZONE); default: throw new IllegalArgumentException("Wrong target type for current date/time"); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/functions/ExecutableFunctionLibrary.java0000644000175000017500000001576211033112257025401 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.Configuration; import net.sf.saxon.expr.Expression; import net.sf.saxon.expr.ExpressionVisitor; import net.sf.saxon.expr.StaticContext; import net.sf.saxon.expr.UserFunctionCall; import net.sf.saxon.instruct.UserFunction; import net.sf.saxon.om.FastStringBuffer; import net.sf.saxon.om.StructuredQName; import net.sf.saxon.trans.XPathException; import java.util.HashMap; import java.util.Iterator; /** * An ExecutableFunctionLibrary is a function library that contains definitions of functions for use at * run-time. Normally functions are bound at compile-time; however there are various situations in which * the information is needed dynamically, for example (a) to support the XSLT function-available() call * (in the pathological case where the argument is not known statically), (b) to allow functions to be * called from saxon:evaluate(), (c) to allow functions to be called from a debugging breakpoint. * * The objects actually held in the ExecutableFunctionLibrary are UserFunctionCall objects that have been * prepared at compile time. These are function calls that do full dynamic type checking: that is, they * are prepared on the basis that the static types of the arguments are all "item()*", meaning that full * type checking is needed at run-time. */ public class ExecutableFunctionLibrary implements FunctionLibrary { private Configuration config; private HashMap functions = new HashMap(20); // The key of the hash table is a Long containing the arity in the top half, and the // fingerprint of the function name in the bottom half. The value is a UserFunction object. /** * Create the ExecutableFunctionLibrary * @param config the Saxon configuration */ public ExecutableFunctionLibrary(Configuration config) { this.config = config; } /** * Make a key that will uniquely identify a function * @param functionName the name of the function * @param arity the number of arguments * @return the constructed key. This is of the form {uri}local/arity */ private String makeKey(StructuredQName functionName, int arity) { String uri = functionName.getNamespaceURI(); String local = functionName.getLocalName(); FastStringBuffer sb = new FastStringBuffer(uri.length() + local.length() + 8); sb.append('{'); sb.append(uri); sb.append('}'); sb.append(local); sb.append("/" + arity); return sb.toString(); } /** * Register a function with the function library * @param fn the function to be registered */ public void addFunction(UserFunction fn) { functions.put(makeKey(fn.getFunctionName(), fn.getNumberOfArguments()), fn); } /** * Test whether a function with a given name and arity is available. This supports * the function-available() function in XSLT. * @param functionName the name of the function being sought * @param arity The number of arguments. This is set to -1 in the case of the single-argument * function-available() function; in this case the method should return true if there is some */ public boolean isAvailable(StructuredQName functionName, int arity) { if (arity == -1) { for (int i=0; i<=20; i++) { if (isAvailable(functionName, i)) { return true; } } return false; } return functions.get(makeKey(functionName, arity)) != null; } /** * Bind a function, given the URI and local parts of the function name, * and the list of expressions supplied as arguments. This method is called at compile * time. * @param functionName The name of the function to be called * @param staticArgs The expressions supplied statically in the function call. The intention is * that the static type of the arguments (obtainable via getItemType() and getCardinality() may * be used as part of the binding algorithm. * @param env the static evaluation context * @return An object representing the extension function to be called, if one is found; * null if no extension function was found matching the required name and arity. * @throws net.sf.saxon.trans.XPathException if a function is found with the required name and arity, but * the implementation of the function cannot be loaded or used; or if an error occurs * while searching for the function; or if this function library "owns" the namespace containing * the function call, but no function was found. */ public Expression bind(StructuredQName functionName, Expression[] staticArgs, StaticContext env) throws XPathException { UserFunction fn = (UserFunction)functions.get(makeKey(functionName, staticArgs.length)); if (fn == null) { return null; } ExpressionVisitor visitor = ExpressionVisitor.make(env); UserFunctionCall fc = new UserFunctionCall(); fc.setFunctionName(functionName); fc.setArguments(staticArgs); fc.setFunction(fn); fc.checkFunctionCall(fn, visitor); fc.setStaticType(fn.getResultType(config.getTypeHierarchy())); return fc; } /** * This method creates a copy of a FunctionLibrary: if the original FunctionLibrary allows * new functions to be added, then additions to this copy will not affect the original, or * vice versa. * * @return a copy of this function library. This must be an instance of the original class. */ public FunctionLibrary copy() { ExecutableFunctionLibrary efl = new ExecutableFunctionLibrary(config); efl.functions = new HashMap(functions); return efl; } /** * Iterate over all the functions defined in this function library. The objects * returned by the iterator are of class {@link UserFunction} * @return an iterator delivering the {@link UserFunction} objects representing * the user-defined functions in a stylesheet or query */ public Iterator iterateFunctions() { return functions.values().iterator(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. //saxonb-9.1.0.8/bj/net/sf/saxon/functions/Aggregate.java0000644000175000017500000003144411033112257022146 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.expr.*; import net.sf.saxon.om.Item; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.om.StandardNames; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.BuiltInAtomicType; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.Type; import net.sf.saxon.type.TypeHierarchy; import net.sf.saxon.value.*; import javax.xml.transform.SourceLocator; /** * This class implements the sum(), avg(), count() functions, */ public class Aggregate extends SystemFunction { public static final int SUM = 0; public static final int AVG = 1; public static final int COUNT = 4; /** * Static analysis: prevent sorting of the argument */ public void checkArguments(ExpressionVisitor visitor) throws XPathException { super.checkArguments(visitor); Optimizer opt = visitor.getConfiguration().getOptimizer(); argument[0] = ExpressionTool.unsorted(opt, argument[0], true); // we don't care about the order of the results, but we do care about how many nodes there are } /** * Determine the item type of the value returned by the function * @param th the type hierarchy cache */ public ItemType getItemType(TypeHierarchy th) { switch (operation) { case COUNT: return super.getItemType(th); case SUM: { //ItemType base = argument[0].getItemType(); ItemType base = Atomizer.getAtomizedItemType(argument[0], false, th); if (base.equals(BuiltInAtomicType.UNTYPED_ATOMIC)) { base = BuiltInAtomicType.DOUBLE; } if (Cardinality.allowsZero(argument[0].getCardinality())) { if (argument.length == 1) { return Type.getCommonSuperType(base, BuiltInAtomicType.INTEGER, th); } else { return Type.getCommonSuperType(base, argument[1].getItemType(th), th); } } else { return base; } } case AVG: { ItemType base = Atomizer.getAtomizedItemType(argument[0], false, th); if (base.equals(BuiltInAtomicType.UNTYPED_ATOMIC)) { return BuiltInAtomicType.DOUBLE; } else if (base.getPrimitiveType() == StandardNames.XS_INTEGER) { return BuiltInAtomicType.DECIMAL; } else { return base; } } default: throw new AssertionError("Unknown aggregate operation"); } } /** * Determine the cardinality of the function. */ public int computeCardinality() { if (operation == AVG && !Cardinality.allowsZero(argument[0].getCardinality())) { return StaticProperty.EXACTLY_ONE; } else { return super.computeCardinality(); } } /** * Evaluate the function */ public Item evaluateItem(XPathContext context) throws XPathException { // Note: these functions do not need to sort the underlying sequence, // but they do need to de-duplicate it switch (operation) { case COUNT: SequenceIterator iter = argument[0].iterate(context); return new Int64Value(count(iter)); case SUM: AtomicValue sum = total(argument[0].iterate(context), context, this); if (sum != null) { return sum; } else { // the sequence was empty if (argument.length == 2) { return argument[1].evaluateItem(context); } else { return Int64Value.ZERO; } } case AVG: return average(argument[0].iterate(context), context, this); default: throw new UnsupportedOperationException("Unknown aggregate function"); } } /** * Calculate the total of a sequence. * @param iter iterator over the items to be totalled * @param context the XPath dynamic context * @param location location of the expression in the source for diagnostics * @return the total, according to the rules of the XPath sum() function, but returning null * if the sequence is empty. (It's then up to the caller to decide what the correct result is * for an empty sequence. */ public static AtomicValue total(SequenceIterator iter, XPathContext context, SourceLocator location) throws XPathException { AtomicValue sum = (AtomicValue)iter.next(); if (sum == null) { // the sequence is empty return null; } // if (!sum.hasBuiltInType()) { // sum = sum.getPrimitiveValue(); // } if (sum instanceof UntypedAtomicValue) { try { sum = sum.convert(BuiltInAtomicType.DOUBLE, true, context).asAtomic(); } catch (XPathException e) { e.maybeSetLocation(location); throw e; } } if (sum instanceof NumericValue) { while (true) { AtomicValue next = (AtomicValue)iter.next(); if (next == null) { return sum; } if (next instanceof UntypedAtomicValue) { next = next.convert(BuiltInAtomicType.DOUBLE, true, context).asAtomic(); } else if (!(next instanceof NumericValue)) { XPathException err = new XPathException("Input to sum() contains a mix of numeric and non-numeric values"); err.setXPathContext(context); err.setErrorCode("FORG0006"); err.setLocator(location); throw err; } //sum = ((NumericValue)sum).arithmetic(Token.PLUS, (NumericValue)next, context); sum = ArithmeticExpression.compute(sum, Calculator.PLUS, next, context); if (sum.isNaN() && sum instanceof DoubleValue) { // take an early bath, once we've got a double NaN it's not going to change return sum; } } } else if (sum instanceof DurationValue) { while (true) { AtomicValue next = (AtomicValue)iter.next(); if (next == null) { return sum; } if (!(next instanceof DurationValue)) { XPathException err = new XPathException("Input to sum() contains a mix of duration and non-duration values"); err.setXPathContext(context); err.setErrorCode("FORG0006"); err.setLocator(location); throw err; } sum = ((DurationValue)sum).add((DurationValue)next); } } else { XPathException err = new XPathException("Input to sum() contains a value that is neither numeric, nor a duration"); err.setXPathContext(context); err.setErrorCode("FORG0006"); err.setLocator(location); throw err; } } /** * Calculate average * @param iter iterator over the items to be totalled * @param context the XPath dynamic context * @param location location of the expression in the source for diagnostics * @return the average of the values */ public static AtomicValue average(SequenceIterator iter, XPathContext context, SourceLocator location) throws XPathException { int count = 0; AtomicValue item = (AtomicValue)iter.next(); if (item == null) { // the sequence is empty return null; } count++; if (item instanceof UntypedAtomicValue) { try { item = item.convert(BuiltInAtomicType.DOUBLE, true, context).asAtomic(); } catch (XPathException e) { e.maybeSetLocation(location); throw e; } } if (item instanceof NumericValue) { while (true) { AtomicValue next = (AtomicValue)iter.next(); if (next == null) { //return ((NumericValue)item).arithmetic(Token.DIV, new Int64Value(count), context); return ArithmeticExpression.compute(item, Calculator.DIV, new Int64Value(count), context); } count++; if (next instanceof UntypedAtomicValue) { try { next = next.convert(BuiltInAtomicType.DOUBLE, true, context).asAtomic(); } catch (XPathException e) { e.maybeSetLocation(location); throw e; } } else if (!(next instanceof NumericValue)) { XPathException err = new XPathException("Input to avg() contains a mix of numeric and non-numeric values"); err.setXPathContext(context); err.setErrorCode("FORG0006"); err.setLocator(location); throw err; } //item = ((NumericValue)item).arithmetic(Token.PLUS, (NumericValue)next, context); item = ArithmeticExpression.compute(item, Calculator.PLUS, next, context); if (item.isNaN() && item instanceof DoubleValue) { // take an early bath, once we've got a double NaN it's not going to change return item; } } } else if (item instanceof DurationValue) { while (true) { AtomicValue next = (AtomicValue)iter.next(); if (next == null) { return ((DurationValue)item).multiply(1.0/count); } count++; if (!(next instanceof DurationValue)) { XPathException err = new XPathException("Input to avg() contains a mix of duration and non-duration values"); err.setXPathContext(context); err.setErrorCode("FORG0006"); err.setLocator(location); throw err; } item = ((DurationValue)item).add((DurationValue)next); } } else { XPathException err = new XPathException("Input to avg() contains a value that is neither numeric, nor a duration"); err.setXPathContext(context); err.setErrorCode("FORG0006"); err.setLocator(location); throw err; } } /** * Get the number of items in a sequence identified by a SequenceIterator * @param iter The SequenceIterator. This method moves the current position * of the supplied iterator; if this isn't safe, make a copy of the iterator * first by calling getAnother(). The supplied iterator must be positioned * before the first item (there must have been no call on next()). * @return the number of items in the underlying sequence * @throws XPathException if a failure occurs reading the input sequence */ public static int count(SequenceIterator iter) throws XPathException { if ((iter.getProperties() & SequenceIterator.LAST_POSITION_FINDER) != 0) { return ((LastPositionFinder)iter).getLastPosition(); } else { int n = 0; while (iter.next() != null) { n++; } return n; } } /** * Determine whether a given expression is a call to the count() function * @param exp an expression to be examined * @return true if the expression is a call to the count() function */ public static boolean isCountFunction(Expression exp) { if (!(exp instanceof Aggregate)) return false; Aggregate ag = (Aggregate)exp; return ag.getNumberOfArguments() == 1 && ag.operation == COUNT; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/functions/Evaluate.java0000644000175000017500000003736411064731733022047 0ustar eugeneeugenepackage net.sf.saxon.functions; import net.sf.saxon.expr.*; import net.sf.saxon.instruct.InstructionDetails; import net.sf.saxon.instruct.SlotManager; import net.sf.saxon.om.*; import net.sf.saxon.sxpath.IndependentContext; import net.sf.saxon.sxpath.XPathVariable; import net.sf.saxon.trace.Location; import net.sf.saxon.trans.SaxonErrorCode; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.Type; import net.sf.saxon.value.AtomicValue; import net.sf.saxon.value.ObjectValue; import net.sf.saxon.value.SequenceType; import net.sf.saxon.value.Value; import java.io.Serializable; import java.util.Iterator; /** * This class implements the saxon:evaluate(), saxon:expression(), and saxon:eval() extension functions, * which are specially-recognized by the system because they need access to parts of the static context */ public class Evaluate extends SystemFunction { // TODO: IDEA: make saxon:expression into a data type rather than a function. The function then comes "for free" // as a constructor function, but it also becomes possible to write things like // @price * @qty // IndependentContext staticContext; // This staticContext is created at stylesheet compile time. It is therefore shared by all // threads in which this stylesheet executes. Therefore it is immutable at run-time. When // an XPath expression is compiled, a mutable copy of the staticContext is made. InstructionDetails details; public static final int EVALUATE = 0; public static final int EXPRESSION = 1; public static final int EVAL = 2; public static final int EVALUATE_NODE = 3; /** * Get the required type of the nth argument */ protected SequenceType getRequiredType(int arg) { if (arg==0) { return super.getRequiredType(arg); } else { return SequenceType.ANY_SEQUENCE; } } /** * Method supplied by each class of function to check arguments during parsing, when all * the argument expressions have been read */ public void checkArguments(ExpressionVisitor visitor) throws XPathException { visitor.getExecutable().setReasonUnableToCompile( "Cannot compile a stylesheet containing calls to saxon:evaluate"); if (staticContext == null) { // only do this once StaticContext env = visitor.getStaticContext(); super.checkArguments(visitor); if (operation == EVALUATE || operation == EXPRESSION) { NamespaceResolver nsContext = env.getNamespaceResolver(); staticContext = new IndependentContext(env.getConfiguration()); staticContext.setBaseURI(env.getBaseURI()); staticContext.setImportedSchemaNamespaces(env.getImportedSchemaNamespaces()); staticContext.setDefaultFunctionNamespace(env.getDefaultFunctionNamespace()); staticContext.setDefaultElementNamespace(env.getDefaultElementNamespace()); for (Iterator iter = nsContext.iteratePrefixes(); iter.hasNext();) { String prefix = (String)iter.next(); if (!"".equals(prefix)) { String uri = nsContext.getURIForPrefix(prefix, true); staticContext.declareNamespace(prefix, uri); } } details = new InstructionDetails(); details.setConstructType(Location.SAXON_EVALUATE); details.setSystemId(env.getLocationMap().getSystemId(this.locationId)); details.setLineNumber(env.getLocationMap().getLineNumber(this.locationId)); } else if (operation == EVALUATE_NODE) { // for saxon:evaluate-node() the static context of the expression is based // on the node in the source document containing the expression. staticContext = new IndependentContext(env.getConfiguration()); } } } /** * preEvaluate: for saxon:expression, if the expression is * known at compile time, then it is compiled at compile time. * In other cases this method suppresses compile-time evaluation by doing nothing * (because the value of the expression depends on the runtime context). * @param visitor an expression visitor */ public Expression preEvaluate(ExpressionVisitor visitor) throws XPathException { if (operation == EXPRESSION && getNumberOfArguments()==1) { // compile-time evaluation of saxon:expression is attempted. However, it may fail // if the expression references stylesheet functions, because the static context does not // yet include these. See xslts-extra/evaluate001 if (argument[0] instanceof StringLiteral) { try { PreparedExpression pexpr = new PreparedExpression(); String exprText = ((StringLiteral)argument[0]).getStringValue(); pexpr.variables = new XPathVariable[10]; for (int i=1; i<10; i++) { pexpr.variables[i-1] = staticContext.declareVariable("", "p"+i); } Expression expr = ExpressionTool.make(exprText, staticContext, 0, Token.EOF, 1, false); ItemType contextItemType = Type.ITEM_TYPE; expr = visitor.typeCheck(expr, contextItemType); pexpr.stackFrameMap = staticContext.getStackFrameMap(); ExpressionTool.allocateSlots(expr, pexpr.stackFrameMap.getNumberOfVariables(), pexpr.stackFrameMap); pexpr.expression = expr; return new Literal(new ObjectValue(pexpr)); } catch (XPathException e) { // If precompilation failed, try again at runtime return this; } } } // the other operations don't allow compile time evaluation because they need a run-time context return this; } private PreparedExpression prepareExpression(XPathContext context) throws XPathException { if (operation == EVAL) { Item item = argument[0].evaluateItem(context); if (!(item instanceof ObjectValue)) { dynamicError( "First argument to saxon:eval must be an expression prepared using saxon:expression", SaxonErrorCode.SXXF0001, context); return null; } ObjectValue obj = (ObjectValue)item; Object v = obj.getObject(); if (!(v instanceof PreparedExpression)) { dynamicError( "First argument to saxon:eval must be an expression prepared using saxon:expression", SaxonErrorCode.SXXF0001, context); return null; } return (PreparedExpression)v; } PreparedExpression pexpr = new PreparedExpression(); String exprText; if (operation == EVALUATE_NODE) { NodeInfo node = (NodeInfo)argument[0].evaluateItem(context); IndependentContext env = staticContext.copy(); pexpr.expStaticContext = env; env.setBaseURI(node.getBaseURI()); env.setFunctionLibrary(getExecutable().getFunctionLibrary()); env.setNamespaces(node); exprText = node.getStringValue(); UnfailingIterator single = SingletonIterator.makeIterator(node); single.next(); context.setCurrentIterator(single); Expression expr; try { expr = ExpressionTool.make(exprText, env, 0, Token.EOF, 1, false); expr.setContainer(env); } catch (XPathException e) { String name = getFunctionName().getDisplayName(); XPathException err = new XPathException("Static error in XPath expression supplied to " + name + ": " + e.getMessage().trim()); err.setXPathContext(context); throw err; } ItemType contextItemType = Type.ITEM_TYPE; ExpressionVisitor visitor = ExpressionVisitor.make(env); visitor.setExecutable(env.getExecutable()); expr = visitor.typeCheck(expr, contextItemType); pexpr.stackFrameMap = env.getStackFrameMap(); ExpressionTool.allocateSlots(expr, pexpr.stackFrameMap.getNumberOfVariables(), pexpr.stackFrameMap); pexpr.expression = expr; expr.setContainer(env); return pexpr; } AtomicValue exprSource = (AtomicValue)argument[0].evaluateItem(context); exprText = exprSource.getStringValue(); IndependentContext env = staticContext.copy(); env.setFunctionLibrary(getExecutable().getFunctionLibrary()); if (operation == EXPRESSION && getNumberOfArguments() == 2) { NodeInfo node = (NodeInfo)argument[1].evaluateItem(context); env.setNamespaces(node); } pexpr.expStaticContext = env; pexpr.variables = new XPathVariable[10]; for (int i=1; i<10; i++) { pexpr.variables[i-1] = env.declareVariable("", "p"+i); } Expression expr; try { expr = ExpressionTool.make(exprText, env, 0, Token.EOF, 1, false); } catch (XPathException e) { String name = getFunctionName().getDisplayName(); XPathException err = new XPathException("Static error in XPath expression supplied to " + name + ": " + e.getMessage().trim()); err.setErrorCode(e.getErrorCodeNamespace(), e.getErrorCodeLocalPart()); err.setXPathContext(context); throw err; } ItemType contextItemType = Type.ITEM_TYPE; ExpressionVisitor visitor = ExpressionVisitor.make(env); visitor.setExecutable(env.getExecutable()); expr = ExpressionTool.resolveCallsToCurrentFunction(expr, env.getConfiguration()); expr = visitor.typeCheck(expr, contextItemType); pexpr.stackFrameMap = env.getStackFrameMap(); ExpressionTool.allocateSlots(expr, pexpr.stackFrameMap.getNumberOfVariables(), pexpr.stackFrameMap); pexpr.expression = expr; expr.setContainer(env); return pexpr; } /** * Add a representation of this expression to a PathMap. The PathMap captures a map of the nodes visited * by an expression in a source tree. *

*

The default implementation of this method assumes that an expression does no navigation other than * the navigation done by evaluating its subexpressions, and that the subexpressions are evaluated in the * same context as the containing expression. The method must be overridden for any expression * where these assumptions do not hold. For example, implementations exist for AxisExpression, ParentExpression, * and RootExpression (because they perform navigation), and for the doc(), document(), and collection() * functions because they create a new navigation root. Implementations also exist for PathExpression and * FilterExpression because they have subexpressions that are evaluated in a different context from the * calling expression.

* *

This particular implementation has to deal with the fact that saxon:evaluate() and related functions * can navigate anywhere in the tree. * * @param pathMap the PathMap to which the expression should be added * @param pathMapNodeSet the PathMapNodeSet to which the paths embodied in this expression should be added * @return the pathMapNodeSet representing the points in the source document that are both reachable by this * expression, and that represent possible results of this expression. For an expression that does * navigation, it represents the end of the arc in the path map that describes the navigation route. For other * expressions, it is the same as the input pathMapNode. */ public PathMap.PathMapNodeSet addToPathMap(PathMap pathMap, PathMap.PathMapNodeSet pathMapNodeSet) { // TODO: this isn't working for a call such as saxon:expression("@xyz") that can be pre-evaluated // It may not be working in other cases either (not tested) return new RootExpression().addToPathMap(pathMap, pathMapNodeSet); } /** * Evaluate in a general context */ public Item evaluateItem(XPathContext c) throws XPathException { if (operation == EXPRESSION) { PreparedExpression pexpr = prepareExpression(c); return new ObjectValue(pexpr); } else if (operation == EVALUATE_NODE) { XPathContextMajor c2 = c.newCleanContext(); PreparedExpression pexpr = prepareExpression(c2); c2.setOrigin(details); c2.openStackFrame(pexpr.stackFrameMap); return pexpr.expression.evaluateItem(c2); } else { XPathContextMajor c2 = c.newCleanContext(); PreparedExpression pexpr = prepareExpression(c2); for (int i=1; i *

This method is called after all references to functions and variables have been resolved * to the declaration of the function or variable, and after all type checking has been done.

* * @param visitor an expression visitor * @param contextItemType the static type of "." at the point where this expression is invoked. * The parameter is set to null if it is known statically that the context item will be undefined. * If the type of the context item is not known statically, the argument is set to * {@link net.sf.saxon.type.Type#ITEM_TYPE} * @return the original expression, rewritten if appropriate to optimize execution * @throws net.sf.saxon.trans.XPathException * if an error is discovered during this phase * (typically a type error) */ public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { Expression e = super.optimize(visitor, contextItemType); // try once again to compile the regular expression once if possible // (used when the regex has been identified as a constant as a result of earlier rewrites) if (e == this) { maybePrecompile(visitor); } return e; } /** * Get the compiled regular expression if available, otherwise return null * @return the compiled regular expression, or null */ public RegularExpression getCompiledRegularExpression() { return regexp; } /** * Iterate over the results of the function */ public SequenceIterator iterate(XPathContext c) throws XPathException { AtomicValue sv = (AtomicValue)argument[0].evaluateItem(c); if (sv==null) { return EmptyIterator.getInstance(); } CharSequence input = sv.getStringValueCS(); if (input.length() == 0) { return EmptyIterator.getInstance(); } RegularExpression re = regexp; if (re == null) { sv = (AtomicValue)argument[1].evaluateItem(c); CharSequence pattern = sv.getStringValueCS(); CharSequence flags; if (argument.length==2) { flags = ""; } else { sv = (AtomicValue)argument[2].evaluateItem(c); flags = sv.getStringValueCS(); } try { final Platform platform = Configuration.getPlatform(); final int xmlVersion = c.getConfiguration().getXMLVersion(); re = platform.compileRegularExpression( pattern, xmlVersion, RegularExpression.XPATH_SYNTAX, flags); } catch (XPathException err) { XPathException de = new XPathException(err); de.setErrorCode("FORX0002"); de.setXPathContext(c); de.setLocator(this); throw de; } // check that it's not a pattern that matches "" if (re.matches("")) { XPathException err = new XPathException("The regular expression in tokenize() must not be one that matches a zero-length string"); err.setErrorCode("FORX0003"); err.setLocator(this); throw err; } } return re.tokenize(input); } /** * Simple command-line interface for testing. * @param args (1) the string to be tokenized (2) the regular expression * @throws Exception */ public static void main(String[] args) throws Exception { String in = args[0]; String[] out = Pattern.compile(args[1]).split(in, 0); System.out.println("results"); for (int i=0; i Package overview for net.sf.saxon.functions

This package provides implementations of all the core functions available for use in XPath expressions. This includes all the functions defined in the XPath 2.0 Functions and Operators specification, as well as the additional functions defined for use in XSLT. The package also includes Saxon extension functions. Most of these are in a single class Extensions, but some of the more complex functions are in their own classes, for example Evaluate implements saxon:evaluate().

There is one class for group of closely-related functions. These all inherit from the class net.sf.saxon.expr.Function. The class StandardFunction is used to map a function name to its implementation; it contains tables of information describing the signature of each function, so that the type-checking code is completely generic.

The package also contains machinery for defining user extension functions. A collection of functions is represented by a FunctionLibrary object. There are several standard function libraries available, covering core functions, Saxon extension functions constructor functions, and user extension functions: each category is covered by a subclass of FunctionLibrary, and there is also a FunctionLibraryList that represents the total collection of functions in these individual libraries. The JavaExtensionLibrary contains the logic for binding Java extension functions given their name and arity and the types of their arguments. The class ExtensionFunctionCall contains the run-time logic for converting XPath values to the required Java types, and for converting the result back to an XPath value.

These classes, although public, will not normally be used directly by user-written Java applications.


Michael H. Kay
Saxonica Limited
9 February 2005

saxonb-9.1.0.8/bj/net/sf/saxon/AugmentedSource.java0000644000175000017500000004367611033112257021354 0ustar eugeneeugenepackage net.sf.saxon; import net.sf.saxon.event.Builder; import net.sf.saxon.event.ParseOptions; import net.sf.saxon.event.ProxyReceiver; import net.sf.saxon.om.StructuredQName; import net.sf.saxon.om.Validation; import net.sf.saxon.type.SchemaType; import org.xml.sax.EntityResolver; import org.xml.sax.InputSource; import org.xml.sax.XMLReader; import javax.xml.transform.ErrorListener; import javax.xml.transform.Source; import javax.xml.transform.sax.SAXSource; import javax.xml.transform.stream.StreamSource; import java.io.IOException; import java.util.List; /** * This class is an extension of the JAXP Source interface. The class can be used * wherever a JAXP Source object can be used, and it provides additional information * about the way that the Source is to be processed: for example, it indicates * whether or not it should be validated against a schema. Other options that can * be set include the SAX XMLReader to be used, and the choice of whether a source * in the form of an existing tree should be copied or wrapped. * @since 8.8 */ public class AugmentedSource implements Source { private Source source; private ParseOptions options = new ParseOptions(); // private int schemaValidation = Validation.DEFAULT; // private int dtdValidation = Validation.DEFAULT; // private StructuredQName topLevelElement; // private SchemaType topLevelType; // private XMLReader parser = null; // private Boolean wrapDocument = null; // private int treeModel = Builder.UNSPECIFIED_TREE_MODEL; // private int stripSpace; // private Boolean lineNumbering = null; // private Boolean xIncludeAware = null; // private boolean pleaseClose = false; private EntityResolver entityResolver = null; // private ErrorListener errorListener = null; // private List filters = null; // private boolean sourceIsXQJ = false; /** * Create an AugmentedSource that wraps a given Source object (which must not itself be an * AugmentedSource) * @param source the Source object to be wrapped. This must be an implementation of Source * that Saxon recognizes, or an implementation for which a {@link SourceResolver} has been * registered with the {@link Configuration}. The source must not itself be an * AugmentedSource. *

As an alternative to this constructor, consider using the factory method * {@link #makeAugmentedSource}, which does accept any kind of Source including an * AugmentedSource as input.

* @throws IllegalArgumentException if the wrapped source is an AugmentedSource * @since 8.8 */ private AugmentedSource(Source source) { if (source instanceof AugmentedSource) { throw new IllegalArgumentException("Contained source must not be an AugmentedSource"); } this.source = source; } /** * Create an AugmentedSource that wraps a given Source object. If this is already * an AugmentedSource, the original AugmentedSource is returned. Note that this means that * setting any properties on the returned AugmentedSource will also affect the original. * @param source the Source object to be wrapped * @return an AugmentedSource * @since 8.8 */ public static AugmentedSource makeAugmentedSource(Source source) { if (source instanceof AugmentedSource) { return (AugmentedSource)source; } return new AugmentedSource(source); } /** * Add a filter to the list of filters to be applied to the raw input * @param filter the filter to be added */ public void addFilter(ProxyReceiver filter) { options.addFilter(filter); } /** * Get the list of filters to be applied to the input. Returns null if there are no filters. * @return the list of filters, if there are any */ public List getFilters() { return options.getFilters(); } /** * Get the Source object wrapped by this AugmentedSource * @return the contained Source object * @since 8.8 */ public Source getContainedSource() { return source; } /** * Set the space-stripping action to be applied to the source document * @param stripAction one of {@link net.sf.saxon.value.Whitespace#IGNORABLE}, * {@link net.sf.saxon.value.Whitespace#ALL}, or {@link net.sf.saxon.value.Whitespace#NONE} * @since 8.8 */ public void setStripSpace(int stripAction) { options.setStripSpace(stripAction); } /** * Get the space-stripping action to be applied to the source document * @return one of {@link net.sf.saxon.value.Whitespace#IGNORABLE}, * {@link net.sf.saxon.value.Whitespace#ALL}, or {@link net.sf.saxon.value.Whitespace#NONE} * @since 8.8 */ public int getStripSpace() { return options.getStripSpace(); } /** * Set the tree model to use. Default is the tiny tree * @param model one of {@link Builder#TINY_TREE} or {@link Builder#LINKED_TREE} * @since 8.9 */ public void setTreeModel(int model) { options.setTreeModel(model); } /** * Get the tree model that will be used. * @return one of {@link Builder#TINY_TREE} or {@link Builder#LINKED_TREE}, * or {link Builder#UNSPECIFIED_TREE_MODEL} if no call on setTreeModel() has been made * @since 8.9 */ public int getTreeModel() { return options.getTreeModel(); } /** * Set whether or not schema validation of this source is required * @param option one of {@link Validation#STRICT}, * {@link Validation#LAX}, {@link Validation#STRIP}, * {@link Validation#PRESERVE}, {@link Validation#DEFAULT} * @since 8.8 * */ public void setSchemaValidationMode(int option) { options.setSchemaValidationMode(option); } /** * Get whether or not schema validation of this source is required * @return the validation mode requested, or {@link Validation#DEFAULT} * to use the default validation mode from the Configuration. * @since 8.8 */ public int getSchemaValidation() { return options.getSchemaValidationMode(); } /** * Set the name of the top-level element for validation. * If a top-level element is set then the document * being validated must have this as its outermost element * @param elementName the QName of the required top-level element, or null to unset the value * @since 9.0 */ public void setTopLevelElement(StructuredQName elementName) { options.setTopLevelElement(elementName); } /** * Get the name of the top-level element for validation. * If a top-level element is set then the document * being validated must have this as its outermost element * @return the QName of the required top-level element, or null if no value is set * @since 9.0 */ public StructuredQName getTopLevelElement() { return options.getTopLevelElement(); } /** * Set the type of the top-level element for validation. * If this is set then the document element is validated against this type * @param type the schema type required for the document element, or null to unset the value * @since 9.0 */ public void setTopLevelType(SchemaType type) { options.setTopLevelType(type); } /** * Get the type of the document element for validation. * If this is set then the document element of the document * being validated must have this type * @return the type of the required top-level element, or null if no value is set * @since 9.0 */ public SchemaType getTopLevelType() { return options.getTopLevelType(); } /** * Set whether or not DTD validation of this source is required * @param option one of {@link Validation#STRICT}, * {@link Validation#STRIP}, {@link Validation#DEFAULT} * @since 8.8 */ public void setDTDValidationMode(int option) { options.setDTDValidationMode(option); } /** * Get whether or not DTD validation of this source is required * @return the validation mode requested, or {@link Validation#DEFAULT} * to use the default validation mode from the Configuration. * @since 8.8 */ public int getDTDValidation() { return options.getDTDValidationMode(); } /** * Set whether line numbers are to be maintained in the constructed document * @param lineNumbering true if line numbers are to be maintained * @since 8.8 */ public void setLineNumbering(boolean lineNumbering) { options.setLineNumbering(lineNumbering); } /** * Get whether line numbers are to be maintained in the constructed document * @return true if line numbers are maintained * @since 8.8 */ public boolean isLineNumbering() { return options.isLineNumbering(); } /** * Determine whether setLineNumbering() has been called * @return true if setLineNumbering() has been called * @since 8.9 */ public boolean isLineNumberingSet() { return options.isLineNumberingSet(); } /** * Set the SAX parser (XMLReader) to be used * @param parser the SAX parser * @since 8.8 */ public void setXMLReader(XMLReader parser) { options.setXMLReader(parser); if (source instanceof SAXSource) { ((SAXSource)source).setXMLReader(parser); } } /** * Get the SAX parser (XMLReader) to be used * @return the parser * @since 8.8 */ public XMLReader getXMLReader() { XMLReader parser = options.getXMLReader(); if (parser != null) { return parser; } else if (source instanceof SAXSource) { return ((SAXSource)source).getXMLReader(); } else { return null; } } /** * Assuming that the contained Source is a node in a tree, indicate whether a tree should be created * as a view of this supplied tree, or as a copy. * @param wrap if true, the node in the supplied Source is wrapped, to create a view. If false, the node * and its contained subtree is copied. If null, the system default is chosen. * @since 8.8 */ public void setWrapDocument(Boolean wrap) { options.setWrapDocument(wrap); } /** Assuming that the contained Source is a node in a tree, determine whether a tree will be created * as a view of this supplied tree, or as a copy. * @return if true, the node in the supplied Source is wrapped, to create a view. If false, the node * and its contained subtree is copied. If null, the system default is chosen. * @since 8.8 */ public Boolean getWrapDocument() { return options.getWrapDocument(); } /** * Set the System ID. This sets the System Id on the underlying Source object. * @param id the System ID. This provides a base URI for the document, and also the result * of the document-uri() function * @since 8.8 */ public void setSystemId(String id) { source.setSystemId(id); } /** * Get the System ID. This gets the System Id on the underlying Source object. * @return the System ID: effectively the base URI. * @since 8.8 */ public String getSystemId() { return source.getSystemId(); } /** *

Set state of XInclude processing.

*

*

If XInclude markup is found in the document instance, should it be * processed as specified in * XML Inclusions (XInclude) Version 1.0.

*

*

XInclude processing defaults to false.

* * @param state Set XInclude processing to true or * false * @since 8.9 */ public void setXIncludeAware(boolean state) { options.setXIncludeAware(state); } /** *

Determine whether setXIncludeAware() has been called.

* * @return true if setXIncludeAware() has been called * @since 8.9 */ public boolean isXIncludeAwareSet() { return options.isXIncludeAwareSet(); } /** *

Get state of XInclude processing.

* * @return current state of XInclude processing. Default value is false. * @since 8.9 */ public boolean isXIncludeAware() { return options.isXIncludeAware(); } /** * Set an EntityResolver to be used when parsing * @param resolver the EntityResolver to be used * @since 8.9 * @deprecated since 9.1 (this method has never had any effect, other than allowing the EntityResolver to * be retrieved using the getEntityResolver() method) */ public void setEntityResolver(EntityResolver resolver) { entityResolver = resolver; } /** * Get the EntityResolver that will be used when parsing * @return the EntityResolver, if one has been set using {@link #setEntityResolver}, * otherwise null. * @since 8.9 * @deprecated since 9.1 (setting an EntityResolver has never had any effect) */ public EntityResolver getEntityResolver() { return entityResolver; } /** * Set an ErrorListener to be used when parsing * @param listener the ErrorListener to be used * @since 8.9 */ public void setErrorListener(ErrorListener listener) { options.setErrorListener(listener); } /** * Get the ErrorListener that will be used when parsing * @return the ErrorListener, if one has been set using {@link #setErrorListener}, * otherwise null. * @since 8.9 */ public ErrorListener getErrorListener() { return options.getErrorListener(); } /** * Set whether or not the user of this Source is encouraged to close it as soon as reading is finished. * Normally the expectation is that any Stream in a StreamSource will be closed by the component that * created the Stream. However, in the case of a Source returned by a URIResolver, there is no suitable * interface (the URIResolver has no opportunity to close the stream). Also, in some cases such as reading * of stylesheet modules, it is possible to close the stream long before control is returned to the caller * who supplied it. This tends to make a difference on .NET, where a file often can't be opened if there * is a stream attached to it. * @param close true if the source should be closed as soon as it has been consumed * @since 8.8 */ public void setPleaseCloseAfterUse(boolean close) { options.setPleaseCloseAfterUse(close); } /** * Determine whether or not the user of this Source is encouraged to close it as soon as reading is * finished. * @return true if the source should be closed as soon as it has been consumed * @since 8.8 */ public boolean isPleaseCloseAfterUse() { return options.isPleaseCloseAfterUse(); } /** * Indicate that this Source is supporting the weird XQJ createItemFromDocument(XMLReader) method. * This contains a preinitialized XMLReader that needs to be invoked in a special way * @param flag set to true if this is a special XQJ SAXSource */ public void setSourceIsXQJ(boolean flag) { options.setSourceIsXQJ(flag); } /** * Ask whether this Source is supporting the weird XQJ createItemFromDocument(XMLReader) method. * This contains a preinitialized XMLReader that needs to be invoked in a special way * @return true if this is a special XQJ SAXSource */ public boolean sourceIsXQJ() { return options.sourceIsXQJ(); } /** * Close any resources held by this Source. This only works if the underlying Source is one that is * recognized as holding closable resources. * @since 8.8 */ public void close() { try { if (source instanceof StreamSource) { StreamSource ss = (StreamSource)source; if (ss.getInputStream() != null) { ss.getInputStream().close(); } if (ss.getReader() != null) { ss.getReader().close(); } } else if (source instanceof SAXSource) { InputSource is = ((SAXSource)source).getInputSource(); if (is != null) { if (is.getByteStream() != null) { is.getByteStream().close(); } if (is.getCharacterStream() != null) { is.getCharacterStream().close(); } } } } catch (IOException err) { // no action } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. //saxonb-9.1.0.8/bj/net/sf/saxon/Version.java0000644000175000017500000000734411271701317017704 0ustar eugeneeugenepackage net.sf.saxon; /** * The Version class holds the SAXON version information. */ public final class Version { private static final int[] STRUCTURED_VERSION = {9,1,0,8}; private static final String VERSION = "9.1.0.8"; private static final String BUILD = "102723"; //mmddhh private static final String RELEASE_DATE = "2009-10-27"; private Version() { // class is never instantiated } /** * Return the name of this product. Supports the XSLT 2.0 system property xsl:product-name * @return the string "SAXON" */ public static String getProductName() { return "SAXON"; } /** * Get the version number of the schema-aware version of the product * @return the version number of this version of Saxon, as a string */ public static String getSchemaAwareProductVersion() { return "SA " + getProductVersion(); } /** * Get the user-visible version number of this version of the product * @return the version number of this version of Saxon, as a string: for example "9.0.1" */ public static String getProductVersion() { return VERSION; } /** * Get the four components of the structured version number. This is used in the .NET product * to locate an assembly in the dynamic assembly cache: the assumption is that the third * and fourth components represent implementation changes rather than interface changes * @return the four components of the version number, as an array: for example {9, 0, 1, 1} */ public static int[] getStructuredVersionNumber() { return STRUCTURED_VERSION; } /** * Get the issue date of this version of the product * @return the release date, as an ISO 8601 string */ public static String getReleaseDate() { return RELEASE_DATE; } /** * Get the version of the XSLT specification that this product supports * @return the string 2.0 */ public static String getXSLVersionString() { return "2.0"; } /** * Get a message used to identify this product when a transformation is run using the -t option * @return A string containing both the product name and the product * version */ public static String getProductTitle() { return getProductName() + ' ' + getProductVersion() + " from Saxonica"; } /** * Return a web site address containing information about the product. Supports the XSLT system property xsl:vendor-url * @return the string "http://saxon.sf.net/" */ public static String getWebSiteAddress() { return "http://www.saxonica.com/"; } /** * Invoking net.sf.saxon.Version from the command line outputs the build number * @param args not used */ public static void main(String[] args) { System.err.println(getProductTitle() + " (build " + BUILD + ')'); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/CollectionURIResolver.java0000644000175000017500000000556311033112257022450 0ustar eugeneeugenepackage net.sf.saxon; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.trans.XPathException; import java.io.Serializable; /** * This interface defines a CollectionURIResolver. This is a counterpart to the JAXP * URIResolver, but is used to map the URI of collection into a sequence of documents * @author Michael H. Kay */ public interface CollectionURIResolver extends Serializable { /** * Resolve a URI. * @param href The relative URI of the collection. This corresponds to the * argument supplied to the collection() function. If the collection() function * was called with no arguments (to get the "default collection") this argument * will be null. * @param base The base URI that should be used. This is the base URI of the * static context in which the call to collection() was made, typically the URI * of the stylesheet or query module * @param context The dynamic execution context * @return an Iterator over the documents in the collection. The items returned * by this iterator must be instances either of xs:anyURI, or of node() (specifically, * {@link net.sf.saxon.om.NodeInfo}.). If xs:anyURI values are returned, the corresponding * document will be retrieved as if by a call to the doc() function: this means that * the system first checks to see if the document is already loaded, and if not, calls * the registered URIResolver to dereference the URI. This is the recommended approach * to ensure that the resulting collection is stable: however, it has the consequence * that the documents will by default remain in memory for the duration of the query * or transformation. *

* If the URI is not recognized, the method may either return an empty iterator, * in which case no error is reported, or it may throw an exception, in which case * the query or transformation fails. Returning null has the same effect as returning * an empty iterator. */ public SequenceIterator resolve(String href, String base, XPathContext context) throws XPathException; } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/evpull/0000755000175000017500000000000012216261751016716 5ustar eugeneeugenesaxonb-9.1.0.8/bj/net/sf/saxon/evpull/EndDocumentEvent.java0000644000175000017500000000202611033112257022760 0ustar eugeneeugenepackage net.sf.saxon.evpull; import net.sf.saxon.evpull.PullEvent; /** * Pull event representing the end of a document */ public class EndDocumentEvent implements PullEvent { private final static EndDocumentEvent THE_INSTANCE = new EndDocumentEvent(); public static EndDocumentEvent getInstance() { return THE_INSTANCE; } private EndDocumentEvent() { } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/evpull/EventIterator.java0000644000175000017500000000267111033112257022352 0ustar eugeneeugenepackage net.sf.saxon.evpull; import net.sf.saxon.trans.XPathException; /** * An iterator over a sequence of events */ public interface EventIterator extends PullEvent { /** * Get the next event in the sequence * @return the next event, or null when the sequence is exhausted. Note that since an EventIterator is * itself a PullEvent, this method may return a nested iterator. * @throws XPathException if a dynamic evaluation error occurs */ public PullEvent next() throws XPathException; /** * Determine whether the EventIterator returns a flat sequence of events, or whether it can return * nested event iterators * @return true if the next() method is guaranteed never to return an EventIterator */ public boolean isFlatSequence(); } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/evpull/EventIteratorOverSequence.java0000644000175000017500000000341511033112257024674 0ustar eugeneeugenepackage net.sf.saxon.evpull; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.trans.XPathException; /** * This class maps a SequenceIterator to an EventIterator, by simply returning the items in the sequence * as PullEvents. */ public class EventIteratorOverSequence implements EventIterator { SequenceIterator base; /** * Create an EventIterator that wraps a given SequenceIterator * @param base the SequenceIterator to be wrapped */ public EventIteratorOverSequence(SequenceIterator base) { this.base = base; } /** * Get the next PullEvent in the sequence * @return the next PullEvent * @throws XPathException in case of a dynamic error */ public PullEvent next() throws XPathException { return base.next(); } /** * Determine whether the EventIterator returns a flat sequence of events, or whether it can return * nested event iterators * * @return true if the next() method is guaranteed never to return an EventIterator */ public boolean isFlatSequence() { return true; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/evpull/StartElementEvent.java0000644000175000017500000003202411162435365023176 0ustar eugeneeugenepackage net.sf.saxon.evpull; import net.sf.saxon.Configuration; import net.sf.saxon.event.PipelineConfiguration; import net.sf.saxon.expr.ExpressionLocation; import net.sf.saxon.om.NamePool; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.om.Orphan; import net.sf.saxon.om.StandardNames; import net.sf.saxon.sort.IntArraySet; import net.sf.saxon.trans.Err; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.Type; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; /** * This is a PullEvent representing the start of an element node. It contains (or potentially contains) all the * namespace declarations and attributes associated with the element. */ public class StartElementEvent implements PullEvent { PipelineConfiguration pipe; private int nameCode; private int typeCode; private int[] localNamespaces; private List attributes; private int locationId = -1; /** * Create a Start Element Event * @param pipe the pipeline configuration */ public StartElementEvent(PipelineConfiguration pipe) { this.pipe = pipe; } /** * Set the nameCode of this element * @param nameCode the namecode of the element (its name as identified in the NamePool) */ public void setNameCode(int nameCode) { this.nameCode = nameCode; } /** * Get the nameCode of this element * @return the nameCode representing the element's name */ public int getNameCode() { return nameCode; } /** * Set the typeCode of this element * @param typeCode the name pool fingerprint of the element's type annotation */ public void setTypeCode(int typeCode) { this.typeCode = typeCode; } /** * Get the typeCode of this element * @return the name pool fingerprint of the element's type annotation */ public int getTypeCode() { return typeCode; } /** * Set the namespaces that are locally declared (or undeclared) on this element * @param nscodes integer array of namespace codes */ public void setLocalNamespaces(int[] nscodes) { localNamespaces = nscodes; } /** * Add a namespace code representing a locally declared namespace * @param nscode a namespace code * @throws XPathException */ public void addNamespace(int nscode) throws XPathException { if (localNamespaces == null) { localNamespaces = new int[]{nscode, -1, -1, -1}; } for (int n=0; n 0) { message = message.substring(c + 10); } } XPathException err = new XPathException("Error reported by XML parser: " + message); err.setErrorCode(SaxonErrorCode.SXXP0003); err.setLocator(translateLocation(e.getLocation())); throw err; } return currentEvent; } /** * Translate a StAX event into a Saxon PullEvent * @param event the StAX event * @return the Saxon PullEvent * @throws XPathException */ private PullEvent translate(int event) throws XPathException { //System.err.println("EVENT " + event); switch (event) { case XMLStreamConstants.ATTRIBUTE: return next(); // attributes are reported as part of StartElement case XMLStreamConstants.CDATA: case XMLStreamConstants.CHARACTERS: if (depth == 0 && reader.isWhiteSpace()) { return next(); } else { Orphan o = new Orphan(config); o.setNodeKind(Type.TEXT); CharSlice value = new CharSlice( reader.getTextCharacters(), reader.getTextStart(), reader.getTextLength()); o.setStringValue(value); return o; } case XMLStreamConstants.COMMENT: { Orphan o = new Orphan(config); o.setNodeKind(Type.COMMENT); CharSlice value = new CharSlice( reader.getTextCharacters(), reader.getTextStart(), reader.getTextLength()); o.setStringValue(value); return o; } case XMLStreamConstants.DTD: unparsedEntities = (List)reader.getProperty("javax.xml.stream.entities"); return next(); case XMLStreamConstants.END_DOCUMENT: return EndDocumentEvent.getInstance(); case XMLStreamConstants.END_ELEMENT: depth--; return EndElementEvent.getInstance(); case XMLStreamConstants.ENTITY_DECLARATION: return next(); case XMLStreamConstants.ENTITY_REFERENCE: return next(); case XMLStreamConstants.NAMESPACE: return next(); // namespaces are reported as part of StartElement case XMLStreamConstants.NOTATION_DECLARATION: return next(); case XMLStreamConstants.PROCESSING_INSTRUCTION:{ Orphan o = new Orphan(config); o.setNodeKind(Type.PROCESSING_INSTRUCTION); String local = reader.getPITarget(); o.setNameCode(getNamePool().allocate("", "", local)); o.setStringValue(reader.getText()); return o; } case XMLStreamConstants.SPACE: if (depth == 0) { return next(); } else if (ignoreIgnorable) { // (Brave attempt, but Woodstox doesn't seem to report ignorable whitespace) return next(); } else { Orphan o = new Orphan(config); o.setNodeKind(Type.TEXT); o.setStringValue(reader.getText()); return o; } case XMLStreamConstants.START_DOCUMENT: return next(); // we supplied the START_DOCUMENT ourselves case XMLStreamConstants.START_ELEMENT: depth++; StartElementEvent see = new StartElementEvent(pipe); String elocal = reader.getLocalName(); String euri = reader.getNamespaceURI(); String eprefix = reader.getPrefix(); if (eprefix == null) { eprefix = ""; } if (euri == null) { euri = ""; } int enc = getNamePool().allocate(eprefix, euri, elocal); see.setNameCode(enc); see.setTypeCode(StandardNames.XS_UNTYPED); int attCount = reader.getAttributeCount(); for (int index=0; index *

The return value is the public identifier of the document * entity or of the external parsed entity in which the markup * triggering the event appears.

* * @return A string containing the public identifier, or * null if none is available. * @see #getSystemId */ public String getPublicId() { return reader.getLocation().getPublicId(); } /** * Return the system identifier for the current document event. *

*

The return value is the system identifier of the document * entity or of the external parsed entity in which the markup * triggering the event appears.

*

*

If the system identifier is a URL, the parser must resolve it * fully before passing it to the application. For example, a file * name must always be provided as a file:... URL, and other * kinds of relative URI are also resolved against their bases.

* * @return A string containing the system identifier, or null * if none is available. * @see #getPublicId */ public String getSystemId() { return reader.getLocation().getSystemId(); } /** * Return the line number where the current document event ends. * Lines are delimited by line ends, which are defined in * the XML specification. *

*

Warning: The return value from the method * is intended only as an approximation for the sake of diagnostics; * it is not intended to provide sufficient information * to edit the character content of the original XML document. * In some cases, these "line" numbers match what would be displayed * as columns, and in others they may not match the source text * due to internal entity expansion.

*

*

The return value is an approximation of the line number * in the document entity or external parsed entity where the * markup triggering the event appears.

*

*

If possible, the SAX driver should provide the line position * of the first character after the text associated with the document * event. The first line is line 1.

* * @return The line number, or -1 if none is available. * @see #getColumnNumber */ public int getLineNumber() { return reader.getLocation().getLineNumber(); } /** * Return the column number where the current document event ends. * This is one-based number of Java char values since * the last line end. *

*

Warning: The return value from the method * is intended only as an approximation for the sake of diagnostics; * it is not intended to provide sufficient information * to edit the character content of the original XML document. * For example, when lines contain combining character sequences, wide * characters, surrogate pairs, or bi-directional text, the value may * not correspond to the column in a text editor's display.

*

*

The return value is an approximation of the column number * in the document entity or external parsed entity where the * markup triggering the event appears.

*

*

If possible, the SAX driver should provide the line position * of the first character after the text associated with the document * event. The first column in each line is column 1.

* * @return The column number, or -1 if none is available. * @see #getLineNumber */ public int getColumnNumber() { return reader.getLocation().getColumnNumber(); } public String getSystemId(long locationId) { return getSystemId(); } public int getLineNumber(long locationId) { return getLineNumber(); } public int getColumnNumber(long locationId) { return getColumnNumber(); } /** * Get a list of unparsed entities. * * @return a list of unparsed entities, or null if the information is not available, or * an empty list if there are no unparsed entities. Each item in the list will * be an instance of {@link net.sf.saxon.pull.UnparsedEntity} */ public List getUnparsedEntities() { if (unparsedEntities == null) { return null; } List list = new ArrayList(unparsedEntities.size()); for (int i=0; i 1) { emitter.setOutputStream(new FileOutputStream(args[1])); } else { emitter.setOutputStream(System.out); } NamespaceReducer r = new NamespaceReducer(emitter); EventIteratorToReceiver.copy(puller, r); System.err.println("Elapsed time: " + (System.currentTimeMillis() - startTime) + "ms"); } } /** * Determine whether the EventIterator returns a flat sequence of events, or whether it can return * nested event iterators * * @return true if the next() method is guaranteed never to return an EventIterator */ public boolean isFlatSequence() { return false; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/evpull/BracketedDocumentIterator.java0000644000175000017500000000557411033112257024661 0ustar eugeneeugenepackage net.sf.saxon.evpull; import net.sf.saxon.trans.XPathException; /** * The class is an EventIterator that handles the events arising from a document node constructor: * that is, the start/end event pair for the document node, bracketing a sequence of events for the * content of the document. * *

This class does not normalize the content (for example by merging adjacent text nodes). That is the job * of the {@link ComplexContentProcessor}.

* */ public class BracketedDocumentIterator implements EventIterator { private EventIterator content; private int state = INITIAL_STATE; private static final int INITIAL_STATE = 0; private static final int PROCESSING_CHILDREN = 1; private static final int EXHAUSTED = 2; /** * Constructor * @param content iterator that delivers the content of the document */ public BracketedDocumentIterator(EventIterator content) { this.content = EventStackIterator.flatten(content); state = 0; } /** * Get the next event in the sequence * @return the next event, or null when the sequence is exhausted * @throws net.sf.saxon.trans.XPathException if a dynamic evaluation error occurs */ public PullEvent next() throws XPathException { switch (state) { case INITIAL_STATE: state = PROCESSING_CHILDREN; return StartDocumentEvent.getInstance(); case PROCESSING_CHILDREN: PullEvent pe = content.next(); if (pe == null) { state = EXHAUSTED; return EndDocumentEvent.getInstance(); } else { return pe; } case EXHAUSTED: return null; default: throw new AssertionError("BracketedDocumentIterator state " + state); } } /** * Determine whether the EventIterator returns a flat sequence of events, or whether it can return * nested event iterators * * @return true if the next() method is guaranteed never to return an EventIterator */ public boolean isFlatSequence() { return true; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/evpull/EventMappingIterator.java0000644000175000017500000000435611033112257023670 0ustar eugeneeugenepackage net.sf.saxon.evpull; import net.sf.saxon.om.Item; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.trans.XPathException; /** * MappingIterator merges a sequence of sequences into a single sequence. * It takes as inputs an iteration, and a mapping function to be * applied to each Item returned by that iteration. The mapping function itself * returns another iteration. The result is an iteration of iterators. To convert this * int a single flat iterator over a uniform sequence of events, the result must be wrapped * in an {@link EventStackIterator}

*/ public final class EventMappingIterator implements EventIterator { private SequenceIterator base; private EventMappingFunction action; /** * Construct a MappingIterator that will apply a specified MappingFunction to * each Item returned by the base iterator. * @param base the base iterator * @param action the mapping function to be applied */ public EventMappingIterator(SequenceIterator base, EventMappingFunction action) { this.base = base; this.action = action; } public PullEvent next() throws XPathException { Item nextSource = base.next(); return (nextSource == null ? null : action.map(nextSource)); } /** * Determine whether the EventIterator returns a flat sequence of events, or whether it can return * nested event iterators * * @return true if the next() method is guaranteed never to return an EventIterator */ public boolean isFlatSequence() { return false; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/evpull/EventMappingFunction.java0000644000175000017500000000256211033112257023661 0ustar eugeneeugenepackage net.sf.saxon.evpull; import net.sf.saxon.om.Item; import net.sf.saxon.trans.XPathException; /** * EventMappingFunction is an interface that must be satisfied by an object passed to an * EventMappingIterator. It represents an object which, given an Item, can return an * EventIterator that delivers a sequence of zero or more PullEvents. */ public interface EventMappingFunction { /** * Map one item to a sequence of pull events. * @param item The item to be mapped. * @return one of the following: (a) an EventIterator over the sequence of items that the supplied input * item maps to, or (b) null if it maps to an empty sequence. */ public EventIterator map(Item item) throws XPathException; } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/evpull/SequenceComposer.java0000644000175000017500000002222511033112257023034 0ustar eugeneeugenepackage net.sf.saxon.evpull; import net.sf.saxon.om.*; import net.sf.saxon.trans.XPathException; import net.sf.saxon.tinytree.TinyBuilder; import net.sf.saxon.event.PipelineConfiguration; import net.sf.saxon.event.TreeReceiver; import net.sf.saxon.Configuration; import net.sf.saxon.query.QueryResult; import javax.xml.transform.stream.StreamSource; import java.io.File; /** * This class takes a sequence of pull events and composes them into a sequence of items. This involves building * any element or document nodes that are presented in decomposed form. * *

Note: this SequenceIterator does not implement the getAnother() method, which limits its use, * since getAnother() is needed to support the XPath last() function. */ public class SequenceComposer implements SequenceIterator { private EventIterator base; private int position = 0; private Item current = null; private PipelineConfiguration pipe; /** * Create a sequence composer * @param iter the underlying event iterator * @param pipe the pipeline configuration */ public SequenceComposer(EventIterator iter, PipelineConfiguration pipe) { base = EventStackIterator.flatten(iter); this.pipe = pipe; } /** * Get the next item in the sequence. This method changes the state of the * iterator, in particular it affects the result of subsequent calls of * position() and current(). * * @return the next item, or null if there are no more items. Once a call * on next() has returned null, no further calls should be made. The preferred * action for an iterator if subsequent calls on next() are made is to return * null again, and all implementations within Saxon follow this rule. * @throws net.sf.saxon.trans.XPathException * if an error occurs retrieving the next item * @since 8.4 */ public Item next() throws XPathException { PullEvent pe = base.next(); if (pe == null) { position = -1; current = null; return null; } if (pe instanceof Item) { current = (Item)pe; position++; return current; } else if (pe instanceof StartDocumentEvent || pe instanceof StartElementEvent) { SubtreeIterator sub = new SubtreeIterator(base, pe); TinyBuilder builder = new TinyBuilder(); builder.setPipelineConfiguration(pipe); TreeReceiver receiver = new TreeReceiver(builder); builder.setPipelineConfiguration(pipe); EventIteratorToReceiver.copy(sub, receiver); current = builder.getCurrentRoot(); position++; return current; } else { throw new IllegalStateException(pe.getClass().getName()); } } /** * Get the current value in the sequence (the one returned by the * most recent call on next()). This will be null before the first * call of next(). This method does not change the state of the iterator. * * @return the current item, the one most recently returned by a call on * next(). Returns null if next() has not been called, or if the end * of the sequence has been reached. * @since 8.4 */ public Item current() { return current; } public void close() { } /** * Get another SequenceIterator that iterates over the same items as the original, * but which is repositioned at the start of the sequence. *

* This method allows access to all the items in the sequence without disturbing the * current position of the iterator. Internally, its main use is in evaluating the last() * function. *

* This method does not change the state of the iterator. * * @return a SequenceIterator that iterates over the same items, * positioned before the first item * @throws net.sf.saxon.trans.XPathException * if any error occurs * @since 8.4 */ public SequenceIterator getAnother() throws XPathException { throw new UnsupportedOperationException("getAnother"); } /** * Get properties of this iterator, as a bit-significant integer. * * @return the properties of this iterator. This will be some combination of * properties such as {@link #GROUNDED}, {@link #LAST_POSITION_FINDER}, * and {@link #LOOKAHEAD}. It is always * acceptable to return the value zero, indicating that there are no known special properties. * It is acceptable for the properties of the iterator to change depending on its state. * @since 8.6 */ public int getProperties() { return 0; } /** * Get the current position. This will usually be zero before the first call * on next(), otherwise it will be the number of times that next() has * been called. Once next() has returned null, the preferred action is * for subsequent calls on position() to return -1, but not all existing * implementations follow this practice. (In particular, the EmptyIterator * is stateless, and always returns 0 as the value of position(), whether * or not next() has been called.) *

* This method does not change the state of the iterator. * * @return the current position, the position of the item returned by the * most recent call of next(). This is 1 after next() has been successfully * called once, 2 after it has been called twice, and so on. If next() has * never been called, the method returns zero. If the end of the sequence * has been reached, the value returned will always be <= 0; the preferred * value is -1. * @since 8.4 */ public int position() { return position; } private static class SubtreeIterator implements EventIterator { private int level = 0; private EventIterator base; private PullEvent first; public SubtreeIterator(EventIterator base, PullEvent first) { this.base = base; this.first = first; } /** * Get the next event in the sequence * * @return the next event, or null when the sequence is exhausted. Note that since an EventIterator is * itself a PullEvent, this method may return a nested iterator. * @throws net.sf.saxon.trans.XPathException * if a dynamic evaluation error occurs */ public PullEvent next() throws XPathException { if (first != null) { PullEvent pe = first; first = null; return pe; } if (level < 0) { return null; } PullEvent pe = base.next(); if (pe instanceof StartElementEvent || pe instanceof StartDocumentEvent) { level++; } else if (pe instanceof EndElementEvent || pe instanceof EndDocumentEvent) { level--; } return pe; } /** * Determine whether the EventIterator returns a flat sequence of events, or whether it can return * nested event iterators * * @return true if the next() method is guaranteed never to return an EventIterator */ public boolean isFlatSequence() { return base.isFlatSequence(); } } /** * Main method for testing only * @param args not used * @throws Exception */ public static void main(String[] args) throws Exception { Configuration config = new Configuration(); DocumentInfo doc = config.buildDocument(new StreamSource(new File("c:/MyJava/samples/data/books.xml"))); PipelineConfiguration pipe = config.makePipelineConfiguration(); pipe.setHostLanguage(Configuration.XQUERY); EventIterator e = new Decomposer(new SingletonEventIterator(doc), pipe); SequenceIterator iter = new SequenceComposer(e, pipe); while (true) { NodeInfo item = (NodeInfo)iter.next(); if (item == null) { break; } System.out.println(QueryResult.serialize(item)); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/evpull/SingletonEventIterator.java0000644000175000017500000000365011033112257024233 0ustar eugeneeugenepackage net.sf.saxon.evpull; import net.sf.saxon.trans.XPathException; /** * This class represents an EventIterator over a sequence containing a single pull event. */ public class SingletonEventIterator implements EventIterator { private PullEvent event; /** * Create an iterator over a sequence containing a single pull event * @param event the single event. This must not be an EventIterator */ public SingletonEventIterator(PullEvent event) { this.event = event; if (event instanceof EventIterator) { throw new IllegalArgumentException("event"); } } /** * Get the next event in the sequence * * @return the next event, or null when the sequence is exhausted * @throws XPathException if a dynamic evaluation error occurs */ public PullEvent next() throws XPathException { PullEvent next = event; event = null; return next; } /** * Determine whether the EventIterator returns a flat sequence of events, or whether it can return * nested event iterators * * @return true if the next() method is guaranteed never to return an EventIterator */ public boolean isFlatSequence() { return true; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/evpull/EventIteratorToReceiver.java0000644000175000017500000001045211033112257024336 0ustar eugeneeugenepackage net.sf.saxon.evpull; import net.sf.saxon.event.ReceiverOptions; import net.sf.saxon.event.SequenceReceiver; import net.sf.saxon.om.*; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.Type; import java.util.Iterator; /** * Class to read pull events from an EventIterator and write them to a Receiver */ public class EventIteratorToReceiver { /** * Private constructor: this class holds static methods only */ private EventIteratorToReceiver() {} /** * Read the data obtained from an EventIterator and write the same data to a SequenceReceiver * @param in the input EventIterator * @param out the output Receiver * @throws XPathException */ public static void copy(EventIterator in, SequenceReceiver out) throws XPathException { in = EventStackIterator.flatten(in); int level = 0; out.open(); while (true) { PullEvent event = in.next(); if (event == null) { break; } if (event instanceof Orphan && ((Orphan)event).getNodeKind() == Type.TEXT) { out.characters(((Orphan)event).getStringValueCS(), 0, 0); } else if (event instanceof DocumentInfo && level > 0) { AxisIterator kids = ((DocumentInfo)event).iterateAxis(Axis.CHILD); while (true) { NodeInfo node = (NodeInfo)kids.next(); if (node == null) { break; } out.append(node, 0, 0); } } else if (event instanceof Item) { out.append((Item)event, 0, NodeInfo.ALL_NAMESPACES); } else if (event instanceof StartElementEvent) { StartElementEvent see = (StartElementEvent)event; level++; out.startElement(see.getNameCode(), see.getTypeCode(), 0, ReceiverOptions.NAMESPACE_OK); int[] localNamespaces = see.getLocalNamespaces(); for (int n=0; n *

  • An item (that is, a node or an atomic value)
  • *
  • A startElement, endElement, startDocument, or endDocument event
  • *
  • An EventIterator, representing a sequence of PullEvents
  • * */ public interface PullEvent { } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/evpull/TracingEventIterator.java0000644000175000017500000000433011033112257023654 0ustar eugeneeugenepackage net.sf.saxon.evpull; import net.sf.saxon.trans.XPathException; /** * This class is a filter for a sequence of pull events; it returns the input sequence unchanged, * but traces execution to System.err */ public class TracingEventIterator implements EventIterator { private EventIterator base; /** * Create an event iterator that traces all events received from the base sequence, and returns * them unchanged * @param base the iterator over the base sequence */ public TracingEventIterator(EventIterator base) { this.base = base; } /** * Determine whether the EventIterator returns a flat sequence of events, or whether it can return * nested event iterators * * @return true if the next() method is guaranteed never to return an EventIterator */ public boolean isFlatSequence() { return base.isFlatSequence(); } /** * Get the next event in the sequence * * @return the next event, or null when the sequence is exhausted. Note that since an EventIterator is * itself a PullEvent, this method may return a nested iterator. * @throws net.sf.saxon.trans.XPathException * if a dynamic evaluation error occurs */ public PullEvent next() throws XPathException { PullEvent next = base.next(); if (next == null) { System.err.println("EVPULL end-of-sequence"); } else { System.err.println("EVPULL " + next.getClass().getName()); } return next; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/evpull/StartDocumentEvent.java0000644000175000017500000000177511033112257023361 0ustar eugeneeugenepackage net.sf.saxon.evpull; /** * A PullEvent representing the start of a document node */ public class StartDocumentEvent implements PullEvent { private final static StartDocumentEvent THE_INSTANCE = new StartDocumentEvent(); public static StartDocumentEvent getInstance() { return THE_INSTANCE; } private StartDocumentEvent() { } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/evpull/EventAnnotationStripper.java0000644000175000017500000000550111033112257024417 0ustar eugeneeugenepackage net.sf.saxon.evpull; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.om.StandardNames; import net.sf.saxon.om.VirtualUntypedCopy; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.Type; import java.util.Iterator; /** * This class is an EventIterator that filters a stream of pull events setting * the type annotation on element nodes to xs:untyped and on attribute nodes to * xs:untypedAtomic */ public class EventAnnotationStripper implements EventIterator { private EventIterator base; /** * Create an EventAnnotationStripper * @param base the stream of events whose type annotations are to be stripped (set to untyped) */ public EventAnnotationStripper(EventIterator base) { this.base = EventStackIterator.flatten(base); } /** * Get the next event in the sequence * * @return the next event, or null when the sequence is exhausted. Note that since an EventIterator is * itself a PullEvent, this method may return a nested iterator. * @throws net.sf.saxon.trans.XPathException * if a dynamic evaluation error occurs */ public PullEvent next() throws XPathException { PullEvent pe = base.next(); if (pe instanceof StartElementEvent) { StartElementEvent see = (StartElementEvent)pe; see.stripTypeAnnotations(); return see; } else if (pe instanceof NodeInfo) { // Make a virtual untyped copy of the node switch (((NodeInfo)pe).getNodeKind()) { case Type.ELEMENT: case Type.ATTRIBUTE: return VirtualUntypedCopy.makeVirtualUntypedCopy((NodeInfo)pe, (NodeInfo)pe); default: return pe; } } else { return pe; } } /** * Determine whether the EventIterator returns a flat sequence of events, or whether it can return * nested event iterators * * @return true if the next() method is guaranteed never to return an EventIterator */ public boolean isFlatSequence() { return true; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/evpull/ComplexContentProcessor.java0000644000175000017500000002672611033112257024430 0ustar eugeneeugenepackage net.sf.saxon.evpull; import net.sf.saxon.Configuration; import net.sf.saxon.om.FastStringBuffer; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.om.Orphan; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.Type; import net.sf.saxon.value.AtomicValue; /** * The ComplexContentProcessor is an EventIterator that deals with the events occurring between * a startElement and endElement (or startDocument and endDocument) according to the XSLT/XQuery * rules for constructing complex content. This includes: * *
      *
    • Converting atomic values to text nodes (inserting space as a separator between adjacent nodes)
    • *
    • Replacing nested document nodes by their children
    • *
    • Merging adjacent text nodes and dropping zero-length text nodes
    • *
    • Detecting mispositioned or duplicated attribute and namespace nodes
    • * *
    * *

    Note that if the content includes nodes such as element nodes, these will not be decomposed into * a sequence of tree events, they will simply be returned as nodes.

    */ public class ComplexContentProcessor implements EventIterator { private Configuration config; private EventIterator base; private PullEvent[] startEventStack; // contains either startElement or startDocument events private int depth; private NodeInfo pendingTextNode; private boolean pendingTextNodeIsMutable; private boolean prevAtomic = false; private PullEvent pendingOutput = null; /** * Create the ComplexContentProcessor * @param config the Saxon Configuration * @param base the EventIterator that delivers the content of the element or document node */ public ComplexContentProcessor(Configuration config, EventIterator base) { this.config = config; this.base = EventStackIterator.flatten(base); startEventStack = new PullEvent[20]; depth = 0; } /** * Get the next event in the sequence. This will never be an EventIterator. * * @return the next event, or null when the sequence is exhausted * @throws net.sf.saxon.trans.XPathException * if a dynamic evaluation error occurs */ public PullEvent next() throws XPathException { if (pendingOutput != null) { PullEvent next = pendingOutput; pendingOutput = null; return next; } else { return advance(); } } private PullEvent advance() throws XPathException { while (true) { if (depth == 0) { PullEvent e = base.next(); if (e instanceof StartElementEvent) { push(e); } else if (e instanceof StartDocumentEvent) { push(e); } return e; } else { PullEvent e = base.next(); if (e instanceof StartElementEvent) { prevAtomic = false; push(e); if (pendingTextNode != null) { pendingOutput = e; PullEvent next = pendingTextNode; pendingTextNode = null; return next; } else { return e; } } else if (e instanceof StartDocumentEvent) { prevAtomic = false; push(e); if (pendingTextNode != null) { pendingOutput = e; PullEvent next = pendingTextNode; pendingTextNode = null; return next; } else { //continue; } } else if (e instanceof EndElementEvent) { prevAtomic = false; pop(); if (pendingTextNode != null) { pendingOutput = e; PullEvent next = pendingTextNode; pendingTextNode = null; return next; } else { return e; } } else if (e instanceof EndDocumentEvent) { prevAtomic = false; pop(); if (pendingTextNode != null) { pendingOutput = e; PullEvent next = pendingTextNode; pendingTextNode = null; return next; } else { return e; } } else if (e instanceof NodeInfo) { prevAtomic = false; switch (((NodeInfo)e).getNodeKind()) { case Type.TEXT: if (pendingTextNode == null) { pendingTextNode = (NodeInfo)e; pendingTextNodeIsMutable = false; } else if (pendingTextNodeIsMutable) { FastStringBuffer sb = (FastStringBuffer)((Orphan)pendingTextNode).getStringValueCS(); sb.append(((NodeInfo)e).getStringValueCS()); } else { Orphan o = new Orphan(config); o.setNodeKind(Type.TEXT); FastStringBuffer sb = new FastStringBuffer(40); sb.append(pendingTextNode.getStringValueCS()); sb.append(((NodeInfo)e).getStringValueCS()); o.setStringValue(sb); pendingTextNode = o; pendingTextNodeIsMutable = true; } continue; default: if (pendingTextNode != null) { pendingOutput = e; PullEvent next = pendingTextNode; pendingTextNode = null; return next; } else { return e; } } } else if (e instanceof AtomicValue) { if (prevAtomic) { FastStringBuffer sb = (FastStringBuffer)((Orphan)pendingTextNode).getStringValueCS(); sb.append(' '); sb.append(((AtomicValue)e).getStringValueCS()); } else if (pendingTextNode != null) { prevAtomic = true; if (pendingTextNodeIsMutable) { FastStringBuffer sb = (FastStringBuffer)((Orphan)pendingTextNode).getStringValueCS(); sb.append(((AtomicValue)e).getStringValueCS()); } else { Orphan o = new Orphan(config); o.setNodeKind(Type.TEXT); FastStringBuffer sb = new FastStringBuffer(40); sb.append(pendingTextNode.getStringValueCS()); sb.append(((AtomicValue)e).getStringValueCS()); o.setStringValue(sb); pendingTextNode = o; pendingTextNodeIsMutable = true; } } else { prevAtomic = true; Orphan o = new Orphan(config); o.setNodeKind(Type.TEXT); FastStringBuffer sb = new FastStringBuffer(40); sb.append(((AtomicValue)e).getStringValueCS()); o.setStringValue(sb); pendingTextNode = o; pendingTextNodeIsMutable = true; } //continue; } else { throw new AssertionError("Unknown event"); } } } } /** * Push a startElement or startDocument event onto the stack. At the same time, if it is a startElement * event, remove any redundant namespace declarations * @param p the startElement or startDocument event */ private void push(PullEvent p) { if (depth >= startEventStack.length - 1) { PullEvent[] b2 = new PullEvent[depth*2]; System.arraycopy(startEventStack, 0, b2, 0, startEventStack.length); startEventStack = b2; } if (p instanceof StartElementEvent) { int retained = 0; int[] nsp = ((StartElementEvent)p).getLocalNamespaces(); for (int nspi = 0; nspi < nsp.length; nspi++) { if (nsp[nspi] == -1) { break; } retained++; outer: for (int i=depth-1; i>=0; i--) { PullEvent q = startEventStack[i]; if (q instanceof StartElementEvent) { int[] nsq = ((StartElementEvent)q).getLocalNamespaces(); for (int nsqi = 0; nsqi < nsq.length; nsqi++) { if (nsp[nspi] == nsq[nsqi]) { nsp[nspi] = -1; retained--; break outer; } else if (nsp[nspi]>>16 == nsq[nsqi]>>16) { break outer; } } } } } if (retained < nsp.length) { int[] nsr = new int[retained]; int nsri = 0; for (int nspi=0; nspi= children.length) { return null; } } } /** * Determine whether the EventIterator returns a flat sequence of events, or whether it can return * nested event iterators * * @return true if the next() method is guaranteed never to return an EventIterator */ public boolean isFlatSequence() { return false; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/evpull/EventToStaxBridge.java0000644000175000017500000005370111164364640023132 0ustar eugeneeugenepackage net.sf.saxon.evpull; import net.sf.saxon.event.LocationProvider; import net.sf.saxon.event.PipelineConfiguration; import net.sf.saxon.om.*; import net.sf.saxon.pull.NamespaceContextImpl; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.Type; import net.sf.saxon.value.AtomicValue; import net.sf.saxon.value.Whitespace; import javax.xml.namespace.NamespaceContext; import javax.xml.namespace.QName; import javax.xml.stream.Location; import javax.xml.stream.XMLStreamConstants; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamReader; import java.util.Iterator; import java.util.Stack; import java.util.NoSuchElementException; /** * This class bridges EventIterator events to XMLStreamReader (Stax) events. That is, it acts * as an XMLStreamReader, fetching the underlying data from an EventIterator. *

    * An EventIterator may provide access to any XDM sequence, whereas an XMLStreamReader always * reads a document. The conversion of a sequence to a document follows the rules for * "normalizing" a sequence in the Serialization specification: for example, atomic values are * converted into text nodes, with adjacent atomic values being space-separated. */ public class EventToStaxBridge implements XMLStreamReader { private EventIterator provider; private StartElementEvent startElementEvent; private Item currentItem; private Stack stack; // holds instances of StartElementEvent; needed because namespace information // (though not attributes) must be available at EndElement time private NamePool namePool; private boolean previousAtomic; private FastStringBuffer currentTextNode = new FastStringBuffer(100); private int currentStaxEvent = XMLStreamConstants.START_DOCUMENT; private XPathException pendingException = null; /** * Create a EventToStaxBridge instance, which wraps a Saxon EventIterator as a Stax XMLStreamReader * @param provider the Saxon EventIterator from which the events will be read * @param namePool the Saxon NamePool */ public EventToStaxBridge(EventIterator provider, NamePool namePool) { this.namePool = namePool; this.provider = new NamespaceMaintainer(EventStackIterator.flatten(provider), namePool); this.stack = new Stack(); } public int getAttributeCount() { if (currentStaxEvent != START_ELEMENT) { throw new IllegalStateException(""+currentStaxEvent); } return startElementEvent.getAttributeCount(); } public boolean isAttributeSpecified(int i) { if (currentStaxEvent != START_ELEMENT) { throw new IllegalStateException(""+currentStaxEvent); } return true; } public QName getAttributeName(int i) { if (currentStaxEvent != START_ELEMENT) { throw new IllegalStateException(""+currentStaxEvent); } NodeInfo att = startElementEvent.getAttribute(i); return new QName(att.getURI(), att.getLocalPart(), att.getPrefix()); } public String getAttributeLocalName(int i) { if (currentStaxEvent != START_ELEMENT) { throw new IllegalStateException(""+currentStaxEvent); } return startElementEvent.getAttribute(i).getLocalPart(); } public String getAttributeNamespace(int i) { if (currentStaxEvent != START_ELEMENT) { throw new IllegalStateException(""+currentStaxEvent); } return startElementEvent.getAttribute(i).getURI(); } public String getAttributePrefix(int i) { if (currentStaxEvent != START_ELEMENT) { throw new IllegalStateException(""+currentStaxEvent); } return startElementEvent.getAttribute(i).getPrefix(); } public String getAttributeType(int i) { if (currentStaxEvent != START_ELEMENT) { throw new IllegalStateException(""+currentStaxEvent); } int type = startElementEvent.getAttribute(i).getTypeAnnotation(); if (type == StandardNames.XS_ID) { return "ID"; } else if (type == StandardNames.XS_IDREF) { return "IDREF"; } else if (type == StandardNames.XS_IDREFS) { return "IDREFS"; } else if (type == StandardNames.XS_NMTOKEN) { return "NMTOKEN"; } else if (type == StandardNames.XS_NMTOKENS) { return "NMTOKENS"; } else if (type == StandardNames.XS_ENTITY) { return "ENTITY"; } else if (type == StandardNames.XS_ENTITIES) { return "ENTITIES"; } return "CDATA"; } public String getAttributeValue(int i) { if (currentStaxEvent != START_ELEMENT) { throw new IllegalStateException(""+currentStaxEvent); } return startElementEvent.getAttribute(i).getStringValue(); } public String getAttributeValue(String uri, String local) { for (Iterator iter = startElementEvent.iterateAttributes(); iter.hasNext(); ) { NodeInfo att = (NodeInfo)iter.next(); if (att.getURI().equals(uri) && att.getLocalPart().equals(local)) { return att.getStringValue(); } } return null; } public int getEventType() { return currentStaxEvent; } public int getNamespaceCount() { if (currentStaxEvent != START_ELEMENT && currentStaxEvent != END_ELEMENT) { throw new IllegalStateException(""+currentStaxEvent); } int[] nscodes = startElementEvent.getLocalNamespaces(); for (int i=0; i target.length) { throw new IndexOutOfBoundsException("targetStart"); } if (length < 0 || targetStart + length > target.length) { throw new IndexOutOfBoundsException("length"); } String value = getText(); if (sourceStart >= value.length()) { return 0; } int sourceEnd = sourceStart + length; if (sourceEnd > value.length()) { sourceEnd = value.length(); } value.getChars(sourceStart, sourceEnd, target, targetStart); return sourceEnd - sourceStart; } public int next() throws XMLStreamException { if (pendingException != null) { throw new XMLStreamException(pendingException); } PullEvent p; try { p = provider.next(); } catch (XPathException e) { throw new XMLStreamException(e); } if (p == null) { // The spec is ambivalent here; it also says IllegalStateException is appropriate throw new NoSuchElementException("end of stream"); } startElementEvent = null; if (p instanceof StartDocumentEvent) { // STAX doesn't actually report START_DOCUMENT: it's the initial state before reading any events currentStaxEvent = XMLStreamConstants.START_DOCUMENT; return next(); } else if (p instanceof StartElementEvent) { startElementEvent = (StartElementEvent)p; currentStaxEvent = XMLStreamConstants.START_ELEMENT; stack.push(p); return currentStaxEvent; } else if (p instanceof EndElementEvent) { currentStaxEvent = XMLStreamConstants.END_ELEMENT; startElementEvent = (StartElementEvent)stack.pop(); return currentStaxEvent; } else if (p instanceof EndDocumentEvent) { currentStaxEvent = XMLStreamConstants.END_DOCUMENT; return currentStaxEvent; } else if (p instanceof NodeInfo) { currentItem = (NodeInfo)p; switch (((NodeInfo)p).getNodeKind()) { case Type.COMMENT: currentStaxEvent = XMLStreamConstants.COMMENT; return currentStaxEvent; case Type.PROCESSING_INSTRUCTION: currentStaxEvent = XMLStreamConstants.PROCESSING_INSTRUCTION; return currentStaxEvent; case Type.TEXT: currentStaxEvent = XMLStreamConstants.CHARACTERS; return currentStaxEvent; case Type.ATTRIBUTE: throw new XMLStreamException("Encountered top-level attribute in sequence"); default: throw new AssertionError("Unexpected node kind (sequence not decomposed?)"); } } else if (p instanceof AtomicValue) { currentItem = (AtomicValue)p; currentStaxEvent = XMLStreamConstants.CHARACTERS; previousAtomic = true; return currentStaxEvent; } else { throw new AssertionError("Unknown pull event"); } } public int nextTag() throws XMLStreamException { if (pendingException != null) { throw new XMLStreamException(pendingException); } int eventType = next(); while ((eventType == XMLStreamConstants.CHARACTERS && isWhiteSpace()) // skip whitespace || (eventType == XMLStreamConstants.CDATA && isWhiteSpace()) // skip whitespace || eventType == XMLStreamConstants.SPACE || eventType == XMLStreamConstants.PROCESSING_INSTRUCTION || eventType == XMLStreamConstants.COMMENT ) { eventType = next(); } if (eventType != XMLStreamConstants.START_ELEMENT && eventType != XMLStreamConstants.END_ELEMENT) { throw new XMLStreamException("expected start or end tag", getLocation()); } return eventType; } public void close() throws XMLStreamException { if (pendingException != null) { throw new XMLStreamException(pendingException); } } public boolean hasName() { return currentStaxEvent == XMLStreamConstants.START_ELEMENT || currentStaxEvent == XMLStreamConstants.END_ELEMENT; } public boolean hasNext() throws XMLStreamException { if (pendingException != null) { throw new XMLStreamException(pendingException); } return currentStaxEvent != XMLStreamConstants.END_DOCUMENT; } public boolean hasText() { return currentStaxEvent == XMLStreamConstants.CHARACTERS || currentStaxEvent == XMLStreamConstants.COMMENT; } public boolean isCharacters() { return currentStaxEvent == XMLStreamConstants.CHARACTERS; } public boolean isEndElement() { return currentStaxEvent == XMLStreamConstants.END_ELEMENT; } public boolean isStandalone() { return false; } public boolean isStartElement() { return currentStaxEvent == XMLStreamConstants.START_ELEMENT; } public boolean isWhiteSpace() { return currentStaxEvent == XMLStreamConstants.CHARACTERS && Whitespace.isWhite(getText()); } public boolean standaloneSet() { return false; } public String getCharacterEncodingScheme() { return null; } public String getElementText() throws XMLStreamException { if (pendingException != null) { throw new XMLStreamException(pendingException); } if (getEventType() != XMLStreamConstants.START_ELEMENT) { throw new XMLStreamException("parser must be on START_ELEMENT to read next text", getLocation()); } int eventType = next(); StringBuffer content = new StringBuffer(); while (eventType != XMLStreamConstants.END_ELEMENT) { if (eventType == XMLStreamConstants.CHARACTERS || eventType == XMLStreamConstants.CDATA || eventType == XMLStreamConstants.SPACE || eventType == XMLStreamConstants.ENTITY_REFERENCE) { content.append(getText()); } else if (eventType == XMLStreamConstants.PROCESSING_INSTRUCTION || eventType == XMLStreamConstants.COMMENT) { // skipping } else if (eventType == XMLStreamConstants.END_DOCUMENT) { throw new XMLStreamException("unexpected end of document when reading element text content", getLocation()); } else if (eventType == XMLStreamConstants.START_ELEMENT) { throw new XMLStreamException("element text content may not contain START_ELEMENT", getLocation()); } else { throw new XMLStreamException("Unexpected event type " + eventType, getLocation()); } eventType = next(); } return content.toString(); } public String getEncoding() { return null; } public String getLocalName() { if (currentStaxEvent != START_ELEMENT && currentStaxEvent != END_ELEMENT) { throw new IllegalStateException(""+currentStaxEvent); } return namePool.getLocalName(startElementEvent.getNameCode()); } public String getNamespaceURI() { if (currentStaxEvent != START_ELEMENT && currentStaxEvent != END_ELEMENT) { return null; } return namePool.getURI(startElementEvent.getNameCode()); } public String getPIData() { if (currentStaxEvent != XMLStreamConstants.PROCESSING_INSTRUCTION) { throw new IllegalStateException("Not positioned at a processing instruction"); } return getText(); } public String getPITarget() { if (currentStaxEvent != XMLStreamConstants.PROCESSING_INSTRUCTION) { throw new IllegalStateException("Not positioned at a processing instruction"); } return namePool.getLocalName(((NodeInfo)currentItem).getNameCode()); } public String getPrefix() { if (currentStaxEvent != START_ELEMENT && currentStaxEvent != END_ELEMENT) { return null; } return namePool.getPrefix(startElementEvent.getNameCode()); } public String getVersion() { return "1.0"; } public String getNamespacePrefix(int i) { if (currentStaxEvent != START_ELEMENT && currentStaxEvent != END_ELEMENT) { throw new IllegalStateException(""+currentStaxEvent); } int nscode = startElementEvent.getLocalNamespaces()[i]; return namePool.getPrefixFromNamespaceCode(nscode); } public String getNamespaceURI(int i) { if (currentStaxEvent != START_ELEMENT && currentStaxEvent != END_ELEMENT) { throw new IllegalStateException(""+currentStaxEvent); } int nscode = startElementEvent.getLocalNamespaces()[i]; return namePool.getURIFromNamespaceCode(nscode); } public NamespaceContext getNamespaceContext() { return new NamespaceContextImpl((NamespaceResolver)provider); } public QName getName() { if (currentStaxEvent != START_ELEMENT && currentStaxEvent != END_ELEMENT) { throw new IllegalStateException(""+currentStaxEvent); } int nc = startElementEvent.getNameCode(); return new QName(namePool.getURI(nc), namePool.getLocalName(nc), namePool.getPrefix(nc)); } public Location getLocation() { if (startElementEvent != null) { PipelineConfiguration pipe = startElementEvent.getPipelineConfiguration(); final LocationProvider provider = pipe.getLocationProvider(); final int locationId = startElementEvent.getLocationId(); return new Location() { public int getCharacterOffset() { return -1; } public int getColumnNumber() { return provider.getColumnNumber(locationId); } public int getLineNumber() { return provider.getLineNumber(locationId); } public String getPublicId() { return null; } public String getSystemId() { return provider.getSystemId(locationId); } }; } else if (currentItem instanceof NodeInfo) { final NodeInfo node = (NodeInfo)currentItem; return new Location() { public int getCharacterOffset() { return -1; } public int getColumnNumber() { return node.getColumnNumber(); } public int getLineNumber() { return node.getLineNumber(); } public String getPublicId() { return null; } public String getSystemId() { return node.getSystemId(); } }; } else { return DummyLocation.THE_INSTANCE; } } public Object getProperty(String s) throws IllegalArgumentException { return null; } public void require(int event, String uri, String local) throws XMLStreamException { if (pendingException != null) { throw new XMLStreamException(pendingException); } if (currentStaxEvent != event) { throw new XMLStreamException("Required event type is " + event + ", actual event is " + currentStaxEvent); } if (uri != null && !uri.equals(getNamespaceURI())) { throw new XMLStreamException("Required namespace is " + uri + ", actual is " + getNamespaceURI()); } if (local != null && !local.equals(getLocalName())) { throw new XMLStreamException("Required local name is " + local + ", actual is " + getLocalName()); } } public String getNamespaceURI(String prefix) { if (prefix.equals("xmlns")) { return NamespaceConstant.XMLNS; } return ((NamespaceResolver)provider).getURIForPrefix(prefix, true); } public static class DummyLocation implements Location{ public static final Location THE_INSTANCE = new DummyLocation(); private DummyLocation() {} public int getCharacterOffset() { return -1; } public int getColumnNumber() { return -1; } public int getLineNumber() { return -1; } public java.lang.String getPublicId() { return null; } public java.lang.String getSystemId() { return null; } } /** * Temporary test program * @param args command line arguments. First argument is a file containing an XML document * @throws Exception */ // public static void main(String[] args) throws Exception { // Configuration config = new Configuration(); // DocumentInfo doc = config.buildDocument(new StreamSource(new File(args[0]))); // PipelineConfiguration pipe = config.makePipelineConfiguration(); // pipe.setHostLanguage(Configuration.XQUERY); // EventIterator ei = new Decomposer(doc, pipe); // XMLStreamReader sr = new EventToStaxBridge(ei, config.getNamePool()); // StaxBridge bridge = new StaxBridge(); // bridge.setXMLStreamReader(sr); // // bridge.setPipelineConfiguration(pipe); // Receiver out = config.getSerializerFactory().getReceiver(new StreamResult(System.out), pipe, new Properties()); // PullPushCopier copier = new PullPushCopier(bridge, out); // copier.copy(); // } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/evpull/EventStackIterator.java0000644000175000017500000000571511033112257023342 0ustar eugeneeugenepackage net.sf.saxon.evpull; import net.sf.saxon.trans.XPathException; import java.util.Stack; /** * An EventStackIterator is an EventIterator that delivers a flat sequence of PullEvents * containing no nested EventIterators */ public class EventStackIterator implements EventIterator { private Stack eventStack = new Stack(); /** * Factory method to create an iterator that flattens the sequence of PullEvents received * from a base iterator, that is, it returns an EventIterator that will never return any * nested iterators. * @param base the base iterator. Any nested EventIterator returned by the base iterator * will be flattened, recursively. */ public static EventIterator flatten(EventIterator base) { if (base.isFlatSequence()) { return base; } return new EventStackIterator(base); } /** * Create a EventStackIterator that flattens the sequence of PullEvents received * from a base iterator * @param base the base iterator. Any nested EventIterator returned by the base iterator * will be flattened, recursively. */ private EventStackIterator(EventIterator base) { eventStack.push(base); } /** * Get the next event in the sequence. This will never be an EventIterator. * * @return the next event, or null when the sequence is exhausted * @throws net.sf.saxon.trans.XPathException * if a dynamic evaluation error occurs */ public PullEvent next() throws XPathException { if (eventStack.isEmpty()) { return null; } EventIterator iter = (EventIterator)eventStack.peek(); PullEvent next = iter.next(); if (next == null) { eventStack.pop(); return next(); } else if (next instanceof EventIterator) { eventStack.push(next); return next(); } else { return next; } } /** * Determine whether the EventIterator returns a flat sequence of events, or whether it can return * nested event iterators * * @return true if the next() method is guaranteed never to return an EventIterator */ public boolean isFlatSequence() { return true; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/evpull/PullEventTracer.java0000644000175000017500000001173711033112257022641 0ustar eugeneeugenepackage net.sf.saxon.evpull; import net.sf.saxon.om.FastStringBuffer; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.om.DocumentInfo; import net.sf.saxon.om.NamePool; import net.sf.saxon.pattern.NodeKindTest; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.Type; import net.sf.saxon.value.AtomicValue; import net.sf.saxon.Configuration; import net.sf.saxon.event.PipelineConfiguration; import javax.xml.transform.stream.StreamSource; import java.io.PrintStream; import java.io.File; /** * Diagnostic class to display the sequence of events reported by an EventIterator */ public class PullEventTracer implements EventIterator { private EventIterator base; private String label = ("PET" + hashCode()).substring(0, 8) + ": "; private PrintStream out = System.err; //@SuppressWarnings({"FieldCanBeLocal"}) private NamePool pool; /** * Create a tracer for pull events * @param base the event iterator whose events are to be traced * @param config the Saxon configuration */ public PullEventTracer(EventIterator base, Configuration config) { this.base = base; pool = config.getNamePool(); } /** * Get the next event in the sequence * * @return the next event, or null when the sequence is exhausted. Note that since an EventIterator is * itself a PullEvent, this method may return a nested iterator. * @throws net.sf.saxon.trans.XPathException * if a dynamic evaluation error occurs */ public PullEvent next() throws XPathException { PullEvent pe = base.next(); if (pe == null) { return null; } if (pe instanceof StartDocumentEvent) { out.println(label + "StartDocument"); label = " " + label; } else if (pe instanceof StartElementEvent) { out.println(label + "StartElement " + pool.getDisplayName(((StartElementEvent)pe).getNameCode())); label = " " + label; } else if (pe instanceof EndDocumentEvent) { label = label.substring(2); out.println(label + "EndDocument"); } else if (pe instanceof EndElementEvent) { label = label.substring(2); out.println(label + "EndElement"); } else if (pe instanceof NodeInfo) { FastStringBuffer fsb = new FastStringBuffer(80); fsb.append(label); int kind = ((NodeInfo)pe).getNodeKind(); fsb.append(NodeKindTest.toString(kind)); if (kind == Type.ELEMENT || kind == Type.ATTRIBUTE) { fsb.append(' '); fsb.append(((NodeInfo)pe).getDisplayName()); } fsb.append(" \""); fsb.append(((NodeInfo)pe).getStringValueCS()); fsb.append('"'); out.println(fsb.toString()); } else if (pe instanceof AtomicValue) { out.println(label + Type.displayTypeName((AtomicValue)pe) + ' ' + pe); } else if (pe instanceof EventIterator) { out.println(label + "** NESTED ITERATOR **"); } else { out.println(label + pe.getClass().getName()); } return pe; } /** * Determine whether the EventIterator returns a flat sequence of events, or whether it can return * nested event iterators * * @return true if the next() method is guaranteed never to return an EventIterator */ public boolean isFlatSequence() { return base.isFlatSequence(); } /** * Main method for testing only * @param args not used * @throws Exception */ public static void main(String[] args) throws Exception { Configuration config = new Configuration(); DocumentInfo doc = config.buildDocument(new StreamSource(new File("c:/MyJava/samples/data/books.xml"))); PipelineConfiguration pipe = config.makePipelineConfiguration(); pipe.setHostLanguage(Configuration.XQUERY); EventIterator e = new Decomposer(new SingletonEventIterator(doc), pipe); e = EventStackIterator.flatten(e); e = new PullEventTracer(e, config); while (true) { PullEvent pe = e.next(); if (pe == null) { break; } } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/evpull/NamespaceMaintainer.java0000644000175000017500000001736711033112257023473 0ustar eugeneeugenepackage net.sf.saxon.evpull; import net.sf.saxon.om.*; import net.sf.saxon.trans.XPathException; import java.util.Iterator; import java.util.List; import java.util.ArrayList; /** * NamespaceMaintainer is an EventIterator responsible for maintaining namespace context in an * event stream. It allows the current namespace context to be determined at any time while * processing the stream of events. * *

    Note that this class merely provides the service of keeping track of which namespaces are * currently in scope. It does not attempt to remove duplicate namespace declarations, and it does * not perform namespace fixup.

    */ public class NamespaceMaintainer implements EventIterator, NamespaceResolver { private EventIterator base; private NamePool namePool; // We keep track of namespaces to avoid outputting duplicate declarations. The namespaces // vector holds a list of all namespaces currently declared (organised as integer namespace codes). // The countStack contains an entry for each element currently open; the // value on the countStack is an Integer giving the number of namespaces added to the main // namespace stack by that element. private int[] allNamespaces = new int[50]; // all namespace codes currently declared private int allNamespacesSize = 0; // all namespaces currently declared private int[] namespaceCountStack = new int[50]; // one entry per started element, holding the number private int depth = 0; // current depth of element nesting /** * Create a namespace context for a pull-events pipeline * @param base the previous stage in the pipeline, from which events are read * @param namePool the NamePool */ public NamespaceMaintainer(EventIterator base, NamePool namePool) { this.base = EventStackIterator.flatten(base); this.namePool = namePool; } /** * Determine whether the EventIterator returns a flat sequence of events, or whether it can return * nested event iterators * * @return true if the next() method is guaranteed never to return an EventIterator */ public boolean isFlatSequence() { return true; } /** * Get the next event in the sequence * * @return the next event, or null when the sequence is exhausted. Note that since an EventIterator is * itself a PullEvent, this method may return a nested iterator. * @throws net.sf.saxon.trans.XPathException * if a dynamic evaluation error occurs */ public PullEvent next() throws XPathException { PullEvent event = base.next(); if (event instanceof StartElementEvent) { startElement((StartElementEvent)event); } else if (event instanceof EndElementEvent) { endElement(); } return event; } private void startElement(StartElementEvent event) throws XPathException { // Record the current height of the namespace list so it can be reset at endElement time int[] declaredNamespaces = event.getLocalNamespaces(); int numberOfDeclaredNamespaces = declaredNamespaces.length; for (int i=0; i= namespaceCountStack.length) { int[] newstack = new int[depth * 2]; System.arraycopy(namespaceCountStack, 0, newstack, 0, depth); namespaceCountStack = newstack; } namespaceCountStack[depth++] = numberOfDeclaredNamespaces; // expand the stack if necessary while (allNamespacesSize + numberOfDeclaredNamespaces >= allNamespaces.length) { int[] newlist = new int[allNamespacesSize * 2]; System.arraycopy(allNamespaces, 0, newlist, 0, allNamespacesSize); allNamespaces = newlist; } for (int i=0; i= 0; i--) { if ((allNamespaces[i] >> 16) == (prefixCode)) { return (short) (allNamespaces[i] & 0xffff); } } if (prefixCode == 0) { return 0; // by default, no prefix means no namespace URI } else { return -1; } } /** * Get the namespace URI corresponding to a given prefix. Return null * if the prefix is not in scope. * * @param prefix the namespace prefix * @param useDefault true if the default namespace is to be used when the * prefix is "" * @return the uri for the namespace, or null if the prefix is not in scope */ public String getURIForPrefix(String prefix, boolean useDefault) { if ((prefix == null || prefix.length() == 0) && !useDefault) { return ""; } else if ("xml".equals(prefix)) { return NamespaceConstant.XML; } else { short prefixCode = namePool.getCodeForPrefix(prefix); short uriCode = getURICode(prefixCode); if (uriCode == -1) { return null; } return namePool.getURIFromURICode(uriCode); } } /** * Get an iterator over all the prefixes declared in this namespace context. This will include * the default namespace (prefix="") and the XML namespace where appropriate */ public Iterator iteratePrefixes() { List prefixes = new ArrayList(allNamespacesSize); for (int i = allNamespacesSize - 1; i >= 0; i--) { String prefix = namePool.getPrefixFromNamespaceCode(allNamespaces[i]); if (!prefixes.contains(prefix)) { prefixes.add(prefix); } } prefixes.add("xml"); return prefixes.iterator(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/evpull/EndElementEvent.java0000644000175000017500000000202611033112257022573 0ustar eugeneeugenepackage net.sf.saxon.evpull; import net.sf.saxon.evpull.PullEvent; /** * Pull event representing the end of an element node */ public class EndElementEvent implements PullEvent { private final static EndElementEvent THE_INSTANCE = new EndElementEvent(); public static EndElementEvent getInstance() { return THE_INSTANCE; } private EndElementEvent() { } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/evpull/BracketedElementIterator.java0000644000175000017500000001226411033112257024466 0ustar eugeneeugenepackage net.sf.saxon.evpull; import net.sf.saxon.om.NamePool; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.Type; /** * The class is an EventIterator that handles the events arising from an element constructor: * that is, the start/end event pair for the element node, bracketing a sequence of events for the * content of the element. * *

    This class does not normalize the content (for example by merging adjacent text nodes). That is the job * of the {@link ComplexContentProcessor}.

    * *

    The event stream consumed by a BracketedElementIterator may contain freestanding attribute and namespace nodes. * The event stream delivered by a BracketedElementIterator, however, packages all attributes and namespaces as * part of the startElement event.

    */ public class BracketedElementIterator implements EventIterator { private PullEvent start; private EventIterator content; private PullEvent pendingContent; private PullEvent end; private int state = INITIAL_STATE; private static final int INITIAL_STATE = 0; private static final int PROCESSING_FIRST_CHILD = 1; private static final int PROCESSING_REMAINING_CHILDREN = 2; private static final int REACHED_END_TAG = 3; private static final int EXHAUSTED = 4; /** * Constructor * @param start the StartElementEvent object * @param content iterator that delivers the content of the element * @param end the EndElementEvent object */ public BracketedElementIterator(PullEvent start, EventIterator content, PullEvent end) { this.start = start; this.content = EventStackIterator.flatten(content); this.end = end; state = 0; } /** * Get the next event in the sequence * @return the next event, or null when the sequence is exhausted * @throws XPathException if a dynamic evaluation error occurs */ public PullEvent next() throws XPathException { switch (state) { case INITIAL_STATE: while (true) { PullEvent pe = content.next(); if (pe == null) { pendingContent = null; state = REACHED_END_TAG; break; } else if (pe instanceof NodeInfo) { int k = ((NodeInfo)pe).getNodeKind(); if (k == Type.NAMESPACE) { NamePool pool = ((NodeInfo)pe).getNamePool(); int nscode = pool.allocateNamespaceCode( ((NodeInfo)pe).getLocalPart(), ((NodeInfo)pe).getStringValue()); ((StartElementEvent)start).addNamespace(nscode); continue; } else if (k == Type.ATTRIBUTE) { ((StartElementEvent)start).addAttribute((NodeInfo)pe); continue; } else if (k == Type.TEXT && ((NodeInfo)pe).getStringValueCS().length() == 0) { // ignore a zero-length text node continue; } } pendingContent = pe; state = PROCESSING_FIRST_CHILD; break; } ((StartElementEvent)start).namespaceFixup(); return start; case PROCESSING_FIRST_CHILD: state = PROCESSING_REMAINING_CHILDREN; return pendingContent; case PROCESSING_REMAINING_CHILDREN: PullEvent pe = content.next(); if (pe == null) { state = EXHAUSTED; return end; } else { return pe; } case REACHED_END_TAG: state = EXHAUSTED; return end; case EXHAUSTED: return null; default: throw new AssertionError("BracketedEventIterator state " + state); } } /** * Determine whether the EventIterator returns a flat sequence of events, or whether it can return * nested event iterators * * @return true if the next() method is guaranteed never to return an EventIterator */ public boolean isFlatSequence() { return true; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/evpull/Decomposer.java0000644000175000017500000001246511033112257021661 0ustar eugeneeugenepackage net.sf.saxon.evpull; import net.sf.saxon.event.PipelineConfiguration; import net.sf.saxon.om.Axis; import net.sf.saxon.om.AxisIterator; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.tinytree.TinyNodeImpl; import net.sf.saxon.tinytree.TinyTreeEventIterator; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.Type; /** * This class takes a sequence of pull events and turns it into fully-decomposed form, that is, it * takes and document and element nodes in the sequence and turns them into a subsequence consisting of a * start element|document event, a content sequence, and an end element|document event, recursively. * *

    The resulting sequence is decomposed, but not flat (it will contain nested EventIterators). To flatten * it, use {@link EventStackIterator#flatten(EventIterator)}

    */ public class Decomposer implements EventIterator { private EventIterator base; private PipelineConfiguration pipe; /** * Create a Decomposer, which turns an event sequence into fully decomposed form * @param base the base sequence, which may be fully composed, fully decomposed, or * anything in between * @param pipe the Saxon pipeline configuration */ public Decomposer(EventIterator base, PipelineConfiguration pipe) { this.pipe = pipe; this.base = EventStackIterator.flatten(base); } /** * Create a Decomposer which returns the sequence of events corresponding to * a particular node * @param node the node to be decomposed * @param pipe the Saxon pipeline configuration */ public Decomposer(NodeInfo node, PipelineConfiguration pipe) { this.pipe = pipe; base = new SingletonEventIterator(node); } /** * Get the next event in the sequence * * @return the next event, or null when the sequence is exhausted. Note that since an EventIterator is * itself a PullEvent, this method may return a nested iterator. * @throws net.sf.saxon.trans.XPathException * if a dynamic evaluation error occurs */ public PullEvent next() throws XPathException { PullEvent pe = base.next(); if (pe instanceof NodeInfo) { NodeInfo node = (NodeInfo)pe; switch (node.getNodeKind()) { case Type.DOCUMENT: { if (node instanceof TinyNodeImpl) { return new TinyTreeEventIterator(((TinyNodeImpl)node), pipe); } else { SequenceIterator content = node.iterateAxis(Axis.CHILD); EventIterator contentEvents = new EventIteratorOverSequence(content); return new BracketedDocumentIterator( new Decomposer(contentEvents, pipe)); } } case Type.ELEMENT: { if (node instanceof TinyNodeImpl) { return new TinyTreeEventIterator(((TinyNodeImpl)node), pipe); } else { SequenceIterator content = node.iterateAxis(Axis.CHILD); EventIterator contentEvents = new EventIteratorOverSequence(content); StartElementEvent see = new StartElementEvent(pipe); see.setNameCode(node.getNameCode()); see.setTypeCode(node.getTypeAnnotation()); see.setLocalNamespaces(node.getDeclaredNamespaces(null)); AxisIterator atts = node.iterateAxis(Axis.ATTRIBUTE); while (true) { NodeInfo att = (NodeInfo)atts.next(); if (att == null) { break; } see.addAttribute(att); } return new BracketedElementIterator( see, new Decomposer(contentEvents, pipe), EndElementEvent.getInstance()); } } default: return node; } } else { return pe; } } /** * Determine whether the EventIterator returns a flat sequence of events, or whether it can return * nested event iterators * * @return true if the next() method is guaranteed never to return an EventIterator */ public boolean isFlatSequence() { return false; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/evpull/PullEventSource.java0000644000175000017500000000500511033112257022650 0ustar eugeneeugenepackage net.sf.saxon.evpull; import javax.xml.transform.Source; /** * A PullSource is a JAXP Source that encapsulates a PullProvider - that is, an object * that supplies an XML document as a sequence of events that are read under the control * of the recipient. Note that although PullSource implements the JAXP Source interface, * it is not necessarily acceptable to every JAXP implementation that accepts a Source * as input: Source is essentially a marker interface and users of Source objects need * to understand the individual implementation. */ public class PullEventSource implements Source { private String systemId; private EventIterator provider; /** * Create a PullSource based on a supplied EventIterator * @param provider the underlying EventIterator */ public PullEventSource(EventIterator provider) { this.provider = provider; } /** * Get the EventIterator * @return the underlying EventIterator */ public EventIterator getEventIterator() { return provider; } /** * Set the system identifier for this Source. *

    *

    The system identifier is optional if the source does not * get its data from a URL, but it may still be useful to provide one. * The application can use a system identifier, for example, to resolve * relative URIs and to include in error messages and warnings.

    * * @param systemId The system identifier as a URL string. */ public void setSystemId(String systemId) { this.systemId = systemId; } /** * Get the system identifier that was set with setSystemId. * * @return The system identifier that was set with setSystemId, or null * if setSystemId was not called. */ public String getSystemId() { return systemId; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/Controller.java0000644000175000017500000025675311033112257020407 0ustar eugeneeugenepackage net.sf.saxon; import net.sf.saxon.event.*; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.expr.XPathContextMajor; import net.sf.saxon.expr.PathMap; import net.sf.saxon.functions.Component; import net.sf.saxon.functions.EscapeURI; import net.sf.saxon.instruct.*; import net.sf.saxon.om.*; import net.sf.saxon.sort.IntHashMap; import net.sf.saxon.tinytree.TinyBuilder; import net.sf.saxon.trace.*; import net.sf.saxon.trans.*; import net.sf.saxon.tree.TreeBuilder; import net.sf.saxon.value.DateTimeValue; import net.sf.saxon.type.SchemaURIResolver; import org.xml.sax.SAXParseException; import javax.xml.transform.*; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import java.io.*; import java.util.*; /** * The Controller is Saxon's implementation of the JAXP Transformer class, and represents * an executing instance of a transformation or query. Multiple concurrent executions of * the same transformation or query will use different Controller instances. This class is * therefore not thread-safe. *

    * The Controller is serially reusable, as required by JAXP: when one transformation or query * is finished, it can be used to run another. However, there is no advantage in doing this * rather than allocating a new Controller each time. *

    * The Controller can also be used when running Java applications that use neither XSLT nor * XQuery. A dummy Controller is created when running free-standing XPath expressions. *

    * The Controller holds those parts of the dynamic context that do not vary during the course * of a transformation or query, or that do not change once their value has been computed. * This also includes those parts of the static context that are required at run-time. *

    * Wherever possible XSLT applications should use the JAXP Transformer class directly, * rather than relying on Saxon-specific methods in the Controller. However, some * features are currently available only through this class. This applies especially * to new features specific to XSLT 2.0, since the JAXP interface still supports * only XSLT 1.0. Such methods may be superseded in the future by JAXP methods. *

    * Many methods on the Controller are designed for internal use and should not be * considered stable. From release 8.4 onwards, those methods that are considered sufficiently * stable to constitute path of the Saxon public API are labelled with the JavaDoc tag "since": * the value indicates the release at which the method was added to the public API. * * @author Michael H. Kay * @since 8.4 */ public class Controller extends Transformer { private Configuration config; private Item initialContextItem; private Item contextForGlobalVariables; private Bindery bindery; // holds values of global and local variables private NamePool namePool; private Receiver messageEmitter; private RuleManager ruleManager; private Properties localOutputProperties; private GlobalParameterSet parameters; private PreparedStylesheet preparedStylesheet; private TraceListener traceListener; private boolean tracingPaused; private PrintStream traceFunctionDestination = System.err; private URIResolver standardURIResolver; private URIResolver userURIResolver; private Result principalResult; private String principalResultURI; private String cookedPrincipalResultURI; private boolean thereHasBeenAnExplicitResultDocument; private OutputURIResolver outputURIResolver; private UnparsedTextURIResolver unparsedTextResolver; private SchemaURIResolver schemaURIResolver; private ErrorListener errorListener; private int recoveryPolicy; private Executable executable; private int treeModel = Builder.TINY_TREE; private Template initialTemplate = null; private HashSet allOutputDestinations; private DocumentPool sourceDocumentPool; private SequenceOutputter reusableSequenceOutputter = null; private HashMap userDataTable; private DateTimeValue currentDateTime; private boolean dateTimePreset = false; private StructuredQName initialMode = null; private NodeInfo lastRememberedNode = null; private int lastRememberedNumber = -1; private ClassLoader classLoader; private PathMap pathMap = null; // private int nextLocalDocumentNumber = -1; /** * Create a Controller and initialise variables. Note: XSLT applications should * create the Controller by using the JAXP newTransformer() method, or in S9API * by using XsltExecutable.load() * * @param config The Configuration used by this Controller */ public Controller(Configuration config) { this.config = config; // create a dummy executable executable = new Executable(config); executable.setHostLanguage(config.getHostLanguage()); sourceDocumentPool = new DocumentPool(); reset(); } /** * Create a Controller and initialise variables. * * @param config The Configuration used by this Controller * @param executable The executable used by this Controller */ public Controller(Configuration config, Executable executable) { this.config = config; this.executable = executable; sourceDocumentPool = new DocumentPool(); reset(); } /** *

    Reset this Transformer to its original configuration.

    *

    *

    Transformer is reset to the same state as when it was created with * {@link javax.xml.transform.TransformerFactory#newTransformer()}, * {@link javax.xml.transform.TransformerFactory#newTransformer(javax.xml.transform.Source source)} or * {@link javax.xml.transform.Templates#newTransformer()}. * reset() is designed to allow the reuse of existing Transformers * thus saving resources associated with the creation of new Transformers.

    *

    * The above is from the JAXP specification. With Saxon, it's unlikely that reusing a Transformer will * give any performance benefits over creating a new one. The one case where it might be beneficial is * to reuse the document pool (the set of documents that have been loaded using the doc() or document() * functions). Therefore, this method does not clear the document pool. If you want to clear the document * pool, call the method {@link #clearDocumentPool} as well. *

    *

    The reset Transformer is not guaranteed to have the same {@link javax.xml.transform.URIResolver} * or {@link javax.xml.transform.ErrorListener} Objects, e.g. {@link Object#equals(Object obj)}. * It is guaranteed to have a functionally equal URIResolver * and ErrorListener.

    * * @since 1.5 */ public void reset() { bindery = new Bindery(); namePool = config.getNamePool(); standardURIResolver = config.getSystemURIResolver(); userURIResolver = config.getURIResolver(); outputURIResolver = config.getOutputURIResolver(); schemaURIResolver = config.getSchemaURIResolver(); unparsedTextResolver = new StandardUnparsedTextResolver(); errorListener = config.getErrorListener(); recoveryPolicy = config.getRecoveryPolicy(); if (errorListener instanceof StandardErrorListener) { // if using a standard error listener, make a fresh one // for each transformation, because it is stateful - and also because the // host language is now known (a Configuration can serve multiple host languages) PrintStream ps = ((StandardErrorListener)errorListener).getErrorOutput(); errorListener = ((StandardErrorListener)errorListener).makeAnother(executable.getHostLanguage()); ((StandardErrorListener)errorListener).setErrorOutput(ps); ((StandardErrorListener)errorListener).setRecoveryPolicy(recoveryPolicy); } userDataTable = new HashMap(20); traceListener = null; tracingPaused = false; traceFunctionDestination = System.err; TraceListener tracer; try { tracer = config.makeTraceListener(); } catch (XPathException err) { throw new IllegalStateException(err.getMessage()); } if (tracer!=null) { addTraceListener(tracer); } setTreeModel(config.getTreeModel()); initialContextItem = null; contextForGlobalVariables = null; messageEmitter = null; localOutputProperties = null; parameters = null; principalResult = null; principalResultURI = null; initialTemplate = null; allOutputDestinations = null; thereHasBeenAnExplicitResultDocument = false; currentDateTime = null; dateTimePreset = false; initialMode = null; lastRememberedNode = null; lastRememberedNumber = -1; classLoader = null; } /** * Get the Configuration associated with this Controller. The Configuration holds * settings that potentially apply globally to many different queries and transformations. * @return the Configuration object * @since 8.4 */ public Configuration getConfiguration() { return config; } /** * Set the initial mode for the transformation. *

    * XSLT 2.0 allows a transformation to be started in a mode other than the default mode. * The transformation then starts by looking for the template rule in this mode that best * matches the initial context node. *

    * This method may eventually be superseded by a standard JAXP method. * * @param expandedModeName the name of the initial mode. The mode is * supplied as an expanded QName, that is "localname" if there is no * namespace, or "{uri}localname" otherwise * @since 8.4 */ public void setInitialMode(String expandedModeName) { if (expandedModeName==null) return; if (expandedModeName.length() == 0) return; initialMode = StructuredQName.fromClarkName(expandedModeName); } /** * Get the initial mode for the transformation * @return the initial mode, as a name in Clark format */ public String getInitialMode() { return initialMode.getClarkName(); } //////////////////////////////////////////////////////////////////////////////// // Methods for managing output destinations and formatting //////////////////////////////////////////////////////////////////////////////// /** * Set the output properties for the transformation. These * properties will override properties set in the templates * with xsl:output. *

    * As well as the properties defined in the JAXP OutputKeys class, * Saxon defines an additional set of properties in {@link SaxonOutputKeys}. * These fall into two categories: Constants representing serialization * properties defined in XSLT 2.0 (which are not yet supported by JAXP), * and constants supporting Saxon extensions to the set of serialization * properties. * * @param properties the output properties to be used for the * transformation. If the value is null, the properties are reset to * be the properties of the Templates object (that is, for XSLT 2.0, * the properties set in the unnamed xsl:output object). * @throws IllegalArgumentException if any of the properties are invalid (other than * properties in a user-defined namespace) * @see SaxonOutputKeys * @since 8.4 */ public void setOutputProperties(Properties properties) { if (properties == null) { localOutputProperties = null; } else { Enumeration keys = properties.propertyNames(); while(keys.hasMoreElements()) { String key = (String)keys.nextElement(); setOutputProperty(key, properties.getProperty(key)); } } } /** * Get the output properties for the transformation. *

    * As well as the properties defined in the JAXP OutputKeys class, * Saxon defines an additional set of properties in {@link SaxonOutputKeys}. * These fall into two categories: Constants representing serialization * properties defined in XSLT 2.0 (which are not yet supported by JAXP), * and constants supporting Saxon extensions to the set of serialization * properties. * * @return the output properties being used for the transformation, * including properties defined in the stylesheet for the unnamed * output format * @see SaxonOutputKeys * @since 8.4 */ public Properties getOutputProperties() { if (localOutputProperties == null) { if (executable==null) { return new Properties(); } else { localOutputProperties = new Properties(executable.getDefaultOutputProperties()); } } // Make a copy, so that modifications to the returned properties object have no effect (even on the // local output properties) Properties newProps = new Properties(); Enumeration keys = localOutputProperties.propertyNames(); while(keys.hasMoreElements()) { String key = (String)keys.nextElement(); newProps.setProperty(key, localOutputProperties.getProperty(key)); } return newProps; } /** * Set an output property for the transformation. *

    * As well as the properties defined in the JAXP OutputKeys class, * Saxon defines an additional set of properties in {@link SaxonOutputKeys}. * These fall into two categories: Constants representing serialization * properties defined in XSLT 2.0 (which are not yet supported by JAXP), * and constants supporting Saxon extensions to the set of serialization * properties. * * @param name the name of the property * @param value the value of the property * @throws IllegalArgumentException if the property is invalid (except for * properties in a user-defined namespace) * @see SaxonOutputKeys * @since 8.4 */ public void setOutputProperty(String name, String value) { if (localOutputProperties == null) { localOutputProperties = getOutputProperties(); } try { SaxonOutputKeys.checkOutputProperty(name, value, getConfiguration().getNameChecker()); } catch (XPathException err) { throw new IllegalArgumentException(err.getMessage()); } localOutputProperties.setProperty(name, value); } /** * Get the value of an output property. *

    * As well as the properties defined in the JAXP OutputKeys class, * Saxon defines an additional set of properties in {@link SaxonOutputKeys}. * These fall into two categories: Constants representing serialization * properties defined in XSLT 2.0 (which are not yet supported by JAXP), * and constants supporting Saxon extensions to the set of serialization * properties. * * @param name the name of the requested property * @return the value of the requested property * @see SaxonOutputKeys * @since 8.4 */ public String getOutputProperty(String name) { try { SaxonOutputKeys.checkOutputProperty(name, null, getConfiguration().getNameChecker()); } catch (XPathException err) { throw new IllegalArgumentException(err.getMessage()); } if (localOutputProperties == null) { if (executable==null) { return null; } else { localOutputProperties = executable.getDefaultOutputProperties(); } } return localOutputProperties.getProperty(name); } /** * Set the base output URI. * This defaults to the system ID of the principal Result object, but * a different value can be set for use where there is no principal result. * The command line interface sets this to the current working directory. *

    * The concept of the base output URI is new in XSLT 2.0: it defines the * base URI for resolving relative URIs in the href attribute * of the xsl:result-document instruction. This method may be * superseded by a standard JAXP method when JAXP is updated to support XSLT 2.0. * * @param uri the base output URI * @since 8.4 */ public void setBaseOutputURI(String uri) { principalResultURI = uri; } /** * Get the base output URI. * This defaults to the system ID of the principal Result object, but * a different value can be set for use where there is no principal result. * The command line interface sets this to the current working directory. *

    * The concept of the base output URI is new in XSLT 2.0: it defines the * base URI for resolving relative URIs in the href attribute * of the xsl:result-document instruction. This method may be * superseded by a standard JAXP method when JAXP is updated to support XSLT 2.0. * * @return the base output URI * @since 8.4 */ public String getBaseOutputURI() { return principalResultURI; } /** * Get the base output URI after processing. The processing consists of (a) defaulting * to the current user directory if no base URI is available and if the stylesheet is trusted, * and (b) applying IRI-to-URI escaping * @return the base output URI after processing. */ public String getCookedBaseOutputURI() { if (cookedPrincipalResultURI == null) { String base = getBaseOutputURI(); if (base == null && config.isAllowExternalFunctions()) { // if calling external functions is allowed, then the stylesheet is trusted, so // we allow it to write to files relative to the current directory base = new File(System.getProperty("user.dir")).toURI().toString(); } if (base != null) { base = EscapeURI.iriToUri(base).toString(); } cookedPrincipalResultURI = base; } return cookedPrincipalResultURI; } /** * Get the principal result destination. *

    This method is intended for internal use only. It is typically called by Saxon during the course * of a transformation, to discover the result that was supplied in the transform() call.

    * @return the Result object supplied as the principal result destination. */ public Result getPrincipalResult() { return principalResult; } /** * Check that an output destination has not been used before, optionally adding * this URI to the set of URIs that have been used. * @param uri the URI to be used as the output destination * @return true if the URI is available for use; false if it has already been used. *

    * This method is intended for internal use only. */ public boolean checkUniqueOutputDestination(String uri) { if (uri == null) { return true; // happens when writing say to an anonymous StringWriter } if (allOutputDestinations == null) { allOutputDestinations = new HashSet(20); } if (uri.startsWith("file:///")) { uri = "file:/" + uri.substring(8); } return !allOutputDestinations.contains(uri); } /** * Add a URI to the set of output destinations that cannot be written to, either because * they have already been written to, or because they have been read * @param uri A URI that is not available as an output destination */ public void addUnavailableOutputDestination(String uri) { if (allOutputDestinations == null) { allOutputDestinations = new HashSet(20); } allOutputDestinations.add(uri); } /** * Remove a URI from the set of output destinations that cannot be written to or read from. * Used to support saxon:discard-document() * @param uri A URI that is being made available as an output destination */ public void removeUnavailableOutputDestination(String uri) { if (allOutputDestinations != null) { allOutputDestinations.remove(uri); } } /** * Determine whether an output URI is available for use. This method is intended * for use by applications, via an extension function. * @param uri A uri that the application is proposing to use in the href attribute of * xsl:result-document: if this function returns false, then the xsl:result-document * call will fail saying the URI has already been used. * @return true if the URI is available for use. Note that this function is not "stable": * it may return different results for the same URI at different points in the transformation. */ public boolean isUnusedOutputDestination(String uri) { return allOutputDestinations == null || !allOutputDestinations.contains(uri); } /** * Check whether an XSLT implicit result tree can be written. This is allowed only if no xsl:result-document * has been written for the principal output URI */ public void checkImplicitResultTree() throws XPathException { if (!checkUniqueOutputDestination(principalResultURI)) { XPathException err = new XPathException("Cannot write an implicit result document if an explicit result document has been written to the same URI: " + principalResultURI); err.setErrorCode("XTDE1490"); throw err; } } /** * Set that an explicit result tree has been written using xsl:result-document */ public void setThereHasBeenAnExplicitResultDocument() { thereHasBeenAnExplicitResultDocument = true; } /** * Test whether an explicit result tree has been written using xsl:result-document * @return true if the transformation has evaluated an xsl:result-document instruction */ public boolean hasThereBeenAnExplicitResultDocument() { return thereHasBeenAnExplicitResultDocument; } /** * Allocate a SequenceOutputter for a new output destination. Reuse the existing one * if it is available for reuse (this is designed to ensure that the TinyTree structure * is also reused, creating a forest of trees all sharing the same data structure) * @param size the estimated size of the output sequence * @return SequenceOutputter the allocated SequenceOutputter */ public SequenceOutputter allocateSequenceOutputter(int size) { if (reusableSequenceOutputter != null) { SequenceOutputter out = reusableSequenceOutputter; reusableSequenceOutputter = null; return out; } else { return new SequenceOutputter(this, size); } } /** * Accept a SequenceOutputter that is now available for reuse * @param out the SequenceOutputter that is available for reuse */ public void reuseSequenceOutputter(SequenceOutputter out) { reusableSequenceOutputter = out; } /////////////////////////////////////////////////////////////////////////////// /** * Set the initial named template to be used as the entry point. *

    * XSLT 2.0 allows a transformation to start by executing a named template, rather than * by matching an initial context node in a source document. This method may eventually * be superseded by a standard JAXP method once JAXP supports XSLT 2.0. *

    * Note that any parameters supplied using {@link #setParameter} are used as the values * of global stylesheet parameters. There is no way to supply values for local parameters * of the initial template. * * @param expandedName The expanded name of the template in {uri}local format, or null * to indicate that there should be no initial template. * @throws XPathException if there is no named template with this name * @since 8.4 */ public void setInitialTemplate(String expandedName) throws XPathException { if (expandedName == null) { initialTemplate = null; return; } StructuredQName qName = StructuredQName.fromClarkName(expandedName); Template t = getExecutable().getNamedTemplate(qName); if (t == null) { XPathException err = new XPathException("There is no named template with expanded name " + expandedName); err.setErrorCode("XTDE0040"); reportFatalError(err); throw err; } else if (t.hasRequiredParams()) { XPathException err = new XPathException("The named template " + expandedName + " has required parameters, so cannot be used as the entry point"); err.setErrorCode("XTDE0060"); reportFatalError(err); throw err; } else { initialTemplate = t; } } /** * Get the initial template * @return the name of the initial template, as an expanded name in Clark format if set, or null otherwise * @since 8.7 */ public String getInitialTemplate() { if (initialTemplate == null) { return null; } else { return initialTemplate.getTemplateName().getClarkName(); } } /////////////////////////////////////////////////////////////////////////////// /** * Make a PipelineConfiguration based on the properties of this Controller. *

    * This interface is intended primarily for internal use, although it may be necessary * for applications to call it directly if they construct pull or push pipelines * @return a newly constructed PipelineConfiguration holding a reference to this * Controller as well as other configuration information. */ public PipelineConfiguration makePipelineConfiguration() { PipelineConfiguration pipe = new PipelineConfiguration(); pipe.setConfiguration(getConfiguration()); pipe.setErrorListener(getErrorListener()); pipe.setURIResolver(userURIResolver==null ? standardURIResolver : userURIResolver); pipe.setSchemaURIResolver(schemaURIResolver); pipe.setExpandAttributeDefaults(getConfiguration().isExpandAttributeDefaults()); pipe.setUseXsiSchemaLocation(((Boolean)getConfiguration().getConfigurationProperty( FeatureKeys.USE_XSI_SCHEMA_LOCATION)).booleanValue()); pipe.setController(this); final Executable executable = getExecutable(); if (executable != null) { // can be null for an IdentityTransformer pipe.setLocationProvider(executable.getLocationMap()); pipe.setHostLanguage(executable.getHostLanguage()); } return pipe; } /** * Make an Emitter to be used for xsl:message output. *

    * This method is intended for internal use only. * * @exception XPathException if any dynamic error occurs; in * particular, if the registered MessageEmitter class is not an * Emitter * @return The newly constructed message Emitter */ private Receiver makeMessageEmitter() throws XPathException { String emitterClass = config.getMessageEmitterClass(); Object messageReceiver = config.getInstance(emitterClass, getClassLoader()); if (!(messageReceiver instanceof Receiver)) { throw new XPathException(emitterClass + " is not a Receiver"); } setMessageEmitter((Receiver)messageReceiver); // if (messageReceiver instanceof Emitter) { // Properties props = new Properties(); // props.setProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); // ((Emitter)messageReceiver).setOutputProperties(props); // } return (Receiver)messageReceiver; } /** * Set the Receiver to be used for xsl:message output. *

    * Recent versions of the JAXP interface specify that by default the * output of xsl:message is sent to the registered ErrorListener. Saxon * does not yet implement this convention. Instead, the output is sent * to a default message emitter, which is a slightly customised implementation * of the standard Saxon Emitter interface.

    *

    * This interface can be used to change the way in which Saxon outputs * xsl:message output.

    *

    * It is not necessary to use this interface in order to change the destination * to which messages are written: that can be achieved by obtaining the standard * message emitter and calling its {@link Emitter#setWriter} method.

    *

    * Although any Receiver can be supplied as the destination for messages, * applications may find it convenient to implement a subclass of {@link net.sf.saxon.event.SequenceWriter}, * in which only the abstract write() method is implemented. This will have the effect that the * write() method is called to output each message as it is generated, with the Item * that is passed to the write() method being the document node at the root of an XML document * containing the contents of the message. *

    * This method is intended for use by advanced applications. The Receiver interface * itself is subject to change in new Saxon releases.

    *

    * The supplied Receiver will have its open() method called once at the start of * the transformation, and its close() method will be called once at the end of the * transformation. Each individual call of an xsl:message instruction is wrapped by * calls of startDocument() and endDocument(). If terminate="yes" is specified on the * xsl:message call, the properties argument of the startDocument() call will be set * to the value {@link ReceiverOptions#TERMINATE}.

    * @param receiver The receiver to receive xsl:message output. * @since 8.4; changed in 8.9 to supply a Receiver rather than an Emitter */ public void setMessageEmitter(Receiver receiver) { messageEmitter = receiver; if (receiver.getPipelineConfiguration() == null) { messageEmitter.setPipelineConfiguration(makePipelineConfiguration()); } if (messageEmitter instanceof Emitter && ((Emitter)messageEmitter).getOutputProperties() == null) { try { Properties props = new Properties(); props.setProperty(OutputKeys.METHOD, "xml"); props.setProperty(OutputKeys.INDENT, "yes"); props.setProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); ((Emitter)messageEmitter).setOutputProperties(props); } catch (XPathException e) { // no action } } } /** * Get the Emitter used for xsl:message output. This returns the emitter * previously supplied to the {@link #setMessageEmitter} method, or the * default message emitter otherwise. * * @return the Receiver being used for xsl:message output * @since 8.4; changed in 8.9 to return a Receiver rather than an Emitter */ public Receiver getMessageEmitter() { return messageEmitter; } /** * Make a CharacterMapExpander to handle the character map definitions in the serialization * properties. *

    * This method is intended for internal use only. * * @param useMaps the expanded use-character-maps property: a space-separated list of names * of character maps to be used, each one expressed as an expanded-QName in Clark notation * (that is, {uri}local-name). * @param sf the SerializerFactory - used to create a CharacterMapExpander * @return a CharacterMapExpander if one is required, or null if not (for example, if the * useMaps argument is an empty string). * @throws XPathException if a name in the useMaps property cannot be resolved to a declared * character map. */ public CharacterMapExpander makeCharacterMapExpander(String useMaps, SerializerFactory sf) throws XPathException { CharacterMapExpander characterMapExpander = null; HashMap characterMapIndex = getExecutable().getCharacterMapIndex(); if (useMaps != null && characterMapIndex != null) { List characterMaps = new ArrayList(5); StringTokenizer st = new StringTokenizer(useMaps, " \t\n\r", false); while (st.hasMoreTokens()) { String expandedName = st.nextToken(); StructuredQName qName = StructuredQName.fromClarkName(expandedName); IntHashMap map = (IntHashMap)characterMapIndex.get(qName); if (map==null) { throw new XPathException("Character map '" + expandedName + "' has not been defined"); } characterMaps.add(map); } if (!characterMaps.isEmpty()) { characterMapExpander = sf.newCharacterMapExpander(); characterMapExpander.setCharacterMaps(characterMaps); } } return characterMapExpander; } /** * Set the policy for handling recoverable errrors * @param policy the recovery policy to be used. The options are {@link Configuration#RECOVER_SILENTLY}, * {@link Configuration#RECOVER_WITH_WARNINGS}, or {@link Configuration#DO_NOT_RECOVER}. * @since 8.7.1 */ public void setRecoveryPolicy(int policy) { recoveryPolicy = policy; if (errorListener instanceof StandardErrorListener) { ((StandardErrorListener)errorListener).setRecoveryPolicy(policy); } } /** * Get the policy for handling recoverable errors * * @return the current policy. If none has been set with this Controller, the value registered with the * Configuration is returned. * @since 8.7.1 */ public int getRecoveryPolicy() { return recoveryPolicy; } /** * Set the error listener. * * @param listener the ErrorListener to be used */ public void setErrorListener(ErrorListener listener) { errorListener = listener; } /** * Get the error listener. * * @return the ErrorListener in use */ public ErrorListener getErrorListener() { return errorListener; } /** * Report a recoverable error. This is an XSLT concept: by default, such an error results in a warning * message, and processing continues. In XQuery, however, there are no recoverable errors so a fatal * error is reported. *

    * This method is intended for internal use only. * * @param err An exception holding information about the error * @throws XPathException if the error listener decides not to * recover from the error */ public void recoverableError(XPathException err) throws XPathException { try { if (executable.getHostLanguage() == Configuration.XQUERY) { reportFatalError(err); throw err; } else { errorListener.error(err); } } catch (TransformerException e) { XPathException de = XPathException.makeXPathException(e); de.setHasBeenReported(); throw de; } } /** * Report a fatal error * @param err the error to be reported */ public void reportFatalError(XPathException err) { if (!err.hasBeenReported()) { try { getErrorListener().fatalError(err); } catch (TransformerException e) { // } err.setHasBeenReported(); } } ///////////////////////////////////////////////////////////////////////////////////////// // Methods for managing the various runtime control objects ///////////////////////////////////////////////////////////////////////////////////////// /** * Get the Executable object. *

    * This method is intended for internal use only. * * @return the Executable (which represents the compiled stylesheet) */ public Executable getExecutable() { return executable; } /** * Get the document pool. This is used only for source documents, not for stylesheet modules. *

    * This method is intended for internal use only. * * @return the source document pool */ public DocumentPool getDocumentPool() { return sourceDocumentPool; } /** * Clear the document pool. * This is sometimes useful when re-using the same Transformer * for a sequence of transformations, but it isn't done automatically, because when * the transformations use common look-up documents, the caching is beneficial. */ public void clearDocumentPool() { sourceDocumentPool = new DocumentPool(); } /** * Set the initial context node (used for evaluating global variables). * When a transformation is invoked using the {@link #transform} method, the * initial context node is set automatically. This method is useful in XQuery, * to define an initial context node for evaluating global variables, and also * in XSLT 2.0, when the transformation is started by invoking a named template. * * @param doc The principal source document * @since 8.4 * @deprecated From Saxon 8.7, replaced by {@link #setInitialContextItem(Item)} */ public void setPrincipalSourceDocument(DocumentInfo doc) { initialContextItem = doc; } /** * Set the initial context item. *

    * When a transformation is invoked using the {@link #transform} method, the * initial context node is set automatically. This method is useful in XQuery, * to define an initial context node for evaluating global variables, and also * in XSLT 2.0, when the transformation is started by invoking a named template. * *

    When an initial context item is set, it also becomes the context item used for * evaluating global variables. The two context items can only be different when the * {@link #transform} method is used to transform a document starting at a node other * than the root.

    * *

    In XQuery, the two context items are always * the same; in XSLT, the context node for evaluating global variables is the root of the * tree containing the initial context item.

    * * @param item The initial context item. The XSLT specification says that this * must be a node; however this restriction is not enforced, and any item can be supplied * as an initial context item if the transformation is started by calling a named initial template. * (There is no similar restriction in XQuery) * @since 8.7 */ public void setInitialContextItem(Item item) { initialContextItem = item; contextForGlobalVariables = item; // TODO: are we enforcing the rule that in XSLT the context for global variables is always the // root of the tree? } /** * Get the current bindery. *

    * This method is intended for internal use only. * * @return the Bindery (in which values of all variables are held) */ public Bindery getBindery() { return bindery; } /** * Get the initial context item. This returns the item (often a document node) * previously supplied to the {@link #setInitialContextItem} method, or the * initial context node set implicitly using methods such as {@link #transform}. * @return the initial context item. Note that in XSLT this must be a node, but in * XQuery it may also be an atomic value. * @since 8.7 */ public Item getInitialContextItem() { return initialContextItem; } /** * Get the item used as the context for evaluating global variables. In XQuery this * is the same as the initial context item; in XSLT it is the root of the tree containing * the initial context node. * @return the context item for evaluating global variables, or null if there is none * @since 8.7 */ public Item getContextForGlobalVariables() { return contextForGlobalVariables; // See bug 5224, which points out that the rules for XQuery 1.0 weren't clearly defined } /** * Set an object that will be used to resolve URIs used in * document(), etc. * * @param resolver An object that implements the URIResolver interface, or * null. */ public void setURIResolver(URIResolver resolver) { userURIResolver = resolver; if (resolver instanceof StandardURIResolver) { ((StandardURIResolver)resolver).setConfiguration(getConfiguration()); } } /** * Get the URI resolver. * *

    This method changed in Saxon 8.5, to conform to the JAXP specification. If there * is no user-specified URIResolver, it now returns null; previously it returned the system * default URIResolver.

    * * @return the user-supplied URI resolver if there is one, or null otherwise. */ public URIResolver getURIResolver() { return userURIResolver; } /** * Get the fallback URI resolver. This is the URIResolver that Saxon uses when * the user-supplied URI resolver returns null. *

    * This method is intended for internal use only. * * @return the the system-defined URIResolver */ public URIResolver getStandardURIResolver() { return standardURIResolver; } /** * Set the URI resolver for secondary output documents. *

    * XSLT 2.0 introduces the xsl:result-document * This method may eventually be superseded by a standard JAXP method. * * @param resolver An object that implements the OutputURIResolver * interface, or null. * @since 8.4 */ public void setOutputURIResolver(OutputURIResolver resolver) { if (resolver==null) { outputURIResolver = config.getOutputURIResolver(); } else { outputURIResolver = resolver; } } /** * Get the output URI resolver. * * @return the user-supplied URI resolver if there is one, or the * system-defined one otherwise. * @see #setOutputURIResolver * @since 8.4 */ public OutputURIResolver getOutputURIResolver() { return outputURIResolver; } /** * Set an UnparsedTextURIResolver to be used to resolve URIs passed to the XSLT * unparsed-text() function. * @param resolver the unparsed text URI resolver to be used. This replaces any unparsed text * URI resolver previously registered. * @since 8.9 */ public void setUnparsedTextURIResolver(UnparsedTextURIResolver resolver) { unparsedTextResolver = resolver; } /** * Get the URI resolver for the unparsed-text() function. This will * return the UnparsedTextURIResolver previously set using the {@link #setUnparsedTextURIResolver} * method. * @return the registered UnparsedTextURIResolver * @since 8.9 */ public UnparsedTextURIResolver getUnparsedTextURIResolver() { return unparsedTextResolver; } /** * Set the SchemaURIResolver used for resolving references to schema * documents. Defaults to the SchemaURIResolver registered with the * Configuration * @param resolver the resolver for references to schema documents */ public void setSchemaURIResolver(SchemaURIResolver resolver) { schemaURIResolver = resolver; } /** * Get the SchemaURIResolver used for resolving references to schema * documents. If none has been set on the Controller, returns the * SchemaURIResolver registered with the Configuration * @return the resolver for references to schema documents */ public SchemaURIResolver getSchemaURIResolver() { return schemaURIResolver; } /** * Get the KeyManager. *

    * This method is intended for internal use only. * * @return the KeyManager, which holds details of all key declarations */ public KeyManager getKeyManager() { return executable.getKeyManager(); } /** * Get the name pool in use. The name pool is responsible for mapping QNames used in source * documents and compiled stylesheets and queries into numeric codes. All source documents * used by a given transformation or query must use the same name pool as the compiled stylesheet * or query. * * @return the name pool in use * @since 8.4 */ public NamePool getNamePool() { return namePool; } /** * Set the tree data model to use. This affects all source documents subsequently constructed using a * Builder obtained from this Controller. This includes a document built from a StreamSource or * SAXSource supplied as a parameter to the {@link #transform} method. * * @param model the required tree model: {@link Builder#LINKED_TREE} or * {@link Builder#TINY_TREE} * @see net.sf.saxon.event.Builder * @since 8.4 */ public void setTreeModel(int model) { treeModel = model; } /** * Get the tree data model to use. This affects all source documents subsequently constructed using a * Builder obtained from this Controller. This includes a document built from a StreamSource or * SAXSource supplied as a parameter to the {@link #transform} method. * * @return model the tree model: {@link Builder#LINKED_TREE} or * {@link Builder#TINY_TREE} * @see net.sf.saxon.event.Builder * @since 9.1 */ public int getTreeModel() { return treeModel; } /** * Make a builder for the selected tree model. * * @return an instance of the Builder for the chosen tree model * @since 8.4 */ public Builder makeBuilder() { Builder b; if (treeModel==Builder.TINY_TREE) { b = new TinyBuilder(); } else { b = new TreeBuilder(); } b.setTiming(config.isTiming()); b.setLineNumbering(config.isLineNumbering()); b.setPipelineConfiguration(makePipelineConfiguration()); return b; } /** * Make a Stripper configured to implement the whitespace stripping rules. * In the case of XSLT the whitespace stripping rules are normally defined * by xsl:strip-space and xsl:preserve-space * This method is intended for internal use only. * * @param doc the root node of the document to be added * @param systemId the document-URI property of this document */ public void registerDocument(DocumentInfo doc, String systemId) { sourceDocumentPool.add(doc, systemId); } //////////////////////////////////////////////////////////////////////////////// // Methods for registering and retrieving handlers for template rules //////////////////////////////////////////////////////////////////////////////// /** * Set the RuleManager, used to manage template rules for each mode. *

    * This method is intended for internal use only. * * @param r the Rule Manager */ public void setRuleManager(RuleManager r) { ruleManager = r; } /** * Get the Rule Manager. *

    * This method is intended for internal use only. * * @return the Rule Manager, used to hold details of template rules for * all modes */ public RuleManager getRuleManager() { return ruleManager; } ///////////////////////////////////////////////////////////////////////// // Methods for tracing ///////////////////////////////////////////////////////////////////////// /** * Get the TraceListener. By default, there is no TraceListener, and this * method returns null. A TraceListener may be added using the method * {@link #addTraceListener}. If more than one TraceListener has been added, * this method will return a composite TraceListener. Because this form * this takes is implementation-dependent, this method is not part of the * stable Saxon public API. * * @return the TraceListener used for XSLT or XQuery instruction tracing */ public TraceListener getTraceListener() { // e.g. return traceListener; } /** * Test whether instruction execution is being traced. This will be true * if (a) at least one TraceListener has been registered using the * {@link #addTraceListener} method, and (b) tracing has not been temporarily * paused using the {@link #pauseTracing} method. * * @return true if tracing is active, false otherwise * @since 8.4 */ public final boolean isTracing() { // e.g. return traceListener != null && !tracingPaused; } /** * Pause or resume tracing. While tracing is paused, trace events are not sent to any * of the registered TraceListeners. * * @param pause true if tracing is to pause; false if it is to resume * @since 8.4 */ public final void pauseTracing(boolean pause) { tracingPaused = pause; } /** * Adds the specified trace listener to receive trace events from * this instance. Note that although TraceListeners can be added * or removed dynamically, this has no effect unless the stylesheet * or query has been compiled with tracing enabled. This is achieved * by calling {@link Configuration#setTraceListener} or by setting * the attribute {@link FeatureKeys#TRACE_LISTENER} on the * TransformerFactory. Conversely, if this property has been set in the * Configuration or TransformerFactory, the TraceListener will automatically * be added to every Controller that uses that Configuration. * * @param trace the trace listener. If null is supplied, the call has no effect. * @since 8.4 */ public void addTraceListener(TraceListener trace) { // e.g. if (trace != null) { traceListener = TraceEventMulticaster.add(traceListener, trace); } } /** * Removes the specified trace listener so that the listener will no longer * receive trace events. * * @param trace the trace listener. * @since 8.4 */ public void removeTraceListener(TraceListener trace) { // e.g. traceListener = TraceEventMulticaster.remove(traceListener, trace); } /** * Set the destination for output from the fn:trace() function. * By default, the destination is System.err. If a TraceListener is in use, * this is ignored, and the trace() output is sent to the TraceListener. * @param stream the PrintStream to which trace output will be sent. If set to * null, trace output is suppressed entirely. It is the caller's responsibility * to close the stream after use. * @since 9.1 */ public void setTraceFunctionDestination(PrintStream stream) { traceFunctionDestination = stream; } /** * Get the destination for output from the fn:trace() function. * @return the PrintStream to which trace output will be sent. If no explicitly * destination has been set, returns System.err. If the destination has been set * to null to suppress trace output, returns null. * @since 9.1 */ public PrintStream getTraceFunctionDestination() { return traceFunctionDestination; } /** * Associate this Controller with a compiled stylesheet. *

    * This method is intended for internal use only. * * @param sheet the compiled stylesheet */ public void setPreparedStylesheet(PreparedStylesheet sheet) { preparedStylesheet = sheet; executable = sheet.getExecutable(); //setOutputProperties(sheet.getOutputProperties()); // above line deleted for bug 490964 - may have side-effects } /** * Associate this Controller with an Executable. This method is used by the XQuery * processor. The Executable object is overkill in this case - the only thing it * currently holds are copies of the collation table. *

    * This method is intended for internal use only * @param exec the Executable */ public void setExecutable(Executable exec) { executable = exec; } /** * Initialize the controller ready for a new transformation. This method should not normally be called by * users (it is done automatically when transform() is invoked). However, it is available as a low-level API * especially for use with XQuery. */ public void initializeController() throws XPathException { setRuleManager(executable.getRuleManager()); //setDecimalFormatManager(executable.getDecimalFormatManager()); if (traceListener!=null) { traceListener.open(); } // get a new bindery, to clear out any variables from previous runs bindery = new Bindery(); executable.initializeBindery(bindery); // if parameters were supplied, set them up defineGlobalParameters(); } /** * Register the global parameters of the transformation or query. This should be called after a sequence * of calls on {@link #setParameter}. It checks that all required parameters have been supplied, and places * the values of the parameters in the Bindery to make them available for use during the query or * transformation. *

    * This method is intended for internal use only */ public void defineGlobalParameters() throws XPathException { executable.checkAllRequiredParamsArePresent(parameters); bindery.defineGlobalParameters(parameters); } /** * Allocate space in the bindery for global variables. *

    For internal use only.

    * @param numberOfVariables the number of global variables for which space is required */ public void allocateGlobalVariables(int numberOfVariables) { SlotManager map = executable.getGlobalVariableMap(); map.setNumberOfVariables(numberOfVariables); bindery.allocateGlobals(map); } ///////////////////////////////////////////////////////////////////////// // Allow user data to be associated with nodes on a tree ///////////////////////////////////////////////////////////////////////// /** * Get user data associated with a key. To retrieve user data, two objects are required: * an arbitrary object that may be regarded as the container of the data (originally, and * typically still, a node in a tree), and a name. The name serves to distingush data objects * associated with the same node by different client applications. *

    * This method is intended primarily for internal use, though it may also be * used by advanced applications. * * @param key an object acting as a key for this user data value. This must be equal * (in the sense of the equals() method) to the key supplied when the data value was * registered using {@link #setUserData}. * @param name the name of the required property * @return the value of the required property */ public Object getUserData(Object key, String name) { String keyValue = key.hashCode() + " " + name; // System.err.println("getUserData " + name + " on object returning " + userDataTable.get(key)); return userDataTable.get(keyValue); } /** * Set user data associated with a key. To store user data, two objects are required: * an arbitrary object that may be regarded as the container of the data (originally, and * typically still, a node in a tree), and a name. The name serves to distingush data objects * associated with the same node by different client applications. *

    * This method is intended primarily for internal use, though it may also be * used by advanced applications. * * @param key an object acting as a key for this user data value. This must be equal * (in the sense of the equals() method) to the key supplied when the data value was * registered using {@link #setUserData}. If data for the given object and name already * exists, it is overwritten. * @param name the name of the required property * @param data the value of the required property */ public void setUserData(Object key, String name, Object data) { // System.err.println("setUserData " + name + " on object to " + data); String keyVal = key.hashCode() + " " + name; if (data==null) { userDataTable.remove(keyVal); } else { userDataTable.put(keyVal, data); } } ///////////////////////////////////////////////////////////////////////// // implement the javax.xml.transform.Transformer methods ///////////////////////////////////////////////////////////////////////// /** * Perform a transformation from a Source document to a Result document. * * @exception XPathException if the transformation fails. As a * special case, the method throws a TerminationException (a subclass * of XPathException) if the transformation was terminated using * xsl:message terminate="yes". * @param source The input for the source tree. May be null if and only if an * initial template has been supplied. * @param result The destination for the result tree. */ public void transform(Source source, Result result) throws TransformerException { if (preparedStylesheet==null) { throw new XPathException("Stylesheet has not been prepared"); } if (!dateTimePreset) { currentDateTime = null; // reset at start of each transformation } boolean close = false; try { NodeInfo startNode = null; boolean wrap = true; int validationMode = config.getSchemaValidationMode(); Source underSource = source; if (source instanceof AugmentedSource) { Boolean localWrap = ((AugmentedSource)source).getWrapDocument(); if (localWrap != null) { wrap = localWrap.booleanValue(); } close = ((AugmentedSource)source).isPleaseCloseAfterUse(); int localValidate = ((AugmentedSource)source).getSchemaValidation(); if (localValidate != Validation.DEFAULT) { validationMode = localValidate; } if (validationMode == Validation.STRICT || validationMode == Validation.LAX) { // If validation of a DOMSource or NodeInfo is requested, we must copy it, we can't wrap it wrap = false; } underSource = ((AugmentedSource)source).getContainedSource(); } Source s2 = config.getSourceResolver().resolveSource(underSource, config); if (s2 != null) { underSource = s2; } if (wrap && (underSource instanceof NodeInfo || underSource instanceof DOMSource)) { startNode = prepareInputTree(underSource); registerDocument(startNode.getDocumentRoot(), underSource.getSystemId()); } else if (source == null) { if (initialTemplate == null) { throw new XPathException("Either a source document or an initial template must be specified"); } } else { // The input is a SAXSource or StreamSource or AugmentedSource, or // a DOMSource with wrap=no: build the document tree Builder sourceBuilder = makeBuilder(); Sender sender = new Sender(sourceBuilder.getPipelineConfiguration()); Receiver r = sourceBuilder; if (config.isStripsAllWhiteSpace() || executable.stripsWhitespace() || validationMode == Validation.STRICT || validationMode == Validation.LAX) { r = makeStripper(sourceBuilder); } if (executable.stripsInputTypeAnnotations()) { r = config.getAnnotationStripper(r); } sender.send(source, r); if (close) { ((AugmentedSource)source).close(); } DocumentInfo doc = (DocumentInfo)sourceBuilder.getCurrentRoot(); sourceBuilder.reset(); registerDocument(doc, source.getSystemId()); startNode = doc; } transformDocument(startNode, result); } catch (TerminationException err) { //System.err.println("Processing terminated using xsl:message"); throw err; } catch (XPathException err) { Throwable cause = err.getException(); if (cause != null && cause instanceof SAXParseException) { // This generally means the error was already reported. // But if a RuntimeException occurs in Saxon during a callback from // the Crimson parser, Crimson wraps this in a SAXParseException without // reporting it further. SAXParseException spe = (SAXParseException)cause; cause = spe.getException(); if (cause instanceof RuntimeException) { reportFatalError(err); } } else { reportFatalError(err); } throw err; } finally { if (close) { ((AugmentedSource)source).close(); } principalResultURI = null; } } /** * Prepare an input tree for processing. This is used when either the initial * input, or a Source returned by the document() function, is a NodeInfo or a * DOMSource. The preparation consists of wrapping a DOM document inside a wrapper * that implements the NodeInfo interface, and/or adding a space-stripping wrapper * if the stylesheet strips whitespace nodes. *

    * This method is intended for internal use. * * @param source the input tree. Must be either a DOMSource or a NodeInfo * @return the NodeInfo representing the input node, suitably wrapped. */ public NodeInfo prepareInputTree(Source source) { NodeInfo start = getConfiguration().unravel(source); if (executable.stripsWhitespace()) { DocumentInfo docInfo = start.getDocumentRoot(); StrippedDocument strippedDoc = new StrippedDocument(docInfo, makeStripper(null)); start = strippedDoc.wrap(start); } return start; } /** * Get a NodeInfo corresponding to a DOM Node, either by wrapping or unwrapping the DOM Node. *

    * This method is intended for internal use. * @param source the wrapped or unwrapped DOM Node * @param config the Saxon configuration * @return a Saxon NodeInfo object obtained by wrapping or unwrapping the supplied DOM node. * @deprecated since 9.0: use {@link Configuration#unravel} */ public static NodeInfo unravel(Source source, Configuration config) { return config.unravel(source); } /** * Transform a source XML document supplied as a tree.
    *

    * This method is intended for internal use. External applications should use * the {@link #transform} method, which is part of the JAXP interface. Note that * NodeInfo implements the JAXP Source interface, so * it may be supplied directly to the transform() method. * * @exception XPathException if any dynamic error occurs * @param startNode A Node that identifies the source document to be * transformed and the node where the transformation should start. * May be null if the transformation is to start using an initial template. * @param result The output destination */ public void transformDocument(NodeInfo startNode, Result result) throws TransformerException { // System.err.println("*** TransformDocument"); if (executable==null) { throw new XPathException("Stylesheet has not been compiled"); } if (getMessageEmitter() == null) { Receiver me = makeMessageEmitter(); setMessageEmitter(me); if (me instanceof Emitter && ((Emitter)me).getWriter()==null) { try { ((Emitter)me).setWriter(new OutputStreamWriter(System.err)); } catch (Exception err) { // This has been known to fail on .NET because the default encoding set for the // .NET environment is not supported by the Java class library. So we'll try again try { ((Emitter)me).setWriter(new OutputStreamWriter(System.err, "utf8")); } catch (UnsupportedEncodingException e) { throw new XPathException(e); } } } } getMessageEmitter().open(); // Determine whether we need to close the output stream at the end. We // do this if the Result object is a StreamResult and is supplied as a // system ID, not as a Writer or OutputStream boolean mustClose = (result instanceof StreamResult && ((StreamResult)result).getOutputStream() == null); principalResult = result; if (principalResultURI == null) { principalResultURI = result.getSystemId(); } XPathContextMajor initialContext = newXPathContext(); initialContext.setOriginatingConstructType(Location.CONTROLLER); if (startNode != null) { initialContextItem = startNode; contextForGlobalVariables = startNode.getRoot(); if (startNode.getConfiguration()==null) { // must be a non-standard document implementation throw new TransformerException("The supplied source document must be associated with a Configuration"); } if (!startNode.getConfiguration().isCompatible(preparedStylesheet.getConfiguration())) { throw new XPathException( "Source document and stylesheet must use the same or compatible Configurations", SaxonErrorCode.SXXP0004); } SequenceIterator currentIter = SingletonIterator.makeIterator(startNode); if (initialTemplate != null) { currentIter.next(); } initialContext.setCurrentIterator(currentIter); } initializeController(); // In tracing/debugging mode, evaluate all the global variables first if (traceListener != null) { preEvaluateGlobals(initialContext); } Properties xslOutputProps; if (localOutputProperties == null) { xslOutputProps = executable.getDefaultOutputProperties(); } else { xslOutputProps = localOutputProperties; } // deal with stylesheet chaining String nextInChain = xslOutputProps.getProperty(SaxonOutputKeys.NEXT_IN_CHAIN); if (nextInChain != null) { String baseURI = xslOutputProps.getProperty(SaxonOutputKeys.NEXT_IN_CHAIN_BASE_URI); result = prepareNextStylesheet(nextInChain, baseURI, result); } // add a property to indicate that this is the implicit result document, which // should only be created if either it is non-empty, or no xsl:result-document has been executed Properties props = new Properties(xslOutputProps); props.setProperty(SaxonOutputKeys.IMPLICIT_RESULT_DOCUMENT, "yes"); initialContext.changeOutputDestination(props, result, true, Configuration.XSLT, Validation.PRESERVE, null); // Process the source document using the handlers that have been set up if (initialTemplate == null) { // SequenceIterator single = SingletonIterator.makeIterator(startNode); // initialContext.setCurrentIterator(single); initialContextItem = startNode; final Mode mode = getRuleManager().getMode(initialMode, false); if (mode == null || (initialMode != null && mode.isEmpty())) { throw new XPathException("Requested initial mode " + (initialMode == null ? "" : initialMode.getDisplayName()) + " does not exist", "XTDE0045"); } TailCall tc = ApplyTemplates.applyTemplates( initialContext.getCurrentIterator(), mode, null, null, initialContext, false, 0); while (tc != null) { tc = tc.processLeavingTail(); } } else { Template t = initialTemplate; XPathContextMajor c2 = initialContext.newContext(); initialContext.setOriginatingConstructType(Location.CONTROLLER); c2.openStackFrame(t.getStackFrameMap()); c2.setLocalParameters(new ParameterSet()); c2.setTunnelParameters(new ParameterSet()); TailCall tc = t.expand(c2); while (tc != null) { tc = tc.processLeavingTail(); } } if (traceListener!=null) { traceListener.close(); } Receiver out = initialContext.getReceiver(); if (out instanceof ComplexContentOutputter && ((ComplexContentOutputter)out).contentHasBeenWritten()) { if (principalResultURI != null) { if (!checkUniqueOutputDestination(principalResultURI)) { XPathException err = new XPathException( "Cannot write more than one result document to the same URI, or write to a URI that has been read: " + result.getSystemId()); err.setErrorCode("XTDE1490"); throw err; } else { addUnavailableOutputDestination(principalResultURI); } } } out.endDocument(); out.close(); getMessageEmitter().close(); if (mustClose && result instanceof StreamResult) { OutputStream os = ((StreamResult)result).getOutputStream(); if (os != null) { try { os.close(); } catch (java.io.IOException err) { throw new XPathException(err); } } } } /** * Pre-evaluate global variables (when debugging/tracing). *

    * This method is intended for internal use. * @param context the dynamic context for evaluating the global variables * @throws XPathException if a dynamic error occurs while evaluating the global variables. */ public void preEvaluateGlobals(XPathContext context) throws XPathException { HashMap vars = getExecutable().getCompiledGlobalVariables(); if (vars != null) { Iterator iter = vars.values().iterator(); while (iter.hasNext()) { GlobalVariable var = (GlobalVariable)iter.next(); var.evaluateVariable(context); } } } /** * Prepare another stylesheet to handle the output of this one. *

    * This method is intended for internal use, to support the * saxon:next-in-chain extension. * * @exception XPathException if any dynamic error occurs * @param href URI of the next stylesheet to be applied * @param baseURI base URI for resolving href if it's a relative * URI * @param result the output destination of the current stylesheet * @return a replacement destination for the current stylesheet */ public Result prepareNextStylesheet(String href, String baseURI, Result result) throws TransformerException { PreparedStylesheet next = preparedStylesheet.getCachedStylesheet(href, baseURI); if (next == null) { Source source = null; if (userURIResolver != null) { source = userURIResolver.resolve(href, baseURI); } if (source == null) { source = standardURIResolver.resolve(href, baseURI); } TransformerFactoryImpl factory = new TransformerFactoryImpl(); factory.setConfiguration(config); next = (PreparedStylesheet)factory.newTemplates(source); preparedStylesheet.putCachedStylesheet(href, baseURI, next); } TransformerReceiver nextTransformer = new TransformerReceiver((Controller) next.newTransformer()); nextTransformer.setSystemId(principalResultURI); nextTransformer.setPipelineConfiguration(makePipelineConfiguration()); nextTransformer.setResult(result); nextTransformer.open(); return nextTransformer; } ////////////////////////////////////////////////////////////////////////// // Handle parameters to the transformation ////////////////////////////////////////////////////////////////////////// /** * Set a parameter for the transformation. *

    * The following table shows some of the classes that are supported * by this method. (Others may also be supported, but continued support is * not guaranteed.) Each entry in the table shows first the Java class of the * supplied object, and then the type of the resulting XPath value. *

    * * * * * * * * * * * * * * * * *
    Java ClassXPath 2.0 type
    Stringxs:string
    Booleanxs:boolean
    Integerxs:integer
    Longxs:integer
    Doublexs:double
    Floatxs:float
    BigDecimalxs:decimal
    BigIntegerxs:integer
    Datexs:dateTime
    Array or List of any of the abovesequence of the above
    nullempty sequence
    *

    * A node may be supplied as a NodeInfo object, a sequence of nodes * as an array or List of NodeInfo objects. *

    * In addition, any object that implements the Saxon {@link net.sf.saxon.value.Value} interface * may be supplied, and will be used without conversion. *

    * A node belong to an external object model (such as DOM, JDOM, or XOM) may be supplied provided (a) * that the external object model is registered with the Configuration, and (b) that the node is part * of a document tree that has been registered in the document pool. * * @param expandedName The name of the parameter in {uri}local format * @param value The value object. This must follow the rules above. * Other formats in addition to those listed above may be accepted. * @since 8.4 */ public void setParameter(String expandedName, Object value) { if (parameters == null) { parameters = new GlobalParameterSet(); } parameters.put(StructuredQName.fromClarkName(expandedName), value); } /** * Supply a parameter using Saxon-specific representations of the name and value * @param qName The structured representation of the parameter name * @param value The value of the parameter, or null to remove a previously set value */ public void setParameter(StructuredQName qName, ValueRepresentation value) { if (parameters == null) { parameters = new GlobalParameterSet(); } parameters.put(qName, value); } /** * Reset the parameters to a null list. */ public void clearParameters() { parameters = null; } /** * Get a parameter to the transformation. This returns the value of a parameter * that has been previously set using the {@link #setParameter} method. The value * is returned exactly as supplied, that is, before any conversion to an XPath value. * * @param expandedName the name of the required parameter, in * "{uri}local-name" format * @return the value of the parameter, if it exists, or null otherwise */ public Object getParameter(String expandedName) { if (parameters==null) { return null; } return parameters.get(StructuredQName.fromClarkName(expandedName)); } /** * Get an iterator over the names of global parameters that have been defined * @return an Iterator whose items are strings in the form of Clark names, that is {uri}local */ public Iterator iterateParameters() { if (parameters == null) { return Collections.EMPTY_LIST.iterator(); } int k = parameters.getNumberOfKeys(); List list = new ArrayList(k); Collection keys = parameters.getKeys(); for (Iterator it = keys.iterator(); it.hasNext();) { StructuredQName qName = (StructuredQName)it.next(); String clarkName = qName.getClarkName(); list.add(clarkName); } return list.iterator(); } /** * Set the current date and time for this query or transformation. * This method is provided primarily for testing purposes, to allow tests to be run with * a fixed date and time. The supplied date/time must include a timezone, which is used * as the implicit timezone. * *

    Note that comparisons of date/time values currently use the implicit timezone * taken from the system clock, not from the value supplied here.

    * * @param dateTime the date/time value to be used as the current date and time * @throws IllegalStateException if a current date/time has already been * established by calling getCurrentDateTime(), or by a previous call on setCurrentDateTime() */ public void setCurrentDateTime(DateTimeValue dateTime) throws XPathException { if (currentDateTime==null) { if (dateTime.getComponent(Component.TIMEZONE) == null) { throw new XPathException("No timezone is present in supplied value of current date/time"); } currentDateTime = dateTime; dateTimePreset = true; } else { throw new IllegalStateException( "Current date and time can only be set once, and cannot subsequently be changed"); } } /** * Get the current date and time for this query or transformation. * All calls during one transformation return the same answer. * * @return Get the current date and time. This will deliver the same value * for repeated calls within the same transformation */ public DateTimeValue getCurrentDateTime() { if (currentDateTime==null) { currentDateTime = new DateTimeValue(new GregorianCalendar(), true); } return currentDateTime; } /** * Get the implicit timezone for this query or transformation * @return the implicit timezone as an offset in minutes */ public int getImplicitTimezone() { return getCurrentDateTime().getTimezoneInMinutes(); } ///////////////////////////////////////// // Methods for handling dynamic context ///////////////////////////////////////// /** * Make an XPathContext object for expression evaluation. *

    * This method is intended for internal use. * * @return the new XPathContext */ public XPathContextMajor newXPathContext() { return new XPathContextMajor(this); } /** * Set the last remembered node, for node numbering purposes. *

    * This method is strictly for internal use only. * * @param node the node in question * @param number the number of this node */ public void setRememberedNumber(NodeInfo node, int number) { lastRememberedNode = node; lastRememberedNumber = number; } /** * Get the number of a node if it is the last remembered one. *

    * This method is strictly for internal use only. * * @param node the node for which remembered information is required * @return the number of this node if known, else -1. */ public int getRememberedNumber(NodeInfo node) { if (lastRememberedNode == node) { return lastRememberedNumber; } return -1; } /** * Indicate whether document projection should be used, and supply the PathMap used to control it. * Note: this is available only under Saxon-SA. * @param pathMap a path map to be used for projecting source documents */ public void setUseDocumentProjection(PathMap pathMap) { this.pathMap = pathMap; } /** * Get the path map used for document projection, if any. * @return the path map to be used for document projection, if one has been supplied; otherwise null */ public PathMap getPathMapForDocumentProjection() { return pathMap; } /** * Set a ClassLoader to be used when loading external classes. Examples of classes that are * loaded include SAX parsers, localization modules for formatting numbers and dates, * extension functions, external object models. In an environment such as Eclipse that uses * its own ClassLoader, this ClassLoader should be nominated to ensure that any class loaded * by Saxon is identical to a class of the same name loaded by the external environment. *

    * This method is for application use, but is experimental and subject to change. * * @param loader the ClassLoader to be used. */ public void setClassLoader(ClassLoader loader) { classLoader = loader; } /** * Get the ClassLoader supplied using the method {@link #setClassLoader}. * If none has been supplied, return null. *

    * This method is for application use, but is experimental and subject to change. * * @return the ClassLoader in use. */ public ClassLoader getClassLoader() { return classLoader; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): // Portions marked "e.g." are from Edwin Glaser (edwin@pannenleiter.de) // saxonb-9.1.0.8/bj/net/sf/saxon/Platform.java0000644000175000017500000001767611033112257020047 0ustar eugeneeugenepackage net.sf.saxon; import net.sf.saxon.functions.FunctionLibraryList; import net.sf.saxon.functions.FunctionLibrary; import net.sf.saxon.regex.RegularExpression; import net.sf.saxon.sort.StringCollator; import net.sf.saxon.sort.NamedCollation; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.SchemaType; import net.sf.saxon.event.PipelineConfiguration; import javax.xml.transform.Source; import javax.xml.transform.stream.StreamSource; import java.io.Serializable; import java.net.URI; import java.net.URISyntaxException; import java.util.Properties; /** * This interface provides access to methods whose implementation depends on the chosen platform * (typically Java or .NET) */ public interface Platform extends Serializable { /** * Perform platform-specific initialization of the configuration * @param config the Saxon Configuration */ public void initialize(Configuration config); /** * Return true if this is the Java platform * @return true if this is the Java platform */ public boolean isJava(); /** * Return true if this is the .NET platform * @return true if this is the .NET platform */ public boolean isDotNet(); /** * Construct an absolute URI from a relative URI and a base URI * @param relativeURI the relative URI. Null is permitted provided that the base URI is an absolute URI * @param base the base URI * @return the absolutized URI * @throws URISyntaxException */ public URI makeAbsolute(String relativeURI, String base) throws URISyntaxException; /** * Get the platform version * @return the version of the platform, for example "Java version 1.5.09" */ public String getPlatformVersion(); /** * Get a suffix letter to add to the Saxon version number to identify the platform * @return "J" for Java, "N" for .NET */ public String getPlatformSuffix(); /** * Convert a StreamSource to either a SAXSource or a PullSource, depending on the native * parser of the selected platform * @param pipe the pipeline Configuration * @param input the supplied StreamSource * @param validation required validation mode, for example Validation.STRICT * @param dtdValidation true if DTD-based input validation is required * @param stripspace option for whitespace-stripping (ALL, NONE, or IGNORABLE) * @return the PullSource or SAXSource, initialized with a suitable parser, or the original * input Source, if now special handling is required or possible */ public Source getParserSource(PipelineConfiguration pipe, StreamSource input, int validation, boolean dtdValidation, int stripspace); /** * Create a compiled regular expression * @param regex the source text of the regular expression, in XML Schema or XPath syntax * @param xmlVersion version of XML in use (1.0 or 1.1) * @param syntax *@param flags the flags argument as supplied to functions such as fn:matches(), in string form @throws XPathException if the syntax of the regular expression or flags is incorrect @return the compiled regular expression */ public RegularExpression compileRegularExpression(CharSequence regex, int xmlVersion, int syntax, CharSequence flags) throws XPathException; /** * Obtain a collation with a given set of properties. The set of properties is extensible * and variable across platforms. Common properties with example values include lang=ed-GB, * strength=primary, case-order=upper-first, ignore-modifiers=yes, alphanumeric=yes. * Properties that are not supported are generally ignored; however some errors, such as * failing to load a requested class, are fatal. * @param config the configuration object * @param props the desired properties of the collation * @param uri the collation URI * @return a collation with these properties * @throws XPathException if a fatal error occurs */ public StringCollator makeCollation(Configuration config, Properties props, String uri) throws XPathException; /** * Given a collation, determine whether it is capable of returning collation keys. * The essential property of collation keys * is that if two values are equal under the collation, then the collation keys are * equal under the equals() method. * @param collation the collation being examined, provided as a Comparator * @return true if this collation can supply collation keys */ public boolean canReturnCollationKeys(StringCollator collation); /** * Given a collation, get a collation key. The essential property of collation keys * is that if two values are equal under the collation, then the collation keys are * equal under the equals() method. * @param namedCollation the collation in use * @param value the string whose collation key is required * @return a representation of the collation key, such that two collation keys are * equal() if and only if the string values they represent are equal under the specified collation. * @throws ClassCastException if the collation is not one that is capable of supplying * collation keys (this should have been checked in advance) */ public Object getCollationKey(NamedCollation namedCollation, String value); /** * Make the default extension function library (or libraries) appropriate to the platform, * and register them with the Configuration. Note that this does not actually add the libraries * to any library list. * @param config the Saxon Configuration */ public void makeExtensionLibrary(Configuration config); /** * Add the platform-specific function libraries to a function library list. The libraries * that are added are those registered with the Configuration using * {@link Configuration#setExtensionBinder(String, net.sf.saxon.functions.FunctionLibrary)} * @param list the function library list that is to be extended * @param config the Configuration * @param hostLanguage the host language (XSLT, XPath, XQuery) */ public void addFunctionLibraries(FunctionLibraryList list, Configuration config, int hostLanguage); /** * Register a namespace-to-Java-class mapping declared using saxon:script in an XSLT stylesheet * @param library the library to contain the function, which must be a JavaExtensionLibrary * @param uri the namespace of the function name * @param theClass the Java class that implements this namespace */ public void declareJavaClass(FunctionLibrary library, String uri, Class theClass); /** * Get a SchemaType representing a wrapped external (Java or .NET) object * @param config the Saxon Configuration * @param uri the namespace URI of the schema type * @param localName the local name of the schema type * @return the SchemaType object representing this type */ public SchemaType getExternalObjectType(Configuration config, String uri, String localName); } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/TransformerFactoryImpl.java0000644000175000017500000005461611033112257022732 0ustar eugeneeugenepackage net.sf.saxon; import net.sf.saxon.event.PIGrabber; import net.sf.saxon.event.Sender; import net.sf.saxon.om.NamespaceConstant; import net.sf.saxon.trans.CompilerInfo; import net.sf.saxon.trans.XPathException; import org.xml.sax.InputSource; import org.xml.sax.XMLFilter; import javax.xml.transform.*; import javax.xml.transform.dom.DOMResult; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.sax.*; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; import java.io.StringReader; import java.util.List; /** * A TransformerFactoryImpl instance can be used to create Transformer and Template * objects. * *

    The system property that determines which Factory implementation * to create is named "javax.xml.transform.TransformerFactory". This * property names a concrete subclass of the TransformerFactory abstract * class. If the property is not defined, a platform default is be used.

    * *

    This implementation class implements the abstract methods on both the * javax.xml.transform.TransformerFactory and javax.xml.transform.sax.SAXTransformerFactory * classes. */ public class TransformerFactoryImpl extends SAXTransformerFactory { private Configuration config; /** * Default constructor. */ public TransformerFactoryImpl() { config = new Configuration(); } /** * Construct a TransformerFactory using an existing Configuration. * @param config the Saxon configuration */ public TransformerFactoryImpl(Configuration config) { this.config = config; } /** * Set the configuration. This can also be done using the JAXP method * setAttribute, with the attribute name {@link FeatureKeys#CONFIGURATION} * @param config the Saxon configuration */ public void setConfiguration(Configuration config) { this.config = config; } /** * Get the configuration. This can also be done using the JAXP method * getAttribute, with the attribute name {@link FeatureKeys#CONFIGURATION} * @return the Saxon configuration */ public Configuration getConfiguration() { return config; } /** * Process the Source into a Transformer object. Care must * be given not to use this object in multiple threads running concurrently. * Different TransformerFactories can be used concurrently by different * threads. * * @param source An object that holds a URI, input stream, etc. * * @return A Transformer object that may be used to perform a transformation * in a single thread, never null. * * @exception TransformerConfigurationException May throw this during the parse * when it is constructing the Templates object and fails. */ public Transformer newTransformer(Source source) throws TransformerConfigurationException { Templates templates = newTemplates(source); return templates.newTransformer(); } /** * Create a new Transformer object that performs a copy * of the source to the result. * * @return A Transformer object that may be used to perform a transformation * in a single thread, never null. * * @exception TransformerConfigurationException May throw this during * the parse when it is constructing the * Templates object and fails. */ public Transformer newTransformer() throws TransformerConfigurationException { return new IdentityTransformer(config); } /** * Process the Source into a Templates object, which is a * a compiled representation of the source. This Templates object * may then be used concurrently across multiple threads. Creating * a Templates object allows the TransformerFactory to do detailed * performance optimization of transformation instructions, without * penalizing runtime transformation. * * @param source An object that holds a URL, input stream, etc. * * @return A Templates object capable of being used for transformation purposes, * never null. * * @exception TransformerConfigurationException May throw this during the parse when it * is constructing the Templates object and fails. */ public Templates newTemplates(Source source) throws TransformerConfigurationException { CompilerInfo info = new CompilerInfo(); info.setURIResolver(config.getURIResolver()); info.setErrorListener(config.getErrorListener()); info.setCompileWithTracing(config.isCompileWithTracing()); PreparedStylesheet pss = new PreparedStylesheet(config, info); pss.prepare(source); return pss; } /** * Process the Source into a Templates object, which is a * a compiled representation of the source. This Templates object * may then be used concurrently across multiple threads. Creating * a Templates object allows the TransformerFactory to do detailed * performance optimization of transformation instructions, without * penalizing runtime transformation. * * @param source An object that holds a URL, input stream, etc. * @param info compile-time options for this stylesheet compilation * * @return A Templates object capable of being used for transformation purposes, * never null. * * @exception TransformerConfigurationException May throw this during the parse when it * is constructing the Templates object and fails. */ public Templates newTemplates(Source source, CompilerInfo info) throws TransformerConfigurationException { PreparedStylesheet pss = new PreparedStylesheet(config, info); pss.prepare(source); return pss; } /** * Get the stylesheet specification(s) associated * via the xml-stylesheet processing instruction (see * http://www.w3.org/TR/xml-stylesheet/) with the document * document specified in the source parameter, and that match * the given criteria. Note that it is possible to return several * stylesheets, in which case they are applied as if they were * a list of imports or cascades. * * @param source The XML source document. * @param media The media attribute to be matched. May be null, in which * case the prefered templates will be used (i.e. alternate = no). * @param title The value of the title attribute to match. May be null. * @param charset The value of the charset attribute to match. May be null. * * @return A Source object suitable for passing to the TransformerFactory. * * @throws TransformerConfigurationException if any problems occur */ public Source getAssociatedStylesheet( Source source, String media, String title, String charset) throws TransformerConfigurationException { PIGrabber grabber = new PIGrabber(); grabber.setFactory(config); grabber.setCriteria(media, title, charset); grabber.setBaseURI(source.getSystemId()); grabber.setURIResolver(config.getURIResolver()); try { new Sender(config.makePipelineConfiguration()).send(source, grabber); // this parse will be aborted when the first start tag is found } catch (XPathException err) { if (grabber.isTerminated()) { // do nothing } else { throw new TransformerConfigurationException( "Failed while looking for xml-stylesheet PI", err); } } try { Source[] sources = grabber.getAssociatedStylesheets(); if (sources==null) { throw new TransformerConfigurationException( "No matching processing instruction found"); } return compositeStylesheet(source.getSystemId(), sources); } catch (TransformerException err) { if (err instanceof TransformerConfigurationException) { throw (TransformerConfigurationException)err; } else { throw new TransformerConfigurationException(err); } } } /** * Process a series of stylesheet inputs, treating them in import or cascade * order. This is mainly for support of the getAssociatedStylesheets * method, but may be useful for other purposes. * @param baseURI the base URI to be used for the synthesized composite stylesheet * @param sources An array of Source objects representing individual stylesheets. * @return A Source object representing a composite stylesheet. */ private Source compositeStylesheet(String baseURI, Source[] sources) throws TransformerConfigurationException { if (sources.length == 1) { return sources[0]; } else if (sources.length == 0) { throw new TransformerConfigurationException( "No stylesheets were supplied"); } // create a new top-level stylesheet that imports all the others StringBuffer sb = new StringBuffer(250); sb.append(""); for (int i=0; i"); } sb.append(""); InputSource composite = new InputSource(); composite.setSystemId(baseURI); composite.setCharacterStream(new StringReader(sb.toString())); return new SAXSource(config.getSourceParser(), composite); } /** * Set an object that is used by default during the transformation * to resolve URIs used in xsl:import, or xsl:include. * * @param resolver An object that implements the URIResolver interface, * or null. */ public void setURIResolver(URIResolver resolver) { config.setURIResolver(resolver); } /** * Get the object that is used by default during the transformation * to resolve URIs used in document(), xsl:import, or xsl:include. * * @return The URIResolver that was set with setURIResolver. */ public URIResolver getURIResolver() { return config.getURIResolver(); } //======= CONFIGURATION METHODS ======= private static final String FEATURE_SECURE_PROCESSING = //javax.xml.XMLConstants.FEATURE_SECURE_PROCESSING; "http://javax.xml.XMLConstants/feature/secure-processing"; // Avoid reference to this JDK 1.5 constant /** * Look up the value of a feature. * *

    The feature name is any absolute URI.

    * @param name The feature name, which is an absolute URI. * @return The current state of the feature (true or false). */ public boolean getFeature(String name) { if (name.equals(SAXSource.FEATURE)) return true; if (name.equals(SAXResult.FEATURE)) return true; if (name.equals(DOMSource.FEATURE)) return isDOMAvailable(); if (name.equals(DOMResult.FEATURE)) return isDOMAvailable(); if (name.equals(StreamSource.FEATURE)) return true; if (name.equals(StreamResult.FEATURE)) return true; if (name.equals(SAXTransformerFactory.FEATURE)) return true; if (name.equals(SAXTransformerFactory.FEATURE_XMLFILTER)) return true; if (name.equals(FEATURE_SECURE_PROCESSING)) { return !config.isAllowExternalFunctions(); } throw new IllegalArgumentException("Unknown feature " + name); } /** * Test whether DOM processing is available * @return true if DOM processing is available, that is, if the class net.sf.saxon.dom.DOMObjectModel * can be loaded, which will be the case if saxon9-dom.jar is on the classpath */ private boolean isDOMAvailable() { List models = config.getExternalObjectModels(); for (int i=0; iSet a feature for this TransformerFactory and Transformers * or Templates created by this factory.

    *

    *

    * Feature names are fully qualified {@link java.net.URI}s. * Implementations may define their own features. * An {@link javax.xml.transform.TransformerConfigurationException} is thrown if this TransformerFactory or the * Transformers or Templates it creates cannot support the feature. * It is possible for an TransformerFactory to expose a feature value but be unable to change its state. *

    *

    *

    All implementations are required to support the FEATURE_SECURE_PROCESSING feature. * When the feature is:

    *
      *
    • * true: the implementation will limit XML processing to conform to implementation limits * and behave in a secure fashion as defined by the implementation. * Examples include resolving user defined style sheets and functions. * If XML processing is limited for security reasons, it will be reported via a call to the registered * {@link javax.xml.transform.ErrorListener#fatalError(javax.xml.transform.TransformerException exception)}. * See {@link #setErrorListener(javax.xml.transform.ErrorListener listener)}. In the Saxon implementation, * this option causes calls on extension functions and extensions instructions to be disabled, and also * disables the use of xsl:result-document to write to secondary output destinations. *
    • *
    • * false: the implementation will processing XML according to the XML specifications without * regard to possible implementation limits. *
    • *
    * * @param name Feature name. * @param value Is feature state true or false. * @throws javax.xml.transform.TransformerConfigurationException * if this TransformerFactory * or the Transformers or Templates it creates cannot support this feature. * @throws NullPointerException If the name parameter is null. */ public void setFeature(String name, boolean value) throws TransformerConfigurationException { if (name.equals(FEATURE_SECURE_PROCESSING)) { config.setAllowExternalFunctions(!value); } else { throw new TransformerConfigurationException("Unsupported TransformerFactory feature: " + name); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/trans/0000755000175000017500000000000012216261750016535 5ustar eugeneeugenesaxonb-9.1.0.8/bj/net/sf/saxon/trans/RuleManager.java0000644000175000017500000002076211033112257021602 0ustar eugeneeugenepackage net.sf.saxon.trans; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.instruct.Template; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.om.StructuredQName; import net.sf.saxon.pattern.Pattern; import net.sf.saxon.pattern.UnionPattern; import net.sf.saxon.trace.ExpressionPresenter; import java.io.Serializable; import java.util.HashMap; import java.util.Iterator; /** * RuleManager maintains a set of template rules, one set for each mode * @version 10 December 1999: carved out of the old Controller class * @author Michael H. Kay */ public final class RuleManager implements Serializable { private Mode defaultMode; // node handlers with default mode private HashMap modes; // tables of node handlers for non-default modes private Mode omniMode = null; // node handlers that specify mode="all" /** * create a RuleManager and initialise variables. */ public RuleManager() { resetHandlers(); } /** * Set up a new table of handlers. */ public void resetHandlers() { defaultMode = new Mode(Mode.DEFAULT_MODE, Mode.DEFAULT_MODE_NAME); modes = new HashMap(5); } /** * Get the mode object for the default (unnamed) mode */ public Mode getDefaultMode() { return defaultMode; } /** * Get the Mode object for a named mode. If there is not one already registered. * a new Mode is created. * @param modeName The name of the mode. Supply null to get the default * mode or Mode.ALL_MODES to get the Mode object containing "mode=all" rules * @param createIfAbsent if true, then if the mode does not already exist it will be created. * If false, then if the mode does not already exist the method returns null. * @return the Mode with this name */ public Mode getMode(StructuredQName modeName, boolean createIfAbsent) { if (modeName == null || modeName.equals(Mode.DEFAULT_MODE_NAME)) { return defaultMode; } if (modeName.equals(Mode.ALL_MODES)) { if (omniMode==null) { omniMode = new Mode(Mode.NAMED_MODE, modeName); } return omniMode; } //Integer modekey = new Integer(modeNameCode & 0xfffff); Mode m = (Mode)modes.get(modeName); if (m == null && createIfAbsent) { m = new Mode(omniMode, modeName); modes.put(modeName, m); // when creating a specific mode, copy all the rules currently held // in the omniMode, as these apply to all modes } return m; } /** * Register a handler for a particular pattern. The priority of the rule * is the default priority for the pattern, which depends on the syntax of * the pattern suppllied. * @param pattern A match pattern * @param eh The ElementHandler to be used * @param mode The processing mode * @param precedence The import precedence (use 0 by default) */ public void setHandler(Pattern pattern, Template eh, Mode mode, int precedence) { // for a union pattern, register the parts separately (each with its own priority) if (pattern instanceof UnionPattern) { UnionPattern up = (UnionPattern)pattern; Pattern p1 = up.getLHS(); Pattern p2 = up.getRHS(); setHandler(p1, eh, mode, precedence); setHandler(p2, eh, mode, precedence); return; } double priority = pattern.getDefaultPriority(); setHandler(pattern, eh, mode, precedence, priority); } /** * Register a template for a particular pattern. * @param pattern Must be a valid Pattern. * @param eh The Template to be used * @param mode The processing mode to which this template applies * @param precedence The import precedence of this rule * @param priority The priority of the rule: if an element matches several patterns, the * one with highest priority is used * @see Pattern */ public void setHandler(Pattern pattern, Template eh, Mode mode, int precedence, double priority) { // for a union pattern, register the parts separately if (pattern instanceof UnionPattern) { UnionPattern up = (UnionPattern)pattern; Pattern p1 = up.getLHS(); Pattern p2 = up.getRHS(); setHandler(p1, eh, mode, precedence, priority); setHandler(p2, eh, mode, precedence, priority); return; } mode.addRule(pattern, eh, precedence, priority, true); // if adding a rule to the omniMode (mode='all') add it to all // the other modes as well if (mode==omniMode) { defaultMode.addRule(pattern, eh, precedence, priority, false); Iterator iter = modes.values().iterator(); while (iter.hasNext()) { Mode m = (Mode)iter.next(); m.addRule(pattern, eh, precedence, priority, false); } } } /** * Find the template rule registered for a particular node in a specific mode. * @param node The NodeInfo for the relevant node * @param mode The processing mode * @param c The controller for this transformation * @return The template rule that will process this node * Returns null if there is no specific handler registered. */ public Rule getTemplateRule (NodeInfo node, Mode mode, XPathContext c) throws XPathException { if (mode==null) { mode = defaultMode; } return mode.getRule(node, c); } /** * Get a template rule whose import precedence is in a particular range. This is used to support * the xsl:apply-imports function * @param node The node to be matched * @param mode The mode for which a rule is required * @param min The minimum import precedence that the rule must have * @param max The maximum import precedence that the rule must have * @param c The Controller for the transformation * @return The template rule to be invoked * @throws XPathException */ public Rule getTemplateRule (NodeInfo node, Mode mode, int min, int max, XPathContext c) throws XPathException { if (mode==null) { mode = defaultMode; } return mode.getRule(node, min, max, c); } /** * Get the next-match handler after the current one * @param node The node to be matched * @param mode The processing mode * @param currentRule The current template rule * @param c The dynamic context for the transformation * @return The template rule to be executed * @throws XPathException */ public Rule getNextMatchHandler(NodeInfo node, Mode mode, Rule currentRule, XPathContext c) throws XPathException { if (mode==null) { mode = defaultMode; } return mode.getNextMatchRule(node, currentRule, c); } /** * Explain (that is, output the expression tree) all template rules */ public void explainTemplateRules(ExpressionPresenter presenter) { presenter.startElement("templateRules"); defaultMode.explainTemplateRules(presenter); Iterator iter = modes.values().iterator(); while (iter.hasNext()) { Mode mode = (Mode)iter.next(); int s = presenter.startElement("mode"); if (!mode.isDefaultMode()) { presenter.emitAttribute("name", mode.getModeName().getDisplayName()); } mode.explainTemplateRules(presenter); int e = presenter.endElement(); if (s != e) { throw new IllegalStateException("tree unbalanced"); } } presenter.endElement(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/trans/SaxonErrorCode.java0000644000175000017500000001532611033112257022275 0ustar eugeneeugenepackage net.sf.saxon.trans; /** * The class acts as a register of Saxon-specific error codes. *

    * Technically, these codes should be in their own namespace. At present, however, they share the * same namespace as system-defined error codes. */ public class SaxonErrorCode { /** * SXLM0001: stylesheet or query appears to be looping/recursing indefinitely */ public static final String SXLM0001 = "SXLM0001"; /** * SXCH0002: cannot supply output to ContentHandler because it is not well-formed */ public static final String SXCH0002 = "SXCH0002"; /** * SXCH0003: error reported by the ContentHandler (SAXResult) to which the result tree was sent */ public static final String SXCH0003 = "SXCH0003"; /** * SXCH0004: cannot load user-supplied ContentHandler */ public static final String SXCH0004 = "SXCH0004"; /** * SXSE0001: cannot use character maps in an environment with no Controller */ public static final String SXSE0001 = "SXSE0001"; /** * SXSE0002: cannot use output property saxon:supply-source-locator unless tracing was enabled at compile time */ public static final String SXSE0002 = "SXSE0002"; /** * SXXP0003: error reported by XML parser while parsing source document */ public static final String SXXP0003 = "SXXP0003"; /** * SXXP0004: externally supplied node belongs to the wrong Configuration */ public static final String SXXP0004 = "SXXP0004"; /** * SXXF0001: first argument to saxon:eval must be an expression prepared using saxon:expression */ public static final String SXXF0001 = "SXXF0001"; /** * SXXF0002: undeclared namespace prefix used in saxon:script */ public static final String SXXF0002 = "SXXF0002"; /** * SXSQ0001: value of argument to SQL instruction is not a JDBC Connection object */ public static final String SXSQ0001 = "SXSQ0001"; /** * SXSQ0002: failed to close JDBC Connection */ public static final String SXSQ0002 = "SXSQ0002"; /** * SXSQ0003: failed to open JDBC Connection */ public static final String SXSQ0003 = "SXSQ0003"; /** * SXSQ0004: SQL Insert/Update/Delete action failed */ public static final String SXSQ0004 = "SXSQ0004"; /** * SXJE0001: cannot convert xs:boolean to the required Java type */ public static final String SXJE0001 = "SXJE0001"; /** * SXJE0002: cannot convert xs:double to the required Java type */ public static final String SXJE0002 = "SXJE0002"; /** * SXJE0003: cannot convert xs:duration to the required Java type */ public static final String SXJE0003 = "SXJE0003"; /** * SXJE0004: cannot convert xs:float to the required Java type */ public static final String SXJE0004 = "SXJE0004"; /** * SXJE0005: cannot convert xs:string to Java char unless the length is exactly one */ public static final String SXJE0005 = "SXJE0005"; /** * SXJE0006: cannot convert xs:string to the required Java type */ public static final String SXJE0006 = "SXJE0006"; /** * SXJE0007: cannot convert xs:dayTimeDuration to the required Java type */ public static final String SXJE0007 = "SXJE0007"; /** * SXJE0008: cannot convert xs:yearMonthDuration to the required Java type */ public static final String SXJE0008 = "SXJE0008"; /** * SXJE0021: cannot convert XPath value to the type required by the signature of an extension function */ public static final String SXJE0021 = "SXJE0021"; /** * SXJE0022: cannot convert XPath value to the type required by the signature of an extension function, * the XPath value is a sequence of more than one item but the Java type is a singleton */ public static final String SXJE0022 = "SXJE0022"; /** * SXJE0023: cannot convert XPath item to the member type of a Java array */ public static final String SXJE0023 = "SXJE0023"; /** * SXJE0051: supplied Java List/Array contains a member that cannot be converted to an Item */ public static final String SXJE0051 = "SXJE0051"; /** * SXUP0081: attempt to update a non-updateable node */ public static final String SXUP0081 = "SXUP0081"; /** * SXWN9001: a variable declaration with no following siblings has no effect */ public static final String SXWN9001 = "SXWN9001"; /** * SXWN9002: saxon:indent-spaces must be a positive integer */ public static final String SXWN9002 = "SXWN9002"; /** * SXWN9003: saxon:require-well-formed must be "yes" or "no" */ public static final String SXWN9003 = "SXWN9003"; /** * SXWN9004: saxon:next-in-chain cannot be specified dynamically */ public static final String SXWN9004 = "SXWN9004"; /** * SXWN9005: The 'default' attribute of saxon:collation no longer has any effect */ public static final String SXWN9005 = "SXWN9005"; /** * SXWN9006: No schema-location was specified, and no schema with the requested target namespace * is known, so the schema import was ignored */ public static final String SXWN9006 = "SXWN9006"; /** * SXWN9007: Invalid value for saxon:allow-all-built-in-types - must be "yes" or "no" */ public static final String SXWN9007 = "SXWN9007"; /** * SXWN9008: Saxon extension element not recognized because namespace not declared * in extension-element-prefixes */ public static final String SXWN9008 = "SXWN9008"; /** * SXWN9009: an empty xsl:for-each or xsl:for-each-group has no effect */ public static final String SXWN9009 = "SXWN9009"; } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/trans/Mode.java0000644000175000017500000006336711033112257020274 0ustar eugeneeugenepackage net.sf.saxon.trans; import net.sf.saxon.Configuration; import net.sf.saxon.instruct.Template; import net.sf.saxon.trace.ExpressionPresenter; import net.sf.saxon.trace.Location; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.expr.XPathContextMajor; import net.sf.saxon.om.Navigator; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.om.StructuredQName; import net.sf.saxon.om.NamespaceConstant; import net.sf.saxon.pattern.EmptySequenceTest; import net.sf.saxon.pattern.Pattern; import net.sf.saxon.type.Type; import net.sf.saxon.value.Whitespace; import java.io.Serializable; /** * A Mode is a collection of rules; the selection of a rule to apply to a given element * is determined by a Pattern. * * @author Michael H. Kay */ public class Mode implements Serializable { // TODO:PERF the data structure does not cater well for a stylesheet making heavy use of // match="schema-element(X)". We should probably expand the substitution group. public static final int DEFAULT_MODE = -1; public static final int NAMED_MODE = -3; public static final int STRIPPER_MODE = -4; public static final StructuredQName ALL_MODES = new StructuredQName("saxon", NamespaceConstant.SAXON, "_omniMode"); public static final StructuredQName DEFAULT_MODE_NAME = new StructuredQName("saxon", NamespaceConstant.SAXON, "_defaultMode"); private Rule[] ruleDict = new Rule[101 + Type.MAX_NODE_TYPE]; private Rule mostRecentRule; private boolean isDefault; private boolean isStripper; private boolean hasRules = false; private StructuredQName modeName; /** * Default constructor - creates a Mode containing no rules * @param usage one of {@link #DEFAULT_MODE}, {@link #NAMED_MODE}, {@link #STRIPPER_MODE} * @param modeName the name of the mode */ public Mode(int usage, StructuredQName modeName) { isDefault = (usage == DEFAULT_MODE); isStripper = (usage == STRIPPER_MODE); this.modeName = modeName; } /** * Construct a new Mode, copying the contents of an existing Mode * * @param omniMode the existing mode. May be null, in which case it is not copied * @param modeName the name of the new mode to be created */ public Mode(Mode omniMode, StructuredQName modeName) { isDefault = false; isStripper = false; this.modeName = modeName; if (omniMode != null) { for (int i = 0; i < ruleDict.length; i++) { if (omniMode.ruleDict[i] != null) { ruleDict[i] = new Rule(omniMode.ruleDict[i]); } } mostRecentRule = omniMode.mostRecentRule; } } /** * Determine if this is the default mode * @return true if this is the default (unnamed) mode */ public boolean isDefaultMode() { return isDefault; } /** * Get the name of the mode (for diagnostics only) * @return the mode name. Null for the default (unnamed) mode */ public StructuredQName getModeName() { return modeName; } /** * Ask whether there are any template rules in this mode * (a mode could exist merely because it is referenced in apply-templates) * @return true if no template rules exist in this mode */ public boolean isEmpty() { return !hasRules; } /** * Add a rule to the Mode. * * @param p a Pattern * @param action the Object to return from getRule() when the supplied node matches this Pattern * @param precedence the import precedence of the rule * @param priority the explicit or implicit priority of the rule * @param explicitMode true if adding a template rule for a specific (default or named) mode; * false if adding a rule because it applies to all modes */ public void addRule(Pattern p, Object action, int precedence, double priority, boolean explicitMode) { if (explicitMode) { hasRules = true; } // Ignore a pattern that will never match, e.g. "@comment" if (p.getNodeTest() instanceof EmptySequenceTest) { return; } // for fast lookup, we maintain one list for each element name for patterns that can only // match elements of a given name, one list for each node type for patterns that can only // match one kind of non-element node, and one generic list. // Each list is sorted in precedence/priority order so we find the highest-priority rule first int fingerprint = p.getFingerprint(); int type = p.getNodeKind(); int key = getList(fingerprint, type); // System.err.println("Fingerprint " + fingerprint + " key " + key + " type " + type); // This logic is designed to ensure that when a UnionPattern contains multiple branches // with the same priority, next-match doesn't select the same template twice (override20_047) int sequence; if (mostRecentRule == null) { sequence = 0; } else if (action == mostRecentRule.getAction()) { sequence = mostRecentRule.getSequence(); } else { sequence = mostRecentRule.getSequence() + 1; } Rule newRule = new Rule(p, action, precedence, priority, sequence); mostRecentRule = newRule; Rule rule = ruleDict[key]; if (rule == null) { ruleDict[key] = newRule; return; } // insert the new rule into this list before others of the same precedence/priority Rule prev = null; while (rule != null) { if ((rule.getPrecedence() < precedence) || (rule.getPrecedence() == precedence && rule.getPriority() <= priority)) { newRule.setNext(rule); if (prev == null) { ruleDict[key] = newRule; } else { prev.setNext(newRule); } break; } else { prev = rule; rule = rule.getNext(); } } if (rule == null) { prev.setNext(newRule); newRule.setNext(null); } } /** * Determine which list to use for a given pattern (we must also search the generic list) * @param fingerprint the name of the node being matched * @param kind the node kind of the node being matched * @return an index in the hash array for this node name and kind */ public int getList(int fingerprint, int kind) { if (kind == Type.ELEMENT) { if (fingerprint == -1) { return Type.NODE; // the generic list } else { return Type.MAX_NODE_TYPE + (fingerprint % 101); } } else { return kind; } } /** * Get the rule corresponding to a given Node, by finding the best Pattern match. * * @param node the NodeInfo referring to the node to be matched * @param context the XPath dynamic evaluation context * @return the best matching rule, if any (otherwise null). */ public Rule getRule(NodeInfo node, XPathContext context) throws XPathException { int fingerprint = node.getFingerprint(); // This is inefficient with wrapped object models (DOM, XOM, JDOM), // but there's not much we can do about it int type = node.getNodeKind(); int key = getList(fingerprint, type); int policy = context.getController().getRecoveryPolicy(); // If there are match patterns in the stylesheet that use local variables, we need to allocate // a new stack frame for evaluating the match patterns. We base this on the match pattern with // the highest number of range variables, so we can reuse the same stack frame for all rules // that we test against. If no patterns use range variables, we don't bother allocating a new // stack frame. context = perhapsMakeNewContext(context); Rule specificRule = null; Rule generalRule = null; int specificPrecedence = -1; double specificPriority = Double.NEGATIVE_INFINITY; // search the specific list for this node type / node name if (key != Type.NODE) { Rule r = ruleDict[key]; while (r != null) { // if we already have a match, and the precedence or priority of this // rule is lower, quit the search for a second match if (specificRule != null) { if (r.getPrecedence() < specificPrecedence || (r.getPrecedence() == specificPrecedence && r.getPriority() < specificPriority)) { break; } } if (r.getPattern().matches(node, context)) { // is this a second match? if (specificRule != null) { if (r.getPrecedence() == specificPrecedence && r.getPriority() == specificPriority) { reportAmbiguity(node, specificRule, r, context); } break; } specificRule = r; specificPrecedence = r.getPrecedence(); specificPriority = r.getPriority(); if (policy == Configuration.RECOVER_SILENTLY) { break; // find the first; they are in priority order } } r = r.getNext(); } } // search the general list Rule r2 = ruleDict[Type.NODE]; while (r2 != null) { if (r2.getPrecedence() < specificPrecedence || (r2.getPrecedence() == specificPrecedence && r2.getPriority() < specificPriority)) { break; // no point in looking at a lower priority rule than the one we've got } if (r2.getPattern().matches(node, context)) { // is it a second match? if (generalRule != null) { if (r2.getPrecedence() == generalRule.getPrecedence() && r2.getPriority() == generalRule.getPriority()) { reportAmbiguity(node, r2, generalRule, context); } break; } else { generalRule = r2; if (policy == Configuration.RECOVER_SILENTLY) { break; // find only the first; they are in priority order } } } r2 = r2.getNext(); } if (specificRule != null && generalRule == null) { return specificRule; } if (specificRule == null && generalRule != null) { return generalRule; } if (specificRule != null) { if (specificRule.getPrecedence() == generalRule.getPrecedence() && specificRule.getPriority() == generalRule.getPriority()) { // This situation is exceptional: we have a "specific" pattern and // a "general" pattern with the same priority. We have to select // the one that was added last // (Bug reported by Norman Walsh Jan 2002) Rule result = (specificRule.getSequence() > generalRule.getSequence() ? specificRule : generalRule); if (policy != Configuration.RECOVER_SILENTLY) { reportAmbiguity(node, specificRule, generalRule, context); } return result; } if (specificRule.getPrecedence() > generalRule.getPrecedence() || (specificRule.getPrecedence() == generalRule.getPrecedence() && specificRule.getPriority() >= generalRule.getPriority())) { return specificRule; } else { return generalRule; } } return null; } /** * Make a new XPath context for evaluating patterns if there is any possibility that the * pattern uses local variables * * @param context The existing XPath context * @return a new XPath context (or the existing context if no new context was created) */ private XPathContext perhapsMakeNewContext(XPathContext context) { int patternLocals = context.getController().getExecutable().getLargestPatternStackFrame(); if (patternLocals > 0) { context = context.newContext(); context.setOriginatingConstructType(Location.CONTROLLER); ((XPathContextMajor)context).openStackFrame(patternLocals); } return context; } /** * Get the rule corresponding to a given Node, by finding the best Pattern match, subject to a minimum * and maximum precedence. (This supports xsl:apply-imports) * * @param node the NodeInfo referring to the node to be matched * @param min the minimum import precedence * @param max the maximum import precedence * @param context the XPath dynamic evaluation context * @return the Rule registered for that node, if any (otherwise null). */ public Rule getRule(NodeInfo node, int min, int max, XPathContext context) throws XPathException { int fp = node.getFingerprint(); int type = node.getNodeKind(); int key = getList(fp, type); Rule specificRule = null; Rule generalRule = null; context = perhapsMakeNewContext(context); // search the the specific list for this node type / name if (key != Type.NODE) { Rule r = ruleDict[key]; while (r != null) { if (r.getPrecedence() >= min && r.getPrecedence() <= max && r.getPattern().matches(node, context)) { specificRule = r; break; // find the first; they are in priority order } r = r.getNext(); } } // search the generic list Rule r2 = ruleDict[Type.NODE]; while (r2 != null) { if (r2.getPrecedence() >= min && r2.getPrecedence() <= max && r2.getPattern().matches(node, context)) { generalRule = r2; break; // find only the first; they are in priority order } r2 = r2.getNext(); } if (specificRule != null && generalRule == null) { return specificRule; } if (specificRule == null && generalRule != null) { return generalRule; } if (specificRule != null) { if (specificRule.getPrecedence() > generalRule.getPrecedence() || (specificRule.getPrecedence() == generalRule.getPrecedence() && specificRule.getPriority() >= generalRule.getPriority())) { return specificRule; } else { return generalRule; } } return null; } /** * Get the rule corresponding to a given Node, by finding the next-best Pattern match * after the specified object. * * @param node the NodeInfo referring to the node to be matched * @param currentRule the current rule; we are looking for the next match after the current rule * @param context the XPath dynamic evaluation context * @return the object (e.g. a NodeHandler) registered for that element, if any (otherwise null). */ public Rule getNextMatchRule(NodeInfo node, Rule currentRule, XPathContext context) throws XPathException { int fingerprint = node.getFingerprint(); int type = node.getNodeKind(); int key = getList(fingerprint, type); int policy = context.getController().getRecoveryPolicy(); context = perhapsMakeNewContext(context); // First find the Rule object corresponding to the current handler Rule specificRule = null; Rule generalRule = null; int specificPrecedence = -1; double specificPriority = Double.NEGATIVE_INFINITY; // search the specific list for this node type / node name Rule r; if (key != Type.NODE) { r = ruleDict[key]; while (r != null) { // skip this rule if it is the current rule. if (r == currentRule) { // skip this rule } else // skip this rule unless it's "below" the current rule in search order if ((r.getPrecedence() > currentRule.getPrecedence()) || (r.getPrecedence() == currentRule.getPrecedence() && (r.getPriority() > currentRule.getPriority() || (r.getPriority() == currentRule.getPriority() && r.getSequence() >= currentRule.getSequence())))) { // skip this rule } else { // quit the search on finding the second (recoverable error) match if (specificRule != null) { if (r.getPrecedence() < specificPrecedence || (r.getPrecedence() == specificPrecedence && r.getPriority() < specificPriority)) { break; } } //System.err.println("Testing " + Navigator.getPath(node) + " against " + r.pattern); if (r.getPattern().matches(node, context)) { //System.err.println("Matches"); // is this a second match? if (specificRule != null) { if (r.getPrecedence() == specificPrecedence && r.getPriority() == specificPriority) { reportAmbiguity(node, specificRule, r, context); } break; } specificRule = r; specificPrecedence = r.getPrecedence(); specificPriority = r.getPriority(); if (policy == Configuration.RECOVER_SILENTLY) { break; // find the first; they are in priority order } } } r = r.getNext(); } } // search the general list Rule r2 = ruleDict[Type.NODE]; while (r2 != null) { // skip this rule if the rule is the current template rule if (r2 == currentRule) { // skip this rule } else // skip this rule unless it's "after" the current rule in search order if ((r2.getPrecedence() > currentRule.getPrecedence()) || (r2.getPrecedence() == currentRule.getPrecedence() && (r2.getPriority() > currentRule.getPriority() || (r2.getPriority() == currentRule.getPriority() && r2.getSequence() >= currentRule.getSequence())))) { // skip this rule } else { if (r2.getPrecedence() < specificPrecedence || (r2.getPrecedence() == specificPrecedence && r2.getPriority() < specificPriority)) { break; // no point in looking at a lower priority rule than the one we've got } if (r2.getPattern().matches(node, context)) { // is it a second match? if (generalRule != null) { if (r2.getPrecedence() == generalRule.getPrecedence() && r2.getPriority() == generalRule.getPriority()) { reportAmbiguity(node, r2, generalRule, context); } break; } else { generalRule = r2; if (policy == Configuration.RECOVER_SILENTLY) { break; // find only the first; they are in priority order } } } } r2 = r2.getNext(); } if (specificRule != null && generalRule == null) { return specificRule; } if (specificRule == null && generalRule != null) { return generalRule; } if (specificRule != null && generalRule != null) { if (specificRule.getPrecedence() == generalRule.getPrecedence() && specificRule.getPriority() == generalRule.getPriority()) { // This situation is exceptional: we have a "specific" pattern and // a "general" pattern with the same priority. We have to select // the one that was added last // (Bug reported by Norman Walsh Jan 2002) Rule result = (specificRule.getSequence() > generalRule.getSequence() ? specificRule : generalRule); if (policy != Configuration.RECOVER_SILENTLY) { reportAmbiguity(node, specificRule, generalRule, context); } return result; } if (specificRule.getPrecedence() > generalRule.getPrecedence() || (specificRule.getPrecedence() == generalRule.getPrecedence() && specificRule.getPriority() >= generalRule.getPriority())) { return specificRule; } else { return generalRule; } } return null; } /** * Report an ambiguity, that is, the situation where two rules of the same * precedence and priority match the same node * * @param node The node that matches two or more rules * @param r1 The first rule that the node matches * @param r2 The second rule that the node matches * @param c The controller for the transformation */ private void reportAmbiguity(NodeInfo node, Rule r1, Rule r2, XPathContext c) throws XPathException { // don't report an error if the conflict is between two branches of the same Union pattern if (r1.getAction() == r2.getAction()) { return; } String path; String errorCode = "XTRE0540"; if (isStripper) { // don't report an error if the conflict is between strip-space and strip-space, or // preserve-space and preserve-space if (r1.getAction().equals(r2.getAction())) { return; } errorCode = "XTRE0270"; path = "xsl:strip-space"; } else { path = Navigator.getPath(node); } Pattern pat1 = r1.getPattern(); Pattern pat2 = r2.getPattern(); XPathException err = new XPathException("Ambiguous rule match for " + path + '\n' + "Matches both \"" + showPattern(pat1) + "\" on line " + pat1.getLineNumber() + " of " + pat1.getSystemId() + "\nand \"" + showPattern(pat2) + "\" on line " + pat2.getLineNumber() + " of " + pat2.getSystemId()); err.setErrorCode(errorCode); //err.setLocator(pat1.getL); c.getController().recoverableError(err); } private static String showPattern(Pattern p) { // Complex patterns can be laid out with lots of whitespace, which looks messy in the error message return Whitespace.collapseWhitespace(p.toString()).toString(); } /** * Explain all template rules in this mode by showing their * expression tree represented in XML. * @param presenter used to display the expression tree */ public void explainTemplateRules(ExpressionPresenter presenter) { for (int i=0; i * @author Michael H. Kay */ public class KeyDefinition extends Procedure implements Serializable { private PatternFinder match; // the match pattern private SequenceIterable use; private BuiltInAtomicType useType; // the type of the values returned by the atomized use expression private StringCollator collation; // the collating sequence, when type=string private String collationName; // the collation URI private boolean backwardsCompatible = false; private boolean strictComparison = false; private boolean convertUntypedToOther = false; /** * Constructor to create a key definition * @param match the pattern in the xsl:key match attribute * @param use the expression in the xsl:key use attribute, or the expression that results from compiling * the xsl:key contained instructions. Note that a KeyDefinition constructed by the XSLT or XQuery parser will * always use an Expression here; however, a KeyDefinition constructed at run-time by a compiled stylesheet * or XQuery might use a simple ExpressionEvaluator that lacks all the compile-time information associated * with an Expression * @param collationName the name of the collation being used * @param collation the actual collation. This must be one that supports generation of collation keys. */ public KeyDefinition(PatternFinder match, SequenceIterable use, String collationName, StringCollator collation) { setHostLanguage(Configuration.XSLT); this.match = match; this.use = use; if (use instanceof Expression) { setBody((Expression)use); } this.collation = collation; this.collationName = collationName; } /** * Set the primitive item type of the values returned by the use expression * @param itemType the primitive type of the indexed values */ public void setIndexedItemType(BuiltInAtomicType itemType) { useType = itemType; } /** * Get the primitive item type of the values returned by the use expression * @return the primitive item type of the indexed values */ public BuiltInAtomicType getIndexedItemType() { if (useType == null) { return BuiltInAtomicType.ANY_ATOMIC; } else { return useType; } } /** * Set backwards compatibility mode. The key definition is backwards compatible if ANY of the xsl:key * declarations has version="1.0" in scope. * @param bc set to true if running in XSLT 2.0 backwards compatibility mode */ public void setBackwardsCompatible(boolean bc) { backwardsCompatible = bc; } /** * Test backwards compatibility mode * @return true if running in XSLT backwards compatibility mode */ public boolean isBackwardsCompatible() { return backwardsCompatible; } /** * Set whether strict comparison is needed. Strict comparison treats non-comparable values as an * error rather than a no-match. This is used for internal keys that support value comparisons in * Saxon-SA, it is not used for user-defined XSLT keys. * @param strict true if strict comparison is needed */ public void setStrictComparison(boolean strict) { strictComparison = strict; } /** * Get whether strict comparison is needed. Strict comparison treats non-comparable values as an * error rather than a no-match. This is used for internal keys that support value comparisons in * Saxon-SA, it is not used for user-defined XSLT keys. * @return true if strict comparison is needed. */ public boolean isStrictComparison() { return strictComparison; } /** * Indicate that untypedAtomic values should be converted to the type of the other operand, * rather than to strings. This is used for indexes constructed internally by Saxon-SA to * support filter expressions that use the "=" operator, as distinct from "eq". * @param convertToOther true if comparisons follow the semantics of the "=" operator rather than * the "eq" operator */ public void setConvertUntypedToOther(boolean convertToOther) { convertUntypedToOther = convertToOther; } /** * Determine whether untypedAtomic values are converted to the type of the other operand. * @return true if comparisons follow the semantics of the "=" operator rather than * the "eq" operator */ public boolean isConvertUntypedToOther() { return convertUntypedToOther; } /** * Set the map of local variables needed while evaluating the "use" expression */ public void setStackFrameMap(SlotManager map) { if (map != null && map.getNumberOfVariables() > 0) { super.setStackFrameMap(map); } } /** * Set the system Id and line number of the source xsl:key definition * @param systemId the URI of the module containing the key definition * @param lineNumber the line number of the key definition */ public void setLocation(String systemId, int lineNumber) { setSystemId(systemId); setLineNumber(lineNumber); } /** * Get the match pattern for the key definition * @return the pattern specified in the "match" attribute of the xsl:key declaration */ public PatternFinder getMatch() { return match; } /** * Set the body of the key (the use expression). This is held redundantly as an Expression and * as a SequenceIterable (not sure why!) * @param body the use expression of the key */ public void setBody(Expression body) { super.setBody(body); use = body; } /** * Get the use expression for the key definition * @return the expression specified in the "use" attribute of the xsl:key declaration */ public SequenceIterable getUse() { return use; } /** * Get the collation name for this key definition. * @return the collation name (the collation URI) */ public String getCollationName() { return collationName; } /** * Get the collation. * @return the collation */ public StringCollator getCollation() { return collation; } /** * Get the type of construct. This will either be the fingerprint of a standard XSLT instruction name * (values in {@link net.sf.saxon.om.StandardNames}: all less than 1024) * or it will be a constant in class {@link net.sf.saxon.trace.Location}. */ public int getConstructType() { return StandardNames.XSL_KEY; } /** * Get a name identifying the object of the expression, for example a function name, template name, * variable name, key name, element name, etc. This is used only where the name is known statically. * */ public StructuredQName getObjectName() { return null; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/trans/KeyManager.java0000644000175000017500000010246211200246312021415 0ustar eugeneeugenepackage net.sf.saxon.trans; import net.sf.saxon.Configuration; import net.sf.saxon.expr.*; import net.sf.saxon.functions.SystemFunction; import net.sf.saxon.functions.Tokenize; import net.sf.saxon.functions.StringFn; import net.sf.saxon.instruct.SlotManager; import net.sf.saxon.om.*; import net.sf.saxon.om.ListIterator; import net.sf.saxon.pattern.IdrefTest; import net.sf.saxon.pattern.PatternFinder; import net.sf.saxon.sort.LocalOrderComparer; import net.sf.saxon.sort.StringCollator; import net.sf.saxon.trace.ExpressionPresenter; import net.sf.saxon.type.AtomicType; import net.sf.saxon.type.BuiltInAtomicType; import net.sf.saxon.type.BuiltInType; import net.sf.saxon.type.Type; import net.sf.saxon.value.AtomicValue; import net.sf.saxon.value.DoubleValue; import net.sf.saxon.value.NumericValue; import net.sf.saxon.value.UntypedAtomicValue; import java.io.Serializable; import java.lang.ref.WeakReference; import java.util.*; /** * KeyManager manages the set of key definitions in a stylesheet, and the indexes * associated with these key definitions. It handles xsl:sort-key as well as xsl:key * definitions. * *

    The memory management in this class is subtle, with extensive use of weak references. * The idea is that an index should continue to exist in memory so long as both the compiled * stylesheet and the source document exist in memory: if either is removed, the index should * go too. The document itself holds no reference to the index. The compiled stylesheet (which * owns the KeyManager) holds a weak reference to the index. The index, of course, holds strong * references to the nodes in the document. The Controller holds a strong reference to the * list of indexes used for each document, so that indexes remain in memory for the duration * of a transformation even if the documents themselves are garbage collected.

    * *

    Potentially there is a need for more than one index for a given key name, depending * on the primitive type of the value provided to the key() function. An index is built * corresponding to the type of the requested value; if subsequently the key() function is * called with the same name and a different type of value, then a new index is built.

    * *

    For XSLT-defined keys, equality matching follows the rules of the eq operator, which means * that untypedAtomic values are treated as strings. In backwards compatibility mode, all * values are converted to strings.

    * *

    This class is also used for internal indexes constructed (a) to support the idref() function, * and (b) (in Saxon-SA only) to support filter expressions of the form /a/b/c[d=e], where the * path expression being filtered must be a single-document context-free path rooted at a document node, * where exactly one of d and e must be dependent on the focus, and where certain other conditions apply * such as the filter predicate not being positional. The operator in this case may be either "=" or "eq". * If it is "eq", then the semantics are very similar to xsl:key indexes, except that use of non-comparable * types gives an error rather than a non-match. If the operator is "=", however, then the rules for * handling untypedAtomic values are different: these must be converted to the type of the other operand. * In this situation the following rules apply. Assume that the predicate is [use=value], where use is * dependent on the focus (the indexed value), and value is the sought value.

    * *
      *
    • If value is a type other than untypedAtomic, say T, then we build an index for type T, in which any * untypedAtomic values that arise in evaluating "use" are converted to type T. A conversion failure results * in an error. A value of a type that is not comparable to T also results in an error.
    • *
    • If value is untypedAtomic, then we build an index for every type actually encountered in evaluating * the use expression (treating untypedAtomic as string), and then search each of these indexes. (Note that * it is not an error if the use expression returns a mixture of say numbers and dates, provided that the * sought value is untypedAtomic).
    • *
    * * @author Michael H. Kay */ public class KeyManager implements Serializable { private HashMap keyMap; // one entry for each named key; the entry contains // a KeyDefinitionSet holding the key definitions with that name private transient WeakHashMap docIndexes; // one entry for each document that is in memory; // the entry contains a HashMap mapping the fingerprint of // the key name plus the primitive item type // to the HashMap that is the actual index // of key/value pairs. /** * Create a KeyManager and initialise variables * @param config the Saxon configuration */ public KeyManager(Configuration config) { keyMap = new HashMap(10); docIndexes = new WeakHashMap(10); // Create a key definition for the idref() function registerIdrefKey(config); } /** * An internal key definition is used to support the idref() function. The key definition * is equivalent to xsl:key match="element(*, xs:IDREF) | element(*, IDREFS) | * attribute(*, xs:IDREF) | attribute(*, IDREFS)" use=".". This method creates this * key definition. * @param config The configuration. This is needed because the patterns that are * generated need access to schema information. */ private void registerIdrefKey(Configuration config) { PatternFinder idref = IdrefTest.getInstance(); //Expression eval = new Atomizer(new ContextItemExpression(), config); StringFn sf = (StringFn)SystemFunction.makeSystemFunction( "string", new Expression[]{new ContextItemExpression()}); StringLiteral regex = new StringLiteral("\\s+"); Tokenize use = (Tokenize)SystemFunction.makeSystemFunction("tokenize", new Expression[]{sf, regex}); KeyDefinition key = new KeyDefinition(idref, use, null, null); key.setIndexedItemType(BuiltInAtomicType.STRING); try { addKeyDefinition(StandardNames.getStructuredQName(StandardNames.XS_IDREFS), key, config); } catch (XPathException err) { throw new AssertionError(err); // shouldn't happen } } /** * Pre-register a key definition. This simply registers that a key with a given name exists, * without providing any details. * @param keyName the name of the key to be pre-registered */ public void preRegisterKeyDefinition(StructuredQName keyName) { KeyDefinitionSet keySet = (KeyDefinitionSet)keyMap.get(keyName); if (keySet==null) { keySet = new KeyDefinitionSet(keyName, keyMap.size()); keyMap.put(keyName, keySet); } } /** * Register a key definition. Note that multiple key definitions with the same name are * allowed * @param keyName Structured QName representing the name of the key * @param keydef The details of the key's definition * @param config The configuration * @throws XPathException if this key definition is inconsistent with existing key definitions having the same name */ public void addKeyDefinition(StructuredQName keyName, KeyDefinition keydef, Configuration config) throws XPathException { KeyDefinitionSet keySet = (KeyDefinitionSet)keyMap.get(keyName); if (keySet==null) { keySet = new KeyDefinitionSet(keyName, keyMap.size()); keyMap.put(keyName, keySet); } keySet.addKeyDefinition(keydef); boolean backwardsCompatible = keySet.isBackwardsCompatible(); if (backwardsCompatible) { // In backwards compatibility mode, convert all the use-expression results to sequences of strings List v = keySet.getKeyDefinitions(); for (int i=0; i> 32)) == keySetNumber) { int typefp = (int)key; BuiltInAtomicType type = (BuiltInAtomicType)BuiltInType.getSchemaType(typefp); Object indexObject2 = getIndex(doc, keySetNumber, type); if (indexObject2 instanceof String) { // index is under construction XPathException de = new XPathException("Key definition is circular"); de.setXPathContext(context); de.setErrorCode("XTDE0640"); throw de; } HashMap index2 = (HashMap)indexObject2; // NOTE: we've been known to encounter a null index2 here, but it doesn't seem possible if (!index2.isEmpty()) { value = soughtValue.convert(type, true, context).asAtomic(); ArrayList nodes = (ArrayList)index2.get(getCollationKey(value, type, collation, context)); if (nodes != null) { if (result == null) { result = new ListIterator(nodes); } else { result = new UnionEnumeration(result, new ListIterator(nodes), LocalOrderComparer.getInstance()); } } } } } } } if (result == null) { return EmptyIterator.getInstance(); } else { return result; } } } private static Object getCollationKey(AtomicValue value, BuiltInAtomicType itemType, StringCollator collation, XPathContext context) throws XPathException { Object val; if (itemType.equals(BuiltInAtomicType.STRING) || itemType.equals(BuiltInAtomicType.UNTYPED_ATOMIC) || itemType.equals(BuiltInAtomicType.ANY_URI)) { if (collation==null) { val = value.getStringValue(); } else { val = collation.getCollationKey(value.getStringValue()); } } else { val = value.getXPathComparable(false, collation, context); } return val; } /** * Save the index associated with a particular key, a particular item type, * and a particular document. This * needs to be done in such a way that the index is discarded by the garbage collector * if the document is discarded. We therefore use a WeakHashMap indexed on the DocumentInfo, * which returns HashMap giving the index for each key fingerprint. This index is itself another * HashMap. * The methods need to be synchronized because several concurrent transformations (which share * the same KeyManager) may be creating indexes for the same or different documents at the same * time. * @param doc the document being indexed * @param keyFingerprint represents the name of the key definition * @param itemType the primitive type of the values being indexed * @param index the index being saved * @param context the dynamic evaluation context */ private synchronized void putIndex(DocumentInfo doc, int keyFingerprint, AtomicType itemType, Object index, XPathContext context) { if (docIndexes==null) { // it's transient, so it will be null when reloading a compiled stylesheet docIndexes = new WeakHashMap(10); } WeakReference indexRef = (WeakReference)docIndexes.get(doc); HashMap indexList; if (indexRef==null || indexRef.get()==null) { indexList = new HashMap(10); // ensure there is a firm reference to the indexList for the duration of a transformation context.getController().setUserData(doc, "key-index-list", indexList); docIndexes.put(doc, new WeakReference(indexList)); } else { indexList = (HashMap)indexRef.get(); } indexList.put(new Long(((long)keyFingerprint)<<32 | itemType.getFingerprint()), index); } /** * Get the index associated with a particular key, a particular source document, * and a particular primitive item type * @param doc the document whose index is required * @param keyFingerprint the name of the key definition * @param itemType the primitive item type of the values being indexed * @return either an index (as a HashMap), or the String "under construction", or null */ private synchronized Object getIndex(DocumentInfo doc, int keyFingerprint, AtomicType itemType) { if (docIndexes==null) { // it's transient, so it will be null when reloading a compiled stylesheet docIndexes = new WeakHashMap(10); } WeakReference ref = (WeakReference)docIndexes.get(doc); if (ref==null) return null; HashMap indexList = (HashMap)ref.get(); if (indexList==null) return null; return indexList.get(new Long(((long)keyFingerprint)<<32 | itemType.getFingerprint())); } /** * Clear all the indexes for a given document. This is currently done whenever updates * are applied to the document, because updates can potentially invalidate the indexes. * @param doc the document whose indexes are to be invalidated */ public void clearDocumentIndexes(DocumentInfo doc) { docIndexes.remove(doc); } /** * Get the number of distinctly-named key definitions * @return the number of key definition sets (where the key definitions in one set share the same name) */ public int getNumberOfKeyDefinitions() { return keyMap.size(); } /** * Diagnostic output explaining the keys * @param out the expression presenter that will display the information */ public void explainKeys(ExpressionPresenter out) { if (keyMap.size() < 2) { // don't bother with IDREFS if it's the only index return; } out.startElement("keys"); Iterator keyIter = keyMap.keySet().iterator(); while (keyIter.hasNext()) { StructuredQName qName = (StructuredQName)keyIter.next(); List list = ((KeyDefinitionSet)keyMap.get(qName)).getKeyDefinitions(); for (int i=0; i 255) { sb.append("\\u"); String hex = Integer.toHexString(c); while (hex.length() < 4) { hex = "0" + hex; } sb.append(hex); } else { sb.append(c); } } } String s; if (len > 30) { if (valueType == URI) { s = "..." + sb.toString().substring(len-30); } else { s = sb.toString().substring(0, 30) + "..."; } } else { s = sb.toString(); } switch (valueType) { case ELEMENT: return "<" + s + ">"; case ATTRIBUTE: return "@" + s; case FUNCTION: return s + "()"; case VARIABLE: return "$" + s; case VALUE: return "\"" + s + "\""; default: return "{" + s + "}"; } } /** * Create a string representation of an item for use in an error message */ public static CharSequence depict(Item item) { if (item instanceof AtomicValue) { CharSequence cs = item.getStringValueCS(); if (item instanceof StringValue) { return '\"' + truncate30(cs).toString() + '\"'; } else { return truncate30(cs); } } else { NodeInfo node = (NodeInfo)item; switch (node.getNodeKind()) { case Type.DOCUMENT: return "document-node()"; case Type.ELEMENT: return "<" + node.getDisplayName() + "/>"; case Type.ATTRIBUTE: return "@" + node.getDisplayName(); case Type.TEXT: return "text(\"" + truncate30(node.getStringValue()) + "\")"; case Type.COMMENT: return ""; case Type.PROCESSING_INSTRUCTION: return ""; case Type.NAMESPACE: String prefix = node.getLocalPart(); return "xmlns" + (prefix.equals("") ? "" : ":" + prefix) + "=\"" + node.getStringValue() + '"'; default: return ""; } } } private static CharSequence truncate30(CharSequence cs) { if (cs.length() <= 30) { return Whitespace.collapseWhitespace(cs); } else { return Whitespace.collapseWhitespace(cs.subSequence(0, 30)).toString() + "..."; } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. //saxonb-9.1.0.8/bj/net/sf/saxon/trans/NoDynamicContextException.java0000644000175000017500000000241011033112257024473 0ustar eugeneeugenepackage net.sf.saxon.trans; /** * This exception class is used when early (compile-time) evaluation of an expression * is attempted, and the expression requires knowledge of the current dateTime or implicit * timezone. This exception should be caught internally, and should result in evaluation * of the expression being deferred until run-time */ public class NoDynamicContextException extends XPathException { /** * Create a NoDynamicContextException * @param message the error message */ public NoDynamicContextException(String message) { super("Dynamic context missing: " + message); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/trans/UnparsedTextURIResolver.java0000644000175000017500000000422211033112257024121 0ustar eugeneeugenepackage net.sf.saxon.trans; import net.sf.saxon.Configuration; import java.io.Reader; import java.io.Serializable; import java.net.URI; /** * An UnparsedTextURIResolver accepts an absolute URI and optionally an encoding name as input, * and returns a Reader as its result. */ public interface UnparsedTextURIResolver extends Serializable { /** * Resolve the URI passed to the XSLT unparsed-text() function, after resolving * against the base URI. * *

    Note that a user-written resolver is responsible for enforcing some of the rules in the * XSLT specification, such as the rules for inferring an encoding when none is supplied. Saxon * will not report any error if the resolver does this in a non-conformant way.

    * * @param absoluteURI the absolute URI obtained by resolving the supplied * URI against the base URI * @param encoding the encoding requested in the call of unparsed-text(), if any. Otherwise null. * @param config The Saxon configuration. Provided in case the URI resolver * needs it. * @return a Reader, which Saxon will use to read the unparsed text. After the text has been read, * the close() method of the Reader will be called. * @throws XPathException if any failure occurs * @since 8.9 */ public Reader resolve(URI absoluteURI, String encoding, Configuration config) throws XPathException; } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/trans/KeyDefinitionSet.java0000644000175000017500000001003011033112257022600 0ustar eugeneeugenepackage net.sf.saxon.trans; import net.sf.saxon.om.StructuredQName; import java.io.Serializable; import java.util.ArrayList; import java.util.List; /** * A set of xsl:key definitions in a stylesheet that share the same name */ public class KeyDefinitionSet implements Serializable { StructuredQName keyName; int keySetNumber; // unique among the KeyDefinitionSets within a KeyManager List keyDefinitions; String collationName; boolean backwardsCompatible; // true if any of the keys is backwards compatible /** * Create a key definition set for keys sharing a given name * @param keyName the name of the key definitions in this set * @param keySetNumber a unique number identifying this key definition set */ public KeyDefinitionSet(StructuredQName keyName, int keySetNumber) { this.keyName = keyName; this.keySetNumber = keySetNumber; keyDefinitions = new ArrayList(3); } /** * Add a key definition to this set of key definitions. The caller is responsible for ensuring that * all key definitions in a key definition set have the same name * @param keyDef the key definition to be added * @throws XPathException if the key definition uses a different collation from others in the set */ public void addKeyDefinition(KeyDefinition keyDef) throws XPathException { if (keyDefinitions.isEmpty()) { collationName = keyDef.getCollationName(); } else { if ((collationName == null && keyDef.getCollationName() != null) || (collationName != null && !collationName.equals(keyDef.getCollationName()))) { XPathException err = new XPathException("All keys with the same name must use the same collation"); err.setErrorCode("XTSE1220"); throw err; } // ignore this key definition if it is a duplicate of another already present List v = getKeyDefinitions(); for (int i=0; i * This method is intended for external use by advanced users, but should be regarded as * experimental. * @param loader the ClassLoader to be used in this configuration */ public void setClassLoader(ClassLoader loader) { classLoader = loader; } /** * Get the ClassLoader supplied using the method {@link #setClassLoader}. * If none has been supplied, return null. *

    * This method is intended for external use by advanced users, but should be regarded as * experimental. * @return the ClassLoader used in this configuration */ public ClassLoader getClassLoader() { return classLoader; } /** * Load a class using the class name provided. * Note that the method does not check that the object is of the right class. *

    * This method is intended for internal use only. * * @param className A string containing the name of the * class, for example "com.microstar.sax.LarkDriver" * @param tracing true if diagnostic tracing is required * @param classLoader The ClassLoader to be used to load the class. If this is null, then * the classLoader used will be the first one available of: the classLoader registered * with the Configuration using {@link #setClassLoader}; the context class loader for * the current thread; or failing that, the class loader invoked implicitly by a call * of Class.forName() (which is the ClassLoader that was used to load the Configuration * object itself). * @return an instance of the class named, or null if it is not * loadable. * @throws XPathException if the class cannot be loaded. * */ public Class getClass(String className, boolean tracing, ClassLoader classLoader) throws XPathException { if (tracing) { System.err.println("Loading " + className); } try { ClassLoader loader = classLoader; if (loader == null) { loader = this.classLoader; } if (loader == null) { loader = Thread.currentThread().getContextClassLoader(); } if (loader != null) { try { return loader.loadClass(className); } catch (Exception ex) { return Class.forName(className); } } else { return Class.forName(className); } } catch (Exception e) { if (tracing) { // The exception is often masked, especially when calling extension // functions System.err.println("No Java class " + className + " could be loaded"); } throw new XPathException("Failed to load " + className, e ); } } /** * Instantiate a class using the class name provided. * Note that the method does not check that the object is of the right class. *

    * This method is intended for internal use only. * * @param className A string containing the name of the * class, for example "com.microstar.sax.LarkDriver" * @param classLoader The ClassLoader to be used to load the class. If this is null, then * the classLoader used will be the first one available of: the classLoader registered * with the Configuration using {@link #setClassLoader}; the context class loader for * the current thread; or failing that, the class loader invoked implicitly by a call * of Class.forName() (which is the ClassLoader that was used to load the Configuration * object itself). * @return an instance of the class named, or null if it is not * loadable. * @throws XPathException if the class cannot be loaded. * */ public Object getInstance(String className, ClassLoader classLoader) throws XPathException { Class theclass = getClass(className, false, classLoader); try { return theclass.newInstance(); } catch (Exception err) { throw new XPathException("Failed to instantiate class " + className, err); } } /** * Instantiate a class using the class name provided, with the option of tracing * Note that the method does not check that the object is of the right class. *

    * This method is intended for internal use only. * * @param className A string containing the name of the * class, for example "com.microstar.sax.LarkDriver" * @param tracing true if attempts to load classes are to be traced to the console * @param classLoader The ClassLoader to be used to load the class. If this is null, then * the classLoader used will be the first one available of: the classLoader registered * with the Configuration using {@link #setClassLoader}; the context class loader for * the current thread; or failing that, the class loader invoked implicitly by a call * of Class.forName() (which is the ClassLoader that was used to load the Configuration * object itself). * @return an instance of the class named, or null if it is not * loadable. * @throws XPathException if the class cannot be loaded. * */ public Object getInstance(String className, boolean tracing, ClassLoader classLoader) throws XPathException { Class theclass = getClass(className, tracing, classLoader); try { return theclass.newInstance(); } catch (Exception err) { throw new XPathException("Failed to instantiate class " + className, err); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/trans/UncheckedXPathException.java0000644000175000017500000000272111033112257024110 0ustar eugeneeugenepackage net.sf.saxon.trans; /** * When tree construction is deferred, innocuous methods such as NodeInfo#getLocalName() may * trigger a dynamic error. Rather than make all such methods on NodeInfo throw a checked XPathException, * we instead throw an UncheckedXPathException, which is a simple wrapper for an XPathException. * Appropriate places in the client code must check for this condition and translate it back into an * XPathException. */ public class UncheckedXPathException extends RuntimeException { private XPathException cause; public UncheckedXPathException(XPathException cause) { this.cause = cause; } public XPathException getXPathException() { return cause; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/trans/DecimalFormatManager.java0000644000175000017500000001501411033112257023374 0ustar eugeneeugenepackage net.sf.saxon.trans; import net.sf.saxon.functions.FormatNumber; import net.sf.saxon.om.StructuredQName; import net.sf.saxon.om.NamespaceConstant; import java.io.Serializable; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; /** * DecimalFormatManager manages the collection of named and unnamed decimal formats * @author Michael H. Kay */ public class DecimalFormatManager implements Serializable { private DecimalSymbols defaultDFS; private HashMap formatTable; // table for named decimal formats private boolean usingOriginalDefault = true; /** * create a DecimalFormatManager and initialise variables */ public DecimalFormatManager() { formatTable = new HashMap(10); DecimalSymbols d = new DecimalSymbols(); setDefaults(d); defaultDFS = d; } /** * Set up the XSLT-defined default attributes in a DecimalFormatSymbols */ public static void setDefaults(DecimalSymbols d) { d.decimalSeparator = ('.'); d.groupingSeparator = (','); d.infinity = ("Infinity"); d.minusSign = ('-'); d.NaN = ("NaN"); d.percent = ('%'); d.permill = ('\u2030'); d.zeroDigit = ('0'); d.digit = ('#'); d.patternSeparator = (';'); } /** * Register the default decimal-format. * Note that it is an error to register the same decimal-format twice, even with different * precedence */ public void setDefaultDecimalFormat(DecimalSymbols dfs, int precedence) throws XPathException { if (!usingOriginalDefault) { if (!dfs.equals(defaultDFS)) { XPathException err = new XPathException("There are two conflicting definitions of the default decimal format"); err.setErrorCode("XTSE1290"); err.setIsStaticError(true); throw err; } } defaultDFS = dfs; usingOriginalDefault = false; setNamedDecimalFormat(DEFAULT_NAME, dfs, precedence); // this is to trigger fixup of calls } final public static StructuredQName DEFAULT_NAME = new StructuredQName("saxon", NamespaceConstant.SAXON, "default-decimal-format"); /** * Method called at the end of stylesheet compilation to fix up any format-number() calls * to the "default default" decimal format */ public void fixupDefaultDefault() throws XPathException { if (usingOriginalDefault) { setNamedDecimalFormat(DEFAULT_NAME, defaultDFS, -1000); } } /** * Get the default decimal-format. */ public DecimalSymbols getDefaultDecimalFormat() { return defaultDFS; } /** * Set a named decimal format. * Note that it is an error to register the same decimal-format twice, unless hte values are * equal, or unless there is another of higher precedence. This method assumes that decimal-formats * are registered in order of decreasing precedence * @param qName the name of the decimal format */ public void setNamedDecimalFormat(StructuredQName qName, DecimalSymbols dfs, int precedence) throws XPathException { Object o = formatTable.get(qName); if (o != null) { if (o instanceof List) { // this indicates there are forwards references to this decimal format that need to be fixed up for (Iterator iter = ((List)o).iterator(); iter.hasNext(); ) { FormatNumber call = (FormatNumber)iter.next(); call.fixup(dfs); } } else { DecimalFormatInfo info = (DecimalFormatInfo)o; DecimalSymbols old = info.dfs; int oldPrecedence = info.precedence; if (precedence < oldPrecedence) { return; } if (precedence==oldPrecedence && !dfs.equals(old)) { XPathException err = new XPathException("There are two conflicting definitions of the named decimal-format"); err.setErrorCode("XTSE1290"); err.setIsStaticError(true); throw err; } } } DecimalFormatInfo dfi = new DecimalFormatInfo(); dfi.dfs = dfs; dfi.precedence = precedence; formatTable.put(qName, dfi); } /** * Register a format-number() function call that uses a particular decimal format. This * allows early compile time resolution to a DecimalFormatSymbols object where possible, * even in the case of a forwards reference */ public void registerUsage(StructuredQName qName, FormatNumber call) { Object o = formatTable.get(qName); if (o == null) { // it's a forwards reference List list = new ArrayList(10); list.add(call); formatTable.put(qName, list); } else if (o instanceof List) { // it's another forwards reference List list = (List)o; list.add(call); } else { // it's a backwards reference DecimalFormatInfo dfi = (DecimalFormatInfo)o; call.fixup(dfi.dfs); } } /** * Get a named decimal-format registered using setNamedDecimalFormat * @param qName The name of the decimal format * @return the DecimalFormatSymbols object corresponding to the named locale, if any * or null if not set. */ public DecimalSymbols getNamedDecimalFormat(StructuredQName qName) { DecimalFormatInfo dfi = ((DecimalFormatInfo)formatTable.get(qName)); if (dfi == null) { return null; } return dfi.dfs; } private static class DecimalFormatInfo implements Serializable { public DecimalSymbols dfs; public int precedence; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/trans/DecimalSymbols.java0000644000175000017500000000437511033112257022311 0ustar eugeneeugenepackage net.sf.saxon.trans; import java.io.Serializable; /** * This class is modelled on Java's DecimalFormatSymbols, but it allows the use of any * Unicode character to represent symbols such as the decimal point and the grouping * separator, whereas DecimalFormatSymbols restricts these to a char (1-65535). Since * this is essentially a data structure with no behaviour, we don't bother with getter * and setter methods but just expose the fields */ public class DecimalSymbols implements Serializable { public int decimalSeparator; public int groupingSeparator; public int digit; public int minusSign; public int percent; public int permill; public int zeroDigit; public int patternSeparator; public String infinity; public String NaN; public boolean equals(Object obj) { if (!(obj instanceof DecimalSymbols)) return false; DecimalSymbols o = (DecimalSymbols)obj; return decimalSeparator == o.decimalSeparator && groupingSeparator == o.groupingSeparator && digit == o.digit && minusSign == o.minusSign && percent == o.percent && permill == o.permill && zeroDigit == o.zeroDigit && patternSeparator == o.patternSeparator && infinity.equals(o.infinity) && NaN.equals(o.NaN); } public int hashCode() { return decimalSeparator + (37*groupingSeparator) + (41*digit); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/trans/DynamicError.java0000644000175000017500000000640611033112257021775 0ustar eugeneeugenepackage net.sf.saxon.trans; import net.sf.saxon.expr.XPathContext; import javax.xml.transform.SourceLocator; import javax.xml.transform.TransformerException; /** * Subclass of XPathException used for dynamic errors * @deprecated since 9.0 - use the superclass XPathException instead */ public class DynamicError extends XPathException { transient XPathContext context; // declared transient because a compiled stylesheet might contain a "deferred action" dynamic error // and the EarlyEvaluationContext links back to the source stylesheet. public DynamicError(String message) { super(message); } public DynamicError(Throwable err) { super(err); } public DynamicError(String message, Throwable err) { super(message, err); } public DynamicError(String message, SourceLocator loc) { super(message, loc); } public DynamicError(String message, SourceLocator loc, Throwable err) { super(message, loc, err); } public DynamicError(String message, String errorCode) { super(message); setErrorCode(errorCode); } public DynamicError(String message, String errorCode, XPathContext context) { super(message); setErrorCode(errorCode); setXPathContext(context); } public void setXPathContext(XPathContext context) { this.context = context; } public XPathContext getXPathContext() { return context; } public static DynamicError makeDynamicError(TransformerException err) { if (err instanceof DynamicError) { return (DynamicError)err; } else if (err instanceof XPathException) { DynamicError de = new DynamicError(err); de.setErrorCode(((XPathException)err).getErrorCodeLocalPart()); de.setLocator(err.getLocator()); return de; } else { return new DynamicError(err); } } /** * Set the location and/or context of a message, only if they are * not already set * @param locator the current location (or null) * @param context the current context (or null) */ public void maybeSetLocation(SourceLocator locator, XPathContext context) { if ((getLocator() == null || getLocator().getLineNumber() == -1) && locator != null) { setLocator(locator); } if (getXPathContext() == null && context != null) { setXPathContext(context); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. //saxonb-9.1.0.8/bj/net/sf/saxon/trans/CompilerInfo.java0000644000175000017500000000660411033112257021765 0ustar eugeneeugenepackage net.sf.saxon.trans; import javax.xml.transform.URIResolver; import javax.xml.transform.ErrorListener; /** * This class exists to hold information associated with a specific XSLT compilation episode. * In JAXP, the URIResolver and ErrorListener used during XSLT compilation are those defined in the * TransformerFactory. The .NET API, however, allows finer granularity, and this class exists to * support that. */ public class CompilerInfo { private URIResolver uriResolver; private ErrorListener errorListener; private boolean compileWithTracing; /** * Set the URI Resolver to be used in this compilation episode. * @param resolver The URIResolver to be used. This is used to dereference URIs encountered in constructs * such as xsl:include, xsl:import, and xsl:import-schema. * @since 8.7 */ public void setURIResolver(URIResolver resolver) { uriResolver = resolver; } /** * Get the URI Resolver being used in this compilation episode. * @return resolver The URIResolver in use. This is used to dereference URIs encountered in constructs * such as xsl:include, xsl:import, and xsl:import-schema. * @since 8.7 */ public URIResolver getURIResolver() { return uriResolver; } /** * Set the ErrorListener to be used during this compilation episode * @param listener The error listener to be used. This is notified of all errors detected during the * compilation. * @since 8.7 */ public void setErrorListener(ErrorListener listener) { errorListener = listener; } /** * Get the ErrorListener being used during this compilation episode * @return listener The error listener in use. This is notified of all errors detected during the * compilation. * @since 8.7 */ public ErrorListener getErrorListener() { return errorListener; } /** * Set whether trace hooks are to be included in the compiled code. To use tracing, it is necessary * both to compile the code with trace hooks included, and to supply a TraceListener at run-time * @param trueOrFalse true if trace code is to be compiled in, false otherwise * @since 8.9 */ public void setCompileWithTracing(boolean trueOrFalse) { compileWithTracing = trueOrFalse; } /** * Determine whether trace hooks are included in the compiled code. * @return true if trace hooks are included, false if not. * @since 8.9 */ public boolean isCompileWithTracing() { return compileWithTracing; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/trans/Rule.java0000644000175000017500000000560611033112257020307 0ustar eugeneeugenepackage net.sf.saxon.trans; import net.sf.saxon.pattern.Pattern; import java.io.Serializable; /** * Rule: a template rule, or a strip-space rule used to support the implementation */ public final class Rule implements Serializable { private Pattern pattern; // The pattern that fires this rule private Object action; // The action associated with this rule (usually a Template) private int precedence; // The import precedence private double priority; // The priority of the rule private Rule next; // The next rule after this one in the chain of rules private int sequence; // The relative position of this rule, its position in declaration order public int getSequence() { return sequence; } public Object getAction() { return action; } public Rule getNext() { return next; } public void setNext(Rule next) { this.next = next; } public Pattern getPattern() { return pattern; } public int getPrecedence() { return precedence; } public double getPriority() { return priority; } /** * Create a Rule * * @param p the pattern that this rule matches * @param o the object invoked by this rule (usually a Template) * @param prec the precedence of the rule * @param prio the priority of the rule * @param seq a sequence number for ordering of rules */ public Rule(Pattern p, Object o, int prec, double prio, int seq) { pattern = p; action = o; precedence = prec; priority = prio; next = null; sequence = seq; } /** * Copy a rule, including the chain of rules linked to it * @param r the rule to be copied */ public Rule(Rule r) { pattern = r.pattern; action = r.action; precedence = r.precedence; priority = r.priority; sequence = r.sequence; if (r.next == null) { next = null; } else { next = new Rule(r.next); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. //saxonb-9.1.0.8/bj/net/sf/saxon/trans/StandardUnparsedTextResolver.java0000644000175000017500000002561011033112257025226 0ustar eugeneeugenepackage net.sf.saxon.trans; import net.sf.saxon.Configuration; import net.sf.saxon.om.FastStringBuffer; import java.io.*; import java.net.MalformedURLException; import java.net.URI; import java.net.URL; import java.net.URLConnection; import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; import java.nio.charset.CodingErrorAction; import java.util.zip.GZIPInputStream; /** * Default implementation of the UnparsedTextURIResolver, used if no other implementation * is nominated to the Configuration. */ public class StandardUnparsedTextResolver implements UnparsedTextURIResolver { private boolean debug = false; /** * Set debugging on or off. In debugging mode, information is written to System.err * to trace the process of deducing an encoding. * * @param debug set to true to enable debugging */ public void setDebugging(boolean debug) { this.debug = debug; } /** * Resolve the URI passed to the XSLT unparsed-text() function, after resolving * against the base URI. * * @param absoluteURI the absolute URI obtained by resolving the supplied * URI against the base URI * @param encoding the encoding requested in the call of unparsed-text(), if any. Otherwise null. * @param config The configuration. Provided in case the URI resolver * needs it. * @return a Reader, which Saxon will use to read the unparsed text. After the text has been read, * the close() method of the Reader will be called. * @throws XPathException if any failure occurs * @since 8.9 */ public Reader resolve(URI absoluteURI, String encoding, Configuration config) throws XPathException { URL absoluteURL; if (debug) { System.err.println("unparsed-text(): processing " + absoluteURI); System.err.println("unparsed-text(): requested encoding = " + encoding); } try { absoluteURL = absoluteURI.toURL(); } catch (MalformedURLException err) { XPathException e = new XPathException("Cannot convert absolute URI to URL", err); e.setErrorCode("XTDE1170"); throw e; } try { InputStream is; URLConnection connection = absoluteURL.openConnection(); connection.setRequestProperty("Accept-Encoding","gzip"); connection.connect(); is = connection.getInputStream(); String contentEncoding = connection.getContentEncoding(); if ("gzip".equals(contentEncoding)) { is = new GZIPInputStream(is); } if (debug) { System.err.println("unparsed-text(): established connection " + ("gzip".equals(contentEncoding) ? " (zipped)" : "")); } try { if (!is.markSupported()) { is = new BufferedInputStream(is); } // Get any external (HTTP) encoding label. boolean isXmlMediaType = false; // The file:// URL scheme gives no useful information... if (!"file".equals(connection.getURL().getProtocol())) { // Use the contentType from the HTTP header if available String contentType = connection.getContentType(); if (debug) { System.err.println("unparsed-text(): content type = " + contentType); } if (contentType != null) { String mediaType; int pos = contentType.indexOf(';'); if (pos >= 0) { mediaType = contentType.substring(0, pos); } else { mediaType = contentType; } mediaType = mediaType.trim(); if (debug) { System.err.println("unparsed-text(): media type = " + mediaType); } isXmlMediaType = (mediaType.startsWith("application/") || mediaType.startsWith("text/")) && (mediaType.endsWith("/xml") || mediaType.endsWith("+xml")); String charset = ""; pos = contentType.toLowerCase().indexOf("charset"); if (pos >= 0) { pos = contentType.indexOf('=', pos + 7); if (pos >= 0) { charset = contentType.substring(pos + 1); } if ((pos = charset.indexOf(';')) > 0) { charset = charset.substring(0, pos); } // attributes can have comment fields (RFC 822) if ((pos = charset.indexOf('(')) > 0) { charset = charset.substring(0, pos); } // ... and values may be quoted if ((pos = charset.indexOf('"')) > 0) { charset = charset.substring(pos + 1, charset.indexOf('"', pos + 2)); } if (debug) { System.err.println("unparsed-text(): charset = " + charset.trim()); } encoding = charset.trim(); } } } if (encoding == null || isXmlMediaType) { // Try to detect the encoding from the start of the content is.mark(100); byte[] start = new byte[100]; int read = is.read(start, 0, 100); is.reset(); encoding = inferEncoding(start, read); if (debug) { System.err.println("unparsed-text(): inferred encoding = " + encoding); } } } catch (IOException e) { encoding = "UTF-8"; } //} // The following appears to be necessary to ensure that encoding errors are not recovered. Charset charset = Charset.forName(encoding); CharsetDecoder decoder = charset.newDecoder(); decoder = decoder.onMalformedInput(CodingErrorAction.REPORT); decoder = decoder.onUnmappableCharacter(CodingErrorAction.REPORT); return new BufferedReader(new InputStreamReader(is, decoder)); } catch (IOException err) { throw new XPathException(err); } } /** * Infer the encoding of a file by reading the first few bytes of the file * * @param start the first few bytes of the file * @param read the number of bytes that have been read * @return the inferred encoding */ private String inferEncoding(byte[] start, int read) { if (read >= 2) { if (ch(start[0]) == 0xFE && ch(start[1]) == 0xFF) { if (debug) { System.err.println("unparsed-text(): found UTF-16 byte order mark"); } return "UTF-16"; } else if (ch(start[0]) == 0xFF && ch(start[1]) == 0xFE) { if (debug) { System.err.println("unparsed-text(): found UTF-16LE byte order mark"); } return "UTF-16LE"; } } if (read >= 3) { if (ch(start[0]) == 0xEF && ch(start[1]) == 0xBB && ch(start[2]) == 0xBF) { if (debug) { System.err.println("unparsed-text(): found UTF-8 byte order mark"); } return "UTF-8"; } } if (read >= 4) { if (ch(start[0]) == '<' && ch(start[1]) == '?' && ch(start[2]) == 'x' && ch(start[3]) == 'm' && ch(start[4]) == 'l') { if (debug) { System.err.println("unparsed-text(): found XML declaration"); } FastStringBuffer sb = new FastStringBuffer(read); for (int b = 0; b < read; b++) { sb.append((char)start[b]); } String p = sb.toString(); int v = p.indexOf("encoding"); if (v >= 0) { v += 8; while (v < p.length() && " \n\r\t=\"'".indexOf(p.charAt(v)) >= 0) { v++; } sb.setLength(0); while (v < p.length() && p.charAt(v) != '"' && p.charAt(v) != '\'') { sb.append(p.charAt(v++)); } if (debug) { System.err.println("unparsed-text(): encoding in XML declaration = " + sb.toString()); } return sb.toString(); } if (debug) { System.err.println("unparsed-text(): no encoding found in XML declaration"); } } } else if (read > 0 && start[0] == 0 && start[2] == 0 && start[4] == 0 && start[6] == 0) { if (debug) { System.err.println("unparsed-text(): even-numbered bytes are zero, inferring UTF-16"); } return "UTF-16"; } else if (read > 1 && start[1] == 0 && start[3] == 0 && start[5] == 0 && start[7] == 0) { if (debug) { System.err.println("unparsed-text(): odd-numbered bytes are zero, inferring UTF-16LE"); } return "UTF-16LE"; } // If all else fails, assume UTF-8 if (debug) { System.err.println("unparsed-text(): assuming fallback encoding (UTF-8)"); } return "UTF-8"; } private int ch(byte b) { return ((int)b) & 0xff; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/trans/XPathException.java0000644000175000017500000002502411033112257022277 0ustar eugeneeugenepackage net.sf.saxon.trans; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.NamespaceConstant; import net.sf.saxon.value.Value; import javax.xml.transform.SourceLocator; import javax.xml.transform.TransformerException; /** * XPathException is used to indicate an error in an XPath expression. * It will generally be either a StaticError or a DynamicError; * ValidationExceptions (arising from schema validation) form a third category */ public class XPathException extends TransformerException { private boolean isTypeError = false; private boolean isStaticError = false; String errorCodeNamespace; // TODO: implement error codes as QNames throughout String errorCode; Value errorObject; private boolean hasBeenReported = false; transient XPathContext context; // declared transient because a compiled stylesheet might contain a "deferred action" dynamic error // and the EarlyEvaluationContext links back to the source stylesheet. /** * Create an XPathException with an error message * @param message the message explaining what is wrong. This should not include location information. */ public XPathException(String message) { super(message); } /** * Create an XPathException that wraps another exception * @param err the wrapped error or exception */ public XPathException(Throwable err) { super(err); } /** * Create an XPathException that supplies an error message and wraps an underlying exception * @param message the error message (which should generally explain what Saxon was doing when the * underlying exception occurred) * @param err the underlying exception (the cause of this exception) */ public XPathException(String message, Throwable err) { super(message, err); } /** * Create an XPathException that supplies an error message and supplies location information * @param message the error message * @param loc indicates where in the user-written query or stylesheet (or sometimes in a source * document) the error occurred */ public XPathException(String message, SourceLocator loc) { super(message, loc); } /** * Create an XPathException that supplies an error message and wraps an underlying exception * and supplies location information * @param message the error message (which should generally explain what Saxon was doing when the * underlying exception occurred) * @param loc indicates where in the user-written query or stylesheet (or sometimes in a source * document) the error occurred * @param err the underlying exception (the cause of this exception) */ public XPathException(String message, SourceLocator loc, Throwable err) { super(message, loc, err); } /** * Create an XPathException that supplies an error message and an error code * @param message the error message * @param errorCode the error code - an eight-character code, which is taken to be in the standard * system error code namespace */ public XPathException(String message, String errorCode) { super(message); setErrorCode(errorCode); } /** * Create an XPathException that supplies an error message and an error code and provides the * dynamic context * @param message the error message * @param errorCode the error code - an eight-character code, which is taken to be in the standard * system error code namespace * @param context the dynamic evaluation context */ public XPathException(String message, String errorCode, XPathContext context) { super(message); setErrorCode(errorCode); setXPathContext(context); } /** * Create an XPathException from a JAXP TransformerException. If the TransformerException is an XPathException, * or if its cause is an XPathException, that XPathException is returned unchanged; otherwise the * TransformerException is wrapped. * @param err the supplied JAXP TransformerException * @return an XPathException obtained from the supplied TransformerException */ public static XPathException makeXPathException(TransformerException err) { if (err instanceof XPathException) { return (XPathException)err; } else if (err.getException() instanceof XPathException) { return (XPathException)err.getException(); } else { return new XPathException(err); } } /** * Force an exception to a static error * @return this exception, marked as a static error */ public XPathException makeStatic() { setIsStaticError(true); return this; } /** * Set dynamic context information in the exception object * @param context the dynamic context at the time the exception occurred */ public void setXPathContext(XPathContext context) { this.context = context; } /** * Get the dynamic context at the time the exception occurred * @return the dynamic context if known; otherwise null */ public XPathContext getXPathContext() { return context; } /** * Mark this exception to indicate that it represents (or does not represent) a static error * @param is true if this exception is a static error */ public void setIsStaticError(boolean is) { isStaticError = is; } /** * Ask whether this exception represents a static error * @return true if this exception is a static error */ public boolean isStaticError() { return isStaticError; } /** * Mark this exception to indicate that it represents (or does not represent) a type error * @param is true if this exception is a type error */ public void setIsTypeError(boolean is) { isTypeError = is; } /** * Ask whether this exception represents a type error * @return true if this exception is a type error */ public boolean isTypeError() { return isTypeError; } /** * Set the error code. The error code is a QName; this method sets the local part of the name, * and if no other namespace has been set, it sets the namespace of the error code to the standard * system namespace {@link NamespaceConstant#ERR} * @param code The local part of the name of the error code */ public void setErrorCode(String code) { if (code != null) { this.errorCode = code; if (errorCodeNamespace == null) { errorCodeNamespace = NamespaceConstant.ERR; } } } /** * Set the error code. The error code is a QName; this method sets both parts of the name. * @param namespace The namespace URI part of the name of the error code * @param code The local part of the name of the error code */ public void setErrorCode(String namespace, String code) { this.errorCode = code; this.errorCodeNamespace = namespace; } /** * Get the local part of the name of the error code * @return the local part of the name of the error code */ public String getErrorCodeLocalPart() { return errorCode; } /** * Get the namespace URI part of the name of the error code * @return the namespace URI part of the name of the error code */ public String getErrorCodeNamespace() { return errorCodeNamespace; } /** * Set the error object associated with this error. This is used by the standard XPath fn:error() function * @param value the error object, as supplied to the fn:error() function */ public void setErrorObject(Value value) { errorObject = value; } /** * Get the error object associated with this error. This is used by the standard XPath fn:error() function * @return the error object, as supplied to the fn:error() function */ public Value getErrorObject() { return errorObject; } /** * Mark this error to indicate that it has already been reported to the error listener, and should not be * reported again */ public void setHasBeenReported() { hasBeenReported = true; } /** * Ask whether this error is marked to indicate that it has already been reported to the error listener, * and should not be reported again * @return true if this error has already been reported */ public boolean hasBeenReported() { return hasBeenReported; } /** * Set the location of a message, only if it is not already set * @param locator the current location (or null) */ public void maybeSetLocation(SourceLocator locator) { if ((getLocator() == null || getLocator().getLineNumber() == -1) && locator != null) { setLocator(locator); } } /** * Set the context of a message, only if it is not already set * @param context the current XPath context (or null) */ public void maybeSetContext(XPathContext context) { if (getXPathContext() == null) { setXPathContext(context); } } /** * Subclass of XPathException used to report circularities */ public static class Circularity extends XPathException { /** * Create an exception indicating that a circularity was detected * @param message the error message */ public Circularity(String message) { super(message); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/trans/package.html0000644000175000017500000000073311033112257021012 0ustar eugeneeugene Package overview for net.sf.saxon

    This package provides a miscellaneous collection of helper classes for XSLT transformation. They are of no direct interest to user applications, except for the XPathException class, which is used to represent many errors in public methods.


    Michael H. Kay
    Saxonica Limited
    9 February 2005

    saxonb-9.1.0.8/bj/net/sf/saxon/IdentityTransformer.java0000644000175000017500000000501611033112257022260 0ustar eugeneeugenepackage net.sf.saxon; import net.sf.saxon.event.*; import net.sf.saxon.trans.XPathException; import org.xml.sax.SAXParseException; import javax.xml.transform.Result; import javax.xml.transform.Source; import javax.xml.transform.TransformerException; class IdentityTransformer extends Controller { protected IdentityTransformer(Configuration config) { super(config); } /** * Perform identify transformation from Source to Result */ public void transform(Source source, Result result) throws TransformerException { try { PipelineConfiguration pipe = makePipelineConfiguration(); SerializerFactory sf = getConfiguration().getSerializerFactory(); Receiver receiver = sf.getReceiver( result, pipe, getOutputProperties()); NamespaceReducer reducer = new NamespaceReducer(); reducer.setUnderlyingReceiver(receiver); new Sender(pipe).send(source, reducer, true); } catch (XPathException err) { Throwable cause = err.getException(); if (cause != null && cause instanceof SAXParseException) { // This generally means the error was already reported. // But if a RuntimeException occurs in Saxon during a callback from // the Crimson parser, Crimson wraps this in a SAXParseException without // reporting it further. SAXParseException spe = (SAXParseException)cause; cause = spe.getException(); if (cause instanceof RuntimeException) { reportFatalError(err); } } else { reportFatalError(err); } throw err; } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): None // saxonb-9.1.0.8/bj/net/sf/saxon/OutputURIResolver.java0000644000175000017500000000452011033112257021645 0ustar eugeneeugenepackage net.sf.saxon; import javax.xml.transform.Result; import javax.xml.transform.TransformerException; /** * This interface defines an OutputURIResolver. This is a counterpart to the JAXP * URIResolver, but is used to map the URI of a secondary result document to a Result object * which acts as the destination for the new document. * @author Michael H. Kay */ public interface OutputURIResolver { /** * Resolve an output URI. * @param href The relative URI of the output document. This corresponds to the * href attribute of the xsl:result-document instruction. * @param base The base URI that should be used. This is the Base Output URI, typically * the URI of the principal output document * @return a Result object representing the destination for the XML document. The * method can also return null, in which case the standard output URI resolver * will be used to create a Result object. */ public Result resolve(String href, String base) throws TransformerException; /** * Signal completion of the result document. This method is called by the system * when the result document has been successfully written. It allows the resolver * to perform tidy-up actions such as closing output streams, or firing off * processes that take this result tree as input. Note that the OutputURIResolver * is stateless, so the the original Result object is supplied to identify the document * that has been completed. * @param result The result object returned by the previous call of resolve() */ public void close(Result result) throws TransformerException; } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/FeatureKeys.java0000644000175000017500000004462611033112257020505 0ustar eugeneeugenepackage net.sf.saxon; /** * FeatureKeys defines a set of constants, names of Saxon configuration * options which can be supplied to the Saxon implementations of the JAXP * interfaces TransformerFactory, SchemaFactory, Validator, and ValidationHandler. * * @author Michael H. Kay */ public abstract class FeatureKeys { /** * ALLOW_EXTERNAL_FUNCTIONS must be a Boolean; it determines whether calls to external functions are allowed. * More specifically, it disallows all of the following: * *
      *
    • Calls to Java extension functions
    • *
    • Use of the XSLT system-property() function to access Java system properties
    • *
    • Use of a relative URI in the xsl:result-document instruction
    • *
    • Calls to XSLT extension instructions
    • *
    * *

    Note that this option does not disable use of the doc() function or similar * functions to access the filestore of the machine where the transformation or query is running. * That should be done using a user-supplied URIResolver

    */ public static final String ALLOW_EXTERNAL_FUNCTIONS = "http://saxon.sf.net/feature/allow-external-functions"; /** * COLLATION_URI_RESOLVER must be a {@link net.sf.saxon.sort.CollationURIResolver}. * This resolver will be used to resolve collation URIs used in stylesheets compiled or executed under the * control of this TransformerFactory */ public static final String COLLATION_URI_RESOLVER = "http://saxon.sf.net/feature/collation-uri-resolver"; /** * COLLATION_URI_RESOLVER_CLASS must be the name of a class that implements the interface * {@link net.sf.saxon.sort.CollationURIResolver}. The class will be instantiated, and the instance * will act as the value of the {@link #COLLATION_URI_RESOLVER} property. */ public static final String COLLATION_URI_RESOLVER_CLASS = "http://saxon.sf.net/feature/collation-uri-resolver-class"; /** * COLLECTION_URI_RESOLVER must be a {@link net.sf.saxon.CollectionURIResolver}. * This resolver will be used to resolve collection URIs used in calls of the collection() function */ public static final String COLLECTION_URI_RESOLVER = "http://saxon.sf.net/feature/collection-uri-resolver"; /** * COLLECTION_URI_RESOLVER must be must be the name of a class that implements the interface * {@link net.sf.saxon.CollectionURIResolver}. * The class will be instantiated, and the instance * will act as the value of the {@link #COLLECTION_URI_RESOLVER} property. */ public static final String COLLECTION_URI_RESOLVER_CLASS = "http://saxon.sf.net/feature/collection-uri-resolver-class"; /** * COMPILE_WITH_TRACING must be a Boolean. If true, stylesheets and queries * are compiled with tracing enabled, but the choice of a trace listener * is deferred until run time (see {@link Controller#addTraceListener(net.sf.saxon.trace.TraceListener)}) */ public static final String COMPILE_WITH_TRACING = "http://saxon.sf.net/feature/compile-with-tracing"; /** * CONFIGURATION must be an instance of {@link Configuration}. This attribute cannot be set on the * Configuration itself, but it can be set on various JAXP factory objects such as a * TransformerFactory or DocumentBuilderFactory, to ensure that several such factories use the same * configuration. Note that other configuration options are held in the Configuration object, so setting * this attribute will cancel all others that have been set. Also, if two factories share the same * configuration, then setting an attribute on one affects all the others. */ public static final String CONFIGURATION = "http://saxon.sf.net/feature/configuration"; /** * DTD_VALIDATION must be a Boolean. This determines whether source documents should be * parsed with DTD-validation enabled. */ public static final String DTD_VALIDATION = "http://saxon.sf.net/feature/validation"; /** * EXPAND_ATTRIBUTE_DEFAULTS must be a Boolean; it determines whether fixed and default values defined * in a schema or DTD will be expanded. By default (and for conformance with the * specification) validation against a DTD or schema will cause default values defined in the schema * or DTD to be inserted into the document. Setting this feature to false suppresses this behaviour. In * the case of DTD-defined defaults this only works if the XML parser reports whether each attribute was * specified in the source or generated by expanding a default value. Not all XML parsers report this * information. */ public static final String EXPAND_ATTRIBUTE_DEFAULTS = "http://saxon.sf.net/feature/expandAttributeDefaults"; /** * LINE_NUMBERING must be a Boolean; it determines whether line and column numbers are maintained for * source documents. Note that some tree implementations do not support line numbering, and some may support * it only partially; the implementation always has the option of returning -1 as the line number or column * number of a node if the location is unknown. This value sets the default for the Configuration; it can be * overridden for individual documents, or for a PipelineConfiguration */ public static final String LINE_NUMBERING = "http://saxon.sf.net/feature/linenumbering"; /** * MESSAGE_EMITTER_CLASS must be the class name of a class that implements net.sf.saxon.event.Receiver. * Despite the name, it is not required to be an instance of net.sf.saxon.event.Emitter */ public static final String MESSAGE_EMITTER_CLASS = "http://saxon.sf.net/feature/messageEmitterClass"; /** * MODULE_URI_RESOLVER must be an instance of {@link net.sf.saxon.query.ModuleURIResolver}. This is a user-written * class that takes responsibility for locating XQuery modules. */ public static final String MODULE_URI_RESOLVER = "http://saxon.sf.net/feature/moduleURIResolver"; /** * MODULE_URI_RESOLVER_CLASS must be the name of a class that implements the interface * {@link net.sf.saxon.query.ModuleURIResolver}. This is a user-written * class that takes responsibility for locating XQuery modules. */ public static final String MODULE_URI_RESOLVER_CLASS = "http://saxon.sf.net/feature/moduleURIResolverClass"; /** * NAME_POOL must be an instance of net.sf.saxon.om.NamePool */ public static final String NAME_POOL = "http://saxon.sf.net/feature/namePool"; /** * OUTPUT_URI_RESOLVER must be an instance of {@link net.sf.saxon.OutputURIResolver}. This is a * user-written class that takes responsibility for disposing of the result trees produced * using XSLT xsl:result-document instruction */ public static final String OUTPUT_URI_RESOLVER = "http://saxon.sf.net/feature/outputURIResolver"; /** * OUTPUT_URI_RESOLVER_CLASS must be the name of a class that implements the interface * {@link net.sf.saxon.OutputURIResolver}. This is a * user-written class that takes responsibility for disposing of the result trees produced * using XSLT xsl:result-document instruction */ public static final String OUTPUT_URI_RESOLVER_CLASS = "http://saxon.sf.net/feature/outputURIResolverClass"; /** * PRE_EVALUATE_DOC_FUNCTION is a boolean. If set, calls to the doc() or document() function with a statically-known * document URI are evaluated at compile time, so that the document only needs to be parsed and constructed once. * The effect of this is that subsequent changes to the contents of the file will not be reflected during * query or stylesheet processing */ public static final String PRE_EVALUATE_DOC_FUNCTION = "http://saxon.sf.net/feature/preEvaluateDocFunction"; /** * PREFER_JAXP_PARSER is a boolean. It has no effect when running on the Java platform. When running on the * .NET platform, it causes a JAXP XML parser to be used in preference to the .NET XML parser. By default, * the .NET XML parser (System.Xml.XmlTextReader) is used. One advantageof this option is * that the .NET XML parser does not report ID attributes, which means that the id() function * does not work. */ public static final String PREFER_JAXP_PARSER = "http://saxon.sf.net/feature/preferJaxpParser"; /** * RECOGNIZE_URI_QUERY_PARAMETERS must be a Boolean; it determines whether query parameters (things after a question mark) * in a URI passed to the document() or doc() function are specially recognized by the system default URIResolver. * Allowed parameters include, for example validation=strict to perform schema validation, and strip-space=yes * to perform stripping of all whitespace-only text nodes. */ public static final String RECOGNIZE_URI_QUERY_PARAMETERS = "http://saxon.sf.net/feature/recognize-uri-query-parameters"; /** * RECOVERY_POLICY must be an Integer: one of {@link Configuration#RECOVER_SILENTLY}, * {@link Configuration#RECOVER_WITH_WARNINGS}, or {@link Configuration#DO_NOT_RECOVER} */ public static final String RECOVERY_POLICY = "http://saxon.sf.net/feature/recoveryPolicy"; /** * RECOVERY_POLICY_NAME must be a string: one of "recoverSilently", "recoverWithWarnings", "doNotRecover" */ public static final String RECOVERY_POLICY_NAME = "http://saxon.sf.net/feature/recoveryPolicyName"; /** * SCHEMA_URI_RESOLVER must be an instance of {@link net.sf.saxon.type.SchemaURIResolver}. This is a user-written * class that takes responsibility for locating schema documents. */ public static final String SCHEMA_URI_RESOLVER = "http://saxon.sf.net/feature/schemaURIResolver"; /** * SCHEMA_URI_RESOLVER_CLASS must be the name of a class that implements * {@link net.sf.saxon.type.SchemaURIResolver}. This is a user-written * class that takes responsibility for locating schema documents. */ public static final String SCHEMA_URI_RESOLVER_CLASS = "http://saxon.sf.net/feature/schemaURIResolverClass"; /** * SCHEMA_VALIDATION must be an Integer. This determines whether source documents should be * parsed with schema-validation enabled. The string takes one of the values * {@link net.sf.saxon.om.Validation#STRICT}, {@link net.sf.saxon.om.Validation#LAX}, * {@link net.sf.saxon.om.Validation#PRESERVE}, {@link net.sf.saxon.om.Validation#SKIP}. */ public static final String SCHEMA_VALIDATION = "http://saxon.sf.net/feature/schema-validation"; /** * SCHEMA_VALIDATION_MODE must be a String: one of "strict", "lax", "preserve", or "skip". */ public static final String SCHEMA_VALIDATION_MODE = "http://saxon.sf.net/feature/schema-validation-mode"; /** * SOURCE_PARSER_CLASS must be the full class name of an XMLReader. This identifies the parser * used for source documents. */ public static final String SOURCE_PARSER_CLASS = "http://saxon.sf.net/feature/sourceParserClass"; /** * STRIP_WHITESPACE must be a string set to one of the values "all", "none", or "ignorable". * This determines what whitespace is stripped during tree construction: "all" removes all * whitespace-only text nodes; "ignorable" removes whitespace text nodes in element-only content * (as identified by a DTD or Schema), and "none" preserves all whitespace. This whitespace stripping * is additional to any stripping caused by the xsl:strip-space declaration in a stylesheet. * *

    This option also controls stripping of whitespace by a JAXP identity Transformer or identity * transformerHandler.

    */ public static final String STRIP_WHITESPACE = "http://saxon.sf.net/feature/strip-whitespace"; /** * STYLE_PARSER_CLASS must be an XMLReader. This identifies the parser used for stylesheets and * schema modules. */ public static final String STYLE_PARSER_CLASS = "http://saxon.sf.net/feature/styleParserClass"; /** * TIMING must be an Boolean; it determines whether basic timing information is output to System.err * (This attribute is a bit of a misnomer; it outputs timing information when used from the command line, * but also basic tracing information when used from the Java API: for example, names of output files * written using xsl:result-document, and names of classes dynamically loaded) */ public static final String TIMING = "http://saxon.sf.net/feature/timing"; /** * TRACE_EXTERNAL_FUNCTIONS must be a Boolean; it determines whether the loading and binding of extension * functions is traced */ public static final String TRACE_EXTERNAL_FUNCTIONS = "http://saxon.sf.net/feature/trace-external-functions"; /** * TRACE_OPTIMIZER_DECISIONS must be a Boolean; it determines whether decisions made by the optimizer * are traced */ public static final String TRACE_OPTIMIZER_DECISIONS = "http://saxon.sf.net/feature/trace-optimizer-decisions"; /** * TRACE_LISTENER must be an instance of a class that implements * {@link net.sf.saxon.trace.TraceListener}. Setting this property automatically * sets {@link #COMPILE_WITH_TRACING} to true. */ public static final String TRACE_LISTENER = "http://saxon.sf.net/feature/traceListener"; /** * TRACE_LISTENER_CLASS must be the name of a class that implements * {@link net.sf.saxon.trace.TraceListener}. A new instance of this class will be created * as the trace listener for each query or transformation run under this Configuration. * Setting this property automatically * sets {@link #COMPILE_WITH_TRACING} to true. */ public static final String TRACE_LISTENER_CLASS = "http://saxon.sf.net/feature/traceListenerClass"; /** * TREE_MODEL must be an Integer: {@link net.sf.saxon.event.Builder#LINKED_TREE} * or {@link net.sf.saxon.event.Builder#TINY_TREE} */ public static final String TREE_MODEL = "http://saxon.sf.net/feature/treeModel"; /** * TREE_MODEL_NAME must be a string: "linkedTree" or "tinyTree" */ public static final String TREE_MODEL_NAME = "http://saxon.sf.net/feature/treeModelName"; /** * USE_PI_DISABLE_OUTPUT_ESCAPING must be a Boolean. This determines whether a TransformerHandler * created with this Factory or Configuration recognizes the processing instructions * Result.PI_DISABLE_OUTPUT_ESCAPING and Result.PI_ENABLE_OUTPUT_ESCAPING * in the input stream as instructions to disable or to re-enable output escaping. */ public static final String USE_PI_DISABLE_OUTPUT_ESCAPING = "http://saxon.sf.net/feature/use-pi-disable-output-escaping"; /** * USE_XSI_SCHEMA_LOCATION must be a Boolean. This determines whether the schema processor * takes notice of (and attempts to dereference) URIs specified in the xsi:schemaLocation * and xsi:noNamespaceSchemaLocation attributes of the instance document. The default is true. */ public static final String USE_XSI_SCHEMA_LOCATION = "http://saxon.sf.net/feature/useXsiSchemaLocation"; /** * VALIDATION_WARNINGS must be a Boolean. This determines whether validation errors in result * documents should be treated as fatal. By default they are fatal; with this option set, they * are treated as warnings. */ public static final String VALIDATION_WARNINGS = "http://saxon.sf.net/feature/validation-warnings"; /** * VERSION_WARNING must be a Boolean. This determines whether a warning should be output when * running an XSLT 2.0 processor against an XSLT 1.0 stylesheet. The XSLT specification requires * this to be done by default. */ public static final String VERSION_WARNING = "http://saxon.sf.net/feature/version-warning"; /** * XINCLUDE must be a Boolean. This determines whether XInclude processing should be performed by default * when XML source documents (including stylesheets and schemas) are read. */ public static final String XINCLUDE = "http://saxon.sf.net/feature/xinclude-aware"; /** * XML_VERSION is a character string. This determines the XML version used by the Configuration: the * value must be "1.0" or "1.1". For details, see {@link Configuration#setXMLVersion(int)}. * *

    Note that source documents specifying xml version="1.0" or "1.1" are accepted * regardless of this setting. The effect of this switch is to change the validation * rules for types such as Name and NCName, to change the meaning of \i and \c in * regular expressions, and to determine whether the serializer allows XML 1.1 documents * to be constructed.

    */ public static final String XML_VERSION = "http://saxon.sf.net/feature/xml-version"; /** * XSD_VERSION is a character string. This determines the version of XML Schema used by the Configuration: the * value must be "1.0" or "1.1". */ public static final String XSD_VERSION = "http://saxon.sf.net/feature/xsd-version"; private FeatureKeys() { } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/sort/0000755000175000017500000000000012216261750016375 5ustar eugeneeugenesaxonb-9.1.0.8/bj/net/sf/saxon/sort/LocalOrderComparer.java0000644000175000017500000000307211033351443022754 0ustar eugeneeugenepackage net.sf.saxon.sort; import net.sf.saxon.om.NodeInfo; import java.io.Serializable; /** * A Comparer used for comparing nodes in document order. This * comparer assumes that the nodes being compared come from the same document * * @author Michael H. Kay * */ public final class LocalOrderComparer implements NodeOrderComparer, Serializable { private static LocalOrderComparer instance = new LocalOrderComparer(); /** * Get an instance of a LocalOrderComparer. The class maintains no state * so this returns the same instance every time. */ public static LocalOrderComparer getInstance() { return instance; } public int compare(NodeInfo a, NodeInfo b) { NodeInfo n1 = (NodeInfo)a; NodeInfo n2 = (NodeInfo)b; return n1.compareOrder(n2); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none //saxonb-9.1.0.8/bj/net/sf/saxon/sort/TupleSorter.java0000644000175000017500000002104111033351443021521 0ustar eugeneeugenepackage net.sf.saxon.sort; import net.sf.saxon.expr.*; import net.sf.saxon.om.Item; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.om.SingletonIterator; import net.sf.saxon.trace.ExpressionPresenter; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.AnyItemType; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.TypeHierarchy; import net.sf.saxon.value.ObjectValue; import net.sf.saxon.value.StringValue; import net.sf.saxon.value.Value; import java.util.Iterator; /** * A TupleSorter is an expression that sorts a stream of tuples. It is used * to implement XQuery FLWR expressions. */ public class TupleSorter extends Expression { private Expression select; private SortKeyDefinition[] sortKeyDefinitions; private AtomicComparer[] comparators; /** * Create a TupleSorter * @param base The base expression returns the sequence of tuples to be sorted. Each tuple is * represented by an ObjectValue which wraps a Value (that is, in general, a sequence) * @param keys Although this class uses the SortKeyDefinition class to define the sort keys, * the actual sort key expression in the SortKeyDefinition is not used. This is because * the sort key is instead computed as one of the members of the tuple delivered by the * TupleSorter. Therefore, the sort key expression is not managed as a child of this expression. * Moreover, in xquery the other aspects of a sort key are always fixed statically, so we * don't treat those as subexpressions either. */ public TupleSorter(Expression base, SortKeyDefinition[] keys) { select = base; sortKeyDefinitions = keys; adoptChildExpression(base); } /** * Get the array of AtomicComparer objects, one per sort key, that are used to compare values in the sequence * @return an array of AtomicComparer objects, one per sort key */ public AtomicComparer[] getComparators() { return comparators; } /** * Get the base expression, the expression that computes the sequence to be sorted * @return the base expression */ public Expression getBaseExpression() { return select; } public Expression simplify(ExpressionVisitor visitor) throws XPathException { select = visitor.simplify(select); return this; } public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { select = visitor.typeCheck(select, contextItemType); if (comparators == null) { comparators = new AtomicComparer[sortKeyDefinitions.length]; final XPathContext context = visitor.getStaticContext().makeEarlyEvaluationContext(); for (int i=0; iLinkedHashMap. * Synthesized and simplified from various published examples of the genre. * The methods are not synchronized. */ public class LRUCache { private LinkedHashMap map; /** * Creates a new LRU cache. * * @param cacheSize the maximum number of entries that will be kept in this cache. */ public LRUCache(final int cacheSize) { map = new LinkedHashMap(cacheSize, 0.75f, true) { protected boolean removeEldestEntry(Map.Entry eldest) { return cacheSize < size(); } }; } /** * Retrieves an entry from the cache.
    * The retrieved entry becomes the most recently used entry. * * @param key the key whose associated value is to be returned. * @return the value associated to this key, or null if no value with this key exists in the cache. */ public Object get(Object key) { return map.get(key); } /** * Adds an entry to this cache. * If the cache is full, the LRU (least recently used) entry is dropped. * * @param key the key with which the specified value is to be associated. * @param value a value to be associated with the specified key. */ public void put(Object key, Object value) { map.put(key, value); } /** * Clear the cache */ public void clear() { map.clear(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/sort/NodeOrderComparer.java0000644000175000017500000000210511033351443022603 0ustar eugeneeugenepackage net.sf.saxon.sort; import net.sf.saxon.om.NodeInfo; /** * A Comparer used for comparing nodes in document order * * @author Michael H. Kay * */ public interface NodeOrderComparer { /** * Compare two objects. * @return <0 if a0 if a>b */ public int compare(NodeInfo a, NodeInfo b); } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none //saxonb-9.1.0.8/bj/net/sf/saxon/sort/DocumentSorter.java0000644000175000017500000001011211033351443022203 0ustar eugeneeugenepackage net.sf.saxon.sort; import net.sf.saxon.expr.*; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.trace.ExpressionPresenter; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ItemType; /** * A DocumentSorter is an expression that sorts a sequence of nodes into * document order. */ public class DocumentSorter extends UnaryExpression { private NodeOrderComparer comparer; public DocumentSorter(Expression base) { super(base); int props = base.getSpecialProperties(); if (((props & StaticProperty.CONTEXT_DOCUMENT_NODESET) != 0) || (props & StaticProperty.SINGLE_DOCUMENT_NODESET) != 0) { comparer = LocalOrderComparer.getInstance(); } else { comparer = GlobalOrderComparer.getInstance(); } } public NodeOrderComparer getComparer() { return comparer; } public Expression simplify(ExpressionVisitor visitor) throws XPathException { operand = visitor.simplify(operand); if ((operand.getSpecialProperties() & StaticProperty.ORDERED_NODESET) != 0) { // this can happen as a result of further simplification return operand; } return this; } public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { operand = visitor.optimize(operand, contextItemType); if ((operand.getSpecialProperties() & StaticProperty.ORDERED_NODESET) != 0) { // this can happen as a result of further simplification return operand; } if (operand instanceof PathExpression) { return visitor.getConfiguration().getOptimizer().makeConditionalDocumentSorter( this, (PathExpression)operand); } return this; } public int computeSpecialProperties() { return operand.getSpecialProperties() | StaticProperty.ORDERED_NODESET; } /** * Copy an expression. This makes a deep copy. * * @return the copy of the original expression */ public Expression copy() { return new DocumentSorter(getBaseExpression().copy()); } /** * Promote this expression if possible */ public Expression promote(PromotionOffer offer) throws XPathException { Expression exp = offer.accept(this); if (exp != null) { return exp; } else { operand = doPromotion(operand, offer); return this; } } public SequenceIterator iterate(XPathContext context) throws XPathException { //System.err.println("** SORTING **"); return new DocumentOrderIterator(operand.iterate(context), comparer); } public boolean effectiveBooleanValue(XPathContext context) throws XPathException { return operand.effectiveBooleanValue(context); } /** * Diagnostic print of expression structure. The abstract expression tree * is written to the supplied output destination. */ public void explain(ExpressionPresenter out) { out.startElement("sortAndDeduplicate"); out.emitAttribute("intraDocument", comparer instanceof LocalOrderComparer ? "true" : "false"); operand.explain(out); out.endElement(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none //saxonb-9.1.0.8/bj/net/sf/saxon/sort/IntHashSet.java0000644000175000017500000003002711156423042021250 0ustar eugeneeugenepackage net.sf.saxon.sort; import net.sf.saxon.om.FastStringBuffer; import java.io.Serializable; /** * Set of int values. This class is modelled on the java.net.Set interface, but it does * not implement this interface, because the set members are int's rather than Objects. *

    * Not thread safe. * * @author Dominique Devienne * @author Michael Kay: retrofitted to JDK 1.4, added iterator() */ public class IntHashSet implements IntSet, Serializable { private static final int NBIT = 30; // MAX_SIZE = 2^NBIT /** * The maximum number of elements this container can contain. */ public static final int MAX_SIZE = 1 << NBIT; // maximum number of keys mapped /** * This set's NO-DATA-VALUE. */ public final int ndv; /** * Initializes a set with a capacity of 8 and a load factor of 0,25. * */ public IntHashSet() { this(8, Integer.MIN_VALUE); } /** * Initializes a set with the given capacity and a load factor of 0,25. * * @param capacity the initial capacity. */ public IntHashSet(int capacity) { this(capacity, Integer.MIN_VALUE); } /** * Initializes a set with a load factor of 0,25. * * @param capacity the initial capacity. * @param noDataValue the value to use for non-values. */ public IntHashSet(int capacity, int noDataValue) { ndv = noDataValue; //_factor = 0.25; setCapacity(capacity); } public void clear() { _size = 0; for (int i = 0; i < _nmax; ++i) { _values[i] = ndv; } } public int size() { return _size; } public boolean isEmpty() { return _size == 0; } public int getFirst(int defaultValue) { for (int v=0; v<_values.length; v++) { if (_values[v] != ndv) { return _values[v]; } } return defaultValue; } public int[] getValues() { int index = 0; final int[] values = new int[_size]; for (int v=0; v<_values.length; v++) { if (_values[v] != ndv) { values[index++] = _values[v]; } } return values; } public boolean contains(int value) { return (_values[indexOf(value)] != ndv); } public boolean remove(int value) { // Knuth, v. 3, 527, Algorithm R. int i = indexOf(value); if (_values[i] == ndv) { return false; } --_size; for (; ;) { _values[i] = ndv; int j = i; int r; do { i = (i - 1) & _mask; if (_values[i] == ndv) { return true; } r = hash(_values[i]); } while ((i <= r && r < j) || (r < j && j < i) || (j < i && i <= r)); _values[j] = _values[i]; } } public boolean add(int value) { if (value == ndv) { throw new IllegalArgumentException("Can't add the 'no data' value"); } int i = indexOf(value); if (_values[i] == ndv) { ++_size; _values[i] = value; // Check new size if (_size > MAX_SIZE) { throw new RuntimeException("Too many elements (> " + MAX_SIZE + ')'); } if (_nlo < _size && _size <= _nhi) { setCapacity(_size); } return true; } else { return false; // leave set unchanged } } /////////////////////////////////////////////////////////////////////////// // private //private double _factor; // 0.0 <= _factor <= 1.0 - changed by MHK to assume factor = 0.25 private int _nmax; // 0 <= _nmax = 2^nbit <= 2^NBIT = MAX_SIZE private int _size; // 0 <= _size <= _nmax <= MAX_SIZE private int _nlo; // _nmax*_factor (_size<=_nlo, if possible) private int _nhi; // MAX_SIZE*_factor (_size< _nhi, if possible) private int _shift; // _shift = 1 + NBIT - nbit (see function hash() below) private int _mask; // _mask = _nmax - 1 private int[] _values; // array[_nmax] of values private int hash(int key) { // Knuth, v. 3, 509-510. Randomize the 31 low-order bits of c*key // and return the highest nbits (where nbits <= 30) bits of these. // The constant c = 1327217885 approximates 2^31 * (sqrt(5)-1)/2. return ((1327217885 * key) >> _shift) & _mask; } /** * Gets the index of the value, if it exists, or the index at which * this value would be added if it does not exist yet. */ private int indexOf(int value) { int i = hash(value); while (_values[i] != ndv) { if (_values[i] == value) { return i; } i = (i - 1) & _mask; } return i; } private void setCapacity(int capacity) { // Changed MHK in 8.9 to use a constant factor of 0.25, thus avoiding floating point arithmetic if (capacity < _size) { capacity = _size; } //double factor = 0.25; int nbit, nmax; for (nbit = 1, nmax = 2; nmax < capacity * 4 && nmax < MAX_SIZE; ++nbit, nmax *= 2) { ; } int nold = _nmax; if (nmax == nold) { return; } _nmax = nmax; _nlo = (int)(nmax / 4); _nhi = (int)(MAX_SIZE / 4); _shift = 1 + NBIT - nbit; _mask = nmax - 1; _size = 0; int[] values = _values; _values = new int[nmax]; java.util.Arrays.fill(_values, ndv); // empty all values if (values != null) { for (int i = 0; i < nold; ++i) { int value = values[i]; if (value != ndv) { // Don't use add, because the capacity is necessarily large enough, // and the value is necessarily unique (since in this set already)! //add(values[i]); ++_size; _values[indexOf(value)] = value; } } } } /** * Get an iterator over the values */ public IntIterator iterator() { return new IntHashSetIterator(); } /** * Form a new set that is a copy of this set. */ public IntHashSet copy() { IntHashSet n = new IntHashSet((int)(size())); IntIterator it = iterator(); while (it.hasNext()) { n.add(it.next()); } return n; } /** * Form a new set that is the union of this set with another set. */ public IntHashSet union(IntHashSet other) { IntHashSet n = new IntHashSet((int)(size() + other.size())); IntIterator it = iterator(); while (it.hasNext()) { n.add(it.next()); } it = other.iterator(); while (it.hasNext()) { n.add(it.next()); } return n; } /** * Form a new set that is the intersection of this set with another set. */ public IntHashSet intersect(IntHashSet other) { IntHashSet n = new IntHashSet((int)size()); IntIterator it = iterator(); while (it.hasNext()) { int v = it.next(); if (other.contains(v)) { n.add(v); } } return n; } /** * Form a new set that is the difference of this set with another set. */ public IntHashSet except(IntHashSet other) { IntHashSet n = new IntHashSet((int)size()); IntIterator it = iterator(); while (it.hasNext()) { int v = it.next(); if (!other.contains(v)) { n.add(v); } } return n; } /** * Test if this set is a superset of another set */ public boolean containsAll(IntSet other) { IntIterator it = other.iterator(); while (it.hasNext()) { if (!contains(it.next())) { return false; } } return true; } /** * Test if this set has overlapping membership with another set */ public boolean containsSome(IntHashSet other) { IntIterator it = other.iterator(); while (it.hasNext()) { if (contains(it.next())) { return true; } } return false; } /** * Test whether this set has exactly the same members as another set */ public boolean equals(Object other) { if (other instanceof IntSet) { IntHashSet s = (IntHashSet)other; return (size() == s.size() && containsAll(s)); } else { return false; } } /** * Construct a hash key that supports the equals() test */ public int hashCode() { // Note, hashcodes are the same as those used by IntArraySet int h = 936247625; IntIterator it = iterator(); while (it.hasNext()) { h += it.next(); } return h; } /** * Diagnostic output */ public void diagnosticDump() { System.err.println("Contents of IntHashSet"); FastStringBuffer sb = new FastStringBuffer(100); for (int i = 0; i < _values.length; i++) { if (i % 10 == 0) { System.err.println(sb.toString()); sb.setLength(0); } if (_values[i] == ndv) { sb.append("*, "); } else { sb.append(_values[i] + ", "); } } System.err.println(sb.toString()); sb.setLength(0); System.err.println("size: " + _size); System.err.println("ndv: " + ndv); System.err.println("nlo: " + _nlo); System.err.println("nhi: " + _nhi); System.err.println("nmax: " + _nmax); System.err.println("shift: " + _shift); System.err.println("mask: " + _mask); System.err.println("Result of iterator:"); IntIterator iter = iterator(); int i = 0; while (iter.hasNext()) { if (i++ % 10 == 0) { System.err.println(sb.toString()); sb.setLength(0); } sb.append(iter.next() + ", "); } System.err.println(sb.toString()); System.err.println("====================="); } /** * Iterator class */ private class IntHashSetIterator implements IntIterator, Serializable { private int i = 0; public IntHashSetIterator() { i = 0; } public boolean hasNext() { while (i < _values.length) { if (_values[i] != ndv) { return true; } else { i++; } } return false; } public int next() { return _values[i++]; } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Dominique Devienne of Landmark Graphics. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. saxonb-9.1.0.8/bj/net/sf/saxon/sort/StandardCollationURIResolver.java0000644000175000017500000001341111240776702024753 0ustar eugeneeugenepackage net.sf.saxon.sort; import net.sf.saxon.Configuration; import net.sf.saxon.om.FastStringBuffer; import net.sf.saxon.trans.XPathException; import javax.xml.transform.TransformerException; import java.net.URI; import java.net.URISyntaxException; import java.util.Properties; import java.util.StringTokenizer; import java.nio.ByteBuffer; import java.nio.charset.Charset; /** * StandardCollationURIResolver allows a Collation to be created given * a URI starting with "http://saxon.sf.net/collation" followed by a set of query parameters. */ public class StandardCollationURIResolver implements CollationURIResolver { private static final StandardCollationURIResolver theInstance = new StandardCollationURIResolver(); /** * The class is a singleton */ private StandardCollationURIResolver() { } /** * Return the singleton instance of this class */ public static final StandardCollationURIResolver getInstance() { return theInstance; } /** * Create a collator from a parameterized URI * @return null if the collation URI is not recognized. If the collation URI is recognized but contains * errors, the method returns null after sending a warning to the ErrorListener. */ public StringCollator resolve(String uri, String base, Configuration config) { try { if (uri.equals("http://saxon.sf.net/collation")) { return Configuration.getPlatform().makeCollation(config, new Properties(), uri); } else if (uri.startsWith("http://saxon.sf.net/collation?")) { URI uuri; try { uuri = new URI(uri); } catch (URISyntaxException err) { throw new XPathException(err); } Properties props = new Properties(); String query = uuri.getRawQuery(); StringTokenizer queryTokenizer = new StringTokenizer(query, ";&"); while (queryTokenizer.hasMoreElements()) { String param = queryTokenizer.nextToken(); int eq = param.indexOf('='); if (eq > 0 && eq < param.length()-1) { String kw = param.substring(0, eq); String val = decode(param.substring(eq + 1)); props.setProperty(kw, val); } } return Configuration.getPlatform().makeCollation(config, props, uri); } else { return null; } } catch (XPathException e) { try { config.getErrorListener().warning(e); } catch (TransformerException e1) { // } return null; } } public static String decode(String s) { // Evaluates all escapes in s, applying UTF-8 decoding if needed. Assumes // that escapes are well-formed syntactically, i.e., of the form %XX. If a // sequence of escaped octets is not valid UTF-8 then the erroneous octets // are replaced with '\uFFFD'. // Exception: any "%" found between "[]" is left alone. It is an IPv6 literal // with a scope_id // if (s == null) { return s; } int n = s.length(); if (n == 0) { return s; } if (s.indexOf('%') < 0) { return s; } FastStringBuffer sb = new FastStringBuffer(n); ByteBuffer bb = ByteBuffer.allocate(n); Charset utf8 = Charset.forName("UTF-8"); // This is not horribly efficient, but it will do for now char c = s.charAt(0); boolean betweenBrackets = false; for (int i = 0; i < n;) { assert c == s.charAt(i); // Loop invariant if (c == '[') { betweenBrackets = true; } else if (betweenBrackets && c == ']') { betweenBrackets = false; } if (c != '%' || betweenBrackets) { sb.append(c); if (++i >= n) { break; } c = s.charAt(i); continue; } bb.clear(); for (; ;) { assert (n - i >= 2); bb.put(hex(s.charAt(++i), s.charAt(++i))); if (++i >= n) { break; } c = s.charAt(i); if (c != '%') { break; } } bb.flip(); sb.append(utf8.decode(bb)); } return sb.toString(); } private static byte hex(char high, char low) { return (byte)((hexToDec(high)<<4) | hexToDec(low)); } private static int hexToDec(char c) { if (c >= '0' && c <= '9') { return c - '0'; } else if (c >= 'a' && c <= 'f') { return c - 'a' + 10; } else if (c >= 'A' && c <= 'F') { return c - 'A' + 10; } else { return 0; } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/sort/DecimalSortComparer.java0000644000175000017500000000361011033351443023132 0ustar eugeneeugenepackage net.sf.saxon.sort; import net.sf.saxon.om.StandardNames; import net.sf.saxon.value.AtomicValue; /** * An AtomicComparer used for sorting values that are known to be instances of xs:decimal (including xs:integer), * It also supports a separate method for getting a collation key to test equality of items * * @author Michael H. Kay * */ public class DecimalSortComparer extends ComparableAtomicValueComparer { private static DecimalSortComparer THE_INSTANCE = new DecimalSortComparer(); public static DecimalSortComparer getDecimalSortComparerInstance() { return THE_INSTANCE; } private DecimalSortComparer() {} /** * Get a comparison key for an object. This must satisfy the rule that if two objects are equal as defined * by the XPath eq operator, then their comparison keys are equal as defined by the Java equals() method, * and vice versa. There is no requirement that the comparison keys should reflect the ordering of the * underlying objects. */ public ComparisonKey getComparisonKey(AtomicValue a) { return new ComparisonKey(StandardNames.XS_NUMERIC, a); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none //saxonb-9.1.0.8/bj/net/sf/saxon/sort/GroupIterator.java0000644000175000017500000000373311033351443022047 0ustar eugeneeugenepackage net.sf.saxon.sort; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.AtomicValue; /** * A GroupIterator is an iterator that iterates over a sequence of groups. * The normal methods such as next() and current() always deliver the leading item * of the group. Additional methods are available to get the grouping key for the * current group (only applicable to group-by and group-adjacent), and to get all the * members of the current group. */ public interface GroupIterator extends SequenceIterator { /** * Get the grouping key of the current group * @return the current grouping key in the case of group-by or group-adjacent, * or null in the case of group-starting-with and group-ending-with */ public AtomicValue getCurrentGroupingKey(); /** * Get an iterator over the members of the current group, in population * order. This must always be a clean iterator, that is, an iterator that * starts at the first item of the group. * @return an iterator over all the members of the current group, in population * order. */ public SequenceIterator iterateCurrentGroup() throws XPathException; } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none //saxonb-9.1.0.8/bj/net/sf/saxon/sort/NumericComparer.java0000644000175000017500000001300211033351443022322 0ustar eugeneeugenepackage net.sf.saxon.sort; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.StandardNames; import net.sf.saxon.value.AtomicValue; import net.sf.saxon.value.DoubleValue; import net.sf.saxon.value.NumericValue; import net.sf.saxon.value.Value; /** * A Comparer used for comparing sort keys when data-type="number". The items to be * compared are converted to numbers, and the numbers are then compared directly. NaN values * compare equal to each other, and equal to an empty sequence, but less than anything else. *

    * This class is used in XSLT only, so there is no need to handle XQuery's "empty least" vs * "empty greatest" options. * * @author Michael H. Kay * */ public class NumericComparer implements AtomicComparer, java.io.Serializable { private static NumericComparer THE_INSTANCE = new NumericComparer(); public static NumericComparer getInstance() { return THE_INSTANCE; } private NumericComparer() { } /** * Supply the dynamic context in case this is needed for the comparison * @param context the dynamic evaluation context * @return either the original AtomicComparer, or a new AtomicComparer in which the context * is known. The original AtomicComparer is not modified */ public AtomicComparer provideContext(XPathContext context) { return this; } /** * Compare two Items by converting them to numbers and comparing the numeric values. If either * value cannot be converted to a number, it is treated as NaN, and compares less that the other * (two NaN values compare equal). * @param a the first Item to be compared. * @param b the second Item to be compared. * @return <0 if a0 if a>b * @throws ClassCastException if the objects are not Items */ public int compareAtomicValues(AtomicValue a, AtomicValue b) { double d1, d2; if (a instanceof NumericValue) { d1 = ((NumericValue)a).getDoubleValue(); } else if (a == null) { d1 = Double.NaN; } else { try { d1 = Value.stringToNumber(a.getStringValueCS()); } catch (NumberFormatException err) { d1 = Double.NaN; } } if (b instanceof NumericValue) { d2 = ((NumericValue)b).getDoubleValue(); } else if (b == null) { d2 = Double.NaN; } else { try { d2 = Value.stringToNumber(b.getStringValueCS()); } catch (NumberFormatException err) { d2 = Double.NaN; } } if (Double.isNaN(d1)) { if (Double.isNaN(d2)) { return 0; } else { return -1; } } if (Double.isNaN(d2)) { return +1; } if (d1 < d2) return -1; if (d1 > d2) return +1; return 0; } /** * Compare two AtomicValue objects for equality according to the rules for their data type. UntypedAtomic * values are compared by converting to the type of the other operand. * * @param a the first object to be compared. * @param b the second object to be compared. * @return true if the values are equal, false if not * @throws ClassCastException if the objects are not comparable */ public boolean comparesEqual(AtomicValue a, AtomicValue b) { return compareAtomicValues(a, b) == 0; } /** * Get a comparison key for an object. This must satisfy the rule that if two objects are equal * according to the XPath eq operator, then their comparison keys are equal according to the Java * equals() method, and vice versa. There is no requirement that the * comparison keys should reflect the ordering of the underlying objects. */ public ComparisonKey getComparisonKey(AtomicValue a) { if (a instanceof NumericValue) { return new ComparisonKey(StandardNames.XS_NUMERIC, toDoubleValue(((NumericValue)a))); } else if (a == null) { return new ComparisonKey(StandardNames.XS_NUMERIC, "NaN"); } else { try { double d = Value.stringToNumber(a.getStringValueCS()); return new ComparisonKey(StandardNames.XS_NUMERIC, new DoubleValue(d)); } catch (NumberFormatException err) { return new ComparisonKey(StandardNames.XS_NUMERIC, "NaN"); } } } private DoubleValue toDoubleValue(NumericValue nv) { if (nv instanceof DoubleValue) { return ((DoubleValue)nv); } else { return new DoubleValue(nv.getDoubleValue()); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of this module is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. //saxonb-9.1.0.8/bj/net/sf/saxon/sort/RuleBasedSubstringMatcher.java0000644000175000017500000002474711033351443024324 0ustar eugeneeugenepackage net.sf.saxon.sort; import net.sf.saxon.Configuration; import net.sf.saxon.om.FastStringBuffer; import java.text.CollationElementIterator; import java.text.RuleBasedCollator; /** * This class wraps a RuleBasedCollator to provide a SubstringMatcher. This * users the facilities offered by the RuleBasedCollator to implement the XPath * functions contains(), starts-with(), ends-with(), substring-before(), and * substring-after(). */ public class RuleBasedSubstringMatcher implements SubstringMatcher { private RuleBasedCollator collator; /** * Create a RuleBasedSubstringMatcher * @param collator the collation to be used */ public RuleBasedSubstringMatcher(RuleBasedCollator collator) { this.collator = collator; } /** * Test whether one string is equal to another, according to the rules * of the XPath compare() function. The result is true if and only if the * compare() method returns zero: but the implementation may be more efficient * than calling compare and testing the result for zero * * @param s1 the first string * @param s2 the second string * @return true iff s1 equals s2 */ public boolean comparesEqual(String s1, String s2) { return collator.compare(s1, s2) == 0; } /** * Test whether one string contains another, according to the rules * of the XPath contains() function * * @param s1 the containing string * @param s2 the contained string * @return true iff s1 contains s2 */ public boolean contains(String s1, String s2) { CollationElementIterator iter1 = collator.getCollationElementIterator(s1); CollationElementIterator iter2 = collator.getCollationElementIterator(s2); return collationContains(iter1, iter2, null, false); } /** * Test whether one string ends with another, according to the rules * of the XPath ends-with() function * * @param s1 the containing string * @param s2 the contained string * @return true iff s1 ends with s2 */ public boolean endsWith(String s1, String s2) { CollationElementIterator iter1 = collator.getCollationElementIterator(s1); CollationElementIterator iter2 = collator.getCollationElementIterator(s2); return collationContains(iter1, iter2, null, true); } /** * Test whether one string starts with another, according to the rules * of the XPath starts-with() function * * @param s1 the containing string * @param s2 the contained string * @return true iff s1 starts with s2 */ public boolean startsWith(String s1, String s2) { CollationElementIterator iter1 = collator.getCollationElementIterator(s1); CollationElementIterator iter2 = collator.getCollationElementIterator(s2); return collationStartsWith(iter1, iter2); } /** * Return the part of a string after a given substring, according to the rules * of the XPath substring-after() function * * @param s1 the containing string * @param s2 the contained string * @return the part of s1 that follows the first occurrence of s2 */ public String substringAfter(String s1, String s2) { CollationElementIterator iter1 = collator.getCollationElementIterator(s1); CollationElementIterator iter2 = collator.getCollationElementIterator(s2); int[] ia = new int[2]; boolean ba = collationContains(iter1, iter2, ia, false); if (ba) { return s1.substring(ia[1]); } else { return ""; } } /** * Return the part of a string before a given substring, according to the rules * of the XPath substring-before() function * * @param s1 the containing string * @param s2 the contained string * @return the part of s1 that precedes the first occurrence of s2 */ public String substringBefore(String s1, String s2) { CollationElementIterator iter1 = collator.getCollationElementIterator(s1); CollationElementIterator iter2 = collator.getCollationElementIterator(s2); int[] ib = new int[2]; boolean bb = collationContains(iter1, iter2, ib, false); if (bb) { return s1.substring(0, ib[0]); } else { return ""; } } /** * Determine whether one string starts with another, under the terms of a given * collating sequence. * @param s0 iterator over the collation elements of the containing string * @param s1 iterator over the collation elements of the contained string * @return true if the first string starts with the second */ private boolean collationStartsWith(CollationElementIterator s0, CollationElementIterator s1) { while (true) { int e0, e1; do { e1 = s1.next(); } while (e1 == 0); if (e1 == -1) { return true; } do { e0 = s0.next(); } while (e0 == 0); if (e0 != e1) { return false; } } } /** * Determine whether one string contains another, under the terms of a given * collating sequence. If matchAtEnd=true, the match must be at the end of the first * string. * @param s0 iterator over the collation elements of the containing string * @param s1 iterator over the collation elements of the contained string * @param offsets may be null, but if it is supplied, it must be an array of two * integers which, if the function returns true, will contain the start position of the * first matching substring, and the offset of the first character after the first * matching substring. This is not available for matchAtEnd=true * @param matchAtEnd true if the match is required to be at the end of the string * @return true if the first string contains the second */ private boolean collationContains(CollationElementIterator s0, CollationElementIterator s1, int[] offsets, boolean matchAtEnd) { int e0, e1; do { e1 = s1.next(); } while (e1 == 0); if (e1 == -1) { return true; } e0 = -1; while (true) { // scan the first string to find a matching character while (e0 != e1) { do { e0 = s0.next(); } while (e0 == 0); if (e0 == -1) { // hit the end, no match return false; } } // matched first character, note the position of the possible match int start = s0.getOffset(); if (collationStartsWith(s0, s1)) { if (matchAtEnd) { do { e0 = s0.next(); } while (e0 == 0); if (e0 == -1) { // the match is at the end return true; } // else ignore this match and keep looking } else { if (offsets != null) { offsets[0] = start-1; offsets[1] = s0.getOffset(); } return true; } } // reset the position and try again s0.setOffset(start); // workaround for a difference between JDK 1.4.0 and JDK 1.4.1 if (s0.getOffset() != start) { // JDK 1.4.0 takes this path s0.next(); } s1.reset(); e0 = -1; do { e1 = s1.next(); } while (e1 == 0); // loop round to try again } } /** * Compare two strings * * @param o1 the first string * @param o2 the second string * @return 0 if the strings are considered equal, a negative integer if the first string is less than the second, * a positive integer if the first string is greater than the second */ public int compareStrings(String o1, String o2) { return collator.compare(o1, o2); } /** * Get a collation key for two Strings. The essential property of collation keys * is that if two values are equal under the collation, then the collation keys are * compare correctly under the equals() method. */ public Object getCollationKey(String s) { return null; //AUTO } /** * Test program to output the sequence of collation element iterators for a given input string * @param args command line arguments (collationURI, test-string) */ public static void main(String[] args) { Configuration config = new Configuration(); StringCollator collator = StandardCollationURIResolver.getInstance().resolve(args[0], args[0], config); FastStringBuffer sb = new FastStringBuffer(100); if (collator instanceof RuleBasedCollator) { CollationElementIterator iter = ((RuleBasedCollator)collator).getCollationElementIterator(args[1]); while (true) { int e = iter.next(); if (e==-1) { break; } sb.append(e+" "); } System.err.println(sb.toString()); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/sort/TerminatedIntIterator.java0000644000175000017500000000422411033351443023516 0ustar eugeneeugenepackage net.sf.saxon.sort; /** * An iterator over a sequence of integers held in an array. The array * may either be exactly the right size, or may be terminated by an end-of-sequence value. * *

    This data structure is generally used for a sequence of namespace codes.

    */ public class TerminatedIntIterator implements IntIterator { int[] values; int index; int terminator = -1; /** * Construct an iterator over a sequence of integers held in an array, with * the value -1 acting as the terminator * @param values the sequence of integers */ public TerminatedIntIterator(int[] values) { this.values = values; index = 0; } /** * Construct an iterator over a sequence of integers held in an array, with * a specified value acting as the terminator * @param values the sequence of integers * @param terminator the terminator value */ public TerminatedIntIterator(int[] values, int terminator) { this.values = values; index = 0; this.terminator = terminator; } /** * Test whether there are any more integers in the sequence */ public boolean hasNext() { return index < values.length-1 && values[index] != terminator; } /** * Return the next integer in the sequence. The result is undefined unless hasNext() has been called * and has returned true. */ public int next() { return values[index++]; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/sort/DoubleSortComparer.java0000644000175000017500000001043411033351443023010 0ustar eugeneeugenepackage net.sf.saxon.sort; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.StandardNames; import net.sf.saxon.value.AtomicValue; import net.sf.saxon.value.NumericValue; /** * An AtomicComparer used for sorting values that are known to be numeric. * It also supports a separate method for getting a collation key to test equality of items. * This comparator treats NaN values as equal to each other, and less than any other value. * * @author Michael H. Kay * */ public class DoubleSortComparer implements AtomicComparer { private static DoubleSortComparer THE_INSTANCE = new DoubleSortComparer(); /** * Get the singular instance of this class * @return the singular instance */ public static DoubleSortComparer getInstance() { return THE_INSTANCE; } private DoubleSortComparer() { } /** * Supply the dynamic context in case this is needed for the comparison * * @param context the dynamic evaluation context * @return either the original AtomicComparer, or a new AtomicComparer in which the context * is known. The original AtomicComparer is not modified */ public AtomicComparer provideContext(XPathContext context) { return this; } /** * Compare two AtomicValue objects according to the rules for their data type. * @param a the first object to be compared. It is intended that this should normally be an instance * of AtomicValue, though this restriction is not enforced. If it is a StringValue, the * collator is used to compare the values, otherwise the value must implement the java.util.Comparable * interface. * @param b the second object to be compared. This must be comparable with the first object: for * example, if one is a string, they must both be strings. * @return <0 if a0 if a>b * @throws ClassCastException if the objects are not comparable */ public int compareAtomicValues(AtomicValue a, AtomicValue b) { if (a == null) { if (b == null) { return 0; } else { return -1; } } else if (b == null) { return +1; } NumericValue an = (NumericValue)a; NumericValue bn = (NumericValue)b; if (an.isNaN()) { return (bn.isNaN() ? 0 : -1); } else if (bn.isNaN()) { return +1; } return an.compareTo(bn); } /** * Test whether two values compare equal. Note that for this comparer, NaN is considered equal to itself */ public boolean comparesEqual(AtomicValue a, AtomicValue b) { return compareAtomicValues(a, b) == 0; } /** * Get a comparison key for an object. This must satisfy the rule that if two objects are equal as defined * by the XPath eq operator, then their comparison keys are equal as defined by the Java equals() method, * and vice versa. There is no requirement that the comparison keys should reflect the ordering of the * underlying objects. */ public ComparisonKey getComparisonKey(AtomicValue a) { if (((NumericValue)a).isNaN()) { // Deal with NaN specially. For sorting and similar operations, NaN is considered equal to itself return new ComparisonKey(StandardNames.XS_NUMERIC, AtomicSortComparer.COLLATION_KEY_NaN); } else { return new ComparisonKey(StandardNames.XS_NUMERIC, a); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none //saxonb-9.1.0.8/bj/net/sf/saxon/sort/EmptyIntIterator.java0000644000175000017500000000305711033351443022523 0ustar eugeneeugenepackage net.sf.saxon.sort; /** * An iterator over a zero-length sequence of integers */ public class EmptyIntIterator implements IntIterator { private static EmptyIntIterator THE_INSTANCE = new EmptyIntIterator(); /** * Get the singular instance of this class * @return the singular instance */ public static EmptyIntIterator getInstance() { return THE_INSTANCE; } private EmptyIntIterator() {} /** * Test whether there are any more integers in the sequence * * @return true if there are more integers to come */ public boolean hasNext() { return false; } /** * Return the next integer in the sequence. The result is undefined unless hasNext() has been called * and has returned true. * * @return the next integer in the sequence */ public int next() { return 0; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/sort/TextComparer.java0000644000175000017500000001031411033351443021647 0ustar eugeneeugenepackage net.sf.saxon.sort; import net.sf.saxon.value.AtomicValue; import net.sf.saxon.value.StringValue; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.trans.NoDynamicContextException; /** * A Comparer used for comparing sort keys when data-type="text". The items to be * compared are converted to strings, and the strings are then compared using an * underlying collator * * @author Michael H. Kay * */ public class TextComparer implements AtomicComparer, java.io.Serializable { private AtomicComparer baseComparer; public TextComparer(AtomicComparer baseComparer) { this.baseComparer = baseComparer; } /** * Get the underlying comparer (which doesn't do conversion to string) */ public AtomicComparer getBaseComparer() { return baseComparer; } /** * Supply the dynamic context in case this is needed for the comparison * @param context the dynamic evaluation context * @return either the original AtomicComparer, or a new AtomicComparer in which the context * is known. The original AtomicComparer is not modified * @throws net.sf.saxon.trans.NoDynamicContextException if the context is an "early evaluation" (compile-time) context */ public AtomicComparer provideContext(XPathContext context) { AtomicComparer newBase = baseComparer.provideContext(context); if (newBase != baseComparer) { return new TextComparer(newBase); } else { return this; } } /** * Compare two Items by converting them to strings and comparing the string values. * @param a the first Item to be compared. * @param b the second Item to be compared. * @return <0 if a0 if a>b * @throws ClassCastException if the objects are not Items, or are items that cannot be convered * to strings (e.g. QNames) */ public int compareAtomicValues(AtomicValue a, AtomicValue b) throws ClassCastException, NoDynamicContextException { return baseComparer.compareAtomicValues(toStringValue(a), toStringValue(b)); } private StringValue toStringValue(AtomicValue a) { if (a instanceof StringValue) { return ((StringValue)a); } else { return new StringValue((a == null ? "" : a.getStringValue())); } } /** * Compare two AtomicValue objects for equality according to the rules for their data type. UntypedAtomic * values are compared by converting to the type of the other operand. * * @param a the first object to be compared. * @param b the second object to be compared. * @return true if the values are equal, false if not * @throws ClassCastException if the objects are not comparable */ public boolean comparesEqual(AtomicValue a, AtomicValue b) throws NoDynamicContextException { return compareAtomicValues(a, b) == 0; } /** * Get a comparison key for an object. This must satisfy the rule that if two objects are equal * according to the XPath eq operator, then their comparison keys are equal according to the Java * equals() method, and vice versa. There is no requirement that the * comparison keys should reflect the ordering of the underlying objects. */ public ComparisonKey getComparisonKey(AtomicValue a) throws NoDynamicContextException{ return baseComparer.getComparisonKey(toStringValue(a)); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of this module is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. //saxonb-9.1.0.8/bj/net/sf/saxon/sort/IntToIntArrayMap.java0000644000175000017500000001166211033351443022406 0ustar eugeneeugenepackage net.sf.saxon.sort; import java.io.Serializable; /** * An implementation of {@link IntToIntMap} that relies on serial searching, and * is therefore optimized for very small map sizes */ public class IntToIntArrayMap implements IntToIntMap, Serializable { private int[] keys; private int[] values; private int used = 0; private int defaultValue = Integer.MIN_VALUE; /** * Create an initial empty map with default space allocation */ public IntToIntArrayMap() { keys = new int[8]; values = new int[8]; } /** * Create an initial empty map with a specified initial capacity * @param capacity the initial capacity (the number of entries that can be held * before more space is allocated) */ public IntToIntArrayMap(int capacity) { if (capacity <= 0) { throw new IllegalArgumentException("capacity <= 0"); } keys = new int[capacity]; values = new int[capacity]; } /** * Clear the map. */ public void clear() { used = 0; } /** * Finds a key in the map. * * @param key Key * @return true if the key is mapped */ public boolean find(int key) { for (int i=0; iThe contents of the hash map must not be modified while this iterator remains in use

    * @return an iterator whose next() call returns the key values (in arbitrary order) */ public IntIterator keyIterator() { return new KeyIterator(); } /** * Adds a key-value pair to the map. * * @param key Key * @param value Value */ public void put(int key, int value) { for (int i=0; i= keys.length) { int[] k2 = new int[used*2]; System.arraycopy(keys, 0, k2, 0, used); keys = k2; int[] v2 = new int[used*2]; System.arraycopy(values, 0, v2, 0, used); values = v2; } keys[used] = key; values[used++] = value; } /** * Removes a key from the map. * * @param key Key to remove * @return true if the value was removed */ public boolean remove(int key) { for (int i=0; i0 if obj[a]>obj[b] */ public int compare(int a, int b); /** * Swap two objects within this Sortable, identified by their position. */ public void swap(int a, int b); } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none //saxonb-9.1.0.8/bj/net/sf/saxon/sort/CollatingAtomicComparer.java0000644000175000017500000001300511033351443023774 0ustar eugeneeugenepackage net.sf.saxon.sort; import net.sf.saxon.Platform; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.NamespaceConstant; import net.sf.saxon.om.StandardNames; import net.sf.saxon.value.AtomicValue; /** * An AtomicComparer used for comparing strings, untypedAtomic values, and URIs using a collation. * A CollatingAtomicComparer is used when it is known in advance that both operands will be of these * types. This enables all conversions and promotions to be bypassed: the string values of both operands * are simply extracted and passed to the collator for comparison. * * @author Michael H. Kay * */ public class CollatingAtomicComparer implements AtomicComparer { private StringCollator collator; private String collationURI; private boolean canReturnCollationKeys; /** * Create an GenericAtomicComparer * @param collator the collation to be used. If the method is called at compile time, this should * be a NamedCollation so that it can be cloned at run-time. * @param platform used to obtain collation keys. */ public CollatingAtomicComparer(StringCollator collator, Platform platform) { if (collator == null) { this.collator = CodepointCollator.getInstance(); collationURI = NamespaceConstant.CODEPOINT_COLLATION_URI; } else { this.collator = collator; collationURI = "*unknown*"; } canReturnCollationKeys = platform.canReturnCollationKeys(this.collator); } /** * Supply the dynamic context in case this is needed for the comparison * * @param context the dynamic evaluation context * @return either the original AtomicComparer, or a new AtomicComparer in which the context * is known. The original AtomicComparer is not modified */ public AtomicComparer provideContext(XPathContext context) { return this; } /** * Get the collation URI * @return the collation URI */ public String getCollationURI() { return collationURI; } /** * Compare two AtomicValue objects according to the rules for their data type. UntypedAtomic * values are compared as if they were strings; if different semantics are wanted, the conversion * must be done by the caller. * @param a the first object to be compared. It is intended that this should be an instance * of AtomicValue, though this restriction is not enforced. If it is a StringValue, the * collator is used to compare the values, otherwise the value must implement the java.util.Comparable * interface. * @param b the second object to be compared. This must be comparable with the first object: for * example, if one is a string, they must both be strings. * @return <0 if a0 if a>b * @throws ClassCastException if the objects are not comparable */ public int compareAtomicValues(AtomicValue a, AtomicValue b) { if (a == null) { if (b == null) { return 0; } else { return -1; } } else if (b == null) { return +1; } return collator.compareStrings(a.getStringValue(), b.getStringValue()); } /** * Compare two AtomicValue objects for equality according to the rules for their data type. UntypedAtomic * values are compared by converting to the type of the other operand. * @param a the first object to be compared. It is intended that this should be an instance * of AtomicValue, though this restriction is not enforced. If it is a StringValue, the * collator is used to compare the values, otherwise the value must implement the equals() method. * @param b the second object to be compared. This must be comparable with the first object: for * example, if one is a string, they must both be strings. * @return <0 if a0 if a>b * @throws ClassCastException if the objects are not comparable */ public boolean comparesEqual(AtomicValue a, AtomicValue b) { return compareAtomicValues(a, b) == 0; } /** * Get a comparison key for an object. This must satisfy the rule that if two objects are equal, * then their comparison keys are equal, and vice versa. There is no requirement that the * comparison keys should reflect the ordering of the underlying objects. */ public ComparisonKey getComparisonKey(AtomicValue a) { if (canReturnCollationKeys) { return new ComparisonKey(StandardNames.XS_STRING, collator.getCollationKey(a.getStringValue())); } else { return new ComparisonKey(StandardNames.XS_STRING, a.getStringValue()); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none //saxonb-9.1.0.8/bj/net/sf/saxon/sort/CodepointCollatingComparer.java0000644000175000017500000001233711033351443024513 0ustar eugeneeugenepackage net.sf.saxon.sort; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.StandardNames; import net.sf.saxon.value.AtomicValue; import net.sf.saxon.value.StringValue; /** * An AtomicComparer used for comparing strings, untypedAtomic values, and URIs using the Unicode codepoint * collation. * A CodepointCollatingComparer is used when it is known in advance that both operands will be of these * types, and when the collation is the unicode codepoint collation. * This enables all conversions and promotions to be bypassed: the string values of both operands * are simply extracted and passed to the collator for comparison. * *

    The difference between using this class and using the underlying CodepointCollator directly is that * the compare() method in this class expects two instances of AtomicValue as its operands, whereas the * underlying class expects two instances of java.lang.String. This class makes use of the extra information * held in the wrapping StringValue object, specifically, the knowledge of whether the string contains * surrogate pairs.

    * * @author Michael H. Kay * */ public class CodepointCollatingComparer implements AtomicComparer { private static CodepointCollator collator = CodepointCollator.getInstance(); private static CodepointCollatingComparer THE_INSTANCE = new CodepointCollatingComparer(); /** * Get the singular instance of this class * @return the singleton instance */ public static CodepointCollatingComparer getInstance() { return THE_INSTANCE; } private CodepointCollatingComparer() {} /** * Supply the dynamic context in case this is needed for the comparison * * @param context the dynamic evaluation context * @return either the original AtomicComparer, or a new AtomicComparer in which the context * is known. The original AtomicComparer is not modified */ public AtomicComparer provideContext(XPathContext context) { return this; } /** * Compare two AtomicValue objects according to the rules for their data type. UntypedAtomic * values are compared as if they were strings; if different semantics are wanted, the conversion * must be done by the caller. * @param a the first object to be compared. This must be either be an instance * of AtomicValue, or null to represent an empty sequence. Empty collates before non-empty. * @param b the second object to be compared. This must be either be an instance * of AtomicValue, or null to represent an empty sequence. * @return <0 if a0 if a>b * @throws ClassCastException if the objects are not comparable */ public int compareAtomicValues(AtomicValue a, AtomicValue b) { if (a == null) { return (b == null ? 0 : -1); } else if (b == null) { return +1; } StringValue as = (StringValue)a; StringValue bs = (StringValue)b; if (as.containsSurrogatePairs() || bs.containsSurrogatePairs()) { return collator.compareCS(as.getStringValueCS(), bs.getStringValueCS()); } else { // optimize to use UTF-16 binary comparison return as.getStringValue().compareTo(bs.getStringValue()); } } /** * Compare two AtomicValue objects for equality. The values must be instances of xs:string or a type * derived from xs:string. The method will also handle xs:untypedAtomic and xs:anyURI values. * @param a the first object to be compared. * @param b the second object to be compared. * @return <0 if a0 if a>b * @throws ClassCastException if either value is not xs:string or a subtype */ public boolean comparesEqual(AtomicValue a, AtomicValue b) { StringValue as = (StringValue)a; StringValue bs = (StringValue)b; return as.codepointEquals(bs); } /** * Get a comparison key for an object. This must satisfy the rule that if two objects are equal * under the XPath eq operator, then their comparison keys are equal under the Java equals() * function, and vice versa. There is no requirement that the * comparison keys should reflect the ordering of the underlying objects. */ public ComparisonKey getComparisonKey(AtomicValue a) { StringValue as = (StringValue)a; return new ComparisonKey(StandardNames.XS_STRING, as.getStringValue()); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none //saxonb-9.1.0.8/bj/net/sf/saxon/sort/IntArraySet.java0000644000175000017500000002621211033351443021443 0ustar eugeneeugenepackage net.sf.saxon.sort; import net.sf.saxon.om.FastStringBuffer; import java.io.Serializable; import java.util.Arrays; /** * Set of int values. This class is modelled on the java.net.Set interface, but it does * not implement this interface, because the set members are int's rather than Objects. *

    * This implementation of a set of integers is optimized to use very little storage * and to provide fast comparison of two sets. The equals() method determines whether * two sets contain the same integers. *

    * This implementation is not efficient at adding new integers to the set. It creates a new * array each time you do that. *

    * Not thread safe. * * @author Michael Kay */ public class IntArraySet implements Serializable, IntSet { public static final int[] EMPTY_INT_ARRAY = new int[0]; /** * The array of integers, which will always be sorted */ private int[] contents; /** * Hashcode, evaluated lazily */ private int hashCode = -1; /** * Create an empty set */ public IntArraySet() { contents = EMPTY_INT_ARRAY; } /** * Create a set containing integers from the specified IntHashSet * @param input the set to be copied */ public IntArraySet(IntHashSet input) { // exploits the fact that getValues() constructs a new array contents = input.getValues(); //System.err.println("new IntArraySet(" + contents.length + ")"); Arrays.sort(contents); } /** * Create one IntArraySet as a copy of another * @param input the set to be copied */ public IntArraySet(IntArraySet input) { contents = new int[input.contents.length]; System.arraycopy(input.contents, 0, contents, 0, contents.length); } public void clear() { contents = EMPTY_INT_ARRAY; hashCode = -1; } public int size() { return contents.length; } public boolean isEmpty() { return contents.length == 0; } /** * Get the set of integer values as an array * @return a sorted array of integers */ public int[] getValues() { return contents; } public boolean contains(int value) { return Arrays.binarySearch(contents, value) >= 0; } public boolean remove(int value) { hashCode = -1; int pos = Arrays.binarySearch(contents, value); if (pos < 0) { return false; } int[] newArray = new int[contents.length - 1]; if (pos > 0) { // copy the items before the one that's being removed System.arraycopy(contents, 0, newArray, 0, pos); } if (pos < newArray.length) { // copy the items after the one that's being removed System.arraycopy(contents, pos+1, newArray, pos, contents.length - pos); } contents = newArray; return true; } /** * Add an integer to the set * @param value the integer to be added * @return true if the integer was added, false if it was already present */ public boolean add(int value) { hashCode = -1; if (contents.length == 0) { contents = new int[] {value}; return true; } int pos = Arrays.binarySearch(contents, value); if (pos >= 0) { return false; // value was already present } pos = -pos - 1; // new insertion point int[] newArray = new int[contents.length + 1]; if (pos > 0) { // copy the items before the insertion point System.arraycopy(contents, 0, newArray, 0, pos); } newArray[pos] = value; if (pos < contents.length) { // copy the items after the insertion point System.arraycopy(contents, pos, newArray, pos+1, newArray.length - pos); } contents = newArray; return true; } /** * Get the first value in the set. * @return the first value in the set, in sorted order * @throws ArrayIndexOutOfBoundsException if the set is empty */ public int getFirst() { return contents[0]; } /** * Get an iterator over the values * @return an iterator over the values, which will be delivered in sorted order */ public IntIterator iterator() { return new IntArraySetIterator(); } /** * Form a new set that is the union of this set with another set. * @param other the other set * @return the union of the two sets */ public IntArraySet union(IntArraySet other) { // Look for special cases: one set empty, or both sets equal if (size() == 0) { return new IntArraySet(other); } else if (other.isEmpty()) { return new IntArraySet(this); } if (equals(other)) { return this; } // Form the union by a merge of the two sorted arrays int[] merged = new int[size() + other.size()]; int[] a = contents; int[] b = other.contents; int m = a.length, n = b.length; int o=0, i=0, j=0; while (true) { if (a[i] < b[j]) { merged[o++] = a[i++]; } else if (b[j] < a[i]) { merged[o++] = b[j++]; } else { merged[o++] = a[i++]; j++; } if (i == m) { System.arraycopy(b, j, merged, o, n-j); o += (n-j); return make(merged, o); } else if (j == n) { System.arraycopy(a, i, merged, o, m-i); o += (m-i); return make(merged, o); } } } /** * Factory method to construct a set from an array of integers * @param in the array of integers, which must be in ascending order * @param size the number of elements in the array that are significant * @return the constructed set */ public static IntArraySet make(int[] in, int size) { int[] out; if (in.length == size) { out = in; } else { out = new int[size]; System.arraycopy(in, 0, out, 0, size); } return new IntArraySet(out); } private IntArraySet(int[] content) { contents = content; } public String toString() { FastStringBuffer sb = new FastStringBuffer(contents.length*4); for (int i=0; i0 if a>b * @throws ClassCastException if the objects are not comparable */ public int compareAtomicValues(AtomicValue a, AtomicValue b) throws NoDynamicContextException { if (a == null) { return (b == null ? 0 : -1); } else if (b == null) { return +1; } return ((CalendarValue)a).compareTo((CalendarValue)b, context); } /** * Compare two AtomicValue objects for equality according to the rules for their data type. UntypedAtomic * values are compared by converting to the type of the other operand. * * @param a the first object to be compared. It is intended that this should be an instance * of AtomicValue, though this restriction is not enforced. If it is a StringValue, the * collator is used to compare the values, otherwise the value must implement the equals() method. * @param b the second object to be compared. This must be comparable with the first object: for * example, if one is a string, they must both be strings. * @return true if the values are equal, false if not * @throws ClassCastException if the objects are not comparable */ public boolean comparesEqual(AtomicValue a, AtomicValue b) throws NoDynamicContextException { return compareAtomicValues(a, b) == 0; } /** * Get a comparison key for an object. This must satisfy the rule that if two objects are equal, * then their comparison keys are equal, and vice versa. There is no requirement that the * comparison keys should reflect the ordering of the underlying objects. */ public ComparisonKey getComparisonKey(AtomicValue a) throws NoDynamicContextException { return ((CalendarValue)a).getComparisonKey(context); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/sort/AlphanumericCollator.java0000644000175000017500000001056611033351443023353 0ustar eugeneeugenepackage net.sf.saxon.sort; import net.sf.saxon.om.FastStringBuffer; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * A Comparer that treats strings as an alternating sequence of alpha parts and numeric parts. The * alpha parts are compared using a base collation supplied as a parameter; the numeric parts are * compared numerically. "Numeric" here means a sequence of consecutive ASCII digits 0-9. *

    * Note: this StringCollator produces an ordering that is not compatible with equals(). *

    */ public class AlphanumericCollator implements StringCollator, java.io.Serializable { private StringCollator baseCollator; private static Pattern pattern = Pattern.compile("\\d+"); /** * Create an alphanumeric collation * @param base the collation used to compare the alphabetic parts of the string */ public AlphanumericCollator(StringCollator base) { baseCollator = base; } /** * Compare two objects. * @return <0 if a0 if a>b */ public int compareStrings(String s1, String s2) { int pos1 = 0; int pos2 = 0; Matcher m1 = pattern.matcher(s1); Matcher m2 = pattern.matcher(s2); while (true) { // find the next number in each string boolean b1 = m1.find(pos1); boolean b2 = m2.find(pos2); int m1start = (b1 ? m1.start() : s1.length()); int m2start = (b2 ? m2.start() : s2.length()); // compare an alphabetic pair (even if zero-length) int c = baseCollator.compareStrings(s1.substring(pos1, m1start), s2.substring(pos2, m2start)); if (c != 0) { return c; } // if one match found a number and the other didn't, exit accordingly if (b1 && !b2) { return +1; } else if (b2 && !b1) { return -1; } else if (!b1 && !b2) { return 0; } // a number was found in each of the strings: compare the numbers int n1 = Integer.parseInt(s1.substring(m1start, m1.end())); int n2 = Integer.parseInt(s2.substring(m2start, m2.end())); if (n1 != n2) { return (n1 - n2); } // the numbers are equal: move on to the next part of the string pos1 = m1.end(); pos2 = m2.end(); } } /** * Get a collation key for two Strings. The essential property of collation keys * is that if two values are equal under the collation, then the collation keys are * compare correctly under the equals() method. */ public Object getCollationKey(String s) { // The string is normalized by removing leading zeros in a numeric component FastStringBuffer sb = new FastStringBuffer(s.length()*2); int pos1 = 0; Matcher m1 = pattern.matcher(s); while (true) { // find the next number in the string boolean b1 = m1.find(pos1); int m1start = (b1 ? m1.start() : s.length()); // handle an alphabetic part (even if zero-length) sb.append(s.substring(pos1, m1start)); // reached end? if (!b1) { return sb.toString(); } // handle a numeric part int n1 = Integer.parseInt(s.substring(m1start, m1.end())); sb.append(n1 + ""); // move on to the next part of the string pos1 = m1.end(); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none //saxonb-9.1.0.8/bj/net/sf/saxon/sort/IntToIntHashMap.java0000644000175000017500000002113411033351443022206 0ustar eugeneeugenepackage net.sf.saxon.sort; import java.io.Serializable; /** * A hash table that maps int keys to int values. * * @author Dave Hale, Landmark Graphics * @author Dominique Devienne * @author Michael Kay: created this class based on IntHashMap */ public class IntToIntHashMap implements Serializable, IntToIntMap { /** * Initializes a map with a capacity of 8 and a load factor of 0,25. */ public IntToIntHashMap() { this(8, 0.25); } /** * Initializes a map with the given capacity and a load factor of 0,25. * * @param capacity the initial capacity. */ public IntToIntHashMap(int capacity) { this(capacity, 0.25); } /** * Constructs a new map with initial capacity, and load factor. *

    * The capacity is the number of keys that can be mapped without resizing * the arrays in which keys and values are stored. For efficiency, only * a fraction of the elements in those arrays are used. That fraction is * the specified load factor. The initial length of the arrays equals the * smallest power of two not less than the ratio capacity/factor. The * capacity of the map is increased, as necessary. The maximum number * of keys that can be mapped is 2^30. * * @param capacity the initial capacity. * @param factor the load factor. */ public IntToIntHashMap(int capacity, double factor) { _factor = factor; setCapacity(capacity); } /** * Set the value to be returned to indicate an unused entry * @param defaultValue the value to be returned by {@link #get(int)} if no entry * exists for the supplied key */ public void setDefaultValue(int defaultValue) { _defaultValue = defaultValue; } /** * Get the default value used to indicate an unused entry * @return the value to be returned by {@link #get(int)} if no entry * exists for the supplied key */ public int getDefaultValue() { return _defaultValue; } /** * Clears the map. */ public void clear() { _n = 0; for (int i = 0; i < _nmax; ++i) { _filled[i] = false; } } /** * Finds a key in the map. * * @param key Key * @return true if the key is mapped */ public boolean find(int key) { return _filled[indexOf(key)]; } /** * Gets the value for this key. * * @param key Key * @return the value, or the default value if not found. */ public int get(int key) { int i = indexOf(key); return _filled[i] ? _value[i] : _defaultValue; } /** * Gets the size of the map. * * @return the size */ public int size() { return _n; } /** * Removes a key from the map. * * @param key Key to remove * @return true if the value was removed */ public boolean remove(int key) { // Knuth, v. 3, 527, Algorithm R. int i = indexOf(key); if (!_filled[i]) { return false; } --_n; for (; ;) { _filled[i] = false; int j = i; int r; do { i = (i - 1) & _mask; if (!_filled[i]) { return true; } r = hash(_key[i]); } while ((i <= r && r < j) || (r < j && j < i) || (j < i && i <= r)); _key[j] = _key[i]; _value[j] = _value[i]; _filled[j] = _filled[i]; } } /** * Adds a key-value pair to the map. * * @param key Key * @param value Value */ public void put(int key, int value) { int i = indexOf(key); if (_filled[i]) { _value[i] = value; } else { _key[i] = key; _value[i] = value; _filled[i] = true; grow(); } } /** * Get an iterator over the integer key values held in the hash map * @return an iterator whose next() call returns the key values (in arbitrary order) */ public IntIterator keyIterator() { return new IntToIntHashMapKeyIterator(); } /////////////////////////////////////////////////////////////////////////// // private private static final int NBIT = 30; // NMAX = 2^NBIT private static final int NMAX = 1 << NBIT; // maximum number of keys mapped private double _factor; // 0.0 <= _factor <= 1.0 private int _defaultValue = Integer.MAX_VALUE; private int _nmax; // 0 <= _nmax = 2^nbit <= 2^NBIT = NMAX private int _n; // 0 <= _n <= _nmax <= NMAX private int _nlo; // _nmax*_factor (_n<=_nlo, if possible) private int _nhi; // NMAX*_factor (_n< _nhi, if possible) private int _shift; // _shift = 1 + NBIT - nbit (see function hash() below) private int _mask; // _mask = _nmax - 1 private int[] _key; // array[_nmax] of keys //@SuppressWarnings(value = {"unchecked"}) private int[] _value; // array[_nmax] of values private boolean[] _filled; // _filled[i]==true iff _key[i] is mapped private int hash(int key) { // Knuth, v. 3, 509-510. Randomize the 31 low-order bits of c*key // and return the highest nbits (where nbits <= 30) bits of these. // The constant c = 1327217885 approximates 2^31 * (sqrt(5)-1)/2. return ((1327217885 * key) >> _shift) & _mask; } private int indexOf(int key) { int i = hash(key); while (_filled[i]) { if (_key[i] == key) { return i; } i = (i - 1) & _mask; } return i; } private void grow() { ++_n; if (_n > NMAX) { throw new RuntimeException("number of keys mapped exceeds " + NMAX); } if (_nlo < _n && _n <= _nhi) { setCapacity(_n); } } private void setCapacity(int capacity) { if (capacity < _n) { capacity = _n; } double factor = (_factor < 0.01) ? 0.01 : (_factor > 0.99) ? 0.99 : _factor; int nbit, nmax; for (nbit = 1, nmax = 2; nmax * factor < capacity && nmax < NMAX; ++nbit, nmax *= 2) { // no-op } int nold = _nmax; if (nmax == nold) { return; } _nmax = nmax; _nlo = (int)(nmax * factor); _nhi = (int)(NMAX * factor); _shift = 1 + NBIT - nbit; _mask = nmax - 1; int[] key = _key; int[] value = _value; boolean[] filled = _filled; _n = 0; _key = new int[nmax]; // semantically equivalent to _value = new V[nmax] _value = new int[nmax]; _filled = new boolean[nmax]; if (key != null) { for (int i = 0; i < nold; ++i) { if (filled[i]) { put(key[i], value[i]); } } } } /** * Iterator over keys */ private class IntToIntHashMapKeyIterator implements IntIterator, Serializable { private int i = 0; private static final long serialVersionUID = -5978261613309710617L; public IntToIntHashMapKeyIterator() { i = 0; } public boolean hasNext() { while (i < _key.length) { if (_filled[i]) { return true; } else { i++; } } return false; } public int next() { return _key[i++]; } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Dave Hale and Dominique Devienne of Landmark Graphics; // the code was retrofitted to JDK 1.4 by Michael Kay, Saxonica. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. saxonb-9.1.0.8/bj/net/sf/saxon/sort/EqualityComparer.java0000644000175000017500000001002011033351443022512 0ustar eugeneeugenepackage net.sf.saxon.sort; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.value.AtomicValue; /** * A comparer for comparing two atomic values where (a) equals is defined, and is implemented * using the Java equals() method, and (b) ordering is not defined, and results in a dynamic error. */ public class EqualityComparer implements AtomicComparer { public static EqualityComparer THE_INSTANCE = new EqualityComparer(); /** * Get the singleton instance of this class * @return the singleton instance of this class */ public static EqualityComparer getInstance() { return THE_INSTANCE; } private EqualityComparer() {} /** * Supply the dynamic context in case this is needed for the comparison * @param context the dynamic evaluation context * @return either the original AtomicComparer, or a new AtomicComparer in which the context * is known. The original AtomicComparer is not modified */ public AtomicComparer provideContext(XPathContext context) { return this; } /** * Compare two AtomicValue objects according to the rules for their data type. UntypedAtomic * values are compared as if they were strings; if different semantics are wanted, the conversion * must be done by the caller. * * @param a the first object to be compared. It is intended that this should be an instance * of AtomicValue, though this restriction is not enforced. If it is a StringValue, the * collator is used to compare the values, otherwise the value must implement the java.util.Comparable * interface. * @param b the second object to be compared. This must be comparable with the first object: for * example, if one is a string, they must both be strings. * @return <0 if a0 if a>b * @throws ClassCastException if the objects are not comparable */ public int compareAtomicValues(AtomicValue a, AtomicValue b) { throw new ClassCastException("Values are not comparable"); } /** * Compare two AtomicValue objects for equality according to the rules for their data type. UntypedAtomic * values are compared by converting to the type of the other operand. * @param a the first object to be compared. This must be an AtomicValue and it must implement * equals() with context-free XPath comparison semantics * @param b the second object to be compared. This must be an AtomicValue and it must implement * equals() with context-free XPath comparison semantics * @return true if the values are equal, false if not * @throws ClassCastException if the objects are not comparable */ public boolean comparesEqual(AtomicValue a, AtomicValue b) { return a.equals(b); } /** * Get a comparison key for an object. This must satisfy the rule that if two objects are equal, * then their comparison keys are equal, and vice versa. There is no requirement that the * comparison keys should reflect the ordering of the underlying objects. */ public ComparisonKey getComparisonKey(AtomicValue a) { return new ComparisonKey(a.getPrimitiveType().getFingerprint(), a); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/sort/GroupAdjacentIterator.java0000644000175000017500000001327311033351443023501 0ustar eugeneeugenepackage net.sf.saxon.sort; import net.sf.saxon.expr.Expression; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.Item; import net.sf.saxon.om.ListIterator; import net.sf.saxon.om.LookaheadIterator; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.Type; import net.sf.saxon.value.AtomicValue; import java.util.ArrayList; import java.util.List; /** * A GroupAdjacentIterator iterates over a sequence of groups defined by * xsl:for-each-group group-adjacent="x". The groups are returned in * order of first appearance. *

    * Each step of this iterator advances to the first item of the next group, * leaving the members of that group in a saved list. */ public class GroupAdjacentIterator implements GroupIterator, LookaheadIterator { private SequenceIterator population; private Expression keyExpression; private StringCollator collator; private AtomicComparer comparer; private ComparisonKey currentComparisonKey; private XPathContext baseContext; private XPathContext runningContext; private AtomicValue currentKey = null; private List currentMembers; private AtomicValue nextKey = null; private Item next; private Item current = null; private int position = 0; public GroupAdjacentIterator(SequenceIterator population, Expression keyExpression, XPathContext baseContext, StringCollator collator) throws XPathException { this.population = population; this.keyExpression = keyExpression; this.baseContext = baseContext; this.runningContext = baseContext.newMinorContext(); runningContext.setCurrentIterator(population); this.collator = collator; int type = keyExpression.getItemType(baseContext.getConfiguration().getTypeHierarchy()).getPrimitiveType(); this.comparer = AtomicSortComparer.makeSortComparer(collator, type, baseContext); next = population.next(); if (next != null) { nextKey = (AtomicValue)keyExpression.evaluateItem(runningContext); } } private void advance() throws XPathException { currentMembers = new ArrayList(20); currentMembers.add(current); while (true) { Item nextCandidate = population.next(); if (nextCandidate == null) { break; } AtomicValue candidateKey = (AtomicValue)keyExpression.evaluateItem(runningContext); try { if (currentComparisonKey.equals(comparer.getComparisonKey(candidateKey))) { currentMembers.add(nextCandidate); } else { next = nextCandidate; nextKey = candidateKey; return; } } catch (ClassCastException e) { XPathException err = new XPathException("Grouping key values are of non-comparable types (" + Type.displayTypeName(currentKey) + " and " + Type.displayTypeName(candidateKey) + ')'); err.setIsTypeError(true); err.setXPathContext(runningContext); throw err; } } next = null; nextKey = null; } public AtomicValue getCurrentGroupingKey() { return currentKey; } public SequenceIterator iterateCurrentGroup() { return new ListIterator(currentMembers); } public boolean hasNext() { return next != null; } public Item next() throws XPathException { if (next == null) { current = null; position = -1; return null; } current = next; currentKey = nextKey; currentComparisonKey = comparer.getComparisonKey(currentKey); position++; advance(); return current; } public Item current() { return current; } public int position() { return position; } public void close() { population.close(); } public SequenceIterator getAnother() throws XPathException { return new GroupAdjacentIterator(population.getAnother(), keyExpression, baseContext, collator); } /** * Get properties of this iterator, as a bit-significant integer. * * @return the properties of this iterator. This will be some combination of * properties such as {@link #GROUNDED}, {@link #LAST_POSITION_FINDER}, * and {@link #LOOKAHEAD}. It is always * acceptable to return the value zero, indicating that there are no known special properties. * It is acceptable for the properties of the iterator to change depending on its state. */ public int getProperties() { return LOOKAHEAD; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none //saxonb-9.1.0.8/bj/net/sf/saxon/sort/GenericAtomicComparer.java0000644000175000017500000002401511033351443023437 0ustar eugeneeugenepackage net.sf.saxon.sort; import net.sf.saxon.Configuration; import net.sf.saxon.Platform; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.StandardNames; import net.sf.saxon.trans.NoDynamicContextException; import net.sf.saxon.type.BuiltInAtomicType; import net.sf.saxon.type.Type; import net.sf.saxon.value.AtomicValue; import net.sf.saxon.value.CalendarValue; import net.sf.saxon.value.StringValue; import java.io.Serializable; /** * An AtomicComparer used for comparing atomic values of arbitrary item types. It encapsulates * a Collator that is used when the values to be compared are strings. It also supports * a separate method for testing equality of items, which can be used for data types that * are not ordered. * * @author Michael H. Kay * */ public class GenericAtomicComparer implements AtomicComparer, Serializable { private StringCollator collator; private transient XPathContext context; /** * Create an GenericAtomicComparer * @param collator the collation to be used * @param conversion a context, used when converting untyped atomic values to the target type. */ public GenericAtomicComparer(StringCollator collator, XPathContext conversion) { this.collator = collator; if (collator == null) { this.collator = CodepointCollator.getInstance(); } context = conversion; } /** * Factory method to make a GenericAtomicComparer for values of known types * @param type0 primitive type of the first operand * @param type1 primitive type of the second operand * @param collator the collation to be used, if any. This is supplied as a NamedCollation object * which encapsulated both the collation URI and the collation itself. * @param context the dynamic context * @return a GenericAtomicComparer for values of known types */ public static AtomicComparer makeAtomicComparer( BuiltInAtomicType type0, BuiltInAtomicType type1, StringCollator collator, XPathContext context) { int fp0 = type0.getFingerprint(); int fp1 = type1.getFingerprint(); if (fp0 == fp1) { switch (fp0) { case StandardNames.XS_DATE_TIME: case StandardNames.XS_DATE: case StandardNames.XS_TIME: case StandardNames.XS_G_DAY: case StandardNames.XS_G_MONTH: case StandardNames.XS_G_YEAR: case StandardNames.XS_G_MONTH_DAY: case StandardNames.XS_G_YEAR_MONTH: return new CalendarValueComparer(context); case StandardNames.XS_BOOLEAN: case StandardNames.XS_DAY_TIME_DURATION: case StandardNames.XS_YEAR_MONTH_DURATION: return ComparableAtomicValueComparer.getInstance(); case StandardNames.XS_BASE64_BINARY: case StandardNames.XS_HEX_BINARY: case StandardNames.XS_QNAME: case StandardNames.XS_NOTATION: return EqualityComparer.getInstance(); } } if (type0.isPrimitiveNumeric() && type1.isPrimitiveNumeric()) { return ComparableAtomicValueComparer.getInstance(); } if ((fp0 == StandardNames.XS_STRING || fp0 == StandardNames.XS_UNTYPED_ATOMIC || fp0 == StandardNames.XS_ANY_URI) && (fp1 == StandardNames.XS_STRING || fp1 == StandardNames.XS_UNTYPED_ATOMIC || fp1 == StandardNames.XS_ANY_URI)) { if (collator instanceof CodepointCollator) { return CodepointCollatingComparer.getInstance(); } else { return new CollatingAtomicComparer(collator, Configuration.getPlatform()); } } return new GenericAtomicComparer(collator, context); } /** * Supply the dynamic context in case this is needed for the comparison * * @param context the dynamic evaluation context * @return either the original AtomicComparer, or a new AtomicComparer in which the context * is known. The original AtomicComparer is not modified */ public AtomicComparer provideContext(XPathContext context) { return new GenericAtomicComparer(collator, context); } /** * Get the underlying string collator * @return the string collator */ public StringCollator getStringCollator() { return collator; } /** * Compare two AtomicValue objects according to the rules for their data type. UntypedAtomic * values are compared as if they were strings; if different semantics are wanted, the conversion * must be done by the caller. * @param a the first object to be compared. It is intended that this should be an instance * of AtomicValue, though this restriction is not enforced. If it is a StringValue, the * collator is used to compare the values, otherwise the value must implement the java.util.Comparable * interface. * @param b the second object to be compared. This must be comparable with the first object: for * example, if one is a string, they must both be strings. * @return <0 if a < b, 0 if a = b, >0 if a > b * @throws ClassCastException if the objects are not comparable * @throws NoDynamicContextException if this comparer required access to dynamic context information, * notably the implicit timezone, and this information is not available. In general this happens if a * context-dependent comparison is attempted at compile-time, and it signals the compiler to generate * code that tries again at run-time. */ public int compareAtomicValues(AtomicValue a, AtomicValue b) throws NoDynamicContextException { // System.err.println("Comparing " + a.getClass() + "(" + a + ") with " + b.getClass() + "(" + b + ") using " + collator); if (a == null) { return (b == null ? 0 : -1); } else if (b == null) { return +1; } if (a instanceof StringValue && b instanceof StringValue) { if (collator instanceof CodepointCollator) { return ((CodepointCollator)collator).compareCS(a.getStringValueCS(), b.getStringValueCS()); } else { return collator.compareStrings(a.getStringValue(), b.getStringValue()); } } else { Comparable ac = (Comparable)a.getXPathComparable(true, collator, context); Comparable bc = (Comparable)b.getXPathComparable(true, collator, context); if (ac == null || bc == null) { throw new ClassCastException("Objects are not comparable (" + Type.displayTypeName(a) + ", " + Type.displayTypeName(b) + ')'); } else { return ac.compareTo(bc); } } } /** * Compare two AtomicValue objects for equality according to the rules for their data type. UntypedAtomic * values are compared as if they were strings; if different semantics are wanted, the conversion * must be done by the caller. * @param a the first object to be compared. If it is a StringValue, the * collator is used to compare the values, otherwise the value must implement the equals() method. * @param b the second object to be compared. This must be comparable with the first object: for * example, if one is a string, they must both be strings. * @return <0 if a0 if a>b * @throws ClassCastException if the objects are not comparable */ public boolean comparesEqual(AtomicValue a, AtomicValue b) throws NoDynamicContextException { // System.err.println("Comparing " + a.getClass() + ": " + a + " with " + b.getClass() + ": " + b); if (a instanceof StringValue && b instanceof StringValue) { return collator.compareStrings(a.getStringValue(), b.getStringValue()) == 0; } else if (a instanceof CalendarValue && b instanceof CalendarValue) { return ((CalendarValue)a).compareTo((CalendarValue)b, context) == 0; } else { Object ac = a.getXPathComparable(false, collator, context); Object bc = b.getXPathComparable(false, collator, context); return ac.equals(bc); } } /** * Get a comparison key for an object. This must satisfy the rule that if two objects are equal, * then their comparison keys are equal, and vice versa. There is no requirement that the * comparison keys should reflect the ordering of the underlying objects. */ public ComparisonKey getComparisonKey(AtomicValue a) { if (a instanceof StringValue) { Platform platform = Configuration.getPlatform(); if (platform.canReturnCollationKeys(collator)) { return new ComparisonKey(StandardNames.XS_STRING, collator.getCollationKey(a.getStringValue())); } else { return new ComparisonKey(StandardNames.XS_STRING, a.getStringValue()); } } else { return new ComparisonKey(StandardNames.XS_STRING, a); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none //saxonb-9.1.0.8/bj/net/sf/saxon/sort/AtomicSortComparer.java0000644000175000017500000002507211033351443023016 0ustar eugeneeugenepackage net.sf.saxon.sort; import net.sf.saxon.Configuration; import net.sf.saxon.Platform; import net.sf.saxon.trans.NoDynamicContextException; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.StandardNames; import net.sf.saxon.om.StructuredQName; import net.sf.saxon.type.AtomicType; import net.sf.saxon.type.Type; import net.sf.saxon.value.*; /** * An AtomicComparer used for comparing atomic values of arbitrary item types. It encapsulates * a collator that is used when the values to be compared are strings. It also supports * a separate method for testing equality of items, which can be used for data types that * are not ordered. * * The AtomicSortComparer is identical to the GenericAtomicComparer except for its handling * of NaN: it treats NaN values as lower than any other value, and as equal to each other. * * @author Michael H. Kay * */ public class AtomicSortComparer implements AtomicComparer { private StringCollator collator; private XPathContext context; private int itemType; /** * Factory method to get an atomic comparer suitable for sorting or for grouping (operations in which * NaN is considered equal to NaN) * @param collator Collating comparer to be used when comparing strings. This argument may be null * if the itemType excludes the possibility of comparing strings. If the method is called at compile * time, this should be a NamedCollation so that it can be cloned at run-time. * @param itemType the primitive item type of the values to be compared * @param context Dynamic context (may be an EarlyEvaluationContext) * @return a suitable AtomicComparer */ public static AtomicComparer makeSortComparer(StringCollator collator, int itemType, XPathContext context) { switch (itemType) { case StandardNames.XS_STRING: case StandardNames.XS_UNTYPED_ATOMIC: case StandardNames.XS_ANY_URI: if (collator instanceof CodepointCollator) { return CodepointCollatingComparer.getInstance(); } else { return new CollatingAtomicComparer(collator, Configuration.getPlatform()); } case StandardNames.XS_INTEGER: case StandardNames.XS_DECIMAL: return DecimalSortComparer.getDecimalSortComparerInstance(); case StandardNames.XS_DOUBLE: case StandardNames.XS_FLOAT: case StandardNames.XS_NUMERIC: return DoubleSortComparer.getInstance(); case StandardNames.XS_DATE_TIME: case StandardNames.XS_DATE: case StandardNames.XS_TIME: return new CalendarValueComparer(context); default: // use the general-purpose comparer that handles all types return new AtomicSortComparer(collator, itemType, context); } } private AtomicSortComparer(StringCollator collator, int itemType, XPathContext context) { this.collator = collator; if (collator == null) { this.collator = CodepointCollator.getInstance(); } this.context = context; this.itemType = itemType; } /** * Supply the dynamic context in case this is needed for the comparison * * @param context the dynamic evaluation context * @return either the original AtomicComparer, or a new AtomicComparer in which the context * is known. The original AtomicComparer is not modified */ public AtomicComparer provideContext(XPathContext context) { return new AtomicSortComparer(collator, itemType, context); } /** * Get the underlying StringCollator * @return the underlying collator */ public StringCollator getStringCollator() { return collator; } /** * Get the requested item type * @return the item type */ public int getItemType() { return itemType; } /** * Compare two AtomicValue objects according to the rules for their data type. UntypedAtomic * values are compared as if they were strings; if different semantics are wanted, the conversion * must be done by the caller. * @param a the first object to be compared. It is intended that this should normally be an instance * of AtomicValue, though this restriction is not enforced. If it is a StringValue, the * collator is used to compare the values, otherwise the value must implement the java.util.Comparable * interface. * @param b the second object to be compared. This must be comparable with the first object: for * example, if one is a string, they must both be strings. * @return <0 if a0 if a>b * @throws ClassCastException if the objects are not comparable */ public int compareAtomicValues(AtomicValue a, AtomicValue b) throws NoDynamicContextException { if (a == null) { if (b == null) { return 0; } else { return -1; } } else if (b == null) { return +1; } // System.err.println("Comparing " + a.getClass() + "(" + a + ") with " + b.getClass() + "(" + b + ") using " + collator); if (a instanceof UntypedAtomicValue) { return ((UntypedAtomicValue)a).compareTo(b, collator, context); } else if (b instanceof UntypedAtomicValue) { return -((UntypedAtomicValue)b).compareTo(a, collator, context); } else if (a.isNaN()) { return (b.isNaN() ? 0 : -1); } else if (b.isNaN()) { return +1; } else if (a instanceof StringValue && b instanceof StringValue) { if (collator instanceof CodepointCollator) { return ((CodepointCollator)collator).compareCS(a.getStringValueCS(), b.getStringValueCS()); } else { return collator.compareStrings(a.getStringValue(), b.getStringValue()); } } else { Comparable ac = (Comparable)a.getXPathComparable(true, collator, context); Comparable bc = (Comparable)b.getXPathComparable(true, collator, context); if (ac == null || bc == null) { throw new ClassCastException("Values are not comparable (" + Type.displayTypeName(a) + ", " + Type.displayTypeName(b) + ')'); } else { return ac.compareTo(bc); } } } /** * Compare two AtomicValue objects for equality according to the rules for their data type. UntypedAtomic * values are compared by converting to the type of the other operand. * * @param a the first object to be compared. It is intended that this should be an instance * of AtomicValue, though this restriction is not enforced. If it is a StringValue, the * collator is used to compare the values, otherwise the value must implement the equals() method. * @param b the second object to be compared. This must be comparable with the first object: for * example, if one is a string, they must both be strings. * @return true if the values are equal, false if not * @throws ClassCastException if the objects are not comparable */ public boolean comparesEqual(AtomicValue a, AtomicValue b) throws NoDynamicContextException { return compareAtomicValues(a, b) == 0; } /** * Get a comparison key for an object. This must satisfy the rule that if two objects are equal, * then their comparison keys are equal, and vice versa. There is no requirement that the * comparison keys should reflect the ordering of the underlying objects. */ public ComparisonKey getComparisonKey(AtomicValue a) throws NoDynamicContextException { if (a instanceof NumericValue) { if (((NumericValue)a).isNaN()) { // Deal with NaN specially. For this function, NaN is considered equal to itself return new ComparisonKey(StandardNames.XS_NUMERIC, COLLATION_KEY_NaN); } else { return new ComparisonKey(StandardNames.XS_NUMERIC, a); } } else if (a instanceof StringValue) { final Platform platform = Configuration.getPlatform(); if (platform.canReturnCollationKeys(collator)) { return new ComparisonKey(StandardNames.XS_STRING, collator.getCollationKey(a.getStringValue())); } else { return new ComparisonKey(StandardNames.XS_STRING, a); } } else if (a instanceof CalendarValue) { CalendarValue cv = (CalendarValue)a; if (cv.hasTimezone()) { return new ComparisonKey(a.getTypeLabel().getPrimitiveType(), a); } else { cv = (CalendarValue)cv.copyAsSubType((AtomicType)cv.getTypeLabel()); cv.setTimezoneInMinutes(context.getImplicitTimezone()); return new ComparisonKey(cv.getTypeLabel().getPrimitiveType(), cv); } } else if (a instanceof DurationValue) { // dayTimeDuration and yearMonthDuration are comparable in the special case of the zero duration return new ComparisonKey(StandardNames.XS_DURATION, a); } else { return new ComparisonKey(a.getTypeLabel().getPrimitiveType(), a); } } protected static StructuredQName COLLATION_KEY_NaN = new StructuredQName("saxon", "http://saxon.sf.net/collation-key", "NaN"); // The logic here is to choose a value that compares equal to itself but not equal to any other // number. We use StructuredQName because it has a simple equals() method. } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none //saxonb-9.1.0.8/bj/net/sf/saxon/sort/GenericSorter.java0000644000175000017500000004547311033351443022023 0ustar eugeneeugenepackage net.sf.saxon.sort; /* Copyright ? 1999 CERN - European Organization for Nuclear Research. Permission to use, copy, moNumbererdify, distribute and sell this software and its documentation for any purpose is hereby granted without fee, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation. CERN makes no representations about the suitability of this software for any purpose. It is provided "as is" without expressed or implied warranty. */ /** * Modified by Michael Kay to use the Saxon Sortable interface rather than a separate IntComparator and Swapper */ /** Generically sorts arbitrary shaped data (for example multiple arrays, 1,2 or 3-d matrices, and so on) using a quicksort or mergesort. This class addresses two problems, namely

    • Sorting multiple arrays in sync
    • Sorting by multiple sorting criteria (primary, secondary, tertiary, ...)

    Sorting multiple arrays in sync

    Assume we have three arrays X, Y and Z. We want to sort all three arrays by X (or some arbitrary comparison function). For example, we have
    X=[3, 2, 1], Y=[3.0, 2.0, 1.0], Z=[6.0, 7.0, 8.0]. The output should be
    X=[1, 2, 3], Y=[1.0, 2.0, 3.0], Z=[8.0, 7.0, 6.0]
    .

    How can we achive this? Here are several alternatives. We could ...

    1. make a list of Point3D objects, sort the list as desired using a comparison function, then copy the results back into X, Y and Z. The classic object-oriented way.
    2. make an index list [0,1,2,...,N-1], sort the index list using a comparison function, then reorder the elements of X,Y,Z as defined by the index list. Reordering cannot be done in-place, so we need to copy X to some temporary array, then copy in the right order back from the temporary into X. Same for Y and Z.
    3. use a generic quicksort or mergesort which, whenever two elements in X are swapped, also swaps the corresponding elements in Y and Z.
    Alternatives 1 and 2 involve quite a lot of copying and allocate significant amounts of temporary memory. Alternative 3 involves more swapping, more polymorphic message dispatches, no copying and does not need any temporary memory.

    This class implements alternative 3. It operates on arbitrary shaped data. In fact, it has no idea what kind of data it is sorting. Comparisons and swapping are delegated to user provided objects which know their data and can do the job.

    Lets call the generic data g (it may be one array, three linked lists or whatever). This class takes a user comparison function operating on two indexes (a,b), namely an {@link Sortable}. The comparison function determines whether g[a] is equal, less or greater than g[b]. The sort, depending on its implementation, can decide to swap the data at index a with the data at index b. It calls a user provided {@link Sortable} object that knows how to swap the data of these indexes.

    The following snippet shows how to solve the problem.
    final int[] x;
    final double[] y;
    final double[] z;
    
    x = new int[]    {3,   2,   1  };
    y = new double[] {3.0, 2.0, 1.0};
    z = new double[] {6.0, 7.0, 8.0};
    
    
    // this one knows how to swap two indexes (a,b)
    Swapper swapper = new Swapper() {
       public void swap(int a, int b) {
          int t1;	double t2, t3;
          t1 = x[a]; x[a] = x[b];	x[b] = t1;
          t2 = y[a]; y[a] = y[b]; y[b] = t2;
          t3 = z[a]; z[a] = z[b];	z[b] = t3;
       }
    };
    // simple comparison: compare by X and ignore Y,Z
    IntComparator comp = new IntComparator() {    public int compare(int a, int b) {       return x[a]==x[b] ? 0 : (x[a]<x[b] ? -1 : 1);    } }; System.out.println("before:"); System.out.println("X="+Arrays.toString(x)); System.out.println("Y="+Arrays.toString(y)); System.out.println("Z="+Arrays.toString(z)); GenericSorting.quickSort(0, X.length, comp, swapper); // GenericSorting.mergeSort(0, X.length, comp, swapper); System.out.println("after:"); System.out.println("X="+Arrays.toString(x)); System.out.println("Y="+Arrays.toString(y)); System.out.println("Z="+Arrays.toString(z));

    Sorting by multiple sorting criterias (primary, secondary, tertiary, ...)

    Assume again we have three arrays X, Y and Z. Now we want to sort all three arrays, primarily by Y, secondarily by Z (if Y elements are equal). For example, we have
    X=[6, 7, 8, 9], Y=[3.0, 2.0, 1.0, 3.0], Z=[5.0, 4.0, 4.0, 1.0]. The output should be
    X=[8, 7, 9, 6], Y=[1.0, 2.0, 3.0, 3.0], Z=[4.0, 4.0, 1.0, 5.0]
    .

    Here is how to solve the problem. All code in the above example stays the same, except that we modify the comparison function as follows

    //compare by Y, if that doesn't help, reside to Z
    IntComparator comp = new IntComparator() {
       public int compare(int a, int b) {
          if (y[a]==y[b]) return z[a]==z[b] ? 0 : (z[a]<z[b] ? -1 : 1);
          return y[a]<y[b] ? -1 : 1;
       }
    };
    

    Notes

    Sorts involving floating point data and not involving comparators, like, for example provided in the JDK {@link java.util.Arrays} and in the Colt (cern.colt.Sorting) handle floating point numbers in special ways to guarantee that NaN's are swapped to the end and -0.0 comes before 0.0. Methods delegating to comparators cannot do this. They rely on the comparator. Thus, if such boundary cases are an issue for the application at hand, comparators explicitly need to implement -0.0 and NaN aware comparisons. Remember: -0.0 < 0.0 == false, (-0.0 == 0.0) == true, as well as 5.0 < Double.NaN == false, 5.0 > Double.NaN == false. Same for float.

    Implementation

    The quicksort is a derivative of the JDK 1.2 V1.26 algorithms (which are, in turn, based on Bentley's and McIlroy's fine work). The mergesort is a derivative of the JAL algorithms, with optimisations taken from the JDK algorithms. Both quick and merge sort are "in-place", i.e. do not allocate temporary memory (helper arrays). Mergesort is stable (by definition), while quicksort is not. A stable sort is, for example, helpful, if matrices are sorted successively by multiple columns. It preserves the relative position of equal elements. @author wolfgang.hoschek@cern.ch @version 1.0, 03-Jul-99 */ public class GenericSorter extends Object { private static final int SMALL = 7; private static final int MEDIUM = 7; private static final int LARGE = 40; /** * Makes this class non instantiable, but still let's others inherit from it. */ protected GenericSorter() {} /** * Sorts the specified range of elements according * to the order induced by the specified comparator. All elements in the * range must be mutually comparable by the specified comparator * (that is, c.compare(a, b) must not throw an * exception for any indexes a and * b in the range).

    * * The sorting algorithm is a tuned quicksort, * adapted from Jon L. Bentley and M. Douglas McIlroy's "Engineering a * Sort Function", Software-Practice and Experience, Vol. 23(11) * P. 1249-1265 (November 1993). For details, see * http://citeseer.ist.psu.edu/bentley93engineering.html. * This algorithm offers n*log(n) performance on many data sets that cause other * quicksorts to degrade to quadratic performance. * * @param fromIndex the index of the first element (inclusive) to be sorted. * @param toIndex the index of the last element (exclusive) to be sorted. * @param c the comparator to determine the order of the generic data; * an object that knows how to swap the elements at any two indexes (a,b). * */ public static void quickSort(int fromIndex, int toIndex, Sortable c) { quickSort1(fromIndex, toIndex-fromIndex, c); } /** * Sorts the specified sub-array into ascending order. */ private static void quickSort1(int off, int len, Sortable comp) { // Insertion sort on smallest arrays if (len < SMALL) { for (int i=off; ioff && (comp.compare(j-1,j)>0); j--) { comp.swap(j, j-1); } return; } // Choose a partition element, v int m = off + (len >>> 1); // len/2; // Small arrays, middle element if (len > MEDIUM) { int l = off; int n = off + len - 1; if (len > LARGE) { // Big arrays, pseudomedian of 9 int s = len >>> 3; // len/8; l = med3(l, l+s, l+2*s, comp); m = med3(m-s, m, m+s, comp); n = med3(n-2*s, n-s, n, comp); } // m = med3(l, m, n, comp); // Mid-size, med of 3 // manually inlined (most time is spent near the leafs of the recursion tree) //a = comp.compare(l,m); //b = comp.compare(l,n); int c = comp.compare(m,n); m = (comp.compare(l,m)<0 ? (c<0 ? m : comp.compare(l,n)<0 ? n : l) : (c>0 ? m : comp.compare(l,n)>0 ? n : l)); } //long v = x[m]; // Establish Invariant: v* (v)* v* int a = off, b = a, c = off + len - 1, d = c; while (true) { int comparison; while (b <= c && ((comparison=comp.compare(b,m))<=0)) { if (comparison == 0) { if (a==m) m = b; // pivot is moving target; DELTA to JDK !!! else if (b==m) m = a; // pivot is moving target; DELTA to JDK !!! comp.swap(a++, b); } b++; } while (c >= b && ((comparison=comp.compare(c,m))>=0)) { if (comparison == 0) { if (c==m) m = d; // pivot is moving target; DELTA to JDK !!! else if (d==m) m = c; // pivot is moving target; DELTA to JDK !!! comp.swap(c, d--); } c--; } if (b > c) break; if (b==m) m = d; // pivot is moving target; DELTA to JDK !!! else if (c==m) m = c; // pivot is moving target; DELTA to JDK !!! comp.swap(b++, c--); } // Swap partition elements back to middle int s = Math.min(a-off, b-a ); // vecswap(swapper, off, b-s, s); // manually inlined int aa = off; int bb = b-s; while (--s >= 0) comp.swap(aa++, bb++); int n = off + len; s = Math.min(d-c, n-d-1); // vecswap(swapper, b, n-s, s); // manually inlined aa = b; bb = n-s; while (--s >= 0) comp.swap(aa++, bb++); // Recursively sort non-partition-elements if ((s = b-a) > 1) quickSort1(off, s, comp); if ((s = d-c) > 1) quickSort1(n-s, s, comp); } /** * Returns the index of the median of the three indexed elements. */ private static int med3(int a, int b, int c, Sortable comp) { int bc = comp.compare(b,c); return (comp.compare(a,b)<0 ? (bc<0 ? b : comp.compare(a,c)<0 ? c : a) : (bc>0 ? b : comp.compare(a,c)>0 ? c : a)); } // /** // * Swaps x[a .. (a+n-1)] with x[b .. (b+n-1)]. // */ // private static void vecswap(Swapper swapper, int a, int b, int n) { // for (int i=0; imutually comparable by the specified comparator * (that is, c.compare(a, b) must not throw an * exception for any indexes a and * b in the range).

    * * This sort is guaranteed to be stable: equal elements will * not be reordered as a result of the sort.

    * * The sorting algorithm is a modified mergesort (in which the merge is * omitted if the highest element in the low sublist is less than the * lowest element in the high sublist). This algorithm offers guaranteed * n*log(n) performance, and can approach linear performance on nearly * sorted lists. * * @param fromIndex the index of the first element (inclusive) to be sorted. * @param toIndex the index of the last element (exclusive) to be sorted. * @param c the comparator to determine the order of the generic data; * an object that knows how to swap the elements at any two indexes (a,b). * */ public static void mergeSort(int fromIndex, int toIndex, Sortable c) { /* * We retain the same method signature as quickSort. Given only a * comparator and swapper we do not know how to copy and move elements * from/to temporary arrays. Hence, in contrast to the JDK mergesorts * this is an "in-place" mergesort, i.e. does not allocate any temporary * arrays. A non-inplace mergesort would be faster in most cases, but * would require non-intuitive delegate objects. Remember that an * in-place merge phase requires N logN swaps, while an out-of-place * merge phase requires only N swaps. This doesn't matter much if swaps * are cheap and comparisons are expensive. Nonetheless this can * certainly be suboptimal. */ // Insertion sort on smallest arrays if (toIndex - fromIndex < SMALL) { for (int i = fromIndex; i < toIndex; i++) { for (int j = i; j > fromIndex && (c.compare(j - 1, j) > 0); j--) { c.swap(j, j - 1); } } return; } // Recursively sort halves int mid = (fromIndex + toIndex) >>> 1; // (fromIndex + toIndex) / 2; mergeSort(fromIndex, mid, c); mergeSort(mid, toIndex, c); // If list is already sorted, nothing left to do. This is an // optimization that results in faster sorts for nearly ordered lists. if (c.compare(mid - 1, mid) <= 0) return; // Merge sorted halves inplaceMerge(fromIndex, mid, toIndex, c); } /** * Transforms two consecutive sorted ranges into a single sorted * range. The initial ranges are [first, middle) * and [middle, last), and the resulting range is * [first, last). * Elements in the first input range will precede equal elements in the * second. */ private static void inplaceMerge(int first, int middle, int last, Sortable comp) { if (first >= middle || middle >= last) return; if (last - first == 2) { if (comp.compare(middle, first)<0) { comp.swap(first,middle); } return; } int firstCut; int secondCut; if (middle - first > last - middle) { firstCut = first + ((middle - first) >>> 1); // first + ((middle - first) / 2); // secondCut = lower_bound(middle, last, firstCut, comp); // manually inlined for speed (speedup = 2) int _first = middle; int len = last - _first; while (len > 0) { int half = len >>> 1; // len / 2; int mid = _first + half; if (comp.compare(mid, firstCut)<0) { _first = mid + 1; len -= half + 1; } else { len = half; } } secondCut = _first; } else { secondCut = middle + ((last - middle) >>> 1); // middle + ((last - middle) / 2); // firstCut = upper_bound(first, middle, secondCut, comp); // manually inlined for speed (speedup = 2) int _first = first; int len = middle - _first; while (len > 0) { int half = len >>> 1; // len / 2; int mid = _first + half; if (comp.compare(secondCut, mid)<0) { len = half; } else { _first = mid + 1; len -= half + 1; } } firstCut = _first; } // rotate(firstCut, middle, secondCut, swapper); // is manually inlined for speed // (hotspot compiler inlining in recursive methods seems to work only for // small call depths, even if methods are "static private") // speedup = 1.7 // begin inline int first2 = firstCut; int middle2 = middle; int last2 = secondCut; if (middle2 != first2 && middle2 != last2) { int first1 = first2; int last1 = middle2; while (first1 < --last1) comp.swap(first1++,last1); first1 = middle2; last1 = last2; while (first1 < --last1) comp.swap(first1++,last1); first1 = first2; last1 = last2; while (first1 < --last1) comp.swap(first1++,last1); } // end inline middle = firstCut + (secondCut - middle); inplaceMerge(first, firstCut, middle, comp); inplaceMerge(middle, secondCut, last, comp); } // /** // * Performs a binary search on an already-sorted range: finds the first // * position where an element can be inserted without violating the ordering. // * Sorting is by a user-supplied comparison function. // * @param array Array containing the range. // * @param first Beginning of the range. // * @param last One past the end of the range. // * @param x Element to be searched for. // * @param comp Comparison function. // * @return The largest index i such that, for every j in the // * range [first, i), // * comp.apply(array[j], x) is // * true. // * @see Sorting#upper_bound // * @see Sorting#equal_range // * @see Sorting#binary_search // */ // private static int lower_bound(int first, int last, int x, IntComparator comp) { // int len = last - first; // while (len > 0) { // int half = len >>> 1; // len / 2; // int middle = first + half; // if (comp.compare(middle, x)<0) { // first = middle + 1; // len -= half + 1; // } // else { // len = half; // } // } // return first; // } // // /** // * Performs a binary search on an already-sorted range: finds the last // * position where an element can be inserted without violating the ordering. // * Sorting is by a user-supplied comparison function. // * @param array Array containing the range. // * @param first Beginning of the range. // * @param last One past the end of the range. // * @param x Element to be searched for. // * @param comp Comparison function. // * @return The largest index i such that, for every j in the // * range [first, i), // * comp.apply(x, array[j]) is // * false. // * @see Sorting#lower_bound // * @see Sorting#equal_range // * @see Sorting#binary_search // */ // private static int upper_bound(int first, int last, int x, IntComparator comp) { // int len = last - first; // while (len > 0) { // int half = len >>> 1; // len / 2; // int middle = first + half; // if (comp.compare(x, middle)<0) { // len = half; // } // else { // first = middle + 1; // len -= half + 1; // } // } // return first; // } } saxonb-9.1.0.8/bj/net/sf/saxon/sort/ComparisonKey.java0000644000175000017500000000432011033351443022015 0ustar eugeneeugenepackage net.sf.saxon.sort; /** * An object used as a comparison key. Two XPath atomic values are equal under the "eq" operator * if and only if their comparison keys are equal under the Java equals() method. */ public class ComparisonKey { int category; Object value; /** * Create a comparison key for a value in a particular category. The "category" here represents a * set of primitive types that allow mutual comparison (so all numeric values are in the same category). * @param category the category * @param value the value within the category */ public ComparisonKey(int category, Object value) { this.category = category; this.value = value; } /** * Test if two comparison keys are equal * @param other the other comparison key * @return true if they are equal * @throws ClassCastException if the other object is not a ComparisonKey */ public boolean equals(Object other) { if (other instanceof ComparisonKey) { ComparisonKey otherKey = (ComparisonKey)other; return category == otherKey.category && value.equals(otherKey.value); } else { throw new ClassCastException("Cannot compare a ComparisonKey to an object of a different class"); } } /** * Get a hashcode for a comparison key. If two comparison keys are equal, they must have the same hash code. * @return the hash code. */ public int hashCode() { return value.hashCode() ^ category; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/sort/StringCollator.java0000644000175000017500000000313011033351443022176 0ustar eugeneeugenepackage net.sf.saxon.sort; import java.io.Serializable; /** * This interface represents a "collation" as defined in XPath, that is, a set of rules for comparing strings */ public interface StringCollator extends Serializable { /** * Compare two strings * @param o1 the first string * @param o2 the second string * @return 0 if the strings are considered equal, a negative integer if the first string is less than the second, * a positive integer if the first string is greater than the second */ int compareStrings(String o1, String o2); /** * Get a collation key for two Strings. The essential property of collation keys * is that if two values are equal under the collation, then the collation keys are * compare correctly under the equals() method. * @param s the string whose collation key is required * @return the collation key */ Object getCollationKey(String s); } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/sort/SortExpression.java0000644000175000017500000004612111033351443022246 0ustar eugeneeugenepackage net.sf.saxon.sort; import net.sf.saxon.trace.ExpressionPresenter; import net.sf.saxon.expr.*; import net.sf.saxon.om.EmptyIterator; import net.sf.saxon.om.Item; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.TypeHierarchy; import net.sf.saxon.value.Cardinality; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /** * Expression equivalent to the imaginary syntax * expr sortby (sort-key)+ */ public class SortExpression extends Expression implements SortKeyEvaluator { private Expression select = null; private SortKeyDefinition[] sortKeyDefinitions = null; private transient AtomicComparer[] comparators = null; // created early if all comparators can be created statically // transient because Java RuleBasedCollator is not serializable /** * Create a sort expression * @param select the expression whose result is to be sorted * @param sortKeys the set of sort key definitions to be used, in major to minor order */ public SortExpression(Expression select, SortKeyDefinition[] sortKeys) { this.select = select; sortKeyDefinitions = sortKeys; Iterator children = iterateSubExpressions(); while (children.hasNext()) { Expression exp = (Expression) children.next(); adoptChildExpression(exp); } } /** * Get the expression defining the sequence being sorted * @return the expression whose result is to be sorted */ public Expression getBaseExpression() { return select; } /** * Get the immediate sub-expressions of this expression. Default implementation * returns a zero-length array, appropriate for an expression that has no * sub-expressions. * * @return an iterator containing the sub-expressions of this expression */ public Iterator iterateSubExpressions() { List list = new ArrayList(8); list.add(select); for (int i = 0; i < sortKeyDefinitions.length; i++) { list.add(sortKeyDefinitions[i].getSortKey()); Expression e = sortKeyDefinitions[i].order; if (e != null) { list.add(e); } e = sortKeyDefinitions[i].caseOrder; if (e != null) { list.add(e); } e = sortKeyDefinitions[i].dataTypeExpression; if (e != null) { list.add(e); } e = sortKeyDefinitions[i].language; if (e != null) { list.add(e); } e = sortKeyDefinitions[i].collationName; if (e != null) { list.add(e); } e = sortKeyDefinitions[i].stable; if (e != null) { list.add(e); } } return list.iterator(); } /** * Add a representation of this expression to a PathMap. The PathMap captures a map of the nodes visited * by an expression in a source tree. *

    *

    The default implementation of this method assumes that an expression does no navigation other than * the navigation done by evaluating its subexpressions, and that the subexpressions are evaluated in the * same context as the containing expression. The method must be overridden for any expression * where these assumptions do not hold. For example, implementations exist for AxisExpression, ParentExpression, * and RootExpression (because they perform navigation), and for the doc(), document(), and collection() * functions because they create a new navigation root. Implementations also exist for PathExpression and * FilterExpression because they have subexpressions that are evaluated in a different context from the * calling expression.

    * * @param pathMap the PathMap to which the expression should be added * @param pathMapNodeSet * @return the pathMapNode representing the focus established by this expression, in the case where this * expression is the first operand of a path expression or filter expression. For an expression that does * navigation, it represents the end of the arc in the path map that describes the navigation route. For other * expressions, it is the same as the input pathMapNode. */ public PathMap.PathMapNodeSet addToPathMap(PathMap pathMap, PathMap.PathMapNodeSet pathMapNodeSet) { PathMap.PathMapNodeSet target = select.addToPathMap(pathMap, pathMapNodeSet); if (sortKeyDefinitions != null) { for (int i = 0; i < sortKeyDefinitions.length; i++) { sortKeyDefinitions[i].getSortKey().addToPathMap(pathMap, target); Expression e = sortKeyDefinitions[i].getOrder(); if (e != null) { e.addToPathMap(pathMap, pathMapNodeSet); } e = sortKeyDefinitions[i].getCaseOrder(); if (e != null) { e.addToPathMap(pathMap, pathMapNodeSet); } e = sortKeyDefinitions[i].getDataTypeExpression(); if (e != null) { e.addToPathMap(pathMap, pathMapNodeSet); } e = sortKeyDefinitions[i].getLanguage(); if (e != null) { e.addToPathMap(pathMap, pathMapNodeSet); } e = sortKeyDefinitions[i].getCollationNameExpression(); if (e != null) { e.addToPathMap(pathMap, pathMapNodeSet); } } } return target; } /** * Given an expression that is an immediate child of this expression, test whether * the evaluation of the parent expression causes the child expression to be * evaluated repeatedly * @param child the immediate subexpression * @return true if the child expression is evaluated repeatedly */ public boolean hasLoopingSubexpression(Expression child) { return isSortKey(child); } /** * Replace one subexpression by a replacement subexpression * * @param original the original subexpression * @param replacement the replacement subexpression * @return true if the original subexpression is found */ public boolean replaceSubExpression(Expression original, Expression replacement) { boolean found = false; if (select == original) { select = replacement; found = true; } for (int i = 0; i < sortKeyDefinitions.length; i++) { if (sortKeyDefinitions[i].getSortKey() == original) { sortKeyDefinitions[i].setSortKey(replacement); found = true; } if (sortKeyDefinitions[i].getOrder() == original) { sortKeyDefinitions[i].setOrder(replacement); found = true; } if (sortKeyDefinitions[i].getCaseOrder() == original) { sortKeyDefinitions[i].setCaseOrder(replacement); found = true; } if (sortKeyDefinitions[i].getDataTypeExpression() == original) { sortKeyDefinitions[i].setDataTypeExpression(replacement); found = true; } if (sortKeyDefinitions[i].getLanguage() == original) { sortKeyDefinitions[i].setLanguage(replacement); found = true; } if (sortKeyDefinitions[i].collationName == original) { sortKeyDefinitions[i].collationName = replacement; found = true; } if (sortKeyDefinitions[i].stable == original) { sortKeyDefinitions[i].stable = replacement; found = true; } } return found; } /** * Simplify an expression * @param visitor an expression visitor */ public Expression simplify(ExpressionVisitor visitor) throws XPathException { select = visitor.simplify(select); return this; } /** * Type-check the expression */ public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { Expression select2 = visitor.typeCheck(select, contextItemType); if (select2 != select) { adoptChildExpression(select2); select = select2; } ItemType sortedItemType = select.getItemType(visitor.getConfiguration().getTypeHierarchy()); boolean allKeysFixed = true; for (int i = 0; i < sortKeyDefinitions.length; i++) { if (!(sortKeyDefinitions[i].isFixed())) { allKeysFixed = false; } } if (allKeysFixed) { comparators = new AtomicComparer[sortKeyDefinitions.length]; } for (int i = 0; i < sortKeyDefinitions.length; i++) { Expression sortKey = sortKeyDefinitions[i].getSortKey(); sortKey = visitor.typeCheck(sortKey, sortedItemType); if (visitor.getStaticContext().isInBackwardsCompatibleMode()) { sortKey = new FirstItemExpression(sortKey); } else { RoleLocator role = new RoleLocator(RoleLocator.INSTRUCTION, "xsl:sort/select", 0); role.setErrorCode("XTTE1020"); sortKey = CardinalityChecker.makeCardinalityChecker(sortKey, StaticProperty.ALLOWS_ZERO_OR_ONE, role); } sortKeyDefinitions[i].setSortKey(sortKey); if (sortKeyDefinitions[i].isFixed()) { AtomicComparer comp = sortKeyDefinitions[i].makeComparator( visitor.getStaticContext().makeEarlyEvaluationContext()); sortKeyDefinitions[i].setFinalComparator(comp); if (allKeysFixed) { comparators[i] = comp; } } if ((sortKey.getDependencies() & StaticProperty.DEPENDS_ON_FOCUS) == 0) { visitor.getStaticContext().issueWarning( "Sort key will have no effect because its value does not depend on the context item", sortKey); } } return this; } /** * Perform optimisation of an expression and its subexpressions. *

    *

    This method is called after all references to functions and variables have been resolved * to the declaration of the function or variable, and after all type checking has been done.

    * * @param visitor an expression visitor * @param contextItemType the static type of "." at the point where this expression is invoked. * The parameter is set to null if it is known statically that the context item will be undefined. * If the type of the context item is not known statically, the argument is set to * {@link net.sf.saxon.type.Type#ITEM_TYPE} * @return the original expression, rewritten if appropriate to optimize execution * @throws XPathException if an error is discovered during this phase * (typically a type error) */ public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { Expression select2 = visitor.optimize(select, contextItemType); if (select2 != select) { adoptChildExpression(select2); select = select2; } // optimize the sort keys ItemType sortedItemType = select.getItemType(visitor.getConfiguration().getTypeHierarchy()); for (int i = 0; i < sortKeyDefinitions.length; i++) { Expression sortKey = sortKeyDefinitions[i].getSortKey(); sortKey = visitor.optimize(sortKey, sortedItemType); sortKeyDefinitions[i].setSortKey(sortKey); } if (Cardinality.allowsMany(select.getCardinality())) { return this; } else { return select; } } /** * Copy an expression. This makes a deep copy. * @return the copy of the original expression */ public Expression copy() { throw new UnsupportedOperationException("copy"); } /** * Offer promotion for this subexpression. The offer will be accepted if the subexpression * is not dependent on the factors (e.g. the context item) identified in the PromotionOffer. * By default the offer is not accepted - this is appropriate in the case of simple expressions * such as constant values and variable references where promotion would give no performance * advantage. This method is always called at compile time. * * @param offer details of the offer, for example the offer to move * expressions that don't depend on the context to an outer level in * the containing expression * @return if the offer is not accepted, return this expression unchanged. * Otherwise return the result of rewriting the expression to promote * this subexpression * @throws net.sf.saxon.trans.XPathException * if any error is detected */ public Expression promote(PromotionOffer offer) throws XPathException { Expression exp = offer.accept(this); if (exp != null) { return exp; } else { select = doPromotion(select, offer); for (int i = 0; i < sortKeyDefinitions.length; i++) { final Expression sk2 = sortKeyDefinitions[i].getSortKey().promote(offer); sortKeyDefinitions[i].setSortKey(sk2); if (sortKeyDefinitions[i].order != null) { sortKeyDefinitions[i].order = sortKeyDefinitions[i].order.promote(offer); } if (sortKeyDefinitions[i].stable != null) { sortKeyDefinitions[i].stable = sortKeyDefinitions[i].stable.promote(offer); } if (sortKeyDefinitions[i].caseOrder != null) { sortKeyDefinitions[i].caseOrder = sortKeyDefinitions[i].caseOrder.promote(offer); } if (sortKeyDefinitions[i].dataTypeExpression != null) { sortKeyDefinitions[i].dataTypeExpression = sortKeyDefinitions[i].dataTypeExpression.promote(offer); } if (sortKeyDefinitions[i].language != null) { sortKeyDefinitions[i].language = sortKeyDefinitions[i].language.promote(offer); } if (sortKeyDefinitions[i].collationName != null) { sortKeyDefinitions[i].collationName = sortKeyDefinitions[i].collationName.promote(offer); } } return this; } } /** * Test whether a given expression is one of the sort keys * @param child the given expression * @return true if the given expression is one of the sort keys */ public boolean isSortKey(Expression child) { for (int i = 0; i < sortKeyDefinitions.length; i++) { Expression exp = sortKeyDefinitions[i].getSortKey(); if (exp == child) { return true; } } return false; } /** * Determine the static cardinality */ public int computeCardinality() { return select.getCardinality(); } /** * Determine the data type of the items returned by the expression, if possible * * @param th the type hierarchy cache * @return a value such as Type.STRING, Type.BOOLEAN, Type.NUMBER, Type.NODE, * or Type.ITEM (meaning not known in advance) */ public ItemType getItemType(TypeHierarchy th) { return select.getItemType(th); } /** * Get the static properties of this expression (other than its type). The result is * bit-significant. These properties are used for optimizations. In general, if * property bit is set, it is true, but if it is unset, the value is unknown. */ public int computeSpecialProperties() { int props = 0; if ((select.getSpecialProperties() & StaticProperty.CONTEXT_DOCUMENT_NODESET) != 0) { props |= StaticProperty.CONTEXT_DOCUMENT_NODESET; } if ((select.getSpecialProperties() & StaticProperty.SINGLE_DOCUMENT_NODESET) != 0) { props |= StaticProperty.SINGLE_DOCUMENT_NODESET; } if ((select.getSpecialProperties() & StaticProperty.NON_CREATIVE) != 0) { props |= StaticProperty.NON_CREATIVE; } return props; } /** * Enumerate the results of the expression */ public SequenceIterator iterate(XPathContext context) throws XPathException { SequenceIterator iter = select.iterate(context); if (iter instanceof EmptyIterator) { return iter; } XPathContext xpc = context.newMinorContext(); xpc.setOrigin(this); AtomicComparer[] comps = comparators; if (comparators == null) { comps = new AtomicComparer[sortKeyDefinitions.length]; for (int s = 0; s < sortKeyDefinitions.length; s++) { AtomicComparer comp = sortKeyDefinitions[s].getFinalComparator(); if (comp == null) { comp = sortKeyDefinitions[s].makeComparator(xpc); } comps[s] = comp; } } iter = new SortedIterator(xpc, iter, this, comps); ((SortedIterator) iter).setHostLanguage(getHostLanguage()); return iter; } /** * Callback for evaluating the sort keys */ public Item evaluateSortKey(int n, XPathContext c) throws XPathException { return sortKeyDefinitions[n].getSortKey().evaluateItem(c); } /** * Diagnostic print of expression structure. The abstract expression tree * is written to the supplied output destination. */ public void explain(ExpressionPresenter out) { out.startElement("sort"); out.startSubsidiaryElement("select"); select.explain(out); out.endSubsidiaryElement(); for (int s = 0; s < sortKeyDefinitions.length; s++) { out.startSubsidiaryElement("by"); sortKeyDefinitions[s].getSortKey().explain(out); out.endSubsidiaryElement(); } out.endElement(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/sort/SortedGroupIterator.java0000644000175000017500000001050611033351443023224 0ustar eugeneeugenepackage net.sf.saxon.sort; import net.sf.saxon.Configuration; import net.sf.saxon.expr.LastPositionFinder; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.expr.XPathContextMajor; import net.sf.saxon.instruct.Instruction; import net.sf.saxon.om.Item; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.AtomicValue; /** * A SortedGroupIterator is a modified SortedIterator. It sorts a sequence of groups, * and is itself a GroupIterator. The modifications retain extra information about * the items being sorted. The items are each the leading item of a group, and as well * as the item itself, the iterator preserves information about the group: specifically, * an iterator over the items in the group, and the value of the grouping key (if any). */ public class SortedGroupIterator extends SortedIterator implements GroupIterator { private Instruction origin; public SortedGroupIterator(XPathContext context, GroupIterator base, SortKeyEvaluator sortKeyEvaluator, AtomicComparer[] comparators, Instruction origin) { super(context, base, sortKeyEvaluator, comparators); setHostLanguage(Configuration.XSLT); this.origin = origin; // add two items to each tuple, for the iterator over the items in the group, // and the grouping key, respectively. recordSize += 2; } /** * Override the method that builds the array of values and sort keys. * @throws XPathException */ protected void buildArray() throws XPathException { int allocated; if ((base.getProperties() & SequenceIterator.LAST_POSITION_FINDER) != 0) { allocated = ((LastPositionFinder)base).getLastPosition(); } else { allocated = 100; } nodeKeys = new Object[allocated * recordSize]; count = 0; XPathContextMajor c2 = context.newContext(); c2.setCurrentIterator(base); c2.setOrigin(origin); c2.setCurrentGroupIterator((GroupIterator)base); // this provides the context for evaluating the sort key // initialise the array with data while (true) { Item item = base.next(); if (item == null) { break; } if (count==allocated) { allocated *= 2; Object[] nk2 = new Object[allocated * recordSize]; System.arraycopy(nodeKeys, 0, nk2, 0, count * recordSize); nodeKeys = nk2; } int k = count*recordSize; nodeKeys[k] = item; for (int n=0; n0 if a>b * @throws ClassCastException if the objects are not comparable * @throws NoDynamicContextException if this comparer required access to dynamic context information, * notably the implicit timezone, and this information is not available. In general this happens if a * context-dependent comparison is attempted at compile-time, and it signals the compiler to generate * code that tries again at run-time. */ public int compareAtomicValues(AtomicValue a, AtomicValue b) throws NoDynamicContextException; /** * Compare two AtomicValue objects for equality according to the rules for their data type. UntypedAtomic * values are compared by converting to the type of the other operand. * @param a the first object to be compared. * @param b the second object to be compared. * @return true if the values are equal, false if not * @throws ClassCastException if the objects are not comparable */ public boolean comparesEqual(AtomicValue a, AtomicValue b) throws NoDynamicContextException; /** * Get a comparison key for an object. This must satisfy the rule that if two objects are equal * according to the XPath eq operator, then their comparison keys are equal according to the Java * equals() method, and vice versa. There is no requirement that the * comparison keys should reflect the ordering of the underlying objects. */ public ComparisonKey getComparisonKey(AtomicValue a) throws NoDynamicContextException; } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/sort/GroupStartingIterator.java0000644000175000017500000001013211033351443023552 0ustar eugeneeugenepackage net.sf.saxon.sort; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.*; import net.sf.saxon.pattern.Pattern; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.AtomicValue; import java.util.ArrayList; import java.util.List; /** * A GroupStartingIterator iterates over a sequence of groups defined by * xsl:for-each-group group-starting-with="x". The groups are returned in * order of first appearance. */ public class GroupStartingIterator implements LookaheadIterator, GroupIterator { private SequenceIterator population; private Pattern startPattern; private XPathContext baseContext; private XPathContext runningContext; private List currentMembers; private Item next; private Item current = null; private int position = 0; public GroupStartingIterator(SequenceIterator population, Pattern startPattern, XPathContext context) throws XPathException { this.population = population; this.startPattern = startPattern; baseContext = context; runningContext = context.newMinorContext(); runningContext.setCurrentIterator(population); // the first item in the population always starts a new group next = population.next(); } private void advance() throws XPathException { currentMembers = new ArrayList(10); currentMembers.add(current); while (true) { NodeInfo nextCandidate = (NodeInfo)population.next(); if (nextCandidate == null) { break; } if (startPattern.matches(nextCandidate, runningContext)) { next = nextCandidate; return; } else { currentMembers.add(nextCandidate); } } next = null; } public AtomicValue getCurrentGroupingKey() { return null; } public SequenceIterator iterateCurrentGroup() { return new ListIterator(currentMembers); } public boolean hasNext() { return next != null; } public Item next() throws XPathException { if (next != null) { current = next; position++; advance(); return current; } else { current = null; position = -1; return null; } } public Item current() { return current; } public int position() { return position; } public void close() { population.close(); } public SequenceIterator getAnother() throws XPathException { return new GroupStartingIterator(population.getAnother(), startPattern, baseContext); } /** * Get properties of this iterator, as a bit-significant integer. * @return the properties of this iterator. This will be some combination of * properties such as {@link #GROUNDED}, {@link #LAST_POSITION_FINDER}, * and {@link #LOOKAHEAD}. It is always * acceptable to return the value zero, indicating that there are no known special properties. * It is acceptable for the properties of the iterator to change depending on its state. */ public int getProperties() { return LOOKAHEAD; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none //saxonb-9.1.0.8/bj/net/sf/saxon/sort/IntIterator.java0000644000175000017500000000237411033351443021505 0ustar eugeneeugenepackage net.sf.saxon.sort; /** * An iterator over a sequence of unboxed int values */ public interface IntIterator { /** * Test whether there are any more integers in the sequence * @return true if there are more integers to come */ public boolean hasNext(); /** * Return the next integer in the sequence. The result is undefined unless hasNext() has been called * and has returned true. * @return the next integer in the sequence */ public int next(); } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/sort/SortKeyEvaluator.java0000644000175000017500000000217311033351443022521 0ustar eugeneeugenepackage net.sf.saxon.sort; import net.sf.saxon.om.Item; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.trans.XPathException; /** * Callback interface used to evaluate sort keys. An instance of this class is passed to the * SortedIterator, and is used whenever a sort key value needs to be computed. */ public interface SortKeyEvaluator { /** * Evaluate the n'th sort key */ public Item evaluateSortKey(int n, XPathContext context) throws XPathException; } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/sort/GroupByIterator.java0000644000175000017500000002200311044033432022326 0ustar eugeneeugenepackage net.sf.saxon.sort; import net.sf.saxon.expr.Expression; import net.sf.saxon.expr.LastPositionFinder; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.Item; import net.sf.saxon.om.ListIterator; import net.sf.saxon.om.LookaheadIterator; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.trace.Location; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.AtomicValue; import java.util.ArrayList; import java.util.HashMap; import java.util.List; /** * A GroupByIterator iterates over a sequence of groups defined by * xsl:for-each-group group-by="x". The groups are returned in * order of first appearance. Note that an item can appear in several groups; * indeed, an item may be the leading item of more than one group, which means * that knowing the leading item is not enough to know the current group. * *

    The GroupByIterator acts as a SequenceIterator, where successive calls of * next() return the leading item of each group in turn. The current item of * the iterator is therefore the leading item of the current group. To get access * to all the members of the current group, the method iterateCurrentGroup() is used; * this underpins the current-group() function in XSLT. The grouping key for the * current group is available via the getCurrentGroupingKey() method.

    */ public class GroupByIterator implements GroupIterator, LastPositionFinder, LookaheadIterator { // The implementation of group-by is not pipelined. All the items in the population // are read at the start, their grouping keys are calculated, and the groups are formed // in memory as a hash table indexed by the grouping key. This hash table is then // flattened into three parallel lists: a list of groups (each group being represented // as a list of items in population order), a list of grouping keys, and a list of // the initial items of the groups. private SequenceIterator population; private Expression keyExpression; private StringCollator collator; private XPathContext keyContext; private int position = 0; // Main data structure holds one entry for each group. The entry is also an ArrayList, // which contains the Items that are members of the group, in population order. // The groups are arranged in order of first appearance within the population. private ArrayList groups = new ArrayList(40); // This parallel structure identifies the grouping key for each group. The list // corresponds one-to-one with the list of groups. private ArrayList groupKeys = new ArrayList(40); // For convenience (so that we can use a standard ArrayListIterator) we define // another parallel array holding the initial items of each group. private ArrayList initialItems = new ArrayList(40); // A SortComparer is used to do the comparisons private AtomicComparer comparer; /** * Create a GroupByIterator * @param population iterator over the population to be grouped * @param keyExpression the expression used to calculate the grouping key * @param keyContext dynamic context for calculating the grouping key * @param collator Collation to be used for comparing grouping keys * @throws XPathException */ public GroupByIterator(SequenceIterator population, Expression keyExpression, XPathContext keyContext, StringCollator collator) throws XPathException { this.population = population; this.keyExpression = keyExpression; this.keyContext = keyContext; this.collator = collator; int type = keyExpression.getItemType(keyContext.getConfiguration().getTypeHierarchy()).getPrimitiveType(); this.comparer = AtomicSortComparer.makeSortComparer(collator, type, keyContext); buildIndexedGroups(); } /** * Build the grouping table forming groups of items with equal keys. * This form of grouping allows a member of the population to be present in zero * or more groups, one for each value of the grouping key. */ private void buildIndexedGroups() throws XPathException { HashMap index = new HashMap(40); XPathContext c2 = keyContext.newMinorContext(); c2.setCurrentIterator(population); c2.setOriginatingConstructType(Location.GROUPING_KEY); while (true) { Item item = population.next(); if (item==null) { break; } SequenceIterator keys = keyExpression.iterate(c2); boolean firstKey = true; while (true) { AtomicValue key = (AtomicValue) keys.next(); if (key==null) { break; } ComparisonKey comparisonKey = comparer.getComparisonKey(key); ArrayList g = (ArrayList) index.get(comparisonKey); if (g == null) { ArrayList newGroup = new ArrayList(20); newGroup.add(item); groups.add(newGroup); groupKeys.add(key); initialItems.add(item); index.put(comparisonKey, newGroup); } else { if (firstKey) { g.add(item); } else { // if this is not the first key value for this item, we // check whether the item is already in this group before // adding it again. If it is in this group, then we know // it will be at the end. if (g.get(g.size() - 1) != item) { g.add(item); } } } firstKey = false; } } } /** * Get the value of the grouping key for the current group * @return the grouping key */ public AtomicValue getCurrentGroupingKey() { return (AtomicValue)groupKeys.get(position-1); } /** * Get an iterator over the items in the current group * @return the iterator */ public SequenceIterator iterateCurrentGroup() { return new ListIterator((ArrayList)groups.get(position-1)); } /** * Get the contents of the current group as a java List * @return the contents of the current group */ public List getCurrentGroup() { return (ArrayList)groups.get(position-1); } public boolean hasNext() { return position < groups.size(); } public Item next() throws XPathException { if (position >=0 && position < groups.size()) { position++; return current(); } else { position = -1; return null; } } public Item current() { if (position < 1) { return null; } // return the initial item of the current group return (Item)((ArrayList)groups.get(position-1)).get(0); } public int position() { return position; } public void close() { } public SequenceIterator getAnother() throws XPathException { XPathContext c2 = keyContext.newMinorContext(); c2.setOriginatingConstructType(Location.GROUPING_KEY); return new GroupByIterator(population.getAnother(), keyExpression, c2, collator); } /** * Get properties of this iterator, as a bit-significant integer. * * @return the properties of this iterator. This will be some combination of * properties such as {@link #GROUNDED}, {@link #LAST_POSITION_FINDER}, * and {@link #LOOKAHEAD}. It is always * acceptable to return the value zero, indicating that there are no known special properties. * It is acceptable for the properties of the iterator to change depending on its state. */ public int getProperties() { return LAST_POSITION_FINDER | LOOKAHEAD; } /** * Get the last position (that is, the number of groups) */ public int getLastPosition() throws XPathException { return groups.size(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none //saxonb-9.1.0.8/bj/net/sf/saxon/sort/UppercaseFirstCollator.java0000644000175000017500000000710511033351443023675 0ustar eugeneeugenepackage net.sf.saxon.sort; /** * A Collator used for comparing strings, with upper case collated before lower case * if the strings are otherwise equal. This is implemented as a wrapper around a collator * that compares the strings ignoring case. * * @author Michael H. Kay * */ public class UppercaseFirstCollator implements StringCollator, java.io.Serializable { private StringCollator baseCollator; /** * Create an UppercaseFirstCollator * @param base the base collator used to compare strings irrespective of case */ public UppercaseFirstCollator(StringCollator base) { baseCollator = base; } /** * Compare two string objects: case is irrelevant, unless the strings are equal ignoring * case, in which case uppercase comes first. * @return <0 if a0 if a>b * @throws ClassCastException if the objects do not implement the CharSequence interface */ public int compareStrings(String a, String b) { int diff = baseCollator.compareStrings(a, b); if (diff != 0) { return diff; } // This is doing a character-by-character comparison, which isn't really right. // There might be a sequence of letters constituting a single collation unit. int i = 0; int j = 0; while (true) { // Skip characters that are equal in the two strings while (i < a.length() && j < b.length() && a.charAt(i) == b.charAt(j)) { i++; j++; } // Skip non-letters in the first string while (i < a.length() && !Character.isLetter(a.charAt(i))) { i++; } // Skip non-letters in the second string while (j < b.length() && !Character.isLetter(b.charAt(j))) { j++; } // if either string is exhausted, treat the strings as equal if (i >= a.length()) { return 0; } if (j >= b.length()) { return 0; } // if one character is upper case and the other isn't, the issue is decided boolean aUpper = Character.isUpperCase(a.charAt(i++)); boolean bUpper = Character.isUpperCase(b.charAt(j++)); if (aUpper && !bUpper) { return -1; } if (bUpper && !aUpper) { return +1; } } } /** * Get a collation key for two Strings. The essential property of collation keys * is that if two values are equal under the collation, then the collation keys are * compare correctly under the equals() method. */ public Object getCollationKey(String s) { return baseCollator.getCollationKey(s); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of this module is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. //saxonb-9.1.0.8/bj/net/sf/saxon/sort/CodepointCollator.java0000644000175000017500000001375611033351443022673 0ustar eugeneeugenepackage net.sf.saxon.sort; import java.io.Serializable; /** * A collating sequence that uses Unicode codepoint ordering */ public class CodepointCollator implements StringCollator, SubstringMatcher, Serializable { private static CodepointCollator theInstance = new CodepointCollator(); public static CodepointCollator getInstance() { return theInstance; } /** * Compare two string objects. * @return <0 if a0 if a>b * @throws ClassCastException if the objects are of the wrong type for this Comparer */ public int compareStrings(String a, String b) { //return ((String)a).compareTo((String)b); // Note that Java does UTF-16 code unit comparison, which is not the same as Unicode codepoint comparison // except in the "equals" case. So we have to do a character-by-character comparison return compareCS((String)a, (String)b); } /** * Compare two CharSequence objects. This is hand-coded to avoid converting the objects into * Strings. * @return <0 if a0 if a>b * @throws ClassCastException if the objects are of the wrong type for this Comparer */ public int compareCS(CharSequence a, CharSequence b) { int alen = a.length(); int blen = b.length(); int i = 0; int j = 0; while (true) { if (i == alen) { if (j == blen) { return 0; } else { return -1; } } if (j == blen) { return +1; } // Following code is needed when comparing a BMP character against a surrogate pair // Note: we could do this comparison without fully computing the codepoint, but it's a very rare case int nexta = (int)a.charAt(i++); if (nexta >= 55296 && nexta <= 56319) { nexta = ((nexta - 55296) * 1024) + ((int)a.charAt(i++) - 56320) + 65536; } int nextb = (int)b.charAt(j++); if (nextb >= 55296 && nextb <= 56319) { nextb = ((nextb - 55296) * 1024) + ((int)b.charAt(j++) - 56320) + 65536; } int c = nexta - nextb; if (c != 0) { return c; } } } /** * Test whether one string is equal to another, according to the rules * of the XPath compare() function. The result is true if and only if the * compare() method returns zero: but the implementation may be more efficient * than calling compare and testing the result for zero * * @param s1 the first string * @param s2 the second string * @return true iff s1 equals s2 */ public boolean comparesEqual(String s1, String s2) { return s1.equals(s2); } /** * Test whether one string contains another, according to the rules * of the XPath contains() function * * @param s1 the containing string * @param s2 the contained string * @return true iff s1 contains s2 */ public boolean contains(String s1, String s2) { return s1.indexOf(s2) >= 0; } /** * Test whether one string ends with another, according to the rules * of the XPath ends-with() function * * @param s1 the containing string * @param s2 the contained string * @return true iff s1 ends with s2 */ public boolean endsWith(String s1, String s2) { return s1.endsWith(s2); } /** * Test whether one string starts with another, according to the rules * of the XPath starts-with() function * * @param s1 the containing string * @param s2 the contained string * @return true iff s1 starts with s2 */ public boolean startsWith(String s1, String s2) { return s1.startsWith(s2); } /** * Return the part of a string after a given substring, according to the rules * of the XPath substring-after() function * * @param s1 the containing string * @param s2 the contained string * @return the part of s1 that follows the first occurrence of s2 */ public String substringAfter(String s1, String s2) { int i = s1.indexOf(s2); if (i<0) { return ""; } return s1.substring(i+s2.length()); } /** * Return the part of a string before a given substring, according to the rules * of the XPath substring-before() function * * @param s1 the containing string * @param s2 the contained string * @return the part of s1 that precedes the first occurrence of s2 */ public String substringBefore(String s1, String s2) { int j = s1.indexOf(s2); if (j<0) { return ""; }; return s1.substring(0, j); } /** * Get a collation key for two Strings. The essential property of collation keys * is that if two values are equal under the collation, then the collation keys are * compare correctly under the equals() method. */ public Object getCollationKey(String s) { return s; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none //saxonb-9.1.0.8/bj/net/sf/saxon/sort/ComparableAtomicValueComparer.java0000644000175000017500000001020011033351443025114 0ustar eugeneeugenepackage net.sf.saxon.sort; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.value.AtomicValue; /** * A comparer for comparing two "ordinary" atomic values, where the values implement the Comparable * interface and the equals() method with the appropriate XPath semantics. This rules out use of * collations, conversion of untyped atomic values, and context dependencies such as implicit timezone. */ public class ComparableAtomicValueComparer implements AtomicComparer { private static ComparableAtomicValueComparer THE_INSTANCE = new ComparableAtomicValueComparer(); /** * Get the singleton instance of this class * @return the singleton instance of this class */ public static ComparableAtomicValueComparer getInstance() { return THE_INSTANCE; } protected ComparableAtomicValueComparer() {} /** * Supply the dynamic context in case this is needed for the comparison * * @param context the dynamic evaluation context * @return either the original AtomicComparer, or a new AtomicComparer in which the context * is known. The original AtomicComparer is not modified */ public AtomicComparer provideContext(XPathContext context) { return this; } /** * Compare two AtomicValue objects according to the rules for their data type. UntypedAtomic * values are compared as if they were strings; if different semantics are wanted, the conversion * must be done by the caller. * * @param a the first object to be compared. This must be an AtomicValue and it must implement * Comparable with context-free XPath comparison semantics * @param b the second object to be compared. This must be an AtomicValue and it must implement * Comparable with context-free XPath comparison semantics * @return <0 if a0 if a>b * @throws ClassCastException if the objects are not comparable */ public int compareAtomicValues(AtomicValue a, AtomicValue b) { if (a == null) { return (b == null ? 0 : -1); } else if (b == null) { return +1; } return ((Comparable)a).compareTo(b); } /** * Compare two AtomicValue objects for equality according to the rules for their data type. UntypedAtomic * values are compared by converting to the type of the other operand. * @param a the first object to be compared. This must be an AtomicValue and it must implement * equals() with context-free XPath comparison semantics * @param b the second object to be compared. This must be an AtomicValue and it must implement * equals() with context-free XPath comparison semantics * @return true if the values are equal, false if not * @throws ClassCastException if the objects are not comparable */ public boolean comparesEqual(AtomicValue a, AtomicValue b) { return a.equals(b); } /** * Get a comparison key for an object. This must satisfy the rule that if two objects are equal, * then their comparison keys are equal, and vice versa. There is no requirement that the * comparison keys should reflect the ordering of the underlying objects. */ public ComparisonKey getComparisonKey(AtomicValue a) { return new ComparisonKey(a.getPrimitiveType().getFingerprint(), a); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/sort/IntRangeSet.java0000644000175000017500000002725111033351443021425 0ustar eugeneeugenepackage net.sf.saxon.sort; import net.sf.saxon.om.FastStringBuffer; import java.io.Serializable; import java.util.Arrays; /** * Set of int values. This implementation of IntSet uses a sorted array * of integer ranges. * * @author Michael Kay */ public class IntRangeSet implements Serializable, IntSet { // The array of start points, which will always be sorted private int[] startPoints; // The array of end points, which will always be sorted private int[] endPoints; // The number of elements of the above two arrays that are actually in use private int used = 0; // Hashcode, evaluated lazily private int hashCode = -1; // The number of items in the set private int size = 0; /** * Create an empty set */ public IntRangeSet() { startPoints = new int[4]; endPoints = new int[4]; used = 0; size = 0; hashCode = -1; } /** * Create one IntRangeSet as a copy of another * @param input the IntRangeSet to be copied */ public IntRangeSet(IntRangeSet input) { startPoints = new int[input.used]; endPoints = new int[input.used]; used = input.used; System.arraycopy(input.startPoints, 0, startPoints, 0, used); System.arraycopy(input.endPoints, 0, endPoints, 0, used); hashCode = input.hashCode; } /** * Create an IntRangeSet given the start points and end points of the integer ranges. * The two arrays must be the same length; each must be in ascending order; and the n'th end point * must be greater than the n'th start point, and less than the n+1'th start point, for all n. * @param startPoints the start points of the integer ranges * @param endPoints the end points of the integer ranges * @throws IllegalArgumentException if the two arrays are different lengths. Other error conditions * in the input are not currently detected. */ public IntRangeSet(int[] startPoints, int[] endPoints) { if (startPoints.length != endPoints.length) { throw new IllegalArgumentException("Array lengths differ"); } this.startPoints = startPoints; this.endPoints = endPoints; used = startPoints.length; for (int i=0; i endPoints[used-1]) { return false; } if (value < startPoints[0]) { return false; } int i = 0; int j = used; do { int mid = i + (j-i)/2; if (endPoints[mid] < value) { i = Math.max(mid, i+1); } else if (startPoints[mid] > value) { j = Math.min(mid, j-1); } else { return true; } } while (i != j); return false; } public boolean remove(int value) { throw new UnsupportedOperationException("remove"); } /** * Add an integer to the set * @param value the integer to be added * @return true if the integer was added, false if it was already present */ public boolean add(int value) { hashCode = -1; if (used == 0) { ensureCapacity(1); startPoints[used-1] = value; endPoints[used-1] = value; size++; return true; } if (value > endPoints[used-1]) { if (value == endPoints[used-1] + 1) { endPoints[used-1]++; } else { ensureCapacity(used+1); startPoints[used-1] = value; endPoints[used-1] = value; } size++; return true; } if (value < startPoints[0]) { if (value == startPoints[0] - 1) { startPoints[0]--; } else { ensureCapacity(used+1); System.arraycopy(startPoints, 0, startPoints, 1, used-1); System.arraycopy(endPoints, 0, endPoints, 1, used-1); startPoints[0] = value; endPoints[0] = value; } size++; return true; } int i = 0; int j = used; do { int mid = i + (j-i)/2; if (endPoints[mid] < value) { i = Math.max(mid, i+1); } else if (startPoints[mid] > value) { j = Math.min(mid, j-1); } else { return false; // value is already present } } while (i != j); if (i > 0 && endPoints[i-1]+1 == value) { i--; } else if (i < used-1 && startPoints[i+1]-1 == value) { i++; } if (endPoints[i]+1 == value) { if (value == startPoints[i+1]-1) { // merge the two ranges endPoints[i] = endPoints[i+1]; System.arraycopy(startPoints, i+2, startPoints, i+1, used-i-2); System.arraycopy(endPoints, i+2, endPoints, i+1, used-i-2); used--; } else { endPoints[i]++; } size++; return true; } else if (startPoints[i]-1 == value) { if (value == endPoints[i-1]+1) { // merge the two ranges endPoints[i-1] = endPoints[i]; System.arraycopy(startPoints, i+1, startPoints, i, used-i-1); System.arraycopy(endPoints, i+1, endPoints, i, used-i-1); used--; } else { startPoints[i]--; } size++; return true; } else { if (value > endPoints[i]) { i++; } ensureCapacity(used+1); try { System.arraycopy(startPoints, i, startPoints, i+1, used-i-1); System.arraycopy(endPoints, i, endPoints, i+1, used-i-1); } catch (Exception err) { err.printStackTrace(); } startPoints[i] = value; endPoints[i] = value; size++; return true; } } private void ensureCapacity(int n) { if (startPoints.length < n) { int[] s = new int[startPoints.length * 2]; int[] e = new int[startPoints.length * 2]; System.arraycopy(startPoints, 0, s, 0, used); System.arraycopy(endPoints, 0, e, 0, used); startPoints = s; endPoints = e; } used = n; } /** * Get an iterator over the values */ public IntIterator iterator() { return new IntRangeSetIterator(); } public String toString() { FastStringBuffer sb = new FastStringBuffer(used*8); for (int i=0; iNOT comparable with other implementations of IntSet */ public boolean equals(Object other) { if (other instanceof IntRangeSet) { return used == ((IntRangeSet)other).used && Arrays.equals(startPoints, ((IntRangeSet)other).startPoints) && Arrays.equals(endPoints, ((IntRangeSet)other).endPoints) ; } return containsAll((IntSet)other); } /** * Construct a hash key that supports the equals() test */ public int hashCode() { // Note, hashcodes are NOT the same as those used by IntHashSet and IntArraySet if (hashCode == -1) { int h = 0x836a89f1; for (int i=0; i endPoints[used-1]) { if (low == endPoints[used-1] + 1) { endPoints[used-1] = high; } else { ensureCapacity(used+1); startPoints[used-1] = low; endPoints[used-1] = high; } size += (high - low + 1); } else { for (int i=low; i<=high; i++) { add(i); } } } /** * Get the start points of the ranges */ public int[] getStartPoints() { return startPoints; } /** * Get the end points of the ranges */ public int[] getEndPoints() { return endPoints; } /** * Get the number of ranges actually in use */ public int getNumberOfRanges() { return used; } /** * Iterator class */ private class IntRangeSetIterator implements IntIterator, Serializable { private int i = 0; private int current = 0; public IntRangeSetIterator() { i = -1; current = Integer.MIN_VALUE; } public boolean hasNext() { if (i<0) { return size > 0; } else { return current < endPoints[used-1]; } } public int next() { if (i < 0) { i = 0; current = startPoints[0]; return current; } if (current == endPoints[i]) { current = startPoints[++i]; return current; } else { return ++current; } } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. saxonb-9.1.0.8/bj/net/sf/saxon/sort/SortedIterator.java0000644000175000017500000002672311033351443022217 0ustar eugeneeugenepackage net.sf.saxon.sort; import net.sf.saxon.Configuration; import net.sf.saxon.expr.ErrorIterator; import net.sf.saxon.expr.LastPositionFinder; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.Item; import net.sf.saxon.om.LookaheadIterator; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.trace.Location; import net.sf.saxon.trans.XPathException; import net.sf.saxon.trans.NoDynamicContextException; import net.sf.saxon.value.AtomicValue; /** * Class to do a sorted iteration */ public class SortedIterator implements SequenceIterator, LastPositionFinder, LookaheadIterator, Sortable { // the items to be sorted protected SequenceIterator base; // the call-back function used to evaluate sort keys protected SortKeyEvaluator sortKeyEvaluator; // the comparators corresponding to these sort keys protected AtomicComparer[] comparators; // The items and keys are read into an array (nodeKeys) for sorting. This // array contains one "record" representing each node: the "record" contains // first, the Item itself, then an entry for each of its sort keys, in turn; // the last sort key is the position of the Item in the original sequence. protected int recordSize; protected Object[] nodeKeys; // The number of items to be sorted. -1 means not yet known. protected int count = -1; // The next item to be delivered from the sorted iteration protected int position = 0; // The context for the evaluation of sort keys protected XPathContext context; // The host language (XSLT, XQuery, XPath). Used only to decide which error code to use on dynamic errors. private int hostLanguage; private SortedIterator(){} /** * Create a sorted iterator * @param context the dynamic XPath evaluation context * @param base an iterator over the sequence to be sorted * @param sortKeyEvaluator an object that allows the n'th sort key for a given item to be evaluated * @param comparators an array of AtomicComparers, one for each sort key, for comparing sort key values */ public SortedIterator(XPathContext context, SequenceIterator base, SortKeyEvaluator sortKeyEvaluator, AtomicComparer[] comparators) { this.context = context.newMinorContext(); this.context.setOriginatingConstructType(Location.SORT_KEY); this.context.setCurrentIterator(base); this.base = base; this.sortKeyEvaluator = sortKeyEvaluator; this.comparators = new AtomicComparer[comparators.length]; for (int n=0; n * This method must not be called unless the result of getProperties() on the iterator * includes the bit setting {@link net.sf.saxon.om.SequenceIterator#LOOKAHEAD} * * @return true if there are more items in the sequence */ public boolean hasNext() { if (position < 0) { return false; } if (count < 0) { // haven't started sorting yet if (base instanceof LookaheadIterator) { return ((LookaheadIterator)base).hasNext(); } else { try { doSort(); return count > 0; } catch (XPathException err) { // can't return the exception now; but we can rely on the fact that // (a) it wouldn't have failed unless there was something to sort, and // (b) it's going to fail again when next() is called count = -1; base = new ErrorIterator(err); return true; } } } else { return (position < count); } } /** * Get the next item, in sorted order */ public Item next() throws XPathException { if (position < 0) { return null; } if (count<0) { doSort(); } if (position < count) { return (Item)nodeKeys[(position++)*recordSize]; } else { position = -1; return null; } } public Item current() { if (position < 1) { return null; } return (Item)nodeKeys[(position-1)*recordSize]; } public int position() { return position; } public int getLastPosition() throws XPathException { if (count<0) { doSort(); } return count; } public void close() { } public SequenceIterator getAnother() throws XPathException { // make sure the sort has been done, so that multiple iterators over the // same sorted data only do the sorting once. if (count<0) { doSort(); } SortedIterator s = new SortedIterator(); // the new iterator is the same as the old ... s.base = base.getAnother(); s.sortKeyEvaluator = sortKeyEvaluator; s.comparators = comparators; s.recordSize = recordSize; s.nodeKeys = nodeKeys; s.count = count; s.context = context; //s.keyComparers = keyComparers; // ... except for its start position. s.position = 0; return s; } /** * Get properties of this iterator, as a bit-significant integer. * * @return the properties of this iterator. This will be some combination of * properties such as {@link #GROUNDED}, {@link #LAST_POSITION_FINDER}, * and {@link #LOOKAHEAD}. It is always * acceptable to return the value zero, indicating that there are no known special properties. * It is acceptable for the properties of the iterator to change depending on its state. */ public int getProperties() { return LAST_POSITION_FINDER; } /** * Create an array holding the items to be sorted and the values of their sort keys * @throws XPathException */ protected void buildArray() throws XPathException { int allocated; if ((base.getProperties() & SequenceIterator.LAST_POSITION_FINDER) != 0) { allocated = ((LastPositionFinder)base).getLastPosition(); } else { allocated = 100; } nodeKeys = new Object[allocated * recordSize]; count = 0; // initialise the array with data while (true) { Item item = base.next(); if (item == null) { break; } if (count==allocated) { allocated *= 2; Object[] nk2 = new Object[allocated * recordSize]; System.arraycopy(nodeKeys, 0, nk2, 0, count * recordSize); nodeKeys = nk2; } int k = count*recordSize; nodeKeys[k] = item; // TODO: delay evaluating the sort keys until we know they are needed. Often the 2nd and subsequent // sort key values will never be used. The only problem is with sort keys that depend on position(). for (int n=0; n 2000) { Object[] nk2 = new Object[count * recordSize]; System.arraycopy(nodeKeys, 0, nk2, 0, count * recordSize); nodeKeys = nk2; } } private void doSort() throws XPathException { buildArray(); if (count<2) return; // sort the array //QuickSort.sort(this, 0, count-1); try { GenericSorter.quickSort(0, count, this); } catch (ClassCastException e) { //e.printStackTrace(); XPathException err = new XPathException("Non-comparable types found while sorting: " + e.getMessage()); if (hostLanguage == Configuration.XSLT) { err.setErrorCode("XTDE1030"); } else { err.setErrorCode("XPTY0004"); } throw err; } //GenericSorter.mergeSort(0, count, this); } /** * Compare two items in sorted sequence * (needed to implement the Sortable interface) * @return <0 if obj[a]0 if obj[a]>obj[b] */ public int compare(int a, int b) { int a1 = a*recordSize + 1; int b1 = b*recordSize + 1; try { for (int i=0; iCase is irrelevant, unless the strings are equal ignoring * case, in which case lowercase comes first.

    * * @author Michael H. Kay */ public class LowercaseFirstCollator implements StringCollator, java.io.Serializable { private StringCollator baseCollator; /** * Create a LowercaseFirstCollator * @param base the base collator, which determines how characters are sorted irrespective of case */ public LowercaseFirstCollator(StringCollator base) { baseCollator = base; } /** * Compare two string objects: case is irrelevant, unless the strings are equal ignoring * case, in which case lowercase comes first. * * @return <0 if a0 if a>b * @throws ClassCastException if the objects are of the wrong type for this Comparer */ public int compareStrings(String a, String b) { int diff = baseCollator.compareStrings(a, b); if (diff != 0) { return diff; } // This is doing a character-by-character comparison, which isn't really right. // There might be a sequence of letters constituting a single collation unit. int i = 0; int j = 0; while (true) { // Skip characters that are equal in the two strings while (i < a.length() && j < b.length() && a.charAt(i) == b.charAt(j)) { i++; j++; } // Skip non-letters in the first string while (i < a.length() && !Character.isLetter(a.charAt(i))) { i++; } // Skip non-letters in the second string while (j < b.length() && !Character.isLetter(b.charAt(j))) { j++; } // If we've got to the end of either string, treat the strings as equal if (i >= a.length()) { return 0; } if (j >= b.length()) { return 0; } // If one of the characters is lower case and the other isn't, the issue is decided boolean aLower = Character.isLowerCase(a.charAt(i++)); boolean bLower = Character.isLowerCase(b.charAt(j++)); if (aLower && !bLower) { return -1; } if (bLower && !aLower) { return +1; } } } /** * Get a collation key for two Strings. The essential property of collation keys * is that if two values are equal under the collation, then the collation keys are * compare correctly under the equals() method. */ public Object getCollationKey(String s) { return baseCollator.getCollationKey(s); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of this module is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. //saxonb-9.1.0.8/bj/net/sf/saxon/sort/SortedTupleIterator.java0000644000175000017500000001010611033351443023215 0ustar eugeneeugenepackage net.sf.saxon.sort; import net.sf.saxon.Configuration; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.om.ValueRepresentation; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.Closure; import net.sf.saxon.value.EmptySequence; import net.sf.saxon.value.ObjectValue; /** * A SortedTupleIterator is a modified SortedIterator. Whereas the sorted iterator * used by XSLT computes the sort key of each item in a sequence, using that item * as the context item, the SortedTupleIterator used by XQuery precomputes the sort * keys from scratch; they do not need to be a function of the item being sorted. * *

    The items returned by the SortedTupleIterator are instance of ObjectValue, * which encapsulate a Value representing the contents of the tuple.

    */ public class SortedTupleIterator extends SortedIterator { /** * Create a sorted tuple iterator * @param context the dynamic context * @param base the base iterator, which returns the unsorted tuples. Each tuple is represented * by an ObjectValue which wraps an array of Value objects. The first Value object represents * the tuple itself. Subsequent Value objects represent the sort key values, in order. * @param comparators the comparators used for comparing sort keys */ public SortedTupleIterator(XPathContext context, SequenceIterator base, AtomicComparer[] comparators) { super(context, base, null, comparators); setHostLanguage(Configuration.XQUERY); } /** * Override the method that builds the array of values and sort keys. * @throws XPathException */ protected void buildArray() throws XPathException { int allocated = 100; nodeKeys = new Object[allocated * recordSize]; count = 0; // initialise the array with data while (true) { ObjectValue tupleObject = (ObjectValue)base.next(); if (tupleObject == null) { break; } ValueRepresentation[] tuple = (ValueRepresentation[])tupleObject.getObject(); if (count==allocated) { allocated *= 2; Object[] nk2 = new Object[allocated * recordSize]; System.arraycopy(nodeKeys, 0, nk2, 0, count * recordSize); nodeKeys = nk2; } int k = count*recordSize; nodeKeys[k] = new ObjectValue(tuple[0]); // this is the "item" that will be returned by the TupleIterator. // In general it is actually a sequence, so we wrap it in an ObjectValue // It subsequently gets unwrapped by the MappingFunction applied to the // output of the SortedTupleIterator. for (int n=1; n<=comparators.length; n++) { ValueRepresentation v = tuple[n]; if (v instanceof Closure) { v = ((Closure)v).reduce(); } if (v instanceof EmptySequence) { nodeKeys[k+n] = null; } else { nodeKeys[k+n] = v; } } nodeKeys[k+comparators.length+1] = new Integer(count); count++; } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none //saxonb-9.1.0.8/bj/net/sf/saxon/sort/SubstringMatcher.java0000644000175000017500000000623211033351443022522 0ustar eugeneeugenepackage net.sf.saxon.sort; /** * This interface is implemented by a collation that is capable of supporting * the XPath functions that require matching of a substring: namely contains(), * starts-with, ends-with, substring-before, and substring-after. */ public interface SubstringMatcher extends StringCollator { /** * Test whether one string is equal to another, according to the rules * of the XPath compare() function. The result is true if and only if the * compareStrings() method returns zero: but the implementation may be more efficient * than calling compare and testing the result for zero * @param s1 the first string * @param s2 the second string * @return true iff s1 equals s2 */ public boolean comparesEqual(String s1, String s2); /** * Test whether one string contains another, according to the rules * of the XPath contains() function * @param s1 the containing string * @param s2 the contained string * @return true iff s1 contains s2 */ public boolean contains(String s1, String s2); /** * Test whether one string starts with another, according to the rules * of the XPath starts-with() function * @param s1 the containing string * @param s2 the contained string * @return true iff s1 starts with s2 */ public boolean startsWith(String s1, String s2); /** * Test whether one string ends with another, according to the rules * of the XPath ends-with() function * @param s1 the containing string * @param s2 the contained string * @return true iff s1 ends with s2 */ public boolean endsWith(String s1, String s2); /** * Return the part of a string before a given substring, according to the rules * of the XPath substring-before() function * @param s1 the containing string * @param s2 the contained string * @return the part of s1 that precedes the first occurrence of s2 */ public String substringBefore(String s1, String s2); /** * Return the part of a string after a given substring, according to the rules * of the XPath substring-after() function * @param s1 the containing string * @param s2 the contained string * @return the part of s1 that follows the first occurrence of s2 */ public String substringAfter(String s1, String s2); } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none //saxonb-9.1.0.8/bj/net/sf/saxon/sort/ConditionalSorter.java0000644000175000017500000002260411033351443022701 0ustar eugeneeugenepackage net.sf.saxon.sort; import net.sf.saxon.trans.XPathException; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.expr.*; import net.sf.saxon.trace.ExpressionPresenter; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.TypeHierarchy; import java.util.Iterator; /** * An expression that sorts an underlying sequence into document order if some condition is true, or that * returns the sequence "as is" (knowing that it doesn't need sorting) if the condition is false. */ public class ConditionalSorter extends Expression { private Expression condition; private DocumentSorter documentSorter; /** * Create a conditional document sorter * @param condition the conditional expression * @param sorter the sorting expression */ public ConditionalSorter(Expression condition, DocumentSorter sorter) { this.condition = condition; documentSorter = sorter; } /** * Get the condition under which the nodes need to be sorted * @return the condition (an expression) */ public Expression getCondition() { return condition; } /** * Get the document sorter, which sorts the nodes if the condition is true * @return the document sorter */ public DocumentSorter getDocumentSorter() { return documentSorter; } /** * Determine the static cardinality of the expression. This establishes how many items * there will be in the result of the expression, at compile time (i.e., without * actually evaluating the result. * * @return one of the values Cardinality.ONE_OR_MORE, * Cardinality.ZERO_OR_MORE, Cardinality.EXACTLY_ONE, * Cardinality.ZERO_OR_ONE, Cardinality.EMPTY. This default * implementation returns ZERO_OR_MORE (which effectively gives no * information). */ public int getCardinality() { return documentSorter.getCardinality(); } /** * Compute the special properties of this expression. These properties are denoted by a bit-significant * integer, possible values are in class {@link net.sf.saxon.expr.StaticProperty}. The "special" properties are properties * other than cardinality and dependencies, and most of them relate to properties of node sequences, for * example whether the nodes are in document order. * * @return the special properties, as a bit-significant integer */ protected int computeSpecialProperties() { return condition.getSpecialProperties() | StaticProperty.ORDERED_NODESET & ~StaticProperty.REVERSE_DOCUMENT_ORDER; } /** * An implementation of Expression must provide at least one of the methods evaluateItem(), iterate(), or process(). * This method indicates which of these methods is provided directly. The other methods will always be available * indirectly, using an implementation that relies on one of the other methods. * * @return the implementation method, for example {@link #ITERATE_METHOD} or {@link #EVALUATE_METHOD} or * {@link #PROCESS_METHOD} */ public int getImplementationMethod() { return ITERATE_METHOD; } /** * Get the immediate sub-expressions of this expression. Default implementation * returns a zero-length array, appropriate for an expression that has no * sub-expressions. * * @return an iterator containing the sub-expressions of this expression */ public Iterator iterateSubExpressions() { return new PairIterator(condition, documentSorter); } /** * Replace one subexpression by a replacement subexpression * @param original the original subexpression * @param replacement the replacement subexpression * @return true if the original subexpression is found */ public boolean replaceSubExpression(Expression original, Expression replacement) { boolean found = false; if (condition == original) { condition = replacement; found = true; } if (documentSorter == original) { documentSorter = (DocumentSorter)replacement; found = true; } return found; } /** * Compute the static cardinality of this expression * * @return the computed cardinality, as one of the values {@link net.sf.saxon.expr.StaticProperty#ALLOWS_ZERO_OR_ONE}, * {@link net.sf.saxon.expr.StaticProperty#EXACTLY_ONE}, {@link net.sf.saxon.expr.StaticProperty#ALLOWS_ONE_OR_MORE}, * {@link net.sf.saxon.expr.StaticProperty#ALLOWS_ZERO_OR_MORE} */ protected int computeCardinality() { return StaticProperty.ALLOWS_ZERO_OR_MORE; } /** * Copy an expression. This makes a deep copy. * * @return the copy of the original expression */ public Expression copy() { return new ConditionalSorter(condition.copy(), (DocumentSorter)documentSorter.copy()); } /** * Diagnostic print of expression structure. The abstract expression tree * is written to the supplied output destination. * * @param out the expression presenter used to display the structure */ public void explain(ExpressionPresenter out) { out.startElement("conditionalSort"); condition.explain(out); documentSorter.explain(out); out.endElement(); } /** * Determine the data type of the expression, if possible. All expression return * sequences, in general; this method determines the type of the items within the * sequence, assuming that (a) this is known in advance, and (b) it is the same for * all items in the sequence. *

    *

    This method should always return a result, though it may be the best approximation * that is available at the time.

    * * @param th the type hierarchy cache * @return a value such as Type.STRING, Type.BOOLEAN, Type.NUMBER, * Type.NODE, or Type.ITEM (meaning not known at compile time) */ public ItemType getItemType(TypeHierarchy th) { return documentSorter.getItemType(th); } /** * Offer promotion for this subexpression. The offer will be accepted if the subexpression * is not dependent on the factors (e.g. the context item) identified in the PromotionOffer. * By default the offer is not accepted - this is appropriate in the case of simple expressions * such as constant values and variable references where promotion would give no performance * advantage. This method is always called at compile time. * * @param offer details of the offer, for example the offer to move * expressions that don't depend on the context to an outer level in * the containing expression * @return if the offer is not accepted, return this expression unchanged. * Otherwise return the result of rewriting the expression to promote * this subexpression * @throws net.sf.saxon.trans.XPathException * if any error is detected */ public Expression promote(PromotionOffer offer) throws XPathException { Expression exp = offer.accept(this); if (exp != null) { return exp; } else { condition = doPromotion(condition, offer); Expression e = doPromotion(documentSorter, offer); if (e instanceof DocumentSorter) { return this; } else { return e; } } } /** * Return an Iterator to iterate over the values of a sequence. The value of every * expression can be regarded as a sequence, so this method is supported for all * expressions. This default implementation handles iteration for expressions that * return singleton values: for non-singleton expressions, the subclass must * provide its own implementation. * * @param context supplies the context for evaluation * @return a SequenceIterator that can be used to iterate over the result * of the expression * @throws net.sf.saxon.trans.XPathException * if any dynamic error occurs evaluating the * expression */ public SequenceIterator iterate(XPathContext context) throws XPathException { boolean b = condition.effectiveBooleanValue(context); if (b) { return documentSorter.iterate(context); } else { return documentSorter.getBaseExpression().iterate(context); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/sort/IntToIntMap.java0000644000175000017500000000434511033351443021407 0ustar eugeneeugenepackage net.sf.saxon.sort; /** * Interface defining a map from integers to integers */ public interface IntToIntMap { /** * Set the value to be returned to indicate an unused entry * @param defaultValue the value to be returned by {@link #get(int)} if no entry * exists for the supplied key */ void setDefaultValue(int defaultValue); /** * Get the default value used to indicate an unused entry * @return the value to be returned by {@link #get(int)} if no entry * exists for the supplied key */ int getDefaultValue(); /** * Clear the map. */ void clear(); /** * Finds a key in the map. * * @param key Key * @return true if the key is mapped */ boolean find(int key); /** * Gets the value for this key. * * @param key Key * @return the value, or the default value if not found. */ int get(int key); /** * Gets the size of the map. * * @return the size */ int size(); /** * Removes a key from the map. * * @param key Key to remove * @return true if the value was removed */ boolean remove(int key); /** * Adds a key-value pair to the map. * * @param key Key * @param value Value */ void put(int key, int value); /** * Get an iterator over the integer key values held in the hash map * @return an iterator whose next() call returns the key values (in arbitrary order) */ IntIterator keyIterator(); } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/sort/TupleExpression.java0000644000175000017500000001746311033351443022417 0ustar eugeneeugenepackage net.sf.saxon.sort; import net.sf.saxon.trace.ExpressionPresenter; import net.sf.saxon.expr.*; import net.sf.saxon.om.Item; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ExternalObjectType; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.TypeHierarchy; import net.sf.saxon.value.ObjectValue; import net.sf.saxon.value.Value; import java.util.Arrays; import java.util.Iterator; /** * A tuple expression is an expression that returns a tuple. Specifically, * it is a list of n expressions, which are evaluated to create a list of n items. * Tuple expressions are used during the evaluation of a FLWR expression. A tuple * is not a value within the XPath/XQuery type system, so it is represented as * an external object, specifically as a Java array wrapped inside an ObjectValue. * */ public class TupleExpression extends Expression { Expression[] components; int[] evaluationModes; public TupleExpression(int width) { components = new Expression[width]; evaluationModes = new int[width]; } /** * Set the i'th component expression of the tuple * @param i identifies the component to set * @param exp the component expression */ public void setExpression(int i, Expression exp) { components[i] = exp; adoptChildExpression(components[i]); evaluationModes[i] = ExpressionTool.UNDECIDED; } /** * Get the component expressions * @return the component expressions, as an array */ public Expression[] getComponents() { return components; } public Expression simplify(ExpressionVisitor visitor) throws XPathException { for (int i=0; i *

    This method is called after all references to functions and variables have been resolved * to the declaration of the function or variable, and after all type checking has been done.

    * * @param visitor an expression visitor * @param contextItemType the static type of "." at the point where this expression is invoked. * The parameter is set to null if it is known statically that the context item will be undefined. * If the type of the context item is not known statically, the argument is set to * {@link net.sf.saxon.type.Type#ITEM_TYPE} * @return the original expression, rewritten if appropriate to optimize execution * @throws XPathException if an error is discovered during this phase * (typically a type error) */ public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { for (int i=0; i0 if a>b * @throws ClassCastException if the objects are of the wrong type for this Comparer */ public int compareAtomicValues(AtomicValue a, AtomicValue b) throws NoDynamicContextException { return 0 - baseComparer.compareAtomicValues(a, b); } /** * Compare two AtomicValue objects for equality according to the rules for their data type. UntypedAtomic * values are compared by converting to the type of the other operand. * * @param a the first object to be compared. It is intended that this should be an instance * of AtomicValue, though this restriction is not enforced. If it is a StringValue, the * collator is used to compare the values, otherwise the value must implement the equals() method. * @param b the second object to be compared. This must be comparable with the first object: for * example, if one is a string, they must both be strings. * @return true if the values are equal, false if not * @throws ClassCastException if the objects are not comparable */ public boolean comparesEqual(AtomicValue a, AtomicValue b) throws NoDynamicContextException { return baseComparer.comparesEqual(a, b); } /** * Get a comparison key for an object. This must satisfy the rule that if two objects are equal * according to the XPath eq operator, then their comparison keys are equal according to the Java * equals() method, and vice versa. There is no requirement that the * comparison keys should reflect the ordering of the underlying objects. */ public ComparisonKey getComparisonKey(AtomicValue a) throws NoDynamicContextException { return baseComparer.getComparisonKey(a); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none //saxonb-9.1.0.8/bj/net/sf/saxon/sort/NamedCollation.java0000644000175000017500000000656511033351443022140 0ustar eugeneeugenepackage net.sf.saxon.sort; import net.sf.saxon.Platform; import net.sf.saxon.Configuration; import java.util.Comparator; /** * A StringCollator is used for comparing strings (Java String objects). * The URI is retained along with the collation so that the collation can * be reconstructed on demand, typically at run-time by compiled code which has access to the * URI but not the collation object itself. */ public class NamedCollation implements StringCollator { private String uri; private transient Comparator collation; // the collation is not serialized, but is reconstituted on demand private static Platform platform = Configuration.getPlatform(); /** * Create a NamedCollation * @param uri the name of the collation * @param collation the Comparator that does the actual string comparison */ public NamedCollation(String uri, Comparator collation) { this.uri = uri; this.collation = collation; } /** * Compares its two arguments for order. Returns a negative integer, * zero, or a positive integer as the first argument is less than, equal * to, or greater than the second.

    *

    * @param o1 the first object to be compared. * @param o2 the second object to be compared. * @return a negative integer, zero, or a positive integer as the * first argument is less than, equal to, or greater than the * second. * @throws ClassCastException if the arguments' types prevent them from * being compared by this Comparator. */ public int compareStrings(String o1, String o2) { return collation.compare(o1, o2); } /** * Get the URI identifying the collation */ public String getUri() { return uri; } /** * Set the URI identifying the collation * @param uri the collation URI */ public void setUri(String uri) { this.uri = uri; } /** * Get the underlying comparator * @return the underlying comparator */ public Comparator getCollation() { return collation; } /** * Set the underlying comparator * @param collation the underlying comparator */ public void setCollation(Comparator collation) { this.collation = collation; } /** * Get a collation key for two Strings. The essential property of collation keys * is that if two values are equal under the collation, then the collation keys are * compare correctly under the equals() method. */ public Object getCollationKey(String s) { return platform.getCollationKey(this, s); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/sort/IntHashMap.java0000644000175000017500000002540411033351443021234 0ustar eugeneeugenepackage net.sf.saxon.sort; import java.io.Serializable; import java.util.Iterator; /** * A hash table that maps int keys to Object values. * * @author Dave Hale, Landmark Graphics * @author Dominique Devienne * @author Michael Kay: retrofitted to JDK 1.4, added iterator(), modified to disallow null values */ public class IntHashMap implements Serializable { /** * Initializes a map with a capacity of 8 and a load factor of 0,25. */ public IntHashMap() { this(8, 0.25); } /** * Initializes a map with the given capacity and a load factor of 0,25. * * @param capacity the initial capacity. */ public IntHashMap(int capacity) { this(capacity, 0.25); } /** * Constructs a new map with initial capacity, and load factor. *

    * The capacity is the number of keys that can be mapped without resizing * the arrays in which keys and values are stored. For efficiency, only * a fraction of the elements in those arrays are used. That fraction is * the specified load factor. The initial length of the arrays equals the * smallest power of two not less than the ratio capacity/factor. The * capacity of the map is increased, as necessary. The maximum number * of keys that can be mapped is 2^30. * * @param capacity the initial capacity. * @param factor the load factor. */ public IntHashMap(int capacity, double factor) { _factor = factor; setCapacity(capacity); } /** * Clears the map. */ public void clear() { _n = 0; for (int i = 0; i < _nmax; ++i) { //_filled[i] = false; _value[i] = null; } } /** * Finds a key in the map. * * @param key Key * @return true if the key is mapped */ // public boolean find(int key) { // return _filled[indexOf(key)] ? true : false; // } /** * Gets the value for this key. * * @param key Key * @return the value, null if not found. */ public Object get(int key) { // int i = indexOf(key); // return _filled[i] ? _value[i] : null; return _value[indexOf(key)]; } /** * Gets the size of the map. * * @return the size (the number of entries in the map) */ public int size() { return _n; } /** * Removes a key from the map. * * @param key Key to remove * @return true if the value was removed */ public boolean remove(int key) { // Knuth, v. 3, 527, Algorithm R. int i = indexOf(key); //if (!_filled[i]) { if (_value[i] == null) { return false; } --_n; for (; ;) { //_filled[i] = false; _value[i] = null; int j = i; int r; do { i = (i - 1) & _mask; //if (!_filled[i]) { if (_value[i] == null) { return true; } r = hash(_key[i]); } while ((i <= r && r < j) || (r < j && j < i) || (j < i && i <= r)); _key[j] = _key[i]; _value[j] = _value[i]; //_filled[j] = _filled[i]; } } /** * Adds a key-value pair to the map. * * @param key Key * @param value Value * @return the value that was previously associated with the key, or null if there was no previous value */ public Object put(int key, Object value) { if (value == null) { throw new NullPointerException("IntHashMap does not allow null values"); } int i = indexOf(key); Object old = _value[i]; if (old != null) { _value[i] = value; } else { _key[i] = key; _value[i] = value; grow(); } return old; } /////////////////////////////////////////////////////////////////////////// // private private static final int NBIT = 30; // NMAX = 2^NBIT private static final int NMAX = 1 << NBIT; // maximum number of keys mapped private double _factor; // 0.0 <= _factor <= 1.0 private int _nmax; // 0 <= _nmax = 2^nbit <= 2^NBIT = NMAX private int _n; // 0 <= _n <= _nmax <= NMAX private int _nlo; // _nmax*_factor (_n<=_nlo, if possible) private int _nhi; // NMAX*_factor (_n< _nhi, if possible) private int _shift; // _shift = 1 + NBIT - nbit (see function hash() below) private int _mask; // _mask = _nmax - 1 private int[] _key; // array[_nmax] of keys //@SuppressWarnings(value = {"unchecked"}) private Object[] _value; // array[_nmax] of values //private boolean[] _filled; // _filled[i]==true iff _key[i] is mapped private int hash(int key) { // Knuth, v. 3, 509-510. Randomize the 31 low-order bits of c*key // and return the highest nbits (where nbits <= 30) bits of these. // The constant c = 1327217885 approximates 2^31 * (sqrt(5)-1)/2. return ((1327217885 * key) >> _shift) & _mask; } private int indexOf(int key) { int i = hash(key); //while (_filled[i]) { while (_value[i] != null) { if (_key[i] == key) { return i; } i = (i - 1) & _mask; } return i; } private void grow() { ++_n; if (_n > NMAX) { throw new RuntimeException("number of keys mapped exceeds " + NMAX); } if (_nlo < _n && _n <= _nhi) { setCapacity(_n); } } private void setCapacity(int capacity) { if (capacity < _n) { capacity = _n; } double factor = (_factor < 0.01) ? 0.01 : (_factor > 0.99) ? 0.99 : _factor; int nbit, nmax; for (nbit = 1, nmax = 2; nmax * factor < capacity && nmax < NMAX; ++nbit, nmax *= 2) { ; } int nold = _nmax; if (nmax == nold) { return; } _nmax = nmax; _nlo = (int)(nmax * factor); _nhi = (int)(NMAX * factor); _shift = 1 + NBIT - nbit; _mask = nmax - 1; int[] key = _key; Object[] value = _value; //boolean[] filled = _filled; _n = 0; _key = new int[nmax]; // semantically equivalent to _value = new V[nmax] _value = new Object[nmax]; //_filled = new boolean[nmax]; if (key != null) { for (int i = 0; i < nold; ++i) { //if (filled[i]) { if (value[i] != null) { put(key[i], value[i]); } } } } /** * Get an iterator over the keys */ public IntIterator keyIterator() { return new IntHashMapKeyIterator(); } /** * Get an iterator over the values */ public Iterator valueIterator() { return new IntHashMapValueIterator(); } /** * Create a copy of the IntHashMap */ public IntHashMap copy() { IntHashMap n = new IntHashMap(size()); IntIterator it = keyIterator(); while (it.hasNext()) { int k = it.next(); n.put(k, get(k)); } return n; } /** * Diagnostic display of contents */ public void display() { IntIterator iter = new IntHashMapKeyIterator(); while (iter.hasNext()) { int key = iter.next(); Object value = get(key); System.err.println(key + " -> " + value.toString()); } } /** * Iterator over keys */ private class IntHashMapKeyIterator implements IntIterator, Serializable { private int i = 0; public IntHashMapKeyIterator() { i = 0; } public boolean hasNext() { while (i < _key.length) { if (_value[i] != null) { return true; } else { i++; } } return false; } public int next() { return _key[i++]; } } /** * Iterator over keys */ private class IntHashMapValueIterator implements Iterator, Serializable { private int i = 0; public IntHashMapValueIterator() { i = 0; } public boolean hasNext() { while (i < _key.length) { if (_value[i] != null) { return true; } else { i++; } } return false; } public Object next() { return _value[i++]; } /** * Removes from the underlying collection the last element returned by the * iterator (optional operation). * @throws UnsupportedOperationException if the remove * operation is not supported by this Iterator. */ public void remove() { throw new UnsupportedOperationException("remove"); } } /** * Iterator over values */ private class IntHashMapValueIteratorOLD implements Iterator, Serializable { private IntHashMapKeyIterator k; public IntHashMapValueIteratorOLD() { k = new IntHashMapKeyIterator(); } public boolean hasNext() { return k.hasNext(); } public Object next() { return get(k.next()); } public void remove() { throw new UnsupportedOperationException("remove() is not supported on IntHashMapValueIterator"); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Dave Hale and Dominique Devienne of Landmark Graphics; // the code was retrofitted to JDK 1.4 by Michael Kay, Saxonica. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. saxonb-9.1.0.8/bj/net/sf/saxon/sort/EmptyGreatestComparer.java0000644000175000017500000001154311033351443023525 0ustar eugeneeugenepackage net.sf.saxon.sort; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.trans.NoDynamicContextException; import net.sf.saxon.type.Type; import net.sf.saxon.value.AtomicValue; /** * A Comparer that modifies a base comparer by sorting empty key values and NaN values last (greatest), * as opposed to the default which sorts them first. * * @author Michael H. Kay * */ public class EmptyGreatestComparer implements AtomicComparer, java.io.Serializable { private AtomicComparer baseComparer; /** * Create an EmptyGreatestComparer * @param baseComparer the comparer used to compare non-empty values (which typically sorts empty * as least) */ public EmptyGreatestComparer(AtomicComparer baseComparer) { this.baseComparer = baseComparer; } /** * Get the underlying comparer (which compares empty least) * @return the base comparer */ public AtomicComparer getBaseComparer() { return baseComparer; } /** * Supply the dynamic context in case this is needed for the comparison * @param context the dynamic evaluation context * @return either the original AtomicComparer, or a new AtomicComparer in which the context * is known. The original AtomicComparer is not modified */ public AtomicComparer provideContext(XPathContext context) { AtomicComparer newBase = baseComparer.provideContext(context); if (newBase != baseComparer) { return new EmptyGreatestComparer(newBase); } else { return this; } } /** * Compare two AtomicValue objects according to the rules for their data type. UntypedAtomic * values are compared as if they were strings; if different semantics are wanted, the conversion * must be done by the caller. * @param a the first object to be compared. It is intended that this should normally be an instance * of AtomicValue, though this restriction is not enforced. If it is a StringValue, the * collator is used to compare the values, otherwise the value must implement the java.util.Comparable * interface. * @param b the second object to be compared. This must be comparable with the first object: for * example, if one is a string, they must both be strings. * @return <0 if a0 if a>b * @throws ClassCastException if the objects are not comparable */ public int compareAtomicValues(AtomicValue a, AtomicValue b) throws NoDynamicContextException { if (a == null) { if (b == null) { return 0; } else { return +1; } } else if (b == null) { return -1; } if (a.isNaN()) { return (b.isNaN() ? 0 : +1); } else if (b.isNaN()) { return -1; } return baseComparer.compareAtomicValues(a, b); } /** * Compare two AtomicValue objects for equality according to the rules for their data type. UntypedAtomic * values are compared by converting to the type of the other operand. * * @param a the first object to be compared. * @param b the second object to be compared. * @return true if the values are equal, false if not * @throws ClassCastException if the objects are not comparable */ public boolean comparesEqual(AtomicValue a, AtomicValue b) throws NoDynamicContextException { return (a==null && b==null) || baseComparer.comparesEqual(a, b); } /** * Get a comparison key for an object. This must satisfy the rule that if two objects are equal * according to the XPath eq operator, then their comparison keys are equal according to the Java * equals() method, and vice versa. There is no requirement that the * comparison keys should reflect the ordering of the underlying objects. */ public ComparisonKey getComparisonKey(AtomicValue a) throws NoDynamicContextException { return (a==null ? new ComparisonKey(Type.EMPTY, "()") : baseComparer.getComparisonKey(a)); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none //saxonb-9.1.0.8/bj/net/sf/saxon/sort/IntSet.java0000644000175000017500000000372711033351443020452 0ustar eugeneeugenepackage net.sf.saxon.sort; /** * A set of integers represented as int values */ public interface IntSet { /** * Clear the contents of the IntSet (making it an empty set) */ void clear(); /** * Get the number of integers in the set * @return the size of the set */ int size(); /** * Determine if the set is empty * @return true if the set is empty, false if not */ boolean isEmpty(); /** * Determine whether a particular integer is present in the set * @param value the integer under test * @return true if value is present in the set, false if not */ boolean contains(int value); /** * Remove an integer from the set * @param value the integer to be removed * @return true if the integer was present in the set, false if it was not present */ boolean remove(int value); /** * Add an integer to the set * @param value the integer to be added * @return true if the integer was added, false if it was already present */ boolean add(int value); /** * Get an iterator over the values */ IntIterator iterator(); /** * Test if this set is a superset of another set */ public boolean containsAll(IntSet other); } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/sort/SortKeyDefinition.java0000644000175000017500000004131211117204624022646 0ustar eugeneeugenepackage net.sf.saxon.sort; import net.sf.saxon.Configuration; import net.sf.saxon.om.StandardNames; import net.sf.saxon.expr.*; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.TypeHierarchy; import net.sf.saxon.value.StringValue; import net.sf.saxon.value.Whitespace; import java.io.Serializable; import java.net.URI; import java.net.URISyntaxException; import java.util.Properties; /** * A SortKeyDefinition defines one component of a sort key.
    * * Note that most attributes defining the sort key can be attribute value templates, * and can therefore vary from one invocation to another. We hold them as expressions. As * soon as they are all known (which in general is only at run-time), the SortKeyDefinition * is replaced by a FixedSortKeyDefinition in which all these values are fixed. */ // TODO: optimise also for the case where the attributes depend only on global variables // or parameters, in which case the same AtomicComparer can be used for the duration of a // transformation. // TODO: at present the SortKeyDefinition is evaluated to obtain a AtomicComparer, which can // be used to compare two sort keys. It would be more efficient to use a Collator to // obtain collation keys for all the items to be sorted, as these can be compared more // efficiently. public class SortKeyDefinition implements Serializable { private static StringLiteral defaultOrder = new StringLiteral("ascending"); private static StringLiteral defaultCaseOrder = new StringLiteral("#default"); private static StringLiteral defaultLanguage = new StringLiteral(StringValue.EMPTY_STRING); protected Expression sortKey; protected Expression order = defaultOrder; protected Expression dataTypeExpression = null; // used when the type is not known till run-time protected Expression caseOrder = defaultCaseOrder; protected Expression language = defaultLanguage; protected Expression collationName = null; protected Expression stable = null; // not actually used, but present so it can be validated protected StringCollator collation; protected String baseURI; // needed in case collation URI is relative protected boolean emptyLeast = true; // used only in XQuery at present protected boolean backwardsCompatible = false; private transient AtomicComparer finalComparator = null; // Note, the "collation" defines the collating sequence for the sort key. The // "finalComparator" is what is actually used to do comparisons, after taking into account // ascending/descending, caseOrder, etc. // The comparer is transient because a RuleBasedCollator is not serializable. This means that // when a stylesheet is compiled, the finalComparator is discarded, which means a new finalComparator will be // constructed for each sort at run-time. /** * Set the expression used as the sort key * @param exp the sort key select expression */ public void setSortKey(Expression exp) { sortKey = exp; } /** * Get the expression used as the sort key * @return the sort key select expression */ public Expression getSortKey() { return sortKey; } /** * Set the order. This is supplied as an expression which must evaluate to "ascending" * or "descending". If the order is fixed, supply e.g. new StringValue("ascending"). * Default is "ascending". * @param exp the expression that determines the order (always a literal in XQuery, but * can be defined by an AVT in XSLT) */ public void setOrder(Expression exp) { order = exp; } /** * Get the expression that defines the order as ascending or descending * @return the expression that determines the order (always a literal in XQuery, but * can be defined by an AVT in XSLT) */ public Expression getOrder() { return order; } /** * Set the data type. This is supplied as an expression which must evaluate to "text", * "number", or a QName. If the data type is fixed, the valus should be supplied using * setDataType() and not via this method. * @param exp the expression that defines the data type, as used in XSLT 1.0 */ public void setDataTypeExpression(Expression exp) { dataTypeExpression = exp; } /** * Get the expression that defines the data type of the sort keys * @return the expression that defines the data type, as used in XSLT 1.0 */ public Expression getDataTypeExpression() { return dataTypeExpression; } /** * Set the case order. This is supplied as an expression which must evaluate to "upper-first" * or "lower-first" or "#default". If the order is fixed, supply e.g. new StringValue("lower-first"). * Default is "#default". * @param exp the expression that defines the case order */ public void setCaseOrder(Expression exp) { caseOrder = exp; } /** * Get the expression that defines the case order of the sort keys. * @return the expression that defines the case order, whose run-time value will be "upper-first", * "lower-first", or "#default". */ public Expression getCaseOrder() { return caseOrder; } /** * Set the language. This is supplied as an expression which evaluates to the language name. * If the order is fixed, supply e.g. new StringValue("de"). * @param exp the expression that determines the language */ public void setLanguage(Expression exp) { language = exp; } /** * Get the expression that defines the language of the sort keys * @return exp the expression that determines the language */ public Expression getLanguage() { return language; } /** * Set the collation name (specifically, an expression which when evaluated returns the collation URI). * @param collationName the expression that determines the collation name */ public void setCollationNameExpression(Expression collationName) { this.collationName = collationName; } /** * Get the selected collation name * (specifically, an expression which when evaluated returns the collation URI). * @return the expression that determines the collation name */ public Expression getCollationNameExpression() { return collationName; } /** * Set the collation to be used * @param collation A StringCollator, which encapsulates both the collation URI and the collating function */ public void setCollation(StringCollator collation) { this.collation = collation; } /** * Get the collation to be used * @return A StringCollator, which encapsulates both the collation URI and the collating function */ public StringCollator getCollation() { return collation; } /** * Set the base URI of the expression. This is needed to handle the case where a collation URI * evaluated at run-time turns out to be a relative URI. * @param baseURI the static base URI of the expression */ public void setBaseURI(String baseURI) { this.baseURI = baseURI; } /** * Get the static base URI of the expression. This is needed to handle the case where a collation URI * evaluated at run-time turns out to be a relative URI. * @return the static base URI of the expression */ public String getBaseURI() { return baseURI; } /** * Set whether this sort key definition is stable * @param stable the expression that determines whether the sort key definition is stable * (it evaluates to the string "yes" or "no". */ public void setStable(Expression stable) { this.stable = stable; } /** * Ask whether this sort key definition is stable * @return the expression that determines whether the sort key definition is stable * (it evaluates to the string "yes" or "no". */ public Expression getStable() { return stable; } /** * Set whether this sort key is evaluated in XSLT 1.0 backwards compatibility mode * @param compatible true if backwards compatibility mode is selected */ public void setBackwardsCompatible(boolean compatible) { backwardsCompatible = compatible; } /** * Ask whether this sort key is evaluated in XSLT 1.0 backwards compatibility mode * @return true if backwards compatibility mode was selected */ public boolean isBackwardsCompatible() { return backwardsCompatible; } /** * Set whether empty sequence comes before other values or after them * @param emptyLeast true if () is considered lower than any other value */ public void setEmptyLeast(boolean emptyLeast) { this.emptyLeast = emptyLeast; } /** * Ask whether empty sequence comes before other values or after them * @return true if () is considered lower than any other value */ public boolean getEmptyLeast() { return emptyLeast; } /** * Ask whether the sort key definition is fixed, that is, whether all the information needed * to create a Comparator is known statically * @return true if all information needed to create a Comparator is known statically */ public boolean isFixed() { return (order instanceof Literal && (dataTypeExpression == null || dataTypeExpression instanceof Literal) && caseOrder instanceof Literal && language instanceof Literal && (stable == null || stable instanceof Literal) && (collationName == null || collationName instanceof Literal)); } /** * Simplify this sort key definition * @param visitor the expression visitor * @return the simplified sort key definition * @throws XPathException if any failure occurs */ public SortKeyDefinition simplify(ExpressionVisitor visitor) throws XPathException { sortKey = visitor.simplify(sortKey); order = visitor.simplify(order); dataTypeExpression = visitor.simplify(dataTypeExpression); caseOrder = visitor.simplify(caseOrder); language = visitor.simplify(language); stable = visitor.simplify(stable); return this; } /** * Allocate an AtomicComparer to perform the comparisons described by this sort key component. This method * is called at run-time. The AtomicComparer takes into account not only the collation, but also parameters * such as order=descending and handling of empty sequence and NaN (the result of the compare() * method of the comparator is +1 if the second item is to sort after the first item) * @param context the dynamic evaluation context * @return an AtomicComparer suitable for making the sort comparisons */ public AtomicComparer makeComparator(XPathContext context) throws XPathException { String orderX = order.evaluateAsString(context).toString(); final Configuration config = context.getConfiguration(); final TypeHierarchy th = config.getTypeHierarchy(); AtomicComparer atomicComparer; StringCollator stringCollator; if (collation != null) { stringCollator = collation; } else if (collationName != null) { String cname = collationName.evaluateAsString(context).toString(); URI collationURI; try { collationURI = new URI(cname); if (!collationURI.isAbsolute()) { if (baseURI == null) { throw new XPathException("Collation URI is relative, and base URI is unknown"); } else { URI base = new URI(baseURI); collationURI = base.resolve(collationURI); } } } catch (URISyntaxException err) { throw new XPathException("Collation name " + cname + " is not a valid URI: " + err); } try { stringCollator = context.getCollation(collationURI.toString()); } catch (XPathException e) { if ("FOCH0002".equals(e.getErrorCodeLocalPart())) { e.setErrorCode("XTDE1035"); } throw e; } } else { String caseOrderX = caseOrder.evaluateAsString(context).toString(); String languageX = language.evaluateAsString(context).toString(); Properties props = new Properties(); if (languageX.length() != 0) { props.setProperty("lang", languageX); } if (!caseOrderX.equals("#default")) { props.setProperty("case-order", caseOrderX); } stringCollator = Configuration.getPlatform().makeCollation(config, props, ""); // TODO: build a URI allowing the collation to be reconstructed } if (dataTypeExpression==null) { atomicComparer = AtomicSortComparer.makeSortComparer(stringCollator, sortKey.getItemType(th).getAtomizedItemType().getPrimitiveType(), context); if (!emptyLeast) { atomicComparer = new EmptyGreatestComparer(atomicComparer); } } else { String dataType = dataTypeExpression.evaluateAsString(context).toString(); if (dataType.equals("text")) { atomicComparer = AtomicSortComparer.makeSortComparer(stringCollator, StandardNames.XS_STRING, context); atomicComparer = new TextComparer(atomicComparer); } else if (dataType.equals("number")) { atomicComparer = NumericComparer.getInstance(); } else { XPathException err = new XPathException("data-type on xsl:sort must be 'text' or 'number'"); err.setErrorCode("XTDE0030"); throw err; } } if (stable != null) { StringValue stableVal = (StringValue)stable.evaluateItem(context); String s = Whitespace.trim(stableVal.getStringValue()); if (s.equals("yes") || s.equals("no")) { // no action } else { XPathException err = new XPathException("Value of 'stable' on xsl:sort must be 'yes' or 'no'"); err.setErrorCode("XTDE0030"); throw err; } } if (orderX.equals("ascending")) { return atomicComparer; } else if (orderX.equals("descending")) { return new DescendingComparer(atomicComparer); } else { XPathException err1 = new XPathException("order must be 'ascending' or 'descending'"); err1.setErrorCode("XTDE0030"); throw err1; } } /** * Set the comparator which is used to compare two values according to this sort key. The comparator makes the final * decision whether one value sorts before or after another: this takes into account the data type, the collation, * whether empty comes first or last, whether the sort order is ascending or descending. * *

    This method is called at compile time if all these factors are known at compile time. * It must not be called at run-time, except to reconstitute a finalComparator that has been * lost by virtue of serialization .

    * @param comp the Atomic Comparer to be used */ public void setFinalComparator(AtomicComparer comp) { finalComparator = comp; } /** * Get the comparator which is used to compare two values according to this sort key. This method * may be called either at compile time or at run-time. If no comparator has been allocated, * it returns null. It is then necessary to allocate a comparator using the {@link #makeComparator} * method. * @return the Atomic Comparer to be used */ public AtomicComparer getFinalComparator() { return finalComparator; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/sort/package.html0000644000175000017500000000136111033351443020652 0ustar eugeneeugene Package overview for net.sf.saxon.sort

    This package provides utility routines for sorting and grouping. Specifically, it contains a QuickSort implementation, and some AtomicComparer objects that handle character and numeric comparisons, together with the important DocumentOrderIterator which iterates over a set of nodes in document order.

    The package also contains the classes to support the implementation of the XSLT 2.0 instruction xsl:for-each-group, and some utilities for maintaining sets and maps whose keys are unboxed integer values.


    Michael H. Kay
    Saxonica Limited
    22 September 2005

    saxonb-9.1.0.8/bj/net/sf/saxon/pattern/0000755000175000017500000000000012216261744017066 5ustar eugeneeugenesaxonb-9.1.0.8/bj/net/sf/saxon/pattern/NamespaceTest.java0000644000175000017500000001314311033112257022455 0ustar eugeneeugenepackage net.sf.saxon.pattern; import net.sf.saxon.om.NamePool; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.TypeHierarchy; import net.sf.saxon.tinytree.TinyTree; /** * NodeTest is an interface that enables a test of whether a node has a particular * name and type. A NamespaceTest matches the node type and the namespace URI. * * @author Michael H. Kay */ public final class NamespaceTest extends NodeTest { private NamePool namePool; private int nodeKind; private short uriCode; private String uri; public NamespaceTest(NamePool pool, int nodeKind, String uri) { namePool = pool; this.nodeKind = nodeKind; this.uri = uri; this.uriCode = pool.allocateCodeForURI(uri); } /** * Test whether this node test is satisfied by a given node * @param nodeType The type of node to be matched * @param fingerprint identifies the expanded name of the node to be matched */ public boolean matches(int nodeType, int fingerprint, int annotation) { if (fingerprint == -1) return false; if (nodeType != nodeKind) return false; return uriCode == namePool.getURICode(fingerprint); } /** * Test whether this node test is satisfied by a given node on a TinyTree. The node * must be a document, element, text, comment, or processing instruction node. * This method is provided * so that when navigating a TinyTree a node can be rejected without * actually instantiating a NodeInfo object. * * @param tree the TinyTree containing the node * @param nodeNr the number of the node within the TinyTree */ public boolean matches(TinyTree tree, int nodeNr) { int fingerprint = tree.getNameCode(nodeNr) & NamePool.FP_MASK; if (fingerprint == -1) return false; if (tree.getNodeKind(nodeNr) != nodeKind) return false; return uriCode == namePool.getURICode(fingerprint); } /** * Test whether this node test is satisfied by a given node. This alternative * method is used in the case of nodes where calculating the fingerprint is expensive, * for example DOM or JDOM nodes. * @param node the node to be matched */ public boolean matches(NodeInfo node) { return node.getNodeKind()==nodeKind && node.getURI().equals(uri); } /** * Determine the default priority of this node test when used on its own as a Pattern */ public final double getDefaultPriority() { return -0.25; } /** * Determine the types of nodes to which this pattern applies. Used for optimisation. * For patterns that match nodes of several types, return Type.NODE * @return the type of node matched by this pattern. e.g. Type.ELEMENT or Type.TEXT */ public int getPrimitiveType() { return nodeKind; } /** * Get the type from which this item type is derived by restriction. This * is the supertype in the XPath type heirarchy, as distinct from the Schema * base type: this means that the supertype of xs:boolean is xs:anyAtomicType, * whose supertype is item() (rather than xs:anySimpleType). *

    * In fact the concept of "supertype" is not really well-defined, because the types * form a lattice rather than a hierarchy. The only real requirement on this function * is that it returns a type that strictly subsumes this type, ideally as narrowly * as possible. * @return the supertype, or null if this type is item() * @param th the type hierarchy cache */ public ItemType getSuperType(TypeHierarchy th) { return NodeKindTest.makeNodeKindTest(nodeKind); } /** * Get a mask indicating which kinds of nodes this NodeTest can match. This is a combination * of bits: 1<Note that the SubstitutionGroupTest only tests whether the element name is in the * required set of names. It does not test that the content type matches. For this reason, * it is always used as part of a CombinedNodeTest that also tests the type annotation.

    * * @author Michael H. Kay */ public class SubstitutionGroupTest extends NodeTest { private int head; private IntHashSet group; /** * Constructor * @param head The name of the head element of the substitution group * @param group An IntSet containing Integer values representing the fingerprints * of element names included in the substitution group */ public SubstitutionGroupTest(int head, IntHashSet group) { this.group = group; this.head = head; } /** * Constructor * @param head The name of the head element of the substitution group * @param members An array containing integer values representing the fingerprints * of element names included in the substitution group */ public SubstitutionGroupTest(int head, int[] members) { //(used from XQuery compiled code) group = new IntHashSet(members.length); for (int i=0; i= 0; i--) { Expression filter = filters[i]; filter = visitor.simplify(filter); filters[i] = filter; } } return this; } /** * Type-check the pattern, performing any type-dependent optimizations. * @param visitor an expression visitor * @param contextItemType the type of the context item at the point where the pattern appears * @return the optimised Pattern */ public Pattern analyze(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { // analyze each component of the pattern StaticContext env = visitor.getStaticContext(); final TypeHierarchy th = visitor.getConfiguration().getTypeHierarchy(); if (parentPattern != null) { parentPattern = parentPattern.analyze(visitor, contextItemType); // Check that this step in the pattern makes sense in the context of the parent step AxisExpression step; if (nodeTest.getPrimitiveType() == Type.ATTRIBUTE) { step = new AxisExpression(Axis.ATTRIBUTE, nodeTest); } else { step = new AxisExpression(Axis.CHILD, nodeTest); } step.setLocationId(env.getLocationMap().allocateLocationId(env.getSystemId(), getLineNumber())); step.setContainer(this); Expression exp = visitor.typeCheck(step, parentPattern.getNodeTest()); refinedNodeTest = (NodeTest) exp.getItemType(th); } else if (ancestorPattern != null) { ancestorPattern = ancestorPattern.analyze(visitor, contextItemType); } if (filters != null) { Optimizer opt = visitor.getConfiguration().getOptimizer(); for (int i = numberOfFilters - 1; i >= 0; i--) { Expression filter = visitor.typeCheck(filters[i], getNodeTest()); filter = ExpressionTool.unsortedIfHomogeneous(opt, filter); filter = visitor.optimize(filter, getNodeTest()); // System.err.println("Filter after analyze:");filter.display(10); filters[i] = filter; if (Literal.isConstantBoolean(filter, true)) { // if a filter is constant true, remove it if (i == numberOfFilters - 1) { numberOfFilters--; } else { System.arraycopy(filters, i+1, filters, i, numberOfFilters - i - 1); numberOfFilters--; } // let the garbage collecter take the unwanted filter filters[numberOfFilters] = null; } else if (Literal.isConstantBoolean(filter, false)) { // if a filter is constant false, the pattern doesn't match anything return new NodeTestPattern(EmptySequenceTest.getInstance()); } } } // see if it's an element pattern with a single positional predicate of [1] if (nodeTest.getPrimitiveType() == Type.ELEMENT && numberOfFilters == 1) { if (Literal.isConstantOne(filters[0])) { firstElementPattern = true; specialFilter = true; numberOfFilters = 0; filters = null; } else if (filters[0] instanceof ComparisonExpression) { ComparisonExpression comp = (ComparisonExpression)filters[0]; if (comp.getSingletonOperator() == Token.FEQ && (comp.getOperands()[0] instanceof Position && Literal.isConstantOne(comp.getOperands()[1])) || (comp.getOperands()[1] instanceof Position && Literal.isConstantOne(comp.getOperands()[0]))) { firstElementPattern = true; specialFilter = true; numberOfFilters = 0; filters = null; } } } // see if it's an element pattern with a single positional predicate // of [position()=last()] if (nodeTest.getPrimitiveType() == Type.ELEMENT && numberOfFilters == 1 && filters[0] instanceof IsLastExpression && ((IsLastExpression) filters[0]).getCondition()) { lastElementPattern = true; specialFilter = true; numberOfFilters = 0; filters = null; } if (isPositional(th)) { equivalentExpr = makePositionalExpression(); equivalentExpr = visitor.typeCheck(equivalentExpr, contextItemType); specialFilter = true; } return this; // TODO:PERF: identify subexpressions within a pattern predicate that could be promoted // In the case of match patterns in template rules, these would have to become global variables. } /** * Get the dependencies of the pattern. The only possible dependency for a pattern is * on local variables. This is analyzed in those patterns where local variables may appear. */ public int getDependencies() { int dependencies = 0; if (parentPattern != null) { dependencies |= parentPattern.getDependencies(); } if (ancestorPattern != null) { dependencies |= ancestorPattern.getDependencies(); } for (int i = 0; i < numberOfFilters; i++) { dependencies |= filters[i].getDependencies(); } // the only dependency that's interesting is a dependency on local variables dependencies &= StaticProperty.DEPENDS_ON_LOCAL_VARIABLES; return dependencies; } /** * Iterate over the subexpressions within this pattern */ public Iterator iterateSubExpressions() { Iterator iter; if (numberOfFilters == 0) { iter = Collections.EMPTY_LIST.iterator(); } else { iter = Arrays.asList(filters).subList(0, numberOfFilters).iterator(); } if (variableBinding != null) { // Note that the variable binding must come first to ensure slots are allocated to the "current" // variable before the variable reference is encountered Iterator[] pair = {new MonoIterator(variableBinding), iter}; iter = new MultiIterator(pair); } if (parentPattern != null) { Iterator[] pair = {iter, parentPattern.iterateSubExpressions()}; iter = new MultiIterator(pair); } if (ancestorPattern != null) { Iterator[] pair = {iter, ancestorPattern.iterateSubExpressions()}; iter = new MultiIterator(pair); } return iter; } /** * Replace one subexpression by a replacement subexpression * * @param original the original subexpression * @param replacement the replacement subexpression * @return true if the original subexpression is found */ public boolean replaceSubExpression(Expression original, Expression replacement) { boolean found = false; for (int i = 0; i < numberOfFilters; i++) { if (filters[i] == original) { filters[i] = replacement; found = true; } } if (parentPattern != null) { found |= parentPattern.replaceSubExpression(original, replacement); } if (ancestorPattern != null) { found |= ancestorPattern.replaceSubExpression(original, replacement); } if (variableBinding == original) { variableBinding = replacement; found = true; } return found; } /** * Allocate slots to any variables used within the pattern * @param env the static context in the XSLT stylesheet * @param slotManager *@param nextFree the next slot that is free to be allocated @return the next slot that is free to be allocated */ public int allocateSlots(StaticContext env, SlotManager slotManager, int nextFree) { // See tests cnfr23, idky239, match54, group018 // SlotManager slotManager = env.getStyleElement().getContainingSlotManager(); if (variableBinding != null) { nextFree = ExpressionTool.allocateSlots(variableBinding, nextFree, slotManager); } for (int i = 0; i < numberOfFilters; i++) { nextFree = ExpressionTool.allocateSlots(filters[i], nextFree, slotManager); } if (parentPattern != null) { nextFree = parentPattern.allocateSlots(env, slotManager, nextFree); } if (ancestorPattern != null) { nextFree = ancestorPattern.allocateSlots(env, slotManager, nextFree); } //env.getStyleElement().getPrincipalStylesheet().allocatePatternSlots(nextFree); return nextFree; } /** * Offer promotion for subexpressions within this pattern. The offer will be accepted if the subexpression * is not dependent on the factors (e.g. the context item) identified in the PromotionOffer. * By default the offer is not accepted - this is appropriate in the case of simple expressions * such as constant values and variable references where promotion would give no performance * advantage. This method is always called at compile time. *

    *

    Unlike the corresponding method on {@link net.sf.saxon.expr.Expression}, this method does not return anything: * it can make internal changes to the pattern, but cannot return a different pattern. Only certain * kinds of promotion are applicable within a pattern: specifically, promotions affecting local * variable references within the pattern. * * @param offer details of the offer, for example the offer to move * expressions that don't depend on the context to an outer level in * the containing expression * @throws net.sf.saxon.trans.XPathException * if any error is detected */ public void promote(PromotionOffer offer) throws XPathException { if (parentPattern != null) { parentPattern.promote(offer); } if (ancestorPattern != null) { ancestorPattern.promote(offer); } for (int i = 0; i < numberOfFilters; i++) { filters[i] = filters[i].promote(offer); } } /** * For a positional pattern, make an equivalent path expression to evaluate the filters. * This expression takes the node being tested as the context node, and returns a set of nodes * which will include the context node if and only if it matches the pattern. The expression only * tests nodes against the filters, not against any parent or ancestor patterns. * @return the equivalent path expression */ private Expression makePositionalExpression() { byte axis = (nodeTest.getPrimitiveType() == Type.ATTRIBUTE ? Axis.ATTRIBUTE : Axis.CHILD); Expression step = new AxisExpression(axis, nodeTest); for (int n = 0; n < numberOfFilters; n++) { step = new FilterExpression(step, filters[n]); } ParentNodeExpression start = new ParentNodeExpression(); start.setContainer(this); PathExpression path = new PathExpression(start, step); path.setContainer(this); return path; // Note, the resulting expression is not required to deliver results in document order } /** * Determine whether the pattern matches a given node. * * @param node the node to be tested * @return true if the pattern matches, else false */ public boolean matches(NodeInfo node, XPathContext context) throws XPathException { // if there is a variable to hold the value of current(), bind it now if (variableBinding != null) { XPathContext c2 = context; Item ci = context.getContextItem(); if (!(ci instanceof NodeInfo && ((NodeInfo)ci).isSameNodeInfo(node))) { c2 = context.newContext(); UnfailingIterator si = SingletonIterator.makeIterator(node); si.next(); c2.setCurrentIterator(si); } variableBinding.evaluateItem(c2); } return internalMatches(node, context); // matches() and internalMatches() differ in the way they handle the current() function. // The variable holding the value of current() is initialized on entry to the top-level // LocationPathPattern, but not on entry to its subordinate patterns. } /** * Test whether the pattern matches, but without changing the current() node */ protected boolean internalMatches(NodeInfo node, XPathContext context) throws XPathException { // System.err.println("Matching node type and fingerprint"); if (!nodeTest.matches(node)) { return false; } if (parentPattern != null) { //System.err.println("Testing parent pattern " + parentPattern + "(" + parentPattern.getClass() + ")"); NodeInfo par = node.getParent(); if (par == null) return false; if (!parentPattern.internalMatches(par, context)) { return false; } } if (ancestorPattern != null) { NodeInfo anc = node.getParent(); while (true) { if (anc == null) return false; if (ancestorPattern.internalMatches(anc, context)) break; anc = anc.getParent(); } } if (specialFilter) { if (firstElementPattern) { SequenceIterator iter = node.iterateAxis(Axis.PRECEDING_SIBLING, nodeTest); return iter.next() == null; } if (lastElementPattern) { SequenceIterator iter = node.iterateAxis(Axis.FOLLOWING_SIBLING, nodeTest); return iter.next() == null; } if (equivalentExpr != null) { // for a positional pattern, we do it the hard way: test whether the // node is a member of the nodeset obtained by evaluating the // equivalent expression // System.err.println("Testing positional pattern against node " + node.generateId()); XPathContext c2 = context.newMinorContext(); c2.setOriginatingConstructType(Location.PATTERN); UnfailingIterator single = SingletonIterator.makeIterator(node); single.next(); c2.setCurrentIterator(single); try { SequenceIterator nsv = equivalentExpr.iterate(c2); while (true) { NodeInfo n = (NodeInfo) nsv.next(); if (n == null) { return false; } if (n.isSameNodeInfo(node)) { return true; } } } catch (XPathException e) { XPathException err = new XPathException("An error occurred matching pattern {" + toString() + "}: ", e); err.setXPathContext(c2); err.setErrorCode(e.getErrorCodeLocalPart()); err.setLocator(this); c2.getController().recoverableError(err); return false; } } } if (filters != null) { XPathContext c2 = context.newMinorContext(); c2.setOriginatingConstructType(Location.PATTERN); UnfailingIterator iter = SingletonIterator.makeIterator(node); iter.next(); c2.setCurrentIterator(iter); // it's a non-positional filter, so we can handle each node separately for (int i = 0; i < numberOfFilters; i++) { try { if (!filters[i].effectiveBooleanValue(c2)) { return false; } } catch (XPathException e) { if ("XTDE0640".equals(e.getErrorCodeLocalPart())) { // Treat circularity error as fatal (test error213) throw e; } XPathException err = new XPathException("An error occurred matching pattern {" + toString() + "}: ", e); err.setXPathContext(c2); err.setErrorCode(e.getErrorCodeLocalPart()); err.setLocator(this); c2.getController().recoverableError(err); return false; } } } return true; } /** * Determine the types of nodes to which this pattern applies. Used for optimisation. * For patterns that match nodes of several types, return Node.NODE * * @return the type of node matched by this pattern. e.g. Node.ELEMENT or Node.TEXT */ public int getNodeKind() { return nodeTest.getPrimitiveType(); } /** * Determine the fingerprint of nodes to which this pattern applies. * Used for optimisation. * * @return the fingerprint of nodes matched by this pattern. */ public int getFingerprint() { return nodeTest.getFingerprint(); } /** * Get a NodeTest that all the nodes matching this pattern must satisfy */ public NodeTest getNodeTest() { if (refinedNodeTest != null) { return refinedNodeTest; } else { return nodeTest; } } /** * Determine if the pattern uses positional filters * @param th the type hierarchy cache * @return true if there is a numeric filter in the pattern, or one that uses the position() * or last() functions */ private boolean isPositional(TypeHierarchy th) { if (filters == null) return false; for (int i = 0; i < numberOfFilters; i++) { int type = filters[i].getItemType(th).getPrimitiveType(); if (type == StandardNames.XS_DOUBLE || type == StandardNames.XS_DECIMAL || type == StandardNames.XS_INTEGER || type == StandardNames.XS_FLOAT || type == StandardNames.XS_ANY_ATOMIC_TYPE) return true; if ((filters[i].getDependencies() & (StaticProperty.DEPENDS_ON_POSITION | StaticProperty.DEPENDS_ON_LAST)) != 0) return true; } return false; } /** * If the pattern contains any calls on current(), this method is called to modify such calls * to become variable references to a variable declared in a specially-allocated local variable * * @param let the expression that assigns the local variable. This returns a dummy result, and is executed * just before evaluating the pattern, to get the value of the context item into the variable. * @param offer A PromotionOffer used to process the expressions and change the call on current() into * a variable reference * @param topLevel * @throws XPathException */ public void resolveCurrent(LetExpression let, PromotionOffer offer, boolean topLevel) throws XPathException { for (int i = 0; i < numberOfFilters; i++) { filters[i] = filters[i].promote(offer); } if (parentPattern instanceof LocationPathPattern) { ((LocationPathPattern) parentPattern).resolveCurrent(let, offer, false); } if (ancestorPattern instanceof LocationPathPattern) { ((LocationPathPattern) ancestorPattern).resolveCurrent(let, offer, false); } if (topLevel) { variableBinding = let; } } /** * Determine whether this pattern is the same as another pattern * @param other the other object */ public boolean equals(Object other) { if (other instanceof LocationPathPattern) { LocationPathPattern lpp = (LocationPathPattern)other; if (numberOfFilters != lpp.numberOfFilters) { return false; } for (int i=0; i * In fact the concept of "supertype" is not really well-defined, because the types * form a lattice rather than a hierarchy. The only real requirement on this function * is that it returns a type that strictly subsumes this type, ideally as narrowly * as possible. * @return the supertype, or null if this type is item() * @param th the type hierarchy cache */ public ItemType getSuperType(TypeHierarchy th) { return NodeKindTest.makeNodeKindTest(nodeKind); } /** * Get a mask indicating which kinds of nodes this NodeTest can match. This is a combination * of bits: 1< *

    Unlike the corresponding method on {@link net.sf.saxon.expr.Expression}, this method does not return anything: * it can make internal changes to the pattern, but cannot return a different pattern. Only certain * kinds of promotion are applicable within a pattern: specifically, promotions affecting local * variable references within the pattern. * * @param offer details of the offer, for example the offer to move * expressions that don't depend on the context to an outer level in * the containing expression * @throws net.sf.saxon.trans.XPathException * if any error is detected */ public void promote(PromotionOffer offer) throws XPathException { keyExpression = keyExpression.promote(offer); } public boolean replaceSubExpression(Expression original, Expression replacement) { if (keyExpression == original) { keyExpression = replacement; return true; } else { return false; } } /** * Allocate slots to any variables used within the pattern * @param env the static context in the XSLT stylesheet * @param slotManager the slot manager representing the stack frame for local variables * @param nextFree the next slot that is free to be allocated @return the next slot that is free to be allocated */ public int allocateSlots(StaticContext env, SlotManager slotManager, int nextFree) { return ExpressionTool.allocateSlots(keyExpression, nextFree, slotManager); } /** * Determine whether this Pattern matches the given Node. * * @param e The NodeInfo representing the Element or other node to be tested against the Pattern * @return true if the node matches the Pattern, false otherwise */ public boolean matches(NodeInfo e, XPathContext context) throws XPathException { KeyDefinitionSet kds = keySet; if (kds == null) { // shouldn't happen kds = context.getController().getExecutable().getKeyManager().getKeyDefinitionSet(keyName); } DocumentInfo doc = e.getDocumentRoot(); if (doc == null) { return false; } KeyManager km = context.getController().getKeyManager(); SequenceIterator iter = keyExpression.iterate(context); while (true) { Item it = iter.next(); if (it == null) { return false; } SequenceIterator nodes = km.selectByKey(kds, doc, (AtomicValue)it, context); while (true) { NodeInfo n = (NodeInfo)nodes.next(); if (n == null) { break; } if (n.isSameNodeInfo(e)) { return true; } } } } /** * Get a NodeTest that all the nodes matching this pattern must satisfy */ public NodeTest getNodeTest() { return AnyNodeTest.getInstance(); } /** * Determine whether this pattern is the same as another pattern * @param other the other object */ public boolean equals(Object other) { return (other instanceof KeyPattern) && ((KeyPattern)other).keyName.equals(keyName) && ((KeyPattern)other).keyExpression.equals(keyExpression); } /** * Hashcode supporting equals() */ public int hashCode() { return 0x87287310 ^ keyExpression.hashCode() & keyName.hashCode(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/pattern/DocumentNodeTest.java0000644000175000017500000001254711033112257023154 0ustar eugeneeugenepackage net.sf.saxon.pattern; import net.sf.saxon.om.Axis; import net.sf.saxon.om.AxisIterator; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.om.NamePool; import net.sf.saxon.type.Type; import net.sf.saxon.tinytree.TinyTree; /** * A DocumentNodeTest implements the test document-node(element(~,~)) */ // This is messy because the standard interface for a NodeTest does not allow // any navigation from the node in question - it only tests for the node kind, // node name, and type annotation of the node. public class DocumentNodeTest extends NodeTest { private NodeTest elementTest; public DocumentNodeTest(NodeTest elementTest) { this.elementTest = elementTest; } /** * Test whether this node test is satisfied by a given node * @param nodeKind The type of node to be matched * @param fingerprint identifies the expanded name of the node to be matched */ public boolean matches(int nodeKind, int fingerprint, int annotation) { throw new UnsupportedOperationException("DocumentNodeTest doesn't support this method"); } /** * Test whether this node test is satisfied by a given node on a TinyTree. The node * must be a document, element, text, comment, or processing instruction node. * This method is provided * so that when navigating a TinyTree a node can be rejected without * actually instantiating a NodeInfo object. * * @param tree the TinyTree containing the node * @param nodeNr the number of the node within the TinyTree * @return true if the node matches the NodeTest, otherwise false */ public boolean matches(TinyTree tree, int nodeNr) { if (tree.getNodeKind(nodeNr) != Type.DOCUMENT) { return false; } return matches(tree.getNode(nodeNr)); } /** * Determine whether this Pattern matches the given Node. * @param node The NodeInfo representing the Element or other node to be tested against the Pattern * uses variables, or contains calls on functions such as document() or key(). * @return true if the node matches the Pattern, false otherwise */ public boolean matches(NodeInfo node) { if (node.getNodeKind() != Type.DOCUMENT) { return false; } AxisIterator iter = node.iterateAxis(Axis.CHILD); // The match is true if there is exactly one element node child, no text node // children, and the element node matches the element test. boolean found = false; while (true) { NodeInfo n = (NodeInfo)iter.next(); if (n==null) { return found; } int kind = n.getNodeKind(); if (kind==Type.TEXT) { return false; } else if (kind==Type.ELEMENT) { if (found) { return false; } if (elementTest.matches(n)) { found = true; } else { return false; } } } } /** * Determine the default priority of this node test when used on its own as a Pattern */ public final double getDefaultPriority() { return elementTest.getDefaultPriority(); } /** * Determine the types of nodes to which this pattern applies. Used for optimisation. * @return the type of node matched by this pattern. e.g. Type.ELEMENT or Type.TEXT */ public int getPrimitiveType() { return Type.DOCUMENT; } /** * Get a mask indicating which kinds of nodes this NodeTest can match. This is a combination * of bits: 1< * Patterns are created by calling the static method Pattern.make(string).
    * The pattern is used to test a particular node by calling match(). */ public abstract class Pattern implements PatternFinder, Serializable, Container { private String originalText; private Executable executable; private String systemId; // the module where the pattern occurred private int lineNumber; // the line number where the pattern occurred /** * Static method to make a Pattern by parsing a String.
    * @param pattern The pattern text as a String * @param env An object defining the compile-time context for the expression * @param exec The executable containing this pattern * @return The pattern object */ public static Pattern make(String pattern, StaticContext env, Executable exec) throws XPathException { Pattern pat = (new ExpressionParser()).parsePattern(pattern, env); pat.setSystemId(env.getSystemId()); pat.setLineNumber(env.getLineNumber()); // System.err.println("Simplified [" + pattern + "] to " + pat.getClass() + " default prio = " + pat.getDefaultPriority()); // set the pattern text for use in diagnostics pat.setOriginalText(pattern); pat.setExecutable(exec); ExpressionVisitor visitor = ExpressionVisitor.make(env); visitor.setExecutable(exec); pat = pat.simplify(visitor); return pat; } /** * Get the executable containing this pattern * @return the executable */ public Executable getExecutable() { return executable; } /** * Set the executable containing this pattern * @param executable the executable */ public void setExecutable(Executable executable) { this.executable = executable; } /** * Get the LocationProvider allowing location identifiers to be resolved. */ public LocationProvider getLocationProvider() { return executable.getLocationMap(); } /** * Set the original text of the pattern for use in diagnostics * @param text the original text of the pattern */ public void setOriginalText(String text) { originalText = text; } /** * Simplify the pattern by applying any context-independent optimisations. * Default implementation does nothing. * @return the optimised Pattern * @param visitor the expression visitor */ public Pattern simplify(ExpressionVisitor visitor) throws XPathException { return this; } /** * Type-check the pattern. * Default implementation does nothing. This is only needed for patterns that contain * variable references or function calls. * @param visitor the expression visitor * @param contextItemType the type of the context item, if known, at the point where the pattern * is defined * @return the optimised Pattern */ public Pattern analyze(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { return this; } /** * Get the dependencies of the pattern. The only possible dependency for a pattern is * on local variables. This is analyzed in those patterns where local variables may appear. * @return the dependencies, as a bit-significant mask */ public int getDependencies() { return 0; } /** * Iterate over the subexpressions within this pattern * @return an iterator over the subexpressions. Default implementation returns an empty sequence */ public Iterator iterateSubExpressions() { return Collections.EMPTY_LIST.iterator(); } /** * Allocate slots to any variables used within the pattern * @param env the static context in the XSLT stylesheet * @param slotManager the slot manager representing the stack frame for local variables * @param nextFree the next slot that is free to be allocated @return the next slot that is free to be allocated */ public int allocateSlots(StaticContext env, SlotManager slotManager, int nextFree) { return nextFree; } /** * Offer promotion for subexpressions within this pattern. The offer will be accepted if the subexpression * is not dependent on the factors (e.g. the context item) identified in the PromotionOffer. * By default the offer is not accepted - this is appropriate in the case of simple expressions * such as constant values and variable references where promotion would give no performance * advantage. This method is always called at compile time. * *

    Unlike the corresponding method on {@link Expression}, this method does not return anything: * it can make internal changes to the pattern, but cannot return a different pattern. Only certain * kinds of promotion are applicable within a pattern: specifically, promotions affecting local * variable references within the pattern. * * @param offer details of the offer, for example the offer to move * expressions that don't depend on the context to an outer level in * the containing expression * @throws net.sf.saxon.trans.XPathException * if any error is detected */ public void promote(PromotionOffer offer) throws XPathException { // default implementation does nothing } /** * Set the system ID where the pattern occurred * @param systemId the URI of the module containing the pattern */ public void setSystemId(String systemId) { this.systemId = systemId; } /** * Set the line number where the pattern occurred * @param lineNumber the line number of the pattern in the source module */ public void setLineNumber(int lineNumber) { this.lineNumber = lineNumber; } /** * Determine whether this Pattern matches the given Node. This is the main external interface * for matching patterns: it sets current() to the node being tested * @param node The NodeInfo representing the Element or other node to be tested against the Pattern * @param context The dynamic context. Only relevant if the pattern * uses variables, or contains calls on functions such as document() or key(). * @return true if the node matches the Pattern, false otherwise */ public abstract boolean matches(NodeInfo node, XPathContext context) throws XPathException; /** * Determine whether this Pattern matches the given Node. This is an internal interface used * for matching sub-patterns; it does not alter the value of current(). The default implementation * is identical to matches(). * @param node The NodeInfo representing the Element or other node to be tested against the Pattern * @param context The dynamic context. Only relevant if the pattern * uses variables, or contains calls on functions such as document() or key(). * @return true if the node matches the Pattern, false otherwise */ protected boolean internalMatches(NodeInfo node, XPathContext context) throws XPathException { return matches(node, context); } /** * Select nodes in a document using this PatternFinder. * @param doc the document node at the root of a tree * @param context the dynamic evaluation context * @return an iterator over the selected nodes in the document. */ public SequenceIterator selectNodes(DocumentInfo doc, final XPathContext context) throws XPathException { final int kind = getNodeKind(); switch (kind) { case Type.DOCUMENT: if (matches(doc, context)) { return SingletonIterator.makeIterator(doc); } else { return EmptyIterator.getInstance(); } case Type.ATTRIBUTE: { AxisIterator allElements = doc.iterateAxis(Axis.DESCENDANT, NodeKindTest.ELEMENT); MappingFunction atts = new MappingFunction() { public SequenceIterator map(Item item) { return ((NodeInfo)item).iterateAxis(Axis.ATTRIBUTE); } }; SequenceIterator allAttributes = new MappingIterator(allElements, atts); ItemMappingFunction test = new ItemMappingFunction() { public Item map(Item item) throws XPathException { if ((matches((NodeInfo)item, context))) { return item; } else { return null; } } }; return new ItemMappingIterator(allAttributes, test); } case Type.ELEMENT: case Type.COMMENT: case Type.TEXT: case Type.PROCESSING_INSTRUCTION: { AxisIterator allChildren = doc.iterateAxis(Axis.DESCENDANT, NodeKindTest.makeNodeKindTest(kind)); ItemMappingFunction test = new ItemMappingFunction() { public Item map(Item item) throws XPathException { if ((matches((NodeInfo)item, context))) { return item; } else { return null; } } }; return new ItemMappingIterator(allChildren, test); } case Type.NODE: { AxisIterator allChildren = doc.iterateAxis(Axis.DESCENDANT); MappingFunction attsOrSelf = new MappingFunction() { public SequenceIterator map(Item item) { return new PrependIterator((NodeInfo)item, ((NodeInfo)item).iterateAxis(Axis.ATTRIBUTE)); } }; SequenceIterator attributesOrSelf = new MappingIterator(allChildren, attsOrSelf); ItemMappingFunction test = new ItemMappingFunction() { public Item map(Item item) throws XPathException { if ((matches((NodeInfo)item, context))) { return item; } else { return null; } } }; return new ItemMappingIterator(attributesOrSelf, test); } case Type.NAMESPACE: throw new UnsupportedOperationException("Patterns can't match namespace nodes"); default: throw new UnsupportedOperationException("Unknown node kind"); } } /** * Make an expression whose effect is to select all the nodes that match this pattern * in a given document. This expression takes the root of the tree (always a document node) * as the context node; it takes into account all the constraints expressed by the pattern * including the parent and ancestor nodes and the filters */ public Expression makeSearchExpression() { // TODO:PERF could improve the logic for LocationPathPatterns final int kind = getNodeKind(); Expression base; switch (kind) { case Type.DOCUMENT: base = new ContextItemExpression(); break; case Type.ATTRIBUTE: Expression allElements = new AxisExpression(Axis.DESCENDANT, NodeKindTest.ELEMENT); base = new PathExpression(allElements, new AxisExpression(Axis.ATTRIBUTE, AnyNodeTest.getInstance())); break; case Type.ELEMENT: case Type.COMMENT: case Type.TEXT: case Type.PROCESSING_INSTRUCTION: base = new AxisExpression(Axis.DESCENDANT, NodeKindTest.makeNodeKindTest(kind)); break; case Type.NODE: Expression allChildren = new AxisExpression(Axis.DESCENDANT, NodeKindTest.ELEMENT); Block block = new Block(); Expression[] union = {new ContextItemExpression(), new AxisExpression(Axis.ATTRIBUTE, AnyNodeTest.getInstance())}; block.setChildren(union); base = new PathExpression(allChildren, block); break; case Type.NAMESPACE: throw new UnsupportedOperationException("Patterns can't match namespace nodes"); default: throw new UnsupportedOperationException("Unknown node kind"); } return new FilterExpression(base, new PatternMatchExpression(this)); } /** * Determine the types of nodes to which this pattern applies. Used for optimisation. * For patterns that match nodes of several types, return Type.NODE * @return the type of node matched by this pattern. e.g. Type.ELEMENT or Type.TEXT */ public int getNodeKind() { return Type.NODE; } /** * Determine the name fingerprint of nodes to which this pattern applies. Used for * optimisation. * @return A fingerprint that the nodes must match, or -1 if it can match multiple fingerprints */ public int getFingerprint() { return -1; } /** * Get a NodeTest that all the nodes matching this pattern must satisfy * @return a NodeTest, as specific as possible, which all the matching nodes satisfy */ public abstract NodeTest getNodeTest(); /** * Determine the default priority to use if this pattern appears as a match pattern * for a template with no explicit priority attribute. * @return the default priority for the pattern */ public double getDefaultPriority() { return 0.5; } /** * Get the system id of the entity in which the pattern occurred */ public String getSystemId() { return systemId; } /** * Get the line number on which the pattern was defined */ public int getLineNumber() { return lineNumber; } /** * Get the column number (always -1) */ public int getColumnNumber() { return -1; } /** * Get the public ID (always null) */ public String getPublicId() { return null; } /** * Get the original pattern text */ public String toString() { if (originalText != null) { return originalText; } else { return "pattern matching " + getNodeTest().toString(); } } /** * Get the host language (XSLT, XQuery, XPath) used to implement the code in this container * @return typically {@link net.sf.saxon.Configuration#XSLT} or {@link net.sf.saxon.Configuration#XQUERY} */ public int getHostLanguage() { return Configuration.XSLT; } public boolean replaceSubExpression(Expression original, Expression replacement) { throw new IllegalArgumentException("Invalid replacement"); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): Michael Kay // saxonb-9.1.0.8/bj/net/sf/saxon/pattern/NodeTest.java0000644000175000017500000002226011033112257021446 0ustar eugeneeugenepackage net.sf.saxon.pattern; import net.sf.saxon.Configuration; import net.sf.saxon.om.Item; import net.sf.saxon.om.NamePool; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.sort.IntHashSet; import net.sf.saxon.tinytree.TinyTree; import net.sf.saxon.type.*; import java.io.Serializable; /** * A NodeTest is a simple kind of pattern that enables a context-free test of whether * a node has a particular * name. There are several kinds of node test: a full name test, a prefix test, and an * "any node of a given type" test, an "any node of any type" test, a "no nodes" * test (used, e.g. for "@comment()"). * *

    As well as being used to support XSLT pattern matching, NodeTests act as predicates in * axis steps, and also act as item types for type matching.

    * *

    For use in user-written application calling {@link NodeInfo#iterateAxis(byte, NodeTest)}, * it is possible to write a user-defined subclass of NodeTest that implements * a single method, {@link #matches(int, int, int)}

    * * @author Michael H. Kay */ public abstract class NodeTest implements ItemType, Serializable { /** * Test whether a given item conforms to this type. This implements a method of the ItemType interface. * @param item The item to be tested * @param allowURIPromotion * @param config * @return true if the item is an instance of this type; false otherwise */ public boolean matchesItem(Item item, boolean allowURIPromotion, Configuration config) { if (item instanceof NodeInfo) { return matches((NodeInfo)item); } else { return false; } } /** * Get the type from which this item type is derived by restriction. This * is the supertype in the XPath type heirarchy, as distinct from the Schema * base type: this means that the supertype of xs:boolean is xs:anyAtomicType, * whose supertype is item() (rather than xs:anySimpleType). *

    * In fact the concept of "supertype" is not really well-defined, because the types * form a lattice rather than a hierarchy. The only real requirement on this function * is that it returns a type that strictly subsumes this type, ideally as narrowly * as possible. * @return the supertype, or null if this type is item() * @param th the type hierarchy cache */ public ItemType getSuperType(TypeHierarchy th) { return AnyNodeTest.getInstance(); // overridden for AnyNodeTest itself } /** * Determine the default priority of this node test when used on its own as a Pattern */ public abstract double getDefaultPriority(); /** * Get the primitive item type corresponding to this item type. For item(), * this is Type.ITEM. For node(), it is Type.NODE. For specific node kinds, * it is the value representing the node kind, for example Type.ELEMENT. * For anyAtomicValue it is Type.ATOMIC_VALUE. For numeric it is Type.NUMBER. * For other atomic types it is the primitive type as defined in XML Schema, * except that INTEGER is considered to be a primitive type. */ public ItemType getPrimitiveItemType() { int p = getPrimitiveType(); if (p == Type.NODE) { return AnyNodeTest.getInstance(); } else { return NodeKindTest.makeNodeKindTest(p); } } /** * Get the basic kind of object that this ItemType matches: for a NodeTest, this is the kind of node, * or Type.Node if it matches different kinds of nodes. * @return the node kind matched by this node test */ public int getPrimitiveType() { return Type.NODE; } /** * Get the name of the nodes matched by this nodetest, if it matches a specific name. * Return -1 if the node test matches nodes of more than one name */ public int getFingerprint() { return -1; } /** * Determine whether this item type is atomic (that is, whether it can ONLY match * atomic values) * * @return false: this is not ANY_ATOMIC_TYPE or a subtype thereof */ public boolean isAtomicType() { return false; } /** * Get the item type of the atomic values that will be produced when an item * of this type is atomized (assuming that atomization succeeds) */ public AtomicType getAtomizedItemType() { // This is overridden for a ContentTypeTest return BuiltInAtomicType.ANY_ATOMIC; } /** * Test whether this node test is satisfied by a given node on a TinyTree. The node * must be a document, element, text, comment, or processing instruction node. * This method is provided so that when navigating a TinyTree a node can be rejected without * actually instantiating a NodeInfo object. The default implementation instantiates the node * and then calls the method {@link #matches(NodeInfo)} * @param tree the TinyTree containing the node * @param nodeNr the number of the node within the TinyTree * @return true if the node matches the NodeTest, otherwise false * */ public boolean matches(TinyTree tree, int nodeNr) { return matches(tree.getNode(nodeNr)); } /** * Test whether this node test is satisfied by a given node. This method is only * fully supported for a subset of NodeTests, because it doesn't provide all the information * needed to evaluate all node tests. In particular (a) it can't be used to evaluate a node * test of the form element(N,T) or schema-element(E) where it is necessary to know whether the * node is nilled, and (b) it can't be used to evaluate a node test of the form * document-node(element(X)). This in practice means that it is used (a) to evaluate the * simple node tests found in the XPath 1.0 subset used in XML Schema, and (b) to evaluate * node tests where the node kind is known to be an attribute. * @param nodeKind The kind of node to be matched * @param fingerprint identifies the expanded name of the node to be matched. * The value should be -1 for a node with no name. * @param annotation The actual content type of the node * */ public abstract boolean matches(int nodeKind, int fingerprint, int annotation); /** * Test whether this node test is satisfied by a given node. This alternative * method is used in the case of nodes where calculating the fingerprint is expensive, * for example DOM or JDOM nodes. The default implementation calls the method * {@link #matches(int, int, int)} * @param node the node to be matched */ public boolean matches(NodeInfo node) { return matches(node.getNodeKind(), node.getFingerprint(), node.getTypeAnnotation()); } /** * Get a mask indicating which kinds of nodes this NodeTest can match. This is a combination * of bits: 1< *

    Unlike the corresponding method on {@link net.sf.saxon.expr.Expression}, this method does not return anything: * it can make internal changes to the pattern, but cannot return a different pattern. Only certain * kinds of promotion are applicable within a pattern: specifically, promotions affecting local * variable references within the pattern. * * @param offer details of the offer, for example the offer to move * expressions that don't depend on the context to an outer level in * the containing expression * @throws net.sf.saxon.trans.XPathException * if any error is detected */ public void promote(PromotionOffer offer) throws XPathException { idExpression = idExpression.promote(offer); } public boolean replaceSubExpression(Expression original, Expression replacement) { if (idExpression == original) { idExpression = replacement; return true; } else { return false; } } /** * Allocate slots to any variables used within the pattern * @param env the static context in the XSLT stylesheet * @param slotManager the slot manager representing the stack frame for local variables * @param nextFree the next slot that is free to be allocated @return the next slot that is free to be allocated */ public int allocateSlots(StaticContext env, SlotManager slotManager, int nextFree) { return ExpressionTool.allocateSlots(idExpression, nextFree, slotManager); } /** * Determine whether this Pattern matches the given Node * @param e The NodeInfo representing the Element or other node to be tested against the Pattern * @return true if the node matches the Pattern, false otherwise */ public boolean matches(NodeInfo e, XPathContext context) throws XPathException { if (e.getNodeKind() != Type.ELEMENT) { return false; } DocumentInfo doc = e.getDocumentRoot(); if (doc==null) { return false; } AtomicValue idValue = (AtomicValue)idExpression.evaluateItem(context); if (idValue == null) { return false; } String ids = idValue.getStringValue(); if (ids.indexOf(' ') < 0 && ids.indexOf(0x09) < 0 && ids.indexOf(0x0a) < 0 && ids.indexOf(0x0c) < 0) { NodeInfo element = doc.selectID(ids); if (element==null) return false; return (element.isSameNodeInfo(e)); } else { StringTokenizer tokenizer = new StringTokenizer(ids, " \t\n\r", false); while (tokenizer.hasMoreElements()) { String id = (String)tokenizer.nextElement(); NodeInfo element = doc.selectID(id); if (element != null && e.isSameNodeInfo(element)) { return true; } } return false; } } /** * Determine the type of nodes to which this pattern applies. * @return Type.ELEMENT */ public int getNodeKind() { return Type.ELEMENT; } /** * Get a NodeTest that all the nodes matching this pattern must satisfy */ public NodeTest getNodeTest() { return NodeKindTest.ELEMENT; } /** * Determine whether this pattern is the same as another pattern * @param other the other object */ public boolean equals(Object other) { return (other instanceof IDPattern) && ((IDPattern)other).idExpression.equals(idExpression); } /** * Hashcode supporting equals() */ public int hashCode() { return 0x73108728 ^ idExpression.hashCode(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/pattern/PatternSponsor.java0000644000175000017500000004124211241112436022723 0ustar eugeneeugenepackage net.sf.saxon.pattern; import net.sf.saxon.expr.*; import net.sf.saxon.om.*; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.*; import net.sf.saxon.value.BooleanValue; import net.sf.saxon.trace.ExpressionPresenter; import java.util.Iterator; /** * The PatternSponsor class allows a Pattern to be treated like an expression. Although * patterns are not evaluated at run-time in the same way as expressions, they need to * be manipulated in much the same way as expressions at compile time: for example variables * need to be bound, dependencies need to be analyzed, and so on. This is especially true * of patterns appearing in the xsl:number and xsl:for-each-group instructions (less so for * the more common match patterns in xsl:template). * *

    This class implements the Expression interface, so that an Expression can have a * PatternSponsor as a subexpression; it wraps a Pattern.

    * *

    A Pattern is treated as a boolean expression that returns true if the pattern matches * the context node. However, it is not currently evaluated in that way.

    */ public class PatternSponsor extends Expression { private Pattern pattern; /** * Create a sponsor expression for a pattern * @param pattern the pattern being wrapped */ public PatternSponsor(Pattern pattern) { this.pattern = pattern; } /** * Get the wrapped pattern * @return the wrapped pattern */ public Pattern getPattern() { return pattern; } /** * An implementation of Expression must provide at least one of the methods evaluateItem(), iterate(), or process(). * This method indicates which of these methods is provided directly. The other methods will always be available * indirectly, using an implementation that relies on one of the other methods. */ public int getImplementationMethod() { return EVALUATE_METHOD; } /** * Simplify an expression. This performs any static optimization (by rewriting the expression * as a different expression). The default implementation does nothing. * * @return the simplified expression * @throws XPathException if an error is discovered during expression * rewriting * @param visitor an expression visitor */ public Expression simplify(ExpressionVisitor visitor) throws XPathException { pattern = pattern.simplify(visitor); return this; } /** * Perform optimisation of an expression and its subexpressions. *

    *

    This method is called after all references to functions and variables have been resolved * to the declaration of the function or variable, and after all type checking has been done.

    * * @param visitor an expression visitor * @param contextItemType the static type of "." at the point where this expression is invoked. * The parameter is set to null if it is known statically that the context item will be undefined. * If the type of the context item is not known statically, the argument is set to * {@link net.sf.saxon.type.Type#ITEM_TYPE} * @return the original expression, rewritten if appropriate to optimize execution * @throws XPathException if an error is discovered during this phase * (typically a type error) */ public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { return this; } /** * Perform type checking of an expression and its subexpressions. *

    *

    This checks statically that the operands of the expression have * the correct type; if necessary it generates code to do run-time type checking or type * conversion. A static type error is reported only if execution cannot possibly succeed, that * is, if a run-time type error is inevitable. The call may return a modified form of the expression.

    *

    *

    This method is called after all references to functions and variables have been resolved * to the declaration of the function or variable. However, the types of such functions and * variables may not be accurately known if they have not been explicitly declared.

    * * @param visitor an expression visitor * @param contextItemType the static type of "." at the point where this expression is invoked. * The parameter is set to null if it is known statically that the context item will be undefined. * If the type of the context item is not known statically, the argument is set to * {@link net.sf.saxon.type.Type#ITEM_TYPE} * @return the original expression, rewritten to perform necessary * run-time type checks, and to perform other type-related * optimizations * @throws XPathException if an error is discovered during this phase * (typically a type error) */ public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { pattern = pattern.analyze(visitor, contextItemType); return this; } protected int computeCardinality() { return StaticProperty.ALLOWS_ZERO_OR_MORE; } /** * Copy an expression. This makes a deep copy. * * @return the copy of the original expression */ public Expression copy() { throw new UnsupportedOperationException("copy"); } /** * Offer promotion for this subexpression. The offer will be accepted if the subexpression * is not dependent on the factors (e.g. the context item) identified in the PromotionOffer. * By default the offer is not accepted - this is appropriate in the case of simple expressions * such as constant values and variable references where promotion would give no performance * advantage. This method is always called at compile time. * * @param offer details of the offer, for example the offer to move * expressions that don't depend on the context to an outer level in * the containing expression * @return if the offer is not accepted, return this expression unchanged. * Otherwise return the result of rewriting the expression to promote * this subexpression * @throws net.sf.saxon.trans.XPathException * if any error is detected */ public Expression promote(PromotionOffer offer) throws XPathException { pattern.promote(offer); return this; } /** * Treat all subexpressions as being evaluated repeatedly * @param child * @return */ public boolean hasLoopingSubexpression(Expression child) { return true; } /** *

    Determine the static cardinality of the expression. This establishes how many items * there will be in the result of the expression, at compile time (i.e., without * actually evaluating the result.

    *

    *

    This method should always return a result, though it may be the best approximation * that is available at the time.

    * * @return one of the values {@link StaticProperty#ALLOWS_ONE}, * {@link StaticProperty#ALLOWS_ZERO_OR_MORE}, {@link StaticProperty#ALLOWS_ZERO_OR_ONE}, * {@link StaticProperty#ALLOWS_ONE_OR_MORE}, {@link StaticProperty#EMPTY}. */ public int getCardinality() { return StaticProperty.EXACTLY_ONE; } /** * Determine the data type of the expression, if possible. All expression return * sequences, in general; this method determines the type of the items within the * sequence, assuming that (a) this is known in advance, and (b) it is the same for * all items in the sequence. *

    *

    This method should always return a result, though it may be the best approximation * that is available at the time.

    * * @return a value such as Type.STRING, Type.BOOLEAN, Type.NUMBER, * Type.NODE, or Type.ITEM (meaning not known at compile time) * @param th the type hierarchy cache */ public ItemType getItemType(TypeHierarchy th) { return BuiltInAtomicType.BOOLEAN; } /** * Determine which aspects of the context the expression depends on. The result is * a bitwise-or'ed value composed from constants such as {@link net.sf.saxon.expr.StaticProperty#DEPENDS_ON_CONTEXT_ITEM} and * {@link net.sf.saxon.expr.StaticProperty#DEPENDS_ON_CURRENT_ITEM}. The default implementation combines the intrinsic * dependencies of this expression with the dependencies of the subexpressions, * computed recursively. This is overridden for expressions such as FilterExpression * where a subexpression's dependencies are not necessarily inherited by the parent * expression. * * @return a set of bit-significant flags identifying the dependencies of * the expression */ public int getDependencies() { return pattern.getDependencies(); } /** * Get the immediate sub-expressions of this expression. Default implementation * returns a zero-length array, appropriate for an expression that has no * sub-expressions. * * @return an iterator containing the sub-expressions of this expression */ public Iterator iterateSubExpressions() { return pattern.iterateSubExpressions(); } /** * Replace one subexpression by a replacement subexpression * @param original the original subexpression * @param replacement the replacement subexpression * @return true if the original subexpression is found */ public boolean replaceSubExpression(Expression original, Expression replacement) { return pattern.replaceSubExpression(original, replacement); } /** * Get the container that immediately contains this expression. This method * returns null for an outermost expression; it also return null in the case * of literal values. For an XPath expression occurring within an XSLT stylesheet, * this method returns the XSLT instruction containing the XPath expression. * * @return the expression that contains this expression, if known; return null * if there is no containing expression or if the containing expression is unknown. */ public Container getContainer() { return pattern; } /** * Evaluate an expression as a single item. This always returns either a single Item or * null (denoting the empty sequence). No conversion is done. This method should not be * used unless the static type of the expression is a subtype of "item" or "item?": that is, * it should not be called if the expression may return a sequence. There is no guarantee that * this condition will be detected. * * @param context The context in which the expression is to be evaluated * @return the node or atomic value that results from evaluating the * expression; or null to indicate that the result is an empty * sequence * @throws net.sf.saxon.trans.XPathException * if any dynamic error occurs evaluating the * expression */ public Item evaluateItem(XPathContext context) throws XPathException { return BooleanValue.get(effectiveBooleanValue(context)); } /** * Return an Iterator to iterate over the values of a sequence. The value of every * expression can be regarded as a sequence, so this method is supported for all * expressions. This default implementation handles iteration for expressions that * return singleton values: for non-singleton expressions, the subclass must * provide its own implementation. * * @param context supplies the context for evaluation * @return a SequenceIterator that can be used to iterate over the result * of the expression * @throws net.sf.saxon.trans.XPathException * if any dynamic error occurs evaluating the * expression */ public SequenceIterator iterate(XPathContext context) throws XPathException { return SingletonIterator.makeIterator(evaluateItem(context)); } /** * Get the effective boolean value of the expression. This returns false if the value * is the empty sequence, a zero-length string, a number equal to zero, or the boolean * false. Otherwise it returns true. * * @param context The context in which the expression is to be evaluated * @return the effective boolean value * @throws net.sf.saxon.trans.XPathException * if any dynamic error occurs evaluating the * expression */ public boolean effectiveBooleanValue(XPathContext context) throws XPathException { Item contextItem = context.getContextItem(); return contextItem instanceof NodeInfo && pattern.matches((NodeInfo)contextItem, context); } /** * Evaluate an expression as a String. This function must only be called in contexts * where it is known that the expression will return a single string (or where an empty sequence * is to be treated as a zero-length string). Implementations should not attempt to convert * the result to a string, other than converting () to "". This method is used mainly to * evaluate expressions produced by compiling an attribute value template. * * @param context The context in which the expression is to be evaluated * @return the value of the expression, evaluated in the current context. * The expression must return a string or (); if the value of the * expression is (), this method returns "". * @throws net.sf.saxon.trans.XPathException * if any dynamic error occurs evaluating the * expression * @throws ClassCastException if the result type of the * expression is not xs:string? */ public CharSequence evaluateAsString(XPathContext context) throws XPathException { return evaluateItem(context).getStringValueCS(); } /** * Process the instruction, without returning any tail calls * * @param context The dynamic context, giving access to the current node, * the current variables, etc. */ public void process(XPathContext context) throws XPathException { throw new UnsupportedOperationException("Patterns cannot be evaluated in push mode"); } /** * Diagnostic print of expression structure. The abstract expression tree * is written to the supplied output destination. */ public void explain(ExpressionPresenter out) { out.startElement("pattern"); out.emitAttribute("match", pattern.toString()); out.endElement(); } /** * Check statically that the results of the expression are capable of constructing the content * of a given schema type. * * @param parentType The schema type * @param env the static context * @param whole true if this expression is expected to make the whole content of the type, false * if it is expected to make up only a part * @throws net.sf.saxon.trans.XPathException * if the expression doesn't match the required content type */ public void checkPermittedContents(SchemaType parentType, StaticContext env, boolean whole) throws XPathException { throw new UnsupportedOperationException("checkPermittedContents() is not applicable to a pattern"); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): Michael Kay // saxonb-9.1.0.8/bj/net/sf/saxon/pattern/UnionPattern.java0000644000175000017500000001673511037617245022374 0ustar eugeneeugenepackage net.sf.saxon.pattern; import net.sf.saxon.expr.*; import net.sf.saxon.instruct.Executable; import net.sf.saxon.instruct.SlotManager; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.Type; import java.util.Iterator; import java.util.Set; import java.util.HashSet; /** * A pattern formed as the union (or) of two other patterns */ public class UnionPattern extends Pattern { protected Pattern p1, p2; private int nodeType = Type.NODE; /** * Constructor * * @param p1 the left-hand operand * @param p2 the right-hand operand */ public UnionPattern(Pattern p1, Pattern p2) { this.p1 = p1; this.p2 = p2; if (p1.getNodeKind() == p2.getNodeKind()) { nodeType = p1.getNodeKind(); } } /** * Set the executable containing this pattern * * @param executable the executable */ public void setExecutable(Executable executable) { p1.setExecutable(executable); p2.setExecutable(executable); super.setExecutable(executable); } /** * Simplify the pattern: perform any context-independent optimisations * * @param visitor an expression visitor */ public Pattern simplify(ExpressionVisitor visitor) throws XPathException { p1 = p1.simplify(visitor); p2 = p2.simplify(visitor); return this; } /** * Type-check the pattern. * This is only needed for patterns that contain variable references or function calls. * * @return the optimised Pattern */ public Pattern analyze(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { p1 = p1.analyze(visitor, contextItemType); p2 = p2.analyze(visitor, contextItemType); return this; } /** * Set the original text */ public void setOriginalText(String pattern) { super.setOriginalText(pattern); p1.setOriginalText(pattern); p2.setOriginalText(pattern); } public void promote(PromotionOffer offer) throws XPathException { p1.promote(offer); p2.promote(offer); } public boolean replaceSubExpression(Expression original, Expression replacement) { return p1.replaceSubExpression(original, replacement) || p2.replaceSubExpression(original, replacement); } /** * Allocate slots to any variables used within the pattern * * @param env the static context in the XSLT stylesheet * @param slotManager *@param nextFree the next slot that is free to be allocated @return the next slot that is free to be allocated */ public int allocateSlots(StaticContext env, SlotManager slotManager, int nextFree) { nextFree = p1.allocateSlots(env, slotManager, nextFree); nextFree = p2.allocateSlots(env, slotManager, nextFree); return nextFree; } /** * Gather the component (non-union) patterns of this union pattern * @param set the set into which the components will be added */ public void gatherComponentPatterns(Set set) { if (p1 instanceof UnionPattern) { ((UnionPattern)p1).gatherComponentPatterns(set); } else { set.add(p1); } if (p2 instanceof UnionPattern) { ((UnionPattern)p2).gatherComponentPatterns(set); } else { set.add(p2); } } /** * Determine if the supplied node matches the pattern * * @param e the node to be compared * @return true if the node matches either of the operand patterns */ public boolean matches(NodeInfo e, XPathContext context) throws XPathException { return p1.matches(e, context) || p2.matches(e, context); } /** * Determine the types of nodes to which this pattern applies. Used for optimisation. * For patterns that match nodes of several types, return Node.NODE * * @return the type of node matched by this pattern. e.g. Node.ELEMENT or Node.TEXT */ public int getNodeKind() { return nodeType; } /** * Get a NodeTest that all the nodes matching this pattern must satisfy */ public NodeTest getNodeTest() { if (nodeType == Type.NODE) { return AnyNodeTest.getInstance(); } else { return NodeKindTest.makeNodeKindTest(nodeType); } } /** * Get the dependencies of the pattern. The only possible dependency for a pattern is * on local variables. This is analyzed in those patterns where local variables may appear. * * @return the dependencies, as a bit-significant mask */ public int getDependencies() { return p1.getDependencies() | p2.getDependencies(); } /** * Iterate over the subexpressions within this pattern * @return an iterator over the subexpressions. */ public Iterator iterateSubExpressions() { return new MultiIterator(new Iterator[]{p1.iterateSubExpressions(), p2.iterateSubExpressions()}); } /** * Get the LHS of the union * * @return the first operand of the union */ public Pattern getLHS() { return p1; } /** * Get the RHS of the union * * @return the second operand of the union */ public Pattern getRHS() { return p2; } /** * Override method to set the system ID, so it's set on both halves */ public void setSystemId(String systemId) { super.setSystemId(systemId); p1.setSystemId(systemId); p2.setSystemId(systemId); } /** * Override method to set the system ID, so it's set on both halves */ public void setLineNumber(int lineNumber) { super.setLineNumber(lineNumber); p1.setLineNumber(lineNumber); p2.setLineNumber(lineNumber); } /** * Determine whether this pattern is the same as another pattern * @param other the other object */ public boolean equals(Object other) { if (other instanceof UnionPattern) { Set s0 = new HashSet(10); gatherComponentPatterns(s0); Set s1 = new HashSet(10); ((UnionPattern)other).gatherComponentPatterns(s1); return s0.equals(s1); } else { return false; } } /** * Hashcode supporting equals() */ public int hashCode() { return 0x9bd723a6 ^ p1.hashCode() ^ p2.hashCode(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/pattern/package.html0000644000175000017500000000411311033112257021334 0ustar eugeneeugene Package overview for net.sf.saxon.pattern

    This package provides classes associated with XSLT pattern handling.

    The principal classes are:

    Pattern:
    This represents an XSLT Pattern. There is a static method Pattern.make() which is used to construct a Pattern from a String (it is a factory method rather than a constructor, because it typically returns some subclass of Pattern according to the syntax supplied). Subclasses of Pattern represent different kinds of pattern such as LocationPathPattern and IDKeyPattern. What they all have in common is a match() method, which determines whether a given node matches the pattern. A pattern is not in itself an Expression, but the class PatternSponsor is used to wrap a pattern making it look like an expression for the benefit of the static analysis (allowing the same mechanisms to be used for example to find all the references to a variable).

    NodeTest:
    This represents a NodeTest within a step of an XPath expression. A NodeTest performs several roles: as well as its use in conjuction with an axis to form a step of a path expression, it acts as an ItemType used in handling type checking of nodes, and (wrapped in a NodeTestPattern) it acts as an XSLT pattern for use in constructs such as the match attribute of xsl:template and xsl:key. A NodeTest is used directly to implement simple patterns such as match="item" or match="*". There are several subclasses of NodeTest, depending on the conditions to be matched: node type, node name, namespace URI, and so on. The class AnyNodeTest matches any node, while NoNodeTest matches nothing. NodeTests can also be combined using the operators of intersection, difference, and union, to describe the more complex types that are sometimes computed by the type checking machinery.


    Michael H. Kay
    Saxonica Limited
    9 February 2005

    saxonb-9.1.0.8/bj/net/sf/saxon/xom/0000755000175000017500000000000012216261746016216 5ustar eugeneeugenesaxonb-9.1.0.8/bj/net/sf/saxon/xom/DocumentWrapper.java0000644000175000017500000001324711033112257022173 0ustar eugeneeugenepackage net.sf.saxon.xom; import net.sf.saxon.Configuration; import net.sf.saxon.om.DocumentInfo; import net.sf.saxon.om.NamePool; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.type.Type; import nu.xom.Attribute; import nu.xom.Document; import nu.xom.Element; import nu.xom.Node; import java.util.HashMap; import java.util.Iterator; import java.util.Collections; /** * The root node of an XPath tree. (Or equivalently, the tree itself). *

    * This class is used not only for a document, but also for the root * of a document-less tree fragment. * * @author Michael H. Kay * @author Wolfgang Hoschek (ported net.sf.saxon.jdom to XOM) */ public class DocumentWrapper extends NodeWrapper implements DocumentInfo { protected Configuration config; protected String baseURI; protected int documentNumber; private HashMap idIndex; /** * Create a Saxon wrapper for a XOM root node * * @param root * The XOM root node * @param baseURI * The base URI for all the nodes in the tree * @param config * The configuration which defines the name pool used for all * names in this tree */ public DocumentWrapper(Node root, String baseURI, Configuration config) { super(root, null, 0); if (root.getParent() != null) throw new IllegalArgumentException("root node must not have a parent node"); this.baseURI = baseURI; docWrapper = this; setConfiguration(config); } /** * Wrap a node in the XOM document. * * @param node * The node to be wrapped. This must be a node in the same * document (the system does not check for this). * @return the wrapping NodeInfo object */ public NodeInfo wrap(Node node) { if (node == this.node) { return this; } return makeWrapper(node, this); } /** * Set the configuration, which defines the name pool used for all names in * this document. This is always called after a new document has been * created. The implementation must register the name pool with the * document, so that it can be retrieved using getNamePool(). It must also * call NamePool.allocateDocumentNumber(), and return the relevant document * number when getDocumentNumber() is subsequently called. * * @param config The configuration to be used */ public void setConfiguration(Configuration config) { this.config = config; documentNumber = config.getDocumentNumberAllocator().allocateDocumentNumber(); } /** * Get the configuration previously set using setConfiguration */ public Configuration getConfiguration() { return config; } /** * Get the name pool used for the names in this document * * @return the name pool in which all the names used in this document are * registered */ public NamePool getNamePool() { return config.getNamePool(); } /** * Get the unique document number for this document (the number is unique * for all documents within a NamePool) * * @return the unique number identifying this document within the name pool */ public int getDocumentNumber() { return documentNumber; } /** * Get the element with a given ID, if any * * @param id * the required ID value * @return the element with the given ID, or null if there is no such ID * present (or if the parser has not notified attributes as being of * type ID). */ public NodeInfo selectID(String id) { if (idIndex == null) { Element elem; switch (nodeKind) { case Type.DOCUMENT : elem = ((Document) node).getRootElement(); break; case Type.ELEMENT : elem = (Element) node; break; default: return null; } idIndex = new HashMap(50); buildIDIndex(elem); } return (NodeInfo) idIndex.get(id); } private void buildIDIndex(Element elem) { // walk the tree in reverse document order, to satisfy the XPath 1.0 rule // that says if an ID appears twice, the first one wins for (int i=elem.getChildCount(); --i >= 0 ; ) { Node child = elem.getChild(i); if (child instanceof Element) { buildIDIndex((Element)child); } } for (int i=elem.getAttributeCount(); --i >= 0 ; ) { Attribute att = elem.getAttribute(i); if (att.getType() == Attribute.Type.ID) { idIndex.put(att.getValue(), wrap(elem)); } } } /** * Get the list of unparsed entities defined in this document * @return an Iterator, whose items are of type String, containing the names of all * unparsed entities defined in this document. If there are no unparsed entities or if the * information is not available then an empty iterator is returned */ public Iterator getUnparsedEntityNames() { return Collections.EMPTY_LIST.iterator(); } /** * Get the unparsed entity with a given name * * @param name the name of the entity * @return null: XOM does not provide access to unparsed entities */ public String[] getUnparsedEntity(String name) { return null; } } // // The contents of this file are subject to the Mozilla Public License Version // 1.0 (the "License"); // you may not use this file except in compliance with the License. You may // obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations // under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All // Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/xom/NodeWrapper.java0000644000175000017500000015241411033112257021302 0ustar eugeneeugenepackage net.sf.saxon.xom; import net.sf.saxon.Configuration; import net.sf.saxon.om.StandardNames; import net.sf.saxon.trans.XPathException; import net.sf.saxon.event.Receiver; import net.sf.saxon.om.*; import net.sf.saxon.pattern.AnyNodeTest; import net.sf.saxon.pattern.NameTest; import net.sf.saxon.pattern.NodeKindTest; import net.sf.saxon.pattern.NodeTest; import net.sf.saxon.type.Type; import net.sf.saxon.value.UntypedAtomicValue; import net.sf.saxon.value.Value; import net.sf.saxon.value.StringValue; import net.sf.saxon.value.AtomicValue; import nu.xom.*; /** * A node in the XML parse tree representing an XML element, character content, * or attribute. *

    * This is the implementation of the NodeInfo interface used as a wrapper for * XOM nodes. * * @author Michael H. Kay * @author Wolfgang Hoschek (ported net.sf.saxon.jdom to XOM) */ public class NodeWrapper implements NodeInfo, VirtualNode, SiblingCountingNode { protected Node node; protected short nodeKind; private NodeWrapper parent; // null means unknown protected DocumentWrapper docWrapper; protected int index; // -1 means unknown /** * This constructor is protected: nodes should be created using the wrap * factory method on the DocumentWrapper class * * @param node * The XOM node to be wrapped * @param parent * The NodeWrapper that wraps the parent of this node * @param index * Position of this node among its siblings */ protected NodeWrapper(Node node, NodeWrapper parent, int index) { short kind; if (node instanceof Element) { kind = Type.ELEMENT; } else if (node instanceof Text) { kind = Type.TEXT; } else if (node instanceof Attribute) { kind = Type.ATTRIBUTE; } else if (node instanceof Comment) { kind = Type.COMMENT; } else if (node instanceof ProcessingInstruction) { kind = Type.PROCESSING_INSTRUCTION; } else if (node instanceof Document) { kind = Type.DOCUMENT; } else { throwIllegalNode(node); // moved out of fast path to enable better inlining return; // keep compiler happy } nodeKind = kind; this.node = node; this.parent = parent; this.index = index; } /** * Factory method to wrap a XOM node with a wrapper that implements the * Saxon NodeInfo interface. * * @param node * The XOM node * @param docWrapper * The wrapper for the Document containing this node * @return The new wrapper for the supplied node */ protected final NodeWrapper makeWrapper(Node node, DocumentWrapper docWrapper) { return makeWrapper(node, docWrapper, null, -1); } /** * Factory method to wrap a XOM node with a wrapper that implements the * Saxon NodeInfo interface. * * @param node * The XOM node * @param docWrapper * The wrapper for the Document containing this node * @param parent * The wrapper for the parent of the XOM node * @param index * The position of this node relative to its siblings * @return The new wrapper for the supplied node */ protected final NodeWrapper makeWrapper(Node node, DocumentWrapper docWrapper, NodeWrapper parent, int index) { if (node == docWrapper.node) return docWrapper; NodeWrapper wrapper = new NodeWrapper(node, parent, index); wrapper.docWrapper = docWrapper; return wrapper; } private static void throwIllegalNode(Node node) { String str = node == null ? "NULL" : node.getClass() + " instance " + node.toString(); throw new IllegalArgumentException("Bad node type in XOM! " + str); } /** * Get the configuration */ public Configuration getConfiguration() { return docWrapper.getConfiguration(); } /** * Get the underlying XOM node, to implement the VirtualNode interface */ public Object getUnderlyingNode() { return node; } /** * Get the name pool for this node * * @return the NamePool */ public NamePool getNamePool() { return docWrapper.getNamePool(); } /** * Return the type of node. * * @return one of the values Node.ELEMENT, Node.TEXT, Node.ATTRIBUTE, etc. */ public int getNodeKind() { return nodeKind; } /** * Get the typed value of the item */ public SequenceIterator getTypedValue() { return SingletonIterator.makeIterator((AtomicValue)atomize()); } /** * Get the typed value. The result of this method will always be consistent * with the method {@link net.sf.saxon.om.Item#getTypedValue()}. However, * this method is often more convenient and may be more efficient, * especially in the common case where the value is expected to be a * singleton. * * @return the typed value. If requireSingleton is set to true, the result * will always be an AtomicValue. In other cases it may be a Value * representing a sequence whose items are atomic values. * @since 8.5 */ public Value atomize() { switch (getNodeKind()) { case Type.COMMENT: case Type.PROCESSING_INSTRUCTION: return new StringValue(getStringValueCS()); default: return new UntypedAtomicValue(getStringValueCS()); } } /** * Get the type annotation of this node, if any. Returns -1 for kinds of * nodes that have no annotation, and for elements annotated as untyped, and * attributes annotated as untypedAtomic. * * @return the type annotation of the node. * @see net.sf.saxon.type.Type */ public int getTypeAnnotation() { if (getNodeKind() == Type.ATTRIBUTE) { return StandardNames.XS_UNTYPED_ATOMIC; } return StandardNames.XS_UNTYPED; } /** * Determine whether this is the same node as another node.
    * Note: a.isSameNode(b) if and only if generateId(a)==generateId(b) * * @return true if this Node object and the supplied Node object represent * the same node in the tree. */ public boolean isSameNodeInfo(NodeInfo other) { // In XOM equality means identity return other instanceof NodeWrapper && node == ((NodeWrapper)other).node; } /** * The equals() method compares nodes for identity. It is defined to give the same result * as isSameNodeInfo(). * * @param other the node to be compared with this node * @return true if this NodeInfo object and the supplied NodeInfo object represent * the same node in the tree. * @since 8.7 Previously, the effect of the equals() method was not defined. Callers * should therefore be aware that third party implementations of the NodeInfo interface may * not implement the correct semantics. It is safer to use isSameNodeInfo() for this reason. * The equals() method has been defined because it is useful in contexts such as a Java Set or HashMap. */ public boolean equals(Object other) { return other instanceof NodeInfo && isSameNodeInfo((NodeInfo)other); } /** * The hashCode() method obeys the contract for hashCode(): that is, if two objects are equal * (represent the same node) then they must have the same hashCode() * @since 8.7 Previously, the effect of the equals() and hashCode() methods was not defined. Callers * should therefore be aware that third party implementations of the NodeInfo interface may * not implement the correct semantics. */ public int hashCode() { return node.hashCode(); } /** * Get the System ID for the node. * * @return the System Identifier of the entity in the source document * containing the node, or null if not known. Note this is not the * same as the base URI: the base URI can be modified by xml:base, * but the system ID cannot. */ public String getSystemId() { return docWrapper.baseURI; } public void setSystemId(String uri) { docWrapper.baseURI = uri; } /** * Get the Base URI for the node, that is, the URI used for resolving a * relative URI contained in the node. */ public String getBaseURI() { return node.getBaseURI(); } /** * Get line number * * @return the line number of the node in its original source document; or * -1 if not available */ public int getLineNumber() { return -1; } /** * Get column number * @return the column number of the node in its original source document; or -1 if not available */ public int getColumnNumber() { return -1; } /** * Determine the relative position of this node and another node, in * document order. The other node will always be in the same document. * * @param other * The other node, whose position is to be compared with this * node * @return -1 if this node precedes the other node, +1 if it follows the * other node, or 0 if they are the same node. (In this case, * isSameNode() will always return true, and the two nodes will * produce the same result for generateId()) */ public int compareOrder(NodeInfo other) { if (other instanceof NodeWrapper) { return compareOrderFast(node,((NodeWrapper) other).node); } else { // it must be a namespace node return -other.compareOrder(this); } } private static int compareOrderFast(Node first, Node second) { /* * Unfortunately we do not have a sequence number for each node at hand; * this would allow to turn the comparison into a simple sequence number * subtraction. Walking the entire tree and batch-generating sequence * numbers on the fly is no good option either. However, this rewritten * implementation turns out to be more than fast enough. */ // assert first != null && second != null // assert first and second MUST NOT be namespace nodes if (first == second) return 0; ParentNode firstParent = first.getParent(); ParentNode secondParent = second.getParent(); if (firstParent == null) { if (secondParent != null) return -1; // first node is the root // both nodes are parentless, use arbitrary but fixed order: return first.hashCode() - second.hashCode(); } if (secondParent == null) return +1; // second node is the root // do they have the same parent (common case)? if (firstParent == secondParent) { int i1 = firstParent.indexOf(first); int i2 = firstParent.indexOf(second); // note that attributes and namespaces are not children // of their own parent (i = -1). // attribute (if any) comes before child if (i1 != -1) return (i2 != -1) ? i1 - i2 : +1; if (i2 != -1) return -1; // assert: i1 == -1 && i2 == -1 // i.e. both nodes are attributes Element elem = (Element) firstParent; for (int i = elem.getAttributeCount(); --i >= 0;) { Attribute attr = elem.getAttribute(i); if (attr == second) return -1; if (attr == first) return +1; } throw new IllegalStateException("should be unreachable"); } // find the depths of both nodes in the tree int depth1 = 0; int depth2 = 0; Node p1 = first; Node p2 = second; while (p1 != null) { depth1++; p1 = p1.getParent(); if (p1 == second) return +1; } while (p2 != null) { depth2++; p2 = p2.getParent(); if (p2 == first) return -1; } // move up one branch of the tree so we have two nodes on the same level p1 = first; while (depth1 > depth2) { p1 = p1.getParent(); depth1--; } p2 = second; while (depth2 > depth1) { p2 = p2.getParent(); depth2--; } // now move up both branches in sync until we find a common parent while (true) { firstParent = p1.getParent(); secondParent = p2.getParent(); if (firstParent == null || secondParent == null) { // both nodes are documentless, use arbitrary but fixed order // based on their root elements return p1.hashCode() - p2.hashCode(); // throw new NullPointerException("XOM tree compare - internal error"); } if (firstParent == secondParent) { return firstParent.indexOf(p1) - firstParent.indexOf(p2); } p1 = firstParent; p2 = secondParent; } } /** * Return the string value of the node. The interpretation of this depends * on the type of node. For an element it is the accumulated character * content of the element, including descendant elements. * * @return the string value of the node */ public String getStringValue() { return node.getValue(); } /** * Get the value of the item as a CharSequence. This is in some cases more efficient than * the version of the method that returns a String. */ public CharSequence getStringValueCS() { return node.getValue(); } /** * Get name code. The name code is a coded form of the node name: two nodes * with the same name code have the same namespace URI, the same local name, * and the same prefix. By masking the name code with &0xfffff, you get a * fingerprint: two nodes with the same fingerprint have the same local name * and namespace URI. * * @see net.sf.saxon.om.NamePool#allocate allocate */ public int getNameCode() { switch (nodeKind) { case Type.ELEMENT: case Type.ATTRIBUTE: case Type.PROCESSING_INSTRUCTION: return docWrapper.getNamePool().allocate(getPrefix(), getURI(), getLocalPart()); default: return -1; } } /** * Get fingerprint. The fingerprint is a coded form of the expanded name of * the node: two nodes with the same name code have the same namespace URI * and the same local name. A fingerprint of -1 should be returned for a * node with no name. */ public int getFingerprint() { int nc = getNameCode(); if (nc == -1) return -1; return nc & 0xfffff; } /** * Get the local part of the name of this node. This is the name after the * ":" if any. * * @return the local part of the name. For an unnamed node, returns "". */ public String getLocalPart() { switch (nodeKind) { case Type.ELEMENT: return ((Element) node).getLocalName(); case Type.ATTRIBUTE: return ((Attribute) node).getLocalName(); case Type.PROCESSING_INSTRUCTION: return ((ProcessingInstruction) node).getTarget(); default: return ""; } } /** * Get the prefix of the name of the node. This is defined only for elements and attributes. * If the node has no prefix, or for other kinds of node, return a zero-length string. * @return The prefix of the name of the node. */ public String getPrefix() { switch (nodeKind) { case Type.ELEMENT: return ((Element) node).getNamespacePrefix(); case Type.ATTRIBUTE: return ((Attribute) node).getNamespacePrefix(); default: return ""; } } /** * Get the URI part of the name of this node. This is the URI corresponding * to the prefix, or the URI of the default namespace if appropriate. * * @return The URI of the namespace of this node. For an unnamed node, or * for a node with an empty prefix, return an empty string. */ public String getURI() { switch (nodeKind) { case Type.ELEMENT: return ((Element) node).getNamespaceURI(); case Type.ATTRIBUTE: return ((Attribute) node).getNamespaceURI(); default: return ""; } } /** * Get the display name of this node. For elements and attributes this is * [prefix:]localname. For unnamed nodes, it is an empty string. * * @return The display name of this node. For a node with no name, return an * empty string. */ public String getDisplayName() { switch (nodeKind) { case Type.ELEMENT: return ((Element) node).getQualifiedName(); case Type.ATTRIBUTE: return ((Attribute) node).getQualifiedName(); case Type.PROCESSING_INSTRUCTION: return ((ProcessingInstruction) node).getTarget(); default: return ""; } } /** * Get the NodeInfo object representing the parent of this node */ public NodeInfo getParent() { if (parent == null) { ParentNode p = node.getParent(); if (p != null) parent = makeWrapper(p, docWrapper); } return parent; } /** * Get the index position of this node among its siblings (starting from 0) */ public int getSiblingPosition() { // This method is used only to support generate-id() if (index != -1) return index; switch (nodeKind) { case Type.ATTRIBUTE: { Attribute att = (Attribute) node; Element p = (Element) att.getParent(); if (p == null) return 0; for (int i=p.getAttributeCount(); --i >= 0;) { if (p.getAttribute(i) == att) { index = i; return i; } } throw new IllegalStateException("XOM node not linked to parent node"); } default: { ParentNode p = node.getParent(); int i = (p == null ? 0 : p.indexOf(node)); if (i == -1) throw new IllegalStateException("XOM node not linked to parent node"); index = i; return index; } } } /** * Return an iteration over the nodes reached by the given axis from this * node * * @param axisNumber * the axis to be used * @return a SequenceIterator that scans the nodes reached by the axis in * turn. */ public AxisIterator iterateAxis(byte axisNumber) { return iterateAxis(axisNumber, AnyNodeTest.getInstance()); } /** * Return an iteration over the nodes reached by the given axis from this * node * * @param axisNumber * the axis to be used * @param nodeTest * A pattern to be matched by the returned nodes * @return a SequenceIterator that scans the nodes reached by the axis in * turn. */ public AxisIterator iterateAxis(byte axisNumber, NodeTest nodeTest) { // for clarifications, see the W3C specs or: // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/xmlsdk/html/xmrefaxes.asp switch (axisNumber) { case Axis.ANCESTOR: return new AncestorAxisIterator(this, false, nodeTest); case Axis.ANCESTOR_OR_SELF: return new AncestorAxisIterator(this, true, nodeTest); case Axis.ATTRIBUTE: if (nodeKind != Type.ELEMENT || ((Element) node).getAttributeCount() == 0) { return EmptyIterator.getInstance(); } else { return new AttributeAxisIterator(this, nodeTest); } case Axis.CHILD: if (hasChildNodes()) { return new ChildAxisIterator(this, true, true, nodeTest); } else { return EmptyIterator.getInstance(); } case Axis.DESCENDANT: if (hasChildNodes()) { return new DescendantAxisIterator(this, false, false, nodeTest); } else { return EmptyIterator.getInstance(); } case Axis.DESCENDANT_OR_SELF: if (hasChildNodes()) { return new DescendantAxisIterator(this, true, false, nodeTest); } else { return Navigator.filteredSingleton(this, nodeTest); } case Axis.FOLLOWING: if (getParent() == null) { return EmptyIterator.getInstance(); } else { return new DescendantAxisIterator(this, false, true, nodeTest); } case Axis.FOLLOWING_SIBLING: if (nodeKind == Type.ATTRIBUTE || getParent() == null) { return EmptyIterator.getInstance(); } else { return new ChildAxisIterator(this, false, true, nodeTest); } case Axis.NAMESPACE: if (nodeKind == Type.ELEMENT) { return NamespaceIterator.makeIterator(this, nodeTest); } else { return EmptyIterator.getInstance(); } case Axis.PARENT: if (getParent() == null) { return EmptyIterator.getInstance(); } else { return Navigator.filteredSingleton(getParent(), nodeTest); } case Axis.PRECEDING: return new PrecedingAxisIterator(this, false, nodeTest); // return new Navigator.AxisFilter( // new Navigator.PrecedingEnumeration(this, false), nodeTest); case Axis.PRECEDING_SIBLING: if (nodeKind == Type.ATTRIBUTE || getParent() == null) { return EmptyIterator.getInstance(); } else { return new ChildAxisIterator(this, false, false, nodeTest); } case Axis.SELF: return Navigator.filteredSingleton(this, nodeTest); case Axis.PRECEDING_OR_ANCESTOR: // This axis is used internally by saxon for the xsl:number implementation, // it returns the union of the preceding axis and the ancestor axis. return new PrecedingAxisIterator(this, true, nodeTest); // return new Navigator.AxisFilter(new Navigator.PrecedingEnumeration( // this, true), nodeTest); default: throw new IllegalArgumentException("Unknown axis number " + axisNumber); } } // private static AxisIterator makeSingleIterator(NodeWrapper wrapper, NodeTest nodeTest) { // if (nodeTest == AnyNodeTest.getInstance() || nodeTest.matches(wrapper)) // return SingletonIterator.makeIterator(wrapper); // else // return EmptyIterator.getInstance(); // } /** * Get the value of a given attribute of this node * * @param fingerprint * The fingerprint of the attribute name * @return the attribute value if it exists or null if not */ public String getAttributeValue(int fingerprint) { if (nodeKind == Type.ELEMENT) { NamePool pool = docWrapper.getNamePool(); String localName = pool.getLocalName(fingerprint); String uri = pool.getURI(fingerprint); Attribute att = ((Element) node).getAttribute(localName, uri); if (att != null) return att.getValue(); } return null; } /** * Get the root node of the tree containing this node * * @return the NodeInfo representing the top-level ancestor of this node. * This will not necessarily be a document node */ public NodeInfo getRoot() { return docWrapper; } /** * Get the root node, if it is a document node. * * @return the DocumentInfo representing the containing document. */ public DocumentInfo getDocumentRoot() { if (docWrapper.node instanceof Document) { return docWrapper; } else { return null; } } /** * Determine whether the node has any children.
    * Note: the result is equivalent to
    * getEnumeration(Axis.CHILD, AnyNodeTest.getInstance()).hasNext() */ public boolean hasChildNodes() { return node.getChildCount() > 0; } /** * Get a character string that uniquely identifies this node. Note: * a.isSameNode(b) if and only if generateId(a)==generateId(b) * * @param buffer a buffer to contain a string that uniquely identifies this node, across all documents */ public void generateId(FastStringBuffer buffer) { Navigator.appendSequentialKey(this, buffer, true); //buffer.append(Navigator.getSequentialKey(this)); } /** * Get the document number of the document containing this node. For a * free-standing orphan node, just return the hashcode. */ public int getDocumentNumber() { return docWrapper.getDocumentNumber(); } /** * Copy this node to a given outputter (deep copy) */ public void copy(Receiver out, int whichNamespaces, boolean copyAnnotations, int locationId) throws XPathException { Navigator.copy(this, out, docWrapper.getNamePool(), whichNamespaces, copyAnnotations, locationId); } /** * Get all namespace undeclarations and undeclarations defined on this element. * * @param buffer If this is non-null, and the result array fits in this buffer, then the result * may overwrite the contents of this array, to avoid the cost of allocating a new array on the heap. * @return An array of integers representing the namespace declarations and undeclarations present on * this element. For a node other than an element, return null. Otherwise, the returned array is a * sequence of namespace codes, whose meaning may be interpreted by reference to the name pool. The * top half word of each namespace code represents the prefix, the bottom half represents the URI. * If the bottom half is zero, then this is a namespace undeclaration rather than a declaration. * The XML namespace is never included in the list. If the supplied array is larger than required, * then the first unused entry will be set to -1. *

    *

    For a node other than an element, the method returns null.

    */ public int[] getDeclaredNamespaces(int[] buffer) { if (node instanceof Element) { Element elem = (Element)node; int size = elem.getNamespaceDeclarationCount(); if (size == 0) { return EMPTY_NAMESPACE_LIST; } int[] result = (buffer == null || size > buffer.length ? new int[size] : buffer); NamePool pool = getNamePool(); for (int i=0; i < size; i++) { String prefix = elem.getNamespacePrefix(i); String uri = elem.getNamespaceURI(prefix); result[i] = pool.allocateNamespaceCode(prefix, uri); } if (size < result.length) { result[size] = -1; } return result; } else { return null; } } /** * Determine whether this node has the is-id property * * @return true if the node is an ID */ public boolean isId() { return getNodeKind() == Type.ATTRIBUTE && ((Attribute)node).getType() == Attribute.Type.ID; } /** * Determine whether this node has the is-idref property * * @return true if the node is an IDREF or IDREFS element or attribute */ public boolean isIdref() { return getNodeKind() == Type.ATTRIBUTE && ( ((Attribute)node).getType() == Attribute.Type.IDREF || ((Attribute)node).getType() == Attribute.Type.IDREFS); } /** * Determine whether the node has the is-nilled property * * @return true if the node has the is-nilled property */ public boolean isNilled() { return false; } /////////////////////////////////////////////////////////////////////////////// // Methods to support update access /////////////////////////////////////////////////////////////////////////////// /** * Delete this node (that is, detach it from its parent) */ public void delete() throws XPathException { if (parent != null) { if (nodeKind == Type.ATTRIBUTE) { ((Element)parent.node).removeAttribute((Attribute)node); } else { ((ParentNode)parent.node).removeChild(node); } } } /** * Insert a sequence of nodes as the first children of the target node * @param content the nodes to be inserted. */ // public void insertAsFirst(SequenceIterator content) throws XPathException { // if (!(node instanceof ParentNode)) { // throw new XPathException("Cannot insert children unless parent is an element or document node"); // } // int i = 0; // while (true) { // NodeInfo next = (NodeInfo)content.next(); // if (next == null) { // break; // } // if (next instanceof NodeWrapper) { // Node nextNode = ((NodeWrapper)next).node; // ParentNode existingParent = nextNode.getParent(); // if (existingParent != null) { // existingParent.removeChild(nextNode); // } // ((ParentNode)node).insertChild(nextNode, i++); // } else { // throw new XPathException("Cannot insert non-XOM node"); // } // } // } // // /** // * Insert a sequence of nodes as the last children of the target node // * @param content the nodes to be inserted. // */ // // public void insertAsLast(SequenceIterator content) throws XPathException { // if (!(node instanceof ParentNode)) { // throw new XPathException("Cannot insert children unless parent is an element or document node"); // } // while (true) { // NodeInfo next = (NodeInfo)content.next(); // if (next == null) { // break; // } // if (next instanceof NodeWrapper) { // Node nextNode = ((NodeWrapper)next).node; // ParentNode existingParent = nextNode.getParent(); // if (existingParent != null) { // existingParent.removeChild(nextNode); // } // ((ParentNode)node).appendChild(nextNode); // } else { // throw new XPathException("Cannot insert non-XOM node"); // } // } // } // // // /** // * Add attributes to this node // * // * @param content the attributes to be added // */ // // public void insertAttributes(SequenceIterator content) throws XPathException { // if (nodeKind == Type.ELEMENT) { // while (true) { // NodeInfo next = (NodeInfo)content.next(); // if (next == null) { // break; // } // if (next.getNodeKind() != Type.ATTRIBUTE) { // throw new XPathException("Node to be inserted is not an attribute"); // } // if (next instanceof NodeWrapper) { // Node node = ((NodeWrapper)next).node; // if (node.getParent() != null) { // node = node.copy(); // } // ((Element)node).addAttribute((Attribute)node); // } else { // throw new XPathException("Cannot insert non-XOM node"); // } // } // } else { // throw new XPathException("Cannot insert attributes unless parent is an element node"); // } // } // // /** // * Rename this node // * // * @param newName the new name // */ // // public void rename(StructuredQName newName) throws XPathException { // if (node instanceof Element) { // ((Element)node).setNamespaceURI(newName.getNamespaceURI()); // ((Element)node).setLocalName(newName.getLocalName()); // ((Element)node).setNamespacePrefix(newName.getPrefix()); // } else if (node instanceof Attribute) { // ((Attribute)node).setNamespace(newName.getPrefix(), newName.getNamespaceURI()); // ((Attribute)node).setLocalName(newName.getLocalName()); // } // } /** * Replace this node with a given sequence of nodes * * @param replacement the replacement nodes */ // public void replace(SequenceIterator replacement) throws XPathException { // NodeWrapper parentNode = ((NodeWrapper)) // if (getPar) { // throw new XPathException("Cannot replace node unless parent is an element or document node"); // } // while (true) { // NodeInfo next = (NodeInfo)content.next(); // if (next == null) { // break; // } // if (next instanceof NodeWrapper) { // Node nextNode = ((NodeWrapper)next).node; // ParentNode existingParent = nextNode.getParent(); // if (existingParent != null) { // existingParent.removeChild(nextNode); // } // ((ParentNode)node).appendChild(nextNode); // } else { // throw new XPathException("Cannot insert non-XOM node"); // } // } // } /** * Replace the string-value of this node * * @param stringValue the new string value */ // public void replaceStringValue(CharSequence stringValue) throws XPathException { // switch (nodeKind) { // case Type.ATTRIBUTE: // ((Attribute)node).setValue(stringValue.toString()); // case Type. // } // } /////////////////////////////////////////////////////////////////////////////// // Axis enumeration classes /////////////////////////////////////////////////////////////////////////////// /** * Handles the ancestor axis in a rather direct manner. */ private final class AncestorAxisIterator implements AxisIterator { private NodeWrapper start; private boolean includeSelf; private NodeInfo current; private NodeTest nodeTest; private int position; public AncestorAxisIterator(NodeWrapper start, boolean includeSelf, NodeTest test) { // use lazy instead of eager materialization (performance) this.start = start; if (test == AnyNodeTest.getInstance()) test = null; nodeTest = test; if (!includeSelf) { current = start; } this.includeSelf = includeSelf; position = 0; } /** * Move to the next node, without returning it. Returns true if there is * a next node, false if the end of the sequence has been reached. After * calling this method, the current node may be retrieved using the * current() function. */ public boolean moveNext() { return (next() != null); } public Item next() { NodeInfo curr; do { // until we find a match curr = advance(); } while (curr != null && nodeTest != null && (! nodeTest.matches(curr))); if (curr != null) position++; current = curr; return curr; } private NodeInfo advance() { if (current == null) current = start; else current = current.getParent(); return current; } public Item current() { return current; } public int position() { return position; } public void close() { } /** * Return an iterator over an axis, starting at the current node. * * @param axis the axis to iterate over, using a constant such as * {@link net.sf.saxon.om.Axis#CHILD} * @param test a predicate to apply to the nodes before returning them. * @throws NullPointerException if there is no current node */ public AxisIterator iterateAxis(byte axis, NodeTest test) { return current.iterateAxis(axis, test); } /** * Return the atomized value of the current node. * * @return the atomized value. * @throws NullPointerException if there is no current node */ public Value atomize() throws XPathException { return current.atomize(); } /** * Return the string value of the current node. * * @return the string value, as an instance of CharSequence. * @throws NullPointerException if there is no current node */ public CharSequence getStringValue() { return current.getStringValue(); } public SequenceIterator getAnother() { return new AncestorAxisIterator(start, includeSelf, nodeTest); } public int getProperties() { return 0; } } // end of class AncestorAxisIterator /** * Handles the attribute axis in a rather direct manner. */ private final class AttributeAxisIterator implements AxisIterator { private NodeWrapper start; private NodeInfo current; private int cursor; private NodeTest nodeTest; private int position; public AttributeAxisIterator(NodeWrapper start, NodeTest test) { // use lazy instead of eager materialization (performance) this.start = start; if (test == AnyNodeTest.getInstance()) test = null; nodeTest = test; position = 0; cursor = 0; } /** * Move to the next node, without returning it. Returns true if there is * a next node, false if the end of the sequence has been reached. After * calling this method, the current node may be retrieved using the * current() function. */ public boolean moveNext() { return (next() != null); } public Item next() { NodeInfo curr; do { // until we find a match curr = advance(); } while (curr != null && nodeTest != null && (! nodeTest.matches(curr))); if (curr != null) position++; current = curr; return curr; } private NodeInfo advance() { Element elem = (Element) start.node; if (cursor == elem.getAttributeCount()) return null; NodeInfo curr = makeWrapper(elem.getAttribute(cursor), docWrapper, start, cursor); cursor++; return curr; } public Item current() { return current; } public int position() { return position; } public void close() { } /** * Return an iterator over an axis, starting at the current node. * * @param axis the axis to iterate over, using a constant such as * {@link net.sf.saxon.om.Axis#CHILD} * @param test a predicate to apply to the nodes before returning them. * @throws NullPointerException if there is no current node */ public AxisIterator iterateAxis(byte axis, NodeTest test) { return current.iterateAxis(axis, test); } /** * Return the atomized value of the current node. * * @return the atomized value. * @throws NullPointerException if there is no current node */ public Value atomize() throws XPathException { return current.atomize(); } /** * Return the string value of the current node. * * @return the string value, as an instance of CharSequence. * @throws NullPointerException if there is no current node */ public CharSequence getStringValue() { return current.getStringValue(); } public SequenceIterator getAnother() { return new AttributeAxisIterator(start, nodeTest); } public int getProperties() { return 0; } } // end of class AttributeAxisIterator /** * The class ChildAxisIterator handles not only the child axis, but also the * following-sibling and preceding-sibling axes. It can also iterate the * children of the start node in reverse order, something that is needed to * support the preceding and preceding-or-ancestor axes (the latter being * used by xsl:number) */ private final class ChildAxisIterator implements AxisIterator { private NodeWrapper start; private NodeWrapper commonParent; private int ix; private boolean downwards; // iterate children of start node (not siblings) private boolean forwards; // iterate in document order (not reverse order) private NodeInfo current; private ParentNode par; private int cursor; private NodeTest nodeTest; private int position; private ChildAxisIterator(NodeWrapper start, boolean downwards, boolean forwards, NodeTest test) { this.start = start; this.downwards = downwards; this.forwards = forwards; if (test == AnyNodeTest.getInstance()) test = null; nodeTest = test; position = 0; commonParent = downwards ? start : (NodeWrapper)start.getParent(); par = (ParentNode) commonParent.node; if (downwards) { ix = (forwards ? 0 : par.getChildCount()); } else { // find the start node among the list of siblings // ix = start.getSiblingPosition(); ix = par.indexOf(start.node); if (forwards) ix++; } cursor = ix; if (!downwards && !forwards) ix--; } /** * Move to the next node, without returning it. Returns true if there is * a next node, false if the end of the sequence has been reached. After * calling this method, the current node may be retrieved using the * current() function. */ public boolean moveNext() { return (next() != null); } public Item next() { NodeInfo curr; do { // until we find a match curr = advance(); } while (curr != null && nodeTest != null && (! nodeTest.matches(curr))); if (curr != null) position++; current = curr; return curr; } private NodeInfo advance() { Node nextChild; do { if (forwards) { if (cursor == par.getChildCount()) return null; nextChild = par.getChild(cursor++); } else { // backwards if (cursor == 0) return null; nextChild = par.getChild(--cursor); } } while (nextChild instanceof DocType); // DocType is not an XPath node; can occur for /child::node() NodeInfo curr = makeWrapper(nextChild, docWrapper, commonParent, ix); ix += (forwards ? 1 : -1); return curr; } public Item current() { return current; } public int position() { return position; } public void close() { } /** * Return an iterator over an axis, starting at the current node. * * @param axis the axis to iterate over, using a constant such as * {@link net.sf.saxon.om.Axis#CHILD} * @param test a predicate to apply to the nodes before returning them. * @throws NullPointerException if there is no current node */ public AxisIterator iterateAxis(byte axis, NodeTest test) { return current.iterateAxis(axis, test); } /** * Return the atomized value of the current node. * * @return the atomized value. * @throws NullPointerException if there is no current node */ public Value atomize() throws XPathException { return current.atomize(); } /** * Return the string value of the current node. * * @return the string value, as an instance of CharSequence. * @throws NullPointerException if there is no current node */ public CharSequence getStringValue() { return current.getStringValue(); } public SequenceIterator getAnother() { return new ChildAxisIterator(start, downwards, forwards, nodeTest); } public int getProperties() { return 0; } } /** * A bit of a misnomer; efficiently takes care of descendants, * descentants-or-self as well as "following" axis. * "includeSelf" must be false for the following axis. * Uses simple and effective O(1) backtracking via indexOf(). */ private final class DescendantAxisIterator implements AxisIterator { private NodeWrapper start; private boolean includeSelf; private boolean following; private Node anchor; // so we know where to stop the scan private Node currNode; private boolean moveToNextSibling; private NodeInfo current; private NodeTest nodeTest; private int position; private String testLocalName; private String testURI; public DescendantAxisIterator(NodeWrapper start, boolean includeSelf, boolean following, NodeTest test) { this.start = start; this.includeSelf = includeSelf; this.following = following; moveToNextSibling = following; if (!following) anchor = start.node; if (!includeSelf) currNode = start.node; if (test == AnyNodeTest.getInstance()) { // performance hack test = null; // mark as AnyNodeTest } else if (test instanceof NameTest) { NameTest nt = (NameTest) test; if (nt.getPrimitiveType() == Type.ELEMENT) { // performance hack // mark as element name test NamePool pool = getNamePool(); testLocalName = pool.getLocalName(nt.getFingerprint()); testURI = pool.getURI(nt.getFingerprint()); } } else if (test instanceof NodeKindTest) { if (test.getPrimitiveType() == Type.ELEMENT) { // performance hack // mark as element type test testLocalName = ""; testURI = null; } } nodeTest = test; position = 0; } /** * Move to the next node, without returning it. Returns true if there is * a next node, false if the end of the sequence has been reached. After * calling this method, the current node may be retrieved using the * current() function. */ public boolean moveNext() { return (next() != null); } public Item next() { NodeInfo curr; do { // until we find a match curr = advance(); } while (curr != null && nodeTest != null && (! nodeTest.matches(curr))); if (curr != null) position++; current = curr; return curr; } // might look expensive at first glance - but it's not private NodeInfo advance() { if (currNode == null) { // if includeSelf currNode = start.node; return start; } int i; do { i = 0; Node p = currNode; if (p.getChildCount() == 0 || moveToNextSibling) { // move to next sibling moveToNextSibling = false; // do it just once while (true) { // if we've reached the root we're done scanning p = currNode.getParent(); if (p == null) return null; // Note: correct even if currNode is an attribute. // Performance is particularly good with the O(1) patch // for XOM's ParentNode.indexOf() i = currNode.getParent().indexOf(currNode) + 1; if (i < p.getChildCount()) { break; // break out of while(true) loop; move to next sibling } else { // reached last sibling; move up currNode = p; // if we've come all the way back to the start anchor we're done if (p == anchor) return null; } } } currNode = p.getChild(i); } while (!conforms(currNode)); // note the null here: makeNodeWrapper(parent, ...) is fast, so it // doesn't really matter that we don't keep a link to it. // In fact, it makes objects more short lived, easing pressure on // the VM allocator and collector for tenured heaps. return makeWrapper(currNode, docWrapper, null, i); } // avoids NodeWrapper allocation when there's clearly a mismatch (common case) private boolean conforms(Node node) { if (testLocalName != null) { // element test? if (!(node instanceof Element)) return false; if (testURI == null) return true; // pure element type test // element name test Element elem = (Element) node; return testLocalName.equals(elem.getLocalName()) && testURI.equals(elem.getNamespaceURI()); } else { // DocType is not an XPath node; can occur for /descendants::node() return !(node instanceof DocType); } } public Item current() { return current; } public int position() { return position; } public void close() { } /** * Return an iterator over an axis, starting at the current node. * * @param axis the axis to iterate over, using a constant such as * {@link net.sf.saxon.om.Axis#CHILD} * @param test a predicate to apply to the nodes before returning them. * @throws NullPointerException if there is no current node */ public AxisIterator iterateAxis(byte axis, NodeTest test) { return current.iterateAxis(axis, test); } /** * Return the atomized value of the current node. * * @return the atomized value. * @throws NullPointerException if there is no current node */ public Value atomize() throws XPathException { return current.atomize(); } /** * Return the string value of the current node. * * @return the string value, as an instance of CharSequence. * @throws NullPointerException if there is no current node */ public CharSequence getStringValue() { return current.getStringValue(); } public SequenceIterator getAnother() { return new DescendantAxisIterator(start, includeSelf, following, nodeTest); } public int getProperties() { return 0; } } /** * Efficiently takes care of preceding axis and Saxon internal preceding-or-ancestor axis. * Uses simple and effective O(1) backtracking via indexOf(). * Implemented along similar lines as DescendantAxisIterator. */ private final class PrecedingAxisIterator implements AxisIterator { private NodeWrapper start; private boolean includeAncestors; private Node currNode; private ParentNode nextAncestor; // next ancestors to skip if !includeAncestors private NodeInfo current; private NodeTest nodeTest; private int position; private String testLocalName; private String testURI; public PrecedingAxisIterator(NodeWrapper start, boolean includeAncestors, NodeTest test) { this.start = start; this.includeAncestors = includeAncestors; currNode = start.node; nextAncestor = includeAncestors ? null : start.node.getParent(); if (test == AnyNodeTest.getInstance()) { // performance hack test = null; // mark as AnyNodeTest } else if (test instanceof NameTest) { NameTest nt = (NameTest) test; if (nt.getPrimitiveType() == Type.ELEMENT) { // performance hack // mark as element name test NamePool pool = getNamePool(); testLocalName = pool.getLocalName(nt.getFingerprint()); testURI = pool.getURI(nt.getFingerprint()); } } else if (test instanceof NodeKindTest) { if (test.getPrimitiveType() == Type.ELEMENT) { // performance hack // mark as element type test testLocalName = ""; testURI = null; } } nodeTest = test; position = 0; } /** * Move to the next node, without returning it. Returns true if there is * a next node, false if the end of the sequence has been reached. After * calling this method, the current node may be retrieved using the * current() function. */ public boolean moveNext() { return (next() != null); } public Item next() { NodeInfo curr; do { // until we find a match curr = advance(); } while (curr != null && nodeTest != null && (! nodeTest.matches(curr))); if (curr != null) position++; current = curr; return curr; } // might look expensive at first glance - but it's not private NodeInfo advance() { int i; do { Node p; while (true) { // if we've reached the root we're done scanning // System.out.println("p="+p); p = currNode.getParent(); if (p == null) return null; // Note: correct even if currNode is an attribute. // Performance is particularly good with the O(1) patch // for XOM's ParentNode.indexOf() i = currNode.getParent().indexOf(currNode) - 1; if (i >= 0) { // move to next sibling's last descendant node p = p.getChild(i); // move to next sibling int j; while ((j = p.getChildCount()-1) >= 0) { // move to last descendant node p = p.getChild(j); i = j; } break; // break out of while(true) loop } else { // there are no more siblings; move up // if !includeAncestors skip the ancestors of the start node // assert p != null if (p != nextAncestor) break; // break out of while(true) loop nextAncestor = nextAncestor.getParent(); currNode = p; } } currNode = p; } while (!conforms(currNode)); // note the null here: makeNodeWrapper(parent, ...) is fast, so it // doesn't really matter that we don't keep a link to it. // In fact, it makes objects more short lived, easing pressure on // the VM allocator and collector for tenured heaps. return makeWrapper(currNode, docWrapper, null, i); } // avoids NodeWrapper allocation when there's clearly a mismatch (common case) // same as for DescendantAxisIterator private boolean conforms(Node node) { if (testLocalName != null) { // element test? if (!(node instanceof Element)) { return false; } if (testURI == null) { return true; // pure element type test } // element name test Element elem = (Element) node; return testLocalName.equals(elem.getLocalName()) && testURI.equals(elem.getNamespaceURI()); } else { // DocType is not an XPath node return !(node instanceof DocType); } } public Item current() { return current; } public int position() { return position; } public void close() { } /** * Return an iterator over an axis, starting at the current node. * * @param axis the axis to iterate over, using a constant such as * {@link net.sf.saxon.om.Axis#CHILD} * @param test a predicate to apply to the nodes before returning them. * @throws NullPointerException if there is no current node */ public AxisIterator iterateAxis(byte axis, NodeTest test) { return current.iterateAxis(axis, test); } /** * Return the atomized value of the current node. * * @return the atomized value. * @throws NullPointerException if there is no current node */ public Value atomize() throws XPathException { return current.atomize(); } /** * Return the string value of the current node. * * @return the string value, as an instance of CharSequence. * @throws NullPointerException if there is no current node */ public CharSequence getStringValue() { return current.getStringValue(); } public SequenceIterator getAnother() { return new PrecedingAxisIterator(start, includeAncestors, nodeTest); } public int getProperties() { return 0; } } } // // The contents of this file are subject to the Mozilla Public License Version // 1.0 (the "License"); // you may not use this file except in compliance with the License. You may // obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations // under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael Kay, with extensive // rewriting by Wolfgang Hoschek // // Portions created by (your name) are Copyright (C) (your legal entity). All // Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/xom/XOMObjectModel.java0000644000175000017500000003053111033417647021635 0ustar eugeneeugenepackage net.sf.saxon.xom; import net.sf.saxon.Configuration; import net.sf.saxon.event.PipelineConfiguration; import net.sf.saxon.event.Receiver; import net.sf.saxon.expr.JPConverter; import net.sf.saxon.expr.PJConverter; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.*; import net.sf.saxon.pattern.AnyNodeTest; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ItemType; import net.sf.saxon.value.SequenceExtent; import net.sf.saxon.value.Value; import nu.xom.Document; import nu.xom.Node; import javax.xml.transform.Result; import javax.xml.transform.Source; import java.io.Serializable; import java.lang.reflect.Array; import java.util.ArrayList; import java.util.HashSet; import java.util.List; /** * This interface must be implemented by any third-party object model that can * be wrapped with a wrapper that implements the Saxon Object Model (the NodeInfo interface). * This implementation of the interface supports wrapping of JDOM Documents. */ public class XOMObjectModel implements ExternalObjectModel, Serializable { public XOMObjectModel() {} /** * Get the URI of the external object model as used in the JAXP factory interfaces for obtaining * an XPath implementation */ public String getIdentifyingURI() { return NamespaceConstant.OBJECT_MODEL_XOM; } public PJConverter getPJConverter(Class targetClass) { if (isRecognizedNodeClass(targetClass)) { return new PJConverter() { public Object convert(ValueRepresentation value, Class targetClass, XPathContext context) throws XPathException { return convertXPathValueToObject(Value.asValue(value), targetClass, context); } }; } else { return null; } } public JPConverter getJPConverter(Class targetClass) { if (isRecognizedNodeClass(targetClass)) { return new JPConverter() { public ValueRepresentation convert(Object object, XPathContext context) throws XPathException { return convertObjectToXPathValue(object, context.getConfiguration()); } public ItemType getItemType() { return AnyNodeTest.getInstance(); } }; } else { return null; } } /** * Get a converter that converts a sequence of XPath nodes to this model's representation * of a node list. * @param node an example of the kind of node used in this model * @return if the model does not recognize this node as one of its own, return null. Otherwise * return a PJConverter that takes a list of XPath nodes (represented as NodeInfo objects) and * returns a collection of nodes in this object model */ public PJConverter getNodeListCreator(Object node) { return null; } /** * Test whether this object model recognizes a given node as one of its own */ public boolean isRecognizedNode(Object object) { return (object instanceof nu.xom.Node); } /** * Test whether this object model recognizes a given class as representing a * node in that object model. This method will generally be called at compile time. * * @param nodeClass A class that possibly represents nodes * @return true if the class is used to represent nodes in this object model */ public boolean isRecognizedNodeClass(Class nodeClass) { return nu.xom.Node.class.isAssignableFrom(nodeClass); } /** * Test whether this object model recognizes a given class as representing a * list of nodes in that object model. This method will generally be called at compile time. * * @param nodeClass A class that possibly represents nodes * @return true if the class is used to represent nodes in this object model */ public boolean isRecognizedNodeListClass(Class nodeClass) { return false; } /** * Test whether this object model recognizes a particular kind of JAXP Result object, * and if it does, return a Receiver that builds an instance of this data model from * a sequence of events. If the Result is not recognised, return null. */ public Receiver getDocumentBuilder(Result result) { return null; } /** * Test whether this object model recognizes a particular kind of JAXP Source object, * and if it does, send the contents of the document to a supplied Receiver, and return true. * Otherwise, return false. */ public boolean sendSource(Source source, Receiver receiver, PipelineConfiguration pipe) throws XPathException { return false; } /** * Wrap or unwrap a node using this object model to return the corresponding Saxon node. If the supplied * source does not belong to this object model, return null */ public NodeInfo unravel(Source source, Configuration config) { return null; } /** * Convert a Java object to an XPath value. If the supplied object is recognized as a representation * of a value using this object model, the object model should convert the value to an XPath value * and return this as the result. If not, it should return null. If the object is recognized but cannot * be converted, an exception should be thrown */ public ValueRepresentation convertObjectToXPathValue(Object object, Configuration config) throws XPathException { if (object instanceof Node) { return wrapNode((Node)object, config); } else if (object instanceof Node[]) { NodeInfo[] nodes = new NodeInfo[((Node[])object).length]; for (int i=0; i=0) { relativeURI = href.substring(0, hash); } URI url; URI relative; try { relativeURI = ResolveURI.escapeSpaces(relativeURI); relative = new URI(relativeURI); } catch (URISyntaxException err) { throw new XPathException("Invalid relative URI " + Err.wrap(relativeURI), err); } Platform platform = JavaPlatform.getInstance(); try { url = platform.makeAbsolute(relativeURI, base); } catch (URISyntaxException err) { // System.err.println("Recovering from " + err); // last resort: if the base URI is null, or is itself a relative URI, we // try to expand it relative to the current working directory String expandedBase = ResolveURI.tryToExpand(base); if (!expandedBase.equals(base)) { // prevent infinite recursion return resolve(href, expandedBase); } //err.printStackTrace(); throw new XPathException("Invalid URI " + Err.wrap(relativeURI) + " - base " + Err.wrap(base), err); } try { Builder builder = new Builder(); Document doc = builder.build(url.toString()); if (getConfiguration() == null) { throw new XPathException("XomUriResolver requires access to the Configuration"); } return new DocumentWrapper(doc, url.toString(), getConfiguration()); } catch (IOException io) { throw new XPathException(io); } catch (ParsingException pe) { throw new XPathException(pe); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/xom/package.html0000644000175000017500000000154511033112257020470 0ustar eugeneeugene Package overview for net.sf.saxon.xom

    This package provides glue classes that enable Saxon to process a source document supplied as a XOM tree (see http://www.cafeconleche.org/XOM).

    These classes are not part of the core saxon8.jar product, but are released as a separate saxon8-xom.jar.

    The package provides implementations of the Saxon DocumentInfo and NodeInfo interfaces that act as wrappers to the relevant XOM classes.

    Much of the implemention of this package was done by Wolfgang Hoschek, based on Michael Kay's similar package for JDOM.

    Michael H. Kay
    Saxonica Limited
    9 February 2005

    saxonb-9.1.0.8/bj/net/sf/saxon/expr/0000755000175000017500000000000012216261745016370 5ustar eugeneeugenesaxonb-9.1.0.8/bj/net/sf/saxon/expr/SubsequenceIterator.java0000644000175000017500000001267411033112257023226 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.om.*; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.Value; /** * A SubsequenceIterator selects a subsequence of a sequence */ public class SubsequenceIterator implements SequenceIterator, LastPositionFinder, LookaheadIterator { private SequenceIterator base; private int position = 0; private int min; private int max; private Item nextItem = null; private Item current = null; /** * Private Constructor: use the factory method instead! * @param base An iteration of the items to be filtered * @param min The position of the first item to be included (1-based) * @param max The position of the last item to be included (1-based) */ private SubsequenceIterator(SequenceIterator base, int min, int max) throws XPathException { this.base = base; this.min = min; if (min<1) min=1; this.max = max; if (max1] * @param base An iteration of the items to be filtered * @param min The position of the first item to be included (base 1) * @param max The position of the last item to be included (base 1) * @return an iterator over the requested subsequence */ public static SequenceIterator make(SequenceIterator base, int min, int max) throws XPathException { if (base instanceof ArrayIterator) { return ((ArrayIterator)base).makeSliceIterator(min, max); } else if (max == Integer.MAX_VALUE) { return TailIterator.make(base, min); } else if (base instanceof GroundedIterator && min > 4) { GroundedValue value = ((GroundedIterator)base).materialize(); value = value.subsequence(min-1, max-min+1); return ((Value)value).iterate(); } else { return new SubsequenceIterator(base, min, max); } } /** * Test whether there are any more items available in the sequence */ public boolean hasNext() { return nextItem != null; } /** * Get the next item if there is one */ public Item next() throws XPathException { if (nextItem == null) { current = null; position = -1; return null; } current = nextItem; position++; if (base.position() < max) { nextItem = base.next(); } else { nextItem = null; base.close(); } return current; } public Item current() { return current; } public int position() { return position; } public void close() { base.close(); } /** * Get another iterator to return the same nodes */ public SequenceIterator getAnother() throws XPathException { return new SubsequenceIterator(base.getAnother(), min, max); } /** * Get properties of this iterator, as a bit-significant integer. * * @return the properties of this iterator. This will be some combination of * properties such as {@link #GROUNDED}, {@link #LAST_POSITION_FINDER}, * and {@link #LOOKAHEAD}. It is always * acceptable to return the value zero, indicating that there are no known special properties. * It is acceptable for the properties of the iterator to change depending on its state. */ public int getProperties() { int p = LOOKAHEAD; p |= (base.getProperties() & LAST_POSITION_FINDER); return p; } /** * Get the last position (that is, the number of items in the sequence). This method is * non-destructive: it does not change the state of the iterator. * The result is undefined if the next() method of the iterator has already returned null. * This method must not be called unless the result of getProperties() on the iterator * includes the bit setting {@link #LAST_POSITION_FINDER} */ public int getLastPosition() throws XPathException { int lastBase = ((LastPositionFinder)base).getLastPosition(); int z = Math.min(lastBase, max); return Math.max(z - min + 1, 0); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/expr/PatternMatchExpression.java0000644000175000017500000002233111033112257023673 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.trace.ExpressionPresenter; import net.sf.saxon.om.Item; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.pattern.Pattern; import net.sf.saxon.pattern.PatternSponsor; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.BuiltInAtomicType; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.TypeHierarchy; import net.sf.saxon.value.BooleanValue; import java.util.Iterator; /** * A PatternMatchExpression is a boolean expression that returns true if and only if the context node * matches a given pattern. */ public class PatternMatchExpression extends Expression { private Pattern pattern; /** * Create a pattern match expression * @param pattern the pattern to be matched */ public PatternMatchExpression(Pattern pattern) { this.pattern = pattern; } /** * Get the underlying pattern * @return the pattern */ public Pattern getPattern() { return pattern; } /** * Get the cardinality of this expression * @return the value @link {StaticProperty#EXACTLY_ONE} */ protected int computeCardinality() { return StaticProperty.EXACTLY_ONE; } /** * Perform type checking of an expression and its subexpressions. This is the second phase of * static optimization. *

    *

    This checks statically that the operands of the expression have * the correct type; if necessary it generates code to do run-time type checking or type * conversion. A static type error is reported only if execution cannot possibly succeed, that * is, if a run-time type error is inevitable. The call may return a modified form of the expression.

    *

    *

    This method is called after all references to functions and variables have been resolved * to the declaration of the function or variable. However, the types of such functions and * variables may not be accurately known if they have not been explicitly declared.

    *

    *

    If the implementation returns a value other than "this", then it is required to ensure that * the parent pointer and location information in the returned expression have been set up correctly. * It should not rely on the caller to do this, although for historical reasons many callers do so.

    * * @param visitor an expression visitor * @param contextItemType the static type of "." at the point where this expression is invoked. * The parameter is set to null if it is known statically that the context item will be undefined. * If the type of the context item is not known statically, the argument is set to * {@link net.sf.saxon.type.Type#ITEM_TYPE} * @return the original expression, rewritten to perform necessary run-time type checks, * and to perform other type-related optimizations * @throws XPathException if an error is discovered during this phase * (typically a type error) */ public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { return this; } /** * Perform optimisation of an expression and its subexpressions. This is the third and final * phase of static optimization. *

    *

    This method is called after all references to functions and variables have been resolved * to the declaration of the function or variable, and after all type checking has been done.

    * * @param visitor an expression visitor * @param contextItemType the static type of "." at the point where this expression is invoked. * The parameter is set to null if it is known statically that the context item will be undefined. * If the type of the context item is not known statically, the argument is set to * {@link net.sf.saxon.type.Type#ITEM_TYPE} * @return the original expression, rewritten if appropriate to optimize execution * @throws XPathException if an error is discovered during this phase * (typically a type error) */ public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { return this; } /** * Determine the data type of the expression, if possible. All expression return * sequences, in general; this method determines the type of the items within the * sequence, assuming that (a) this is known in advance, and (b) it is the same for * all items in the sequence. *

    *

    This method should always return a result, though it may be the best approximation * that is available at the time.

    * * @param th the type hierarchy cache * @return a value such as Type.STRING, Type.BOOLEAN, Type.NUMBER, * Type.NODE, or Type.ITEM (meaning not known at compile time) */ public ItemType getItemType(TypeHierarchy th) { return BuiltInAtomicType.BOOLEAN; } /** * Diagnostic print of expression structure. The abstract expression tree * is written to the supplied output destination. */ public void explain(ExpressionPresenter destination) { destination.startElement("patternMatch"); destination.emitAttribute("match", pattern.toString()); destination.endElement(); } /** * Determine the intrinsic dependencies of an expression, that is, those which are not derived * from the dependencies of its subexpressions. For example, position() has an intrinsic dependency * on the context position, while (position()+1) does not. The default implementation * of the method returns 0, indicating "no dependencies". * * @return a set of bit-significant flags identifying the "intrinsic" * dependencies. The flags are documented in class net.sf.saxon.value.StaticProperty */ public int getIntrinsicDependencies() { return StaticProperty.DEPENDS_ON_CONTEXT_ITEM; } /** * Copy an expression. This makes a deep copy. * @return the copy of the original expression */ public Expression copy() { throw new UnsupportedOperationException("copy"); } /** * Get the immediate sub-expressions of this expression. Default implementation * returns a zero-length array, appropriate for an expression that has no * sub-expressions. * * @return an iterator containing the sub-expressions of this expression */ public Iterator iterateSubExpressions() { return new PatternSponsor(pattern).iterateSubExpressions(); } /** * Evaluate an expression as a single item. This always returns either a single Item or * null (denoting the empty sequence). No conversion is done. This method should not be * used unless the static type of the expression is a subtype of "item" or "item?": that is, * it should not be called if the expression may return a sequence. There is no guarantee that * this condition will be detected. * * @param context The context in which the expression is to be evaluated * @return the node or atomic value that results from evaluating the * expression; or null to indicate that the result is an empty * sequence * @throws net.sf.saxon.trans.XPathException * if any dynamic error occurs evaluating the * expression */ public Item evaluateItem(XPathContext context) throws XPathException { return BooleanValue.get(effectiveBooleanValue(context)); } /** * Get the effective boolean value of the expression. This returns false if the value * is the empty sequence, a zero-length string, a number equal to zero, or the boolean * false. Otherwise it returns true. * * @param context The context in which the expression is to be evaluated * @return the effective boolean value * @throws net.sf.saxon.trans.XPathException * if any dynamic error occurs evaluating the * expression */ public boolean effectiveBooleanValue(XPathContext context) throws XPathException { Item contextItem = context.getContextItem(); return (contextItem instanceof NodeInfo) && pattern.matches(((NodeInfo)contextItem), context); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/expr/NumericPromoter.java0000644000175000017500000001531611133615332022363 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.om.Item; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.trace.ExpressionPresenter; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.BuiltInAtomicType; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.TypeHierarchy; import net.sf.saxon.value.*; /** * A NumericPromoter performs numeric promotion on each item in a supplied sequence */ public final class NumericPromoter extends UnaryExpression { private BuiltInAtomicType requiredType; // always xs:float or xs:double /** * Constructor * @param sequence this must be a sequence of atomic values. This is not checked; a ClassCastException * will occur if the precondition is not satisfied. * @param requiredType the item type to which all items in the sequence should be converted, * using the rules for "cast as". */ public NumericPromoter(Expression sequence, BuiltInAtomicType requiredType) { super(sequence); this.requiredType = requiredType; ExpressionTool.copyLocationInfo(sequence, this); } /** * Simplify an expression * @param visitor an expression visitor */ public Expression simplify(ExpressionVisitor visitor) throws XPathException { operand = visitor.simplify(operand); if (operand instanceof Literal) { if (((Literal)operand).getValue() instanceof AtomicValue) { return Literal.makeLiteral( promote(((AtomicValue)((Literal)operand).getValue()), null)); } else { return Literal.makeLiteral( ((Value)SequenceExtent.makeSequenceExtent( iterate(visitor.getStaticContext().makeEarlyEvaluationContext()))).reduce()); } } return this; } /** * Type-check the expression */ public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { operand = visitor.typeCheck(operand, contextItemType); return this; } /** * Optimize the expression */ public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { operand = visitor.optimize(operand, contextItemType); return this; } /** * Iterate over the sequence of values */ public SequenceIterator iterate(final XPathContext context) throws XPathException { SequenceIterator base = operand.iterate(context); ItemMappingFunction promoter = new ItemMappingFunction() { public Item map(Item item) throws XPathException { return promote(((AtomicValue)item), context); } }; return new ItemMappingIterator(base, promoter); } /** * Copy an expression. This makes a deep copy. * * @return the copy of the original expression */ public Expression copy() { return new NumericPromoter(getBaseExpression().copy(), requiredType); } /** * Evaluate as an Item. This should only be called if the expression has cardinality zero-or-one */ public Item evaluateItem(XPathContext context) throws XPathException { Item item = operand.evaluateItem(context); if (item==null) return null; return promote(((AtomicValue)item), context); } /** * Perform the promotion * @param value the numeric or untyped atomic value to be promoted * @param context the XPath dynamic evaluation context * @return the value that results from the promotion */ private AtomicValue promote(AtomicValue value, XPathContext context) throws XPathException { if (!(value instanceof NumericValue || value instanceof UntypedAtomicValue)) { final TypeHierarchy th = context.getConfiguration().getTypeHierarchy(); XPathException err = new XPathException( "Cannot promote non-numeric value to " + getItemType(th).toString(), "XPTY0004", context); err.setLocator(this); throw err; } if (requiredType.equals(BuiltInAtomicType.FLOAT) && value instanceof DoubleValue) { XPathException err = new XPathException( "Cannot promote from xs:double to xs:float", "XPTY0004", context); err.setLocator(this); throw err; } return value.convert(requiredType, true, context).asAtomic(); } /** * Get the required type. Always StandardNames.XS_DOUBLE or StandardNames.XS_FLOAT * @return the fingerprint of the name of the required type */ public int getRequiredType() { return requiredType.getFingerprint(); } /** * Determine the data type of the items returned by the expression, if possible * @return a value such as Type.STRING, Type.BOOLEAN, Type.NUMBER, Type.NODE, * or Type.ITEM (meaning not known in advance) * @param th the type hierarchy cache */ public ItemType getItemType(TypeHierarchy th) { if (requiredType.equals(BuiltInAtomicType.DOUBLE)) { return BuiltInAtomicType.DOUBLE; } else { return BuiltInAtomicType.FLOAT; } } /** * Is this expression the same as another expression? */ public boolean equals(Object other) { return super.equals(other) && requiredType == ((NumericPromoter)other).requiredType; } /** * Diagnostic print of expression structure. The abstract expression tree * is written to the supplied output destination. */ public void explain(ExpressionPresenter out) { out.startElement("promoteNumeric"); out.emitAttribute("to", getItemType(out.getTypeHierarchy()).toString(out.getConfiguration().getNamePool())); operand.explain(out); out.endElement(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/expr/Literal.java0000644000175000017500000003736011033112257020625 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.trace.ExpressionPresenter; import net.sf.saxon.event.SequenceReceiver; import net.sf.saxon.om.Item; import net.sf.saxon.om.Navigator; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.TypeHierarchy; import net.sf.saxon.value.*; /** * A Literal is an expression whose value is constant: it is a class that implements the Expression * interface as a wrapper around a Value. This may derive from an actual literal in an XPath expression * or query, or it may be the result of evaluating a constant subexpression such as true() or xs:date('2007-01-16') */ public class Literal extends Expression { private Value value; /** * Create a literal as a wrapper around a Value * @param value the value of this literal */ public Literal(Value value) { this.value = value; } /** * Create a literal as a wrapper around a Value (factory method) * @param value the value of this literal * @return the Literal */ public static Literal makeLiteral(Value value) { if (value instanceof StringValue) { return new StringLiteral((StringValue)value); } else { return new Literal(value); } } /** * Make an empty-sequence literal * @return a literal whose value is the empty sequence */ public static Literal makeEmptySequence() { return new Literal(EmptySequence.getInstance()); } /** * Get the value represented by this Literal * @return the constant value */ public Value getValue() { return value; } /** * Simplify an expression * @return for a Value, this always returns the value unchanged * @param visitor an expression visitor */ public final Expression simplify(ExpressionVisitor visitor) { try { value = value.reduce(); } catch (XPathException err) { throw new AssertionError(); } return this; } /** * TypeCheck an expression * @return for a Value, this always returns the value unchanged */ public final Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) { return this; } /** * Optimize an expression * @return for a Value, this always returns the value unchanged */ public final Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) { return this; } /** * Determine the data type of the items in the expression, if possible * @return for the default implementation: AnyItemType (not known) * @param th The TypeHierarchy. Can be null if the target is an AtomicValue. */ public ItemType getItemType(TypeHierarchy th) { return value.getItemType(th); } /** * Determine the cardinality */ public int computeCardinality() { if (value instanceof EmptySequence) { return StaticProperty.EMPTY; } else if (value instanceof AtomicValue) { return StaticProperty.EXACTLY_ONE; } try { SequenceIterator iter = value.iterate(); Item next = iter.next(); if (next == null) { return StaticProperty.EMPTY; } else { if (iter.next() != null) { return StaticProperty.ALLOWS_ONE_OR_MORE; } else { return StaticProperty.EXACTLY_ONE; } } } catch (XPathException err) { // can't actually happen return StaticProperty.ALLOWS_ZERO_OR_MORE; } } /** * Compute the static properties of this expression (other than its type). For a * Value, the only special property is {@link StaticProperty#NON_CREATIVE}. * @return the value {@link StaticProperty#NON_CREATIVE} */ public int computeSpecialProperties() { if (getValue() instanceof EmptySequence) { // An empty sequence has all special properties except "has side effects". return StaticProperty.SPECIAL_PROPERTY_MASK &~ StaticProperty.HAS_SIDE_EFFECTS; } return StaticProperty.NON_CREATIVE; } /** * Copy an expression. This makes a deep copy. * * @return the copy of the original expression */ public Expression copy() { return new Literal(value); } /** * Add a representation of this expression to a PathMap. The PathMap captures a map of the nodes visited * by an expression in a source tree. * * @param pathMap the PathMap to which the expression should be added * @param pathMapNodeSet * @return the pathMapNode representing the focus established by this expression, in the case where this * expression is the first operand of a path expression or filter expression */ public PathMap.PathMapNodeSet addToPathMap(PathMap pathMap, PathMap.PathMapNodeSet pathMapNodeSet) { return pathMapNodeSet; } /** * Determine which aspects of the context the expression depends on. The result is * a bitwise-or'ed value composed from constants such as StaticProperty.VARIABLES and * StaticProperty.CURRENT_NODE * @return for a Value, this always returns zero. */ public final int getDependencies() { return 0; } /** * Return an Iterator to iterate over the values of a sequence. The value of every * expression can be regarded as a sequence, so this method is supported for all * expressions. This default implementation handles iteration for expressions that * return singleton values: for non-singleton expressions, the subclass must * provide its own implementation. * * @param context supplies the context for evaluation * @return a SequenceIterator that can be used to iterate over the result * of the expression * @throws net.sf.saxon.trans.XPathException * if any dynamic error occurs evaluating the * expression */ public SequenceIterator iterate(XPathContext context) throws XPathException { return value.iterate(); } /** * Evaluate as a singleton item (or empty sequence). Note: this implementation returns * the first item in the sequence. The method should not be used unless appropriate type-checking * has been done to ensure that the value will be a singleton. */ public Item evaluateItem(XPathContext context) throws XPathException { if (value instanceof AtomicValue) { return (AtomicValue)value; } return value.iterate().next(); } /** * Process the value as an instruction, without returning any tail calls * @param context The dynamic context, giving access to the current node, * the current variables, etc. */ public void process(XPathContext context) throws XPathException { SequenceIterator iter = value.iterate(); SequenceReceiver out = context.getReceiver(); while (true) { Item it = iter.next(); if (it==null) break; out.append(it, 0, NodeInfo.ALL_NAMESPACES); } } /* * Evaluate an expression as a String. This function must only be called in contexts * where it is known that the expression will return a single string (or where an empty sequence * is to be treated as a zero-length string). Implementations should not attempt to convert * the result to a string, other than converting () to "". This method is used mainly to * evaluate expressions produced by compiling an attribute value template. * * @exception net.sf.saxon.trans.XPathException if any dynamic error occurs evaluating the * expression * @exception ClassCastException if the result type of the * expression is not xs:string? * @param context The context in which the expression is to be evaluated * @return the value of the expression, evaluated in the current context. * The expression must return a string or (); if the value of the * expression is (), this method returns "". */ public CharSequence evaluateAsString(XPathContext context) throws XPathException { AtomicValue value = (AtomicValue) evaluateItem(context); if (value == null) return ""; return value.getStringValueCS(); } /** * Get the effective boolean value of the expression. This returns false if the value * is the empty sequence, a zero-length string, a number equal to zero, or the boolean * false. Otherwise it returns true. * * @param context The context in which the expression is to be evaluated * @exception net.sf.saxon.trans.XPathException if any dynamic error occurs evaluating the * expression * @return the effective boolean value */ public boolean effectiveBooleanValue(XPathContext context) throws XPathException { return value.effectiveBooleanValue(); } /** * Evaluate an updating expression, adding the results to a Pending Update List. * The default implementation of this method, which is used for non-updating expressions, * throws an UnsupportedOperationException. The implementation for a literal representing * an empty sequence, however, is a no-op. * * @param context the XPath dynamic evaluation context * @param pul the pending update list to which the results should be written */ public void evaluatePendingUpdates(XPathContext context, PendingUpdateList pul) throws XPathException { if (value instanceof EmptySequence) { // do nothing } else { super.evaluatePendingUpdates(context, pul); } } /** * Determine whether two literals are equal, when considered as expressions. * @param obj the other expression * @return true if the two literals are equal */ public boolean equals(Object obj) { if (!(obj instanceof Literal)) { return false; } Value v = ((Literal)obj).value; return value.getSchemaComparable().equals(v.getSchemaComparable()); } /** * Return a hash code to support the equals() function */ public int hashCode() { return value.getSchemaComparable().hashCode(); } /** * The toString() method for an expression attempts to give a representation of the expression * in an XPath-like form, but there is no guarantee that the syntax will actually be true XPath. * In the case of XSLT instructions, the toString() method gives an abstracted view of the syntax */ public String toString() { return value.toString(); } /** * Diagnostic print of expression structure. The abstract expression tree * is written to the supplied output destination. */ public void explain(ExpressionPresenter out) { out.startElement("literal"); if (value instanceof EmptySequence) { out.emitAttribute("value", "()"); } else if (value instanceof AtomicValue) { //noinspection RedundantCast out.emitAttribute("value", ((AtomicValue)value).getStringValue()); // cast is needed to tell the compiler there's no exception possible out.emitAttribute("type", ((AtomicValue)value).getTypeLabel().getDisplayName()); } else { try { out.emitAttribute("count", value.getLength()+""); if (value.getLength() < 20) { SequenceIterator iter = iterate(null); while (true) { Item it = iter.next(); if (it == null) { break; } if (it instanceof NodeInfo) { out.startElement("node"); out.emitAttribute("path", Navigator.getPath(((NodeInfo)it))); out.emitAttribute("uri", ((NodeInfo)it).getSystemId()); out.endElement(); } else { out.startElement("atomicValue"); out.emitAttribute("value", it.getStringValue()); out.emitAttribute("type", ((AtomicValue)it).getTypeLabel().getDisplayName()); out.endElement(); } } } } catch (XPathException err) { // } } out.endElement(); } /** * Test whether the literal wraps an atomic value. (Note, if this method returns false, * this still leaves the possibility that the literal wraps a sequence that happens to contain * a single atomic value). * @param exp an expression * @return if the expression is a literal and the literal wraps an AtomicValue */ public static boolean isAtomic(Expression exp) { return exp instanceof Literal && ((Literal)exp).getValue() instanceof AtomicValue; } /** * Test whether the literal explicitly wraps an empty sequence. (Note, if this method returns false, * this still leaves the possibility that the literal wraps a sequence that happens to be empty). * @param exp an expression * @return if the expression is a literal and the literal wraps an AtomicValue */ public static boolean isEmptySequence(Expression exp) { return exp instanceof Literal && ((Literal)exp).getValue() instanceof EmptySequence; } /** * Test if a literal represents the boolean value true * @param exp an expression * @param value true or false * @return if the expression is a literal and the literal represents the boolean value given in the * second argument */ public static boolean isConstantBoolean(Expression exp, boolean value) { if (exp instanceof Literal) { Value b = ((Literal)exp).getValue(); return (b instanceof BooleanValue && ((BooleanValue)b).getBooleanValue() == value); } return false; } /** * Test if a literal represents the integer value 1 * @param exp an expression * @return if the expression is a literal and the literal represents the integer value 1 */ public static boolean isConstantOne(Expression exp) { if (exp instanceof Literal) { Value v = ((Literal)exp).getValue(); return (v instanceof Int64Value && ((Int64Value)v).longValue() == 1); } return false; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/expr/MappingIterator.java0000644000175000017500000001137311033112257022332 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.om.Item; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.trans.XPathException; /** * MappingIterator merges a sequence of sequences into a single flat * sequence. It takes as inputs an iteration, and a mapping function to be * applied to each Item returned by that iteration. The mapping function itself * returns another iteration. The result is an iteration of the concatenation of all * the iterations returned by the mapping function.

    * * This is a powerful class. It is used, with different mapping functions, * in a great variety of ways. It underpins the way that "for" expressions and * path expressions are evaluated, as well as sequence expressions. It is also * used in the implementation of the document(), key(), and id() functions. */ public final class MappingIterator implements SequenceIterator { private SequenceIterator base; private MappingFunction action; private SequenceIterator results = null; //private boolean atomizing = false; private Item current = null; private int position = 0; /** * Construct a MappingIterator that will apply a specified MappingFunction to * each Item returned by the base iterator. * @param base the base iterator * @param action the mapping function to be applied */ public MappingIterator(SequenceIterator base, MappingFunction action) { this.base = base; this.action = action; } public Item next() throws XPathException { Item nextItem; while (true) { if (results != null) { nextItem = results.next(); if (nextItem != null) { break; } else { results = null; } } Item nextSource = base.next(); if (nextSource != null) { // Call the supplied mapping function SequenceIterator obj = action.map(nextSource); // The result may be null (representing an empty sequence), // or a SequenceIterator (any sequence) if (obj != null) { results = obj; nextItem = results.next(); if (nextItem == null) { results = null; } else { break; } } // now go round the loop to get the next item from the base sequence } else { results = null; current = null; position = -1; return null; } } current = nextItem; position++; return nextItem; } public Item current() { return current; } public int position() { return position; } public void close() { if (results != null) { results.close(); } base.close(); } public SequenceIterator getAnother() throws XPathException { SequenceIterator newBase = base.getAnother(); MappingFunction newAction = action instanceof StatefulMappingFunction ? ((StatefulMappingFunction)action).getAnother() : action; return new MappingIterator(newBase, newAction); } /** * Get properties of this iterator, as a bit-significant integer. * * @return the properties of this iterator. This will be some combination of * properties such as {@link SequenceIterator#GROUNDED}, {@link SequenceIterator#LAST_POSITION_FINDER}, * and {@link SequenceIterator#LOOKAHEAD}. It is always * acceptable to return the value zero, indicating that there are no known special properties. * It is acceptable for the properties of the iterator to change depending on its state. */ public int getProperties() { return 0; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/expr/BreakInstr.java0000644000175000017500000000504411033112257021267 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.instruct.Instruction; import net.sf.saxon.instruct.TailCall; import net.sf.saxon.instruct.UserFunction; import net.sf.saxon.om.NamespaceConstant; import net.sf.saxon.om.StructuredQName; import net.sf.saxon.om.ValueRepresentation; import net.sf.saxon.trace.ExpressionPresenter; import net.sf.saxon.trans.XPathException; /** * A compiled saxon:break instruction. The effect of executing this instruction is to register with the * dynamic context that a tail call on a pseudo-function break() has been made; the enclosing saxon:iterate * loop detects this tail call request and uses it as a signal to terminate execution of the loop. */ public class BreakInstr extends Instruction { UserFunction breakFunction; static ValueRepresentation[] emptyArgs = new ValueRepresentation[0]; public static StructuredQName SAXON_BREAK = new StructuredQName("saxon", NamespaceConstant.SAXON, "break"); /** * Create the instruction */ public BreakInstr() { breakFunction = new UserFunction(); breakFunction.setFunctionName(SAXON_BREAK); } public Expression simplify(ExpressionVisitor visitor) throws XPathException { return this; } public Expression copy() { return this; } public boolean createsNewNodes() { // this is a fiction, but it prevents the instruction being moved to a global variable, // which would be pointless and possibly harmful return true; } public TailCall processLeavingTail(XPathContext context) throws XPathException { if (context instanceof XPathContextMajor) { ((XPathContextMajor)context).requestTailCall(breakFunction, emptyArgs); } return null; } public void explain(ExpressionPresenter out) { out.startElement("saxonBreak"); out.endElement(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/expr/VariableReference.java0000644000175000017500000005161211033112257022571 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.instruct.Executable; import net.sf.saxon.instruct.GlobalParam; import net.sf.saxon.instruct.UserFunctionParameter; import net.sf.saxon.om.Item; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.om.ValueRepresentation; import net.sf.saxon.pattern.NodeTest; import net.sf.saxon.trace.ExpressionPresenter; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.AnyItemType; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.TypeHierarchy; import net.sf.saxon.value.Cardinality; import net.sf.saxon.value.SequenceType; import net.sf.saxon.value.SingletonNode; import net.sf.saxon.value.Value; /** * Variable reference: a reference to a variable. This may be an XSLT-defined variable, a range * variable defined within the XPath expression, or a variable defined in some other static context. */ public class VariableReference extends Expression implements BindingReference { protected Binding binding = null; // This will be null until fixup() is called; it will also be null // if the variable reference has been inlined protected SequenceType staticType = null; protected Value constantValue = null; transient String displayName = null; private boolean flattened = false; private boolean inLoop = true; private boolean filtered = false; /** * Create a Variable Reference */ public VariableReference() { //System.err.println("Creating varRef"); } /** * Create a Variable Reference * @param binding the variable binding to which this variable refers */ public VariableReference(Binding binding) { //System.err.println("Creating varRef1"); displayName = binding.getVariableQName().getDisplayName(); fixup(binding); } /** * Create a clone copy of this VariableReference * @return the cloned copy */ public Expression copy() { if (binding == null) { throw new UnsupportedOperationException("Cannot copy a variable reference whose binding is unknown"); } VariableReference ref = new VariableReference(); ref.binding = binding; ref.staticType = staticType; ref.constantValue = constantValue; ref.displayName = displayName; ExpressionTool.copyLocationInfo(this, ref); return ref; } /** * Set static type. This is a callback from the variable declaration object. As well * as supplying the static type, it may also supply a compile-time value for the variable. * As well as the type information, other static properties of the value are supplied: * for example, whether the value is an ordered node-set. * @param type the static type of the variable * @param value the value of the variable if this is a compile-time constant * @param properties static properties of the expression to which the variable is bound */ public void setStaticType(SequenceType type, Value value, int properties) { // System.err.println(this + " Set static type = " + type); staticType = type; constantValue = value; // Although the variable may be a context document node-set at the point it is defined, // the context at the point of use may be different, so this property cannot be transferred. int dependencies = getDependencies(); staticProperties = (properties & ~StaticProperty.CONTEXT_DOCUMENT_NODESET) | type.getCardinality() | dependencies; } /** * Mark an expression as being "flattened". This is a collective term that includes extracting the * string value or typed value, or operations such as simple value construction that concatenate text * nodes before atomizing. The implication of all of these is that although the expression might * return nodes, the identity of the nodes has no significance. This is called during type checking * of the parent expression. At present, only variable references take any notice of this notification. */ public void setFlattened(boolean flattened) { super.setFlattened(flattened); this.flattened = flattened; } /** * Test whether this variable reference is flattened - that is, whether it is atomized etc * @return true if the value of the variable is atomized, or converted to a string or number */ public boolean isFlattened() { return flattened; } /** * Mark an expression as filtered: that is, it appears as the base expression in a filter expression. * This notification currently has no effect except when the expression is a variable reference. */ public void setFiltered(boolean filtered) { this.filtered = filtered; } /** * Determine whether this variable reference is filtered * @return true if the value of the variable is filtered by a predicate */ public boolean isFiltered() { return filtered; } /** * Determine whether this variable reference appears in a loop relative to its declaration. * By default, when in doubt, returns true. This is calculated during type-checking. * @return true if this variable reference occurs in a loop, where the variable declaration is * outside the loop */ public boolean isInLoop() { return inLoop; } /** * Type-check the expression. At this stage details of the static type must be known. * If the variable has a compile-time value, this is substituted for the variable reference */ public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { if (constantValue != null) { binding = null; return Literal.makeLiteral(constantValue); } // if (staticType == null) { // throw new IllegalStateException("Variable $" + getDisplayName() + " has not been fixed up"); // } if (binding instanceof Expression) { inLoop = visitor.isLoopingSubexpression((Expression)binding); // following code removed because it causes error181 to blow the stack - need to check for circularities well // if (binding instanceof GlobalVariable) { // ((GlobalVariable)binding).typeCheck(visitor, AnyItemType.getInstance()); // } } else if (binding instanceof UserFunctionParameter) { inLoop = visitor.isLoopingSubexpression(null); } return this; } /** * Type-check the expression. At this stage details of the static type must be known. * If the variable has a compile-time value, this is substituted for the variable reference */ public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { if (constantValue != null) { binding = null; return Literal.makeLiteral(constantValue); } return this; } /** * Fix up this variable reference to a Binding object, which enables the value of the variable * to be located at run-time. */ public void fixup(Binding binding) { this.binding = binding; resetLocalStaticProperties(); } /** * Provide additional information about the type of the variable, typically derived by analyzing * the initializer of the variable binding * @param type the item type of the variable * @param cardinality the cardinality of the variable * @param constantValue the actual value of the variable, if this is known statically, otherwise null * @param properties additional static properties of the variable's initializer * @param visitor an ExpressionVisitor */ public void refineVariableType( ItemType type, int cardinality, Value constantValue, int properties, ExpressionVisitor visitor) { Executable exec = visitor.getExecutable(); if (exec == null) { // happens during use-when evaluation return; } TypeHierarchy th = exec.getConfiguration().getTypeHierarchy(); ItemType oldItemType = getItemType(th); ItemType newItemType = oldItemType; if (th.isSubType(type, oldItemType)) { newItemType = type; } int newcard = cardinality & getCardinality(); if (newcard==0) { // this will probably lead to a type error later newcard = getCardinality(); } SequenceType seqType = SequenceType.makeSequenceType(newItemType, newcard); setStaticType(seqType, constantValue, properties); } /** * Replace this VariableReference where appropriate by a more efficient implementation. This * can only be done after all slot numbers are allocated. The efficiency is gained by binding the * VariableReference directly to a local or global slot, rather than going via the Binding object * @param parent the parent expression of this variable reference */ // public void refineVariableReference(Expression parent) { // if (binding instanceof Assignation || // binding instanceof LocalParam || binding instanceof UserFunctionParameter) { // // A LocalVariableReference can be evaluated directly, without going via the Binding object. // int slot = binding.getLocalSlotNumber(); // if (slot < 0) { // // if slots haven't been allocated yet, we've come here too early. // // See test group036 with -T option for an example. // return; // } // System.err.println("**** REFINING VARIABLE REFERENCE **** "); // LocalVariableReference ref = new LocalVariableReference(); // ref.setSlotNumber(slot); // ref.binding = binding; // ref.staticType = staticType; // ref.displayName = displayName; // ExpressionTool.copyLocationInfo(this, ref); // boolean found = parent.replaceSubExpression(this, ref); // if (!found) { // throw new IllegalStateException("Child expression not found in parent"); // } // } // } /** * Determine the data type of the expression, if possible * * @param th the type hierarchy cache * @return the type of the variable, if this can be determined statically; * otherwise Type.ITEM (meaning not known in advance) */ public ItemType getItemType(TypeHierarchy th) { if (staticType == null || staticType.getPrimaryType() == AnyItemType.getInstance()) { if (binding != null) { return binding.getRequiredType().getPrimaryType(); } return AnyItemType.getInstance(); } else { return staticType.getPrimaryType(); } } /** * Get the static cardinality */ public int computeCardinality() { if (staticType == null) { if (binding == null) { return StaticProperty.ALLOWS_ZERO_OR_MORE; } else if (binding instanceof LetExpression) { return binding.getRequiredType().getCardinality(); } else if (binding instanceof Assignation) { return StaticProperty.EXACTLY_ONE; } else { return binding.getRequiredType().getCardinality(); } } else { return staticType.getCardinality(); } } /** * Determine the special properties of this expression * * @return {@link StaticProperty#NON_CREATIVE} (unless the variable is assignable using saxon:assign) */ public int computeSpecialProperties() { int p = super.computeSpecialProperties(); if (binding == null || !binding.isAssignable()) { // if the variable reference is assignable, we mustn't move it, or any expression that contains it, // out of a loop. The way to achieve this is to treat it as a "creative" expression, because the // optimizer recognizes such expressions and handles them with care... p |= StaticProperty.NON_CREATIVE; } if (binding instanceof Assignation) { Expression exp = ((Assignation)binding).getSequence(); if (exp != null) { p |= (exp.getSpecialProperties() & StaticProperty.NOT_UNTYPED); } } if (staticType != null && !Cardinality.allowsMany(staticType.getCardinality()) && staticType.getPrimaryType() instanceof NodeTest) { p |= StaticProperty.SINGLE_DOCUMENT_NODESET; } return p; } /** * Test if this expression is the same as another expression. * (Note, we only compare expressions that * have the same static and dynamic context). */ public boolean equals(Object other) { return (other instanceof VariableReference && binding == ((VariableReference) other).binding && binding != null); } /** * get HashCode for comparing two expressions */ public int hashCode() { return binding == null ? 73619830 : binding.hashCode(); } public int getIntrinsicDependencies() { int d = 0; if (binding == null) { // assume the worst // TODO: this is being called before the binding is known, e.g. in xqts-extra test filter-011 d |= (StaticProperty.DEPENDS_ON_LOCAL_VARIABLES | StaticProperty.DEPENDS_ON_ASSIGNABLE_GLOBALS | StaticProperty.DEPENDS_ON_RUNTIME_ENVIRONMENT); } else if (binding.isGlobal()) { if (binding.isAssignable()) { d |= StaticProperty.DEPENDS_ON_ASSIGNABLE_GLOBALS; } if (binding instanceof GlobalParam) { d |= StaticProperty.DEPENDS_ON_RUNTIME_ENVIRONMENT; } } else { d |= StaticProperty.DEPENDS_ON_LOCAL_VARIABLES; } return d; } /** * Promote this expression if possible */ public Expression promote(PromotionOffer offer) throws XPathException { if (offer.action == PromotionOffer.INLINE_VARIABLE_REFERENCES) { Expression exp = offer.accept(this); if (exp != null) { // Replace the variable reference with the given expression. offer.accepted = true; return exp; } } return this; } /** * An implementation of Expression must provide at least one of the methods evaluateItem(), iterate(), or process(). * This method indicates which of these methods is provided. This implementation provides both all three methods * natively. */ public int getImplementationMethod() { return (Cardinality.allowsMany(getCardinality()) ? 0 : EVALUATE_METHOD) | ITERATE_METHOD | PROCESS_METHOD; } /** * Add a representation of this expression to a PathMap. The PathMap captures a map of the nodes visited * by an expression in a source tree. *

    *

    The default implementation of this method assumes that an expression does no navigation other than * the navigation done by evaluating its subexpressions, and that the subexpressions are evaluated in the * same context as the containing expression. The method must be overridden for any expression * where these assumptions do not hold. For example, implementations exist for AxisExpression, ParentExpression, * and RootExpression (because they perform navigation), and for the doc(), document(), and collection() * functions because they create a new navigation root. Implementations also exist for PathExpression and * FilterExpression because they have subexpressions that are evaluated in a different context from the * calling expression.

    * * @param pathMap the PathMap to which the expression should be added * @param pathMapNodeSet the PathMapNodeSet to which the paths embodied in this expression should be added * @return the pathMapNodeSet representing the points in the source document that are both reachable by this * expression, and that represent possible results of this expression. For an expression that does * navigation, it represents the end of the arc in the path map that describes the navigation route. For other * expressions, it is the same as the input pathMapNode. */ public PathMap.PathMapNodeSet addToPathMap(PathMap pathMap, PathMap.PathMapNodeSet pathMapNodeSet) { return pathMap.getPathForVariable(getBinding()); } /** * Get the value of this variable in a given context. * * @param c the XPathContext which contains the relevant variable bindings * @return the value of the variable, if it is defined * @throws XPathException if the variable is undefined */ public SequenceIterator iterate(XPathContext c) throws XPathException { try { ValueRepresentation actual = evaluateVariable(c); return Value.getIterator(actual); } catch (XPathException err) { err.maybeSetLocation(this); throw err; } catch (AssertionError err) { String msg = err.getMessage() + " Variable " + getDisplayName() + " at " + getLineNumber() + " of " + getSystemId(); throw new AssertionError(msg); } } public Item evaluateItem(XPathContext c) throws XPathException { try { ValueRepresentation actual = evaluateVariable(c); if (actual instanceof Item) { return (Item) actual; } return Value.asItem(actual); } catch (XPathException err) { err.maybeSetLocation(this); throw err; } } public void process(XPathContext c) throws XPathException { try { ValueRepresentation actual = evaluateVariable(c); if (actual instanceof NodeInfo) { actual = new SingletonNode((NodeInfo) actual); } ((Value) actual).process(c); } catch (XPathException err) { err.maybeSetLocation(this); throw err; } } /** * Evaluate this variable * @param c the XPath dynamic context * @return the value of the variable * @throws XPathException if any error occurs */ public ValueRepresentation evaluateVariable(XPathContext c) throws XPathException { try { return binding.evaluateVariable(c); } catch (NullPointerException err) { if (binding == null) { throw new IllegalStateException("Variable $" + displayName + " has not been fixed up"); } else { throw err; } } } /** * Get the object bound to the variable * @return the Binding which declares this variable and associates it with a value */ public Binding getBinding() { return binding; } /** * Get the display name of the variable. This is taken from the variable binding if possible * @return the display name (a lexical QName */ public String getDisplayName() { if (binding != null) { return binding.getVariableQName().getDisplayName(); } else { return displayName; } } /** * The toString() method for an expression attempts to give a representation of the expression * in an XPath-like form, but there is no guarantee that the syntax will actually be true XPath. * In the case of XSLT instructions, the toString() method gives an abstracted view of the syntax */ public String toString() { String d = getDisplayName(); return "$" + (d == null ? "$" : d); } /** * Diagnostic print of expression structure. The abstract expression tree * is written to the supplied output destination. */ public void explain(ExpressionPresenter destination) { destination.startElement("variableReference"); String d = getDisplayName(); destination.emitAttribute("name", (d == null ? "null" : getDisplayName())); destination.endElement(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/expr/BooleanExpression.java0000644000175000017500000002230211033112257022656 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.functions.BooleanFn; import net.sf.saxon.functions.SystemFunction; import net.sf.saxon.om.Item; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.BuiltInAtomicType; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.TypeHierarchy; import net.sf.saxon.value.BooleanValue; import net.sf.saxon.instruct.Choose; import java.util.Iterator; import java.util.List; /** * Boolean expression: two truth values combined using AND or OR. */ public class BooleanExpression extends BinaryExpression implements Negatable { /** * Construct a boolean expression * @param p1 the first operand * @param operator one of {@link Token#AND} or {@link Token#OR} * @param p2 the second operand */ public BooleanExpression(Expression p1, int operator, Expression p2) { super(p1, operator, p2); } public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { Expression e = super.typeCheck(visitor, contextItemType); if (e == this) { XPathException err0 = TypeChecker.ebvError(operand0, visitor.getConfiguration().getTypeHierarchy()); if (err0 != null) { err0.setLocator(this); throw err0; } XPathException err1 = TypeChecker.ebvError(operand1, visitor.getConfiguration().getTypeHierarchy()); if (err1 != null) { err1.setLocator(this); throw err1; } // Precompute the EBV of any constant operand if (operand0 instanceof Literal && !(((Literal)operand0).getValue() instanceof BooleanValue)) { operand0 = Literal.makeLiteral(BooleanValue.get(operand0.effectiveBooleanValue(null))); } if (operand1 instanceof Literal && !(((Literal)operand1).getValue() instanceof BooleanValue)) { operand1 = Literal.makeLiteral(BooleanValue.get(operand1.effectiveBooleanValue(null))); } } return e; } /** * Determine the static cardinality. Returns [1..1] */ public int computeCardinality() { return StaticProperty.EXACTLY_ONE; } /** * Perform optimisation of an expression and its subexpressions. *

    *

    This method is called after all references to functions and variables have been resolved * to the declaration of the function or variable, and after all type checking has been done.

    * * @param visitor an expression visitor * @param contextItemType the static type of "." at the point where this expression is invoked. * The parameter is set to null if it is known statically that the context item will be undefined. * If the type of the context item is not known statically, the argument is set to * {@link net.sf.saxon.type.Type#ITEM_TYPE} * @return the original expression, rewritten if appropriate to optimize execution * @throws XPathException if an error is discovered during this phase * (typically a type error) */ public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { final Expression e = super.optimize(visitor, contextItemType); final TypeHierarchy th = visitor.getConfiguration().getTypeHierarchy(); if (e != this) { return e; } Optimizer opt = visitor.getConfiguration().getOptimizer(); operand0 = ExpressionTool.unsortedIfHomogeneous(opt, operand0); operand1 = ExpressionTool.unsortedIfHomogeneous(opt, operand1); // If the value can be determined from knowledge of one operand, precompute the result if (operator == Token.AND && ( Literal.isConstantBoolean(operand0, false) || Literal.isConstantBoolean(operand1, false))) { return new Literal(BooleanValue.FALSE); } if (operator == Token.OR && ( Literal.isConstantBoolean(operand0, true) || Literal.isConstantBoolean(operand1, true))) { return new Literal(BooleanValue.TRUE); } // Rewrite (A and B) as (if (A) then B else false()). The benefit of this is that when B is a recursive // function call, it is treated as a tail call (test qxmp290). To avoid disrupting other optimizations // of "and" expressions (specifically, where clauses in FLWOR expressions), do this ONLY if B is a user // function call (we can't tell if it's recursive), and it's not in a loop. if (e == this && operator == Token.AND && operand1 instanceof UserFunctionCall && th.isSubType(operand1.getItemType(th), BuiltInAtomicType.BOOLEAN) && !visitor.isLoopingSubexpression(null)) { Expression cond = Choose.makeConditional(operand0, operand1, Literal.makeLiteral(BooleanValue.FALSE)); ExpressionTool.copyLocationInfo(this, cond); return cond; } return this; } /** * Copy an expression. This makes a deep copy. * * @return the copy of the original expression */ public Expression copy() { return new BooleanExpression(operand0.copy(), operator, operand1.copy()); } /** * Check whether this specific instance of the expression is negatable * * @return true if it is */ public boolean isNegatable(ExpressionVisitor visitor) { return true; } /** * Return the negation of this boolean expression, that is, an expression that returns true * when this expression returns false, and vice versa * * @return the negation of this expression */ public Expression negate() { // Apply de Morgan's laws if (operator == Token.AND) { // not(A and B) ==> not(A) or not(B) BooleanFn not0 = (BooleanFn)SystemFunction.makeSystemFunction("not", new Expression[]{operand0}); BooleanFn not1 = (BooleanFn)SystemFunction.makeSystemFunction("not", new Expression[]{operand1}); return new BooleanExpression(not0, Token.OR, not1); } else { // not(A or B) => not(A) and not(B) BooleanFn not0 = (BooleanFn)SystemFunction.makeSystemFunction("not", new Expression[]{operand0}); BooleanFn not1 = (BooleanFn)SystemFunction.makeSystemFunction("not", new Expression[]{operand1}); return new BooleanExpression(not0, Token.AND, not1); } } /** * Evaluate the expression */ public Item evaluateItem(XPathContext context) throws XPathException { return BooleanValue.get(effectiveBooleanValue(context)); } /** * Evaluate as a boolean. */ public boolean effectiveBooleanValue(XPathContext c) throws XPathException { switch(operator) { case Token.AND: return operand0.effectiveBooleanValue(c) && operand1.effectiveBooleanValue(c); case Token.OR: return operand0.effectiveBooleanValue(c) || operand1.effectiveBooleanValue(c); default: throw new UnsupportedOperationException("Unknown operator in boolean expression"); } } /** * Determine the data type of the expression * @return BuiltInAtomicType.BOOLEAN * @param th the type hierarchy cache */ public ItemType getItemType(TypeHierarchy th) { return BuiltInAtomicType.BOOLEAN; } /** * Construct a list containing the "anded" subexpressions of an expression: * if the expression is (A and B and C), this returns (A, B, C). * @param exp the expression to be decomposed * @param list the list to which the subexpressions are to be added. */ public static void listAndComponents(Expression exp, List list) { if (exp instanceof BooleanExpression && ((BooleanExpression)exp).getOperator() == Token.AND) { for (Iterator iter = exp.iterateSubExpressions(); iter.hasNext();) { listAndComponents((Expression)iter.next(), list); } } else { list.add(exp); } // TODO: could do more complete analysis to convert the expression to conjunctive normal form. // This is done by applying various transformations: // not(not(X)) => X // not(P and Q) => not(P) or not(Q) // not(P or Q) => not(P) and not(Q) // A or (B and C) => (A or B) and (A or C) } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/expr/InstanceOfExpression.java0000644000175000017500000002026211033112257023333 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.om.Item; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.trace.ExpressionPresenter; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.BuiltInAtomicType; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.TypeHierarchy; import net.sf.saxon.value.AtomicValue; import net.sf.saxon.value.BooleanValue; import net.sf.saxon.value.Cardinality; import net.sf.saxon.value.SequenceType; /** * InstanceOf Expression: implements "Expr instance of data-type" */ public final class InstanceOfExpression extends UnaryExpression { ItemType targetType; int targetCardinality; /** * Construct an "instance of" expression in the form "source instance of target" * @param source the expression whose type is to be tested * @param target the type against which it is tested */ public InstanceOfExpression(Expression source, SequenceType target) { super(source); targetType = target.getPrimaryType(); if (targetType == null) { throw new IllegalArgumentException("Primary item type must not be null"); } targetCardinality = target.getCardinality(); } /** * Get the item type that we are testing for membership of * @return the item type */ public ItemType getRequiredItemType() { return targetType; } /** * Get the cardinality that we are testing for membership of * @return the required cardinality */ public int getRequiredCardinality() { return targetCardinality; } /** * Type-check the expression * @return the checked expression */ public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { operand = visitor.typeCheck(operand, contextItemType); if (operand instanceof Literal) { return Literal.makeLiteral( (AtomicValue)evaluateItem(visitor.getStaticContext().makeEarlyEvaluationContext())); } // See if we can get the answer by static analysis. if (Cardinality.subsumes(targetCardinality, operand.getCardinality())) { final TypeHierarchy th = visitor.getConfiguration().getTypeHierarchy(); int relation = th.relationship(operand.getItemType(th), targetType); if (relation == TypeHierarchy.SAME_TYPE || relation == TypeHierarchy.SUBSUMED_BY) { return Literal.makeLiteral(BooleanValue.TRUE); } else if (relation == TypeHierarchy.DISJOINT) { // if the item types are disjoint, the result might still be true if both sequences are empty if (!Cardinality.allowsZero(targetCardinality) || !Cardinality.allowsZero(operand.getCardinality())) { return Literal.makeLiteral(BooleanValue.FALSE); } } } return this; } /** * Perform optimisation of an expression and its subexpressions. *

    *

    This method is called after all references to functions and variables have been resolved * to the declaration of the function or variable, and after all type checking has been done.

    * * @param visitor an expression visitor * @param contextItemType the static type of "." at the point where this expression is invoked. * The parameter is set to null if it is known statically that the context item will be undefined. * If the type of the context item is not known statically, the argument is set to * {@link net.sf.saxon.type.Type#ITEM_TYPE} * @return the original expression, rewritten if appropriate to optimize execution * @throws XPathException if an error is discovered during this phase * (typically a type error) */ public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { Expression e = super.optimize(visitor, contextItemType); if (e != this) { return e; } if (Cardinality.subsumes(targetCardinality, operand.getCardinality())) { final TypeHierarchy th = visitor.getConfiguration().getTypeHierarchy(); int relation = th.relationship(operand.getItemType(th), targetType); if (relation == TypeHierarchy.SAME_TYPE || relation == TypeHierarchy.SUBSUMED_BY) { return Literal.makeLiteral(BooleanValue.TRUE); } else if (relation == TypeHierarchy.DISJOINT) { // if the item types are disjoint, the result might still be true if both sequences are empty if (!Cardinality.allowsZero(targetCardinality) || !Cardinality.allowsZero(operand.getCardinality())) { return Literal.makeLiteral(BooleanValue.FALSE); } } } return this; } /** * Is this expression the same as another expression? */ public boolean equals(Object other) { return super.equals(other) && targetType == ((InstanceOfExpression)other).targetType && targetCardinality == ((InstanceOfExpression)other).targetCardinality; } /** * Determine the cardinality */ public int computeCardinality() { return StaticProperty.EXACTLY_ONE; } /** * Copy an expression. This makes a deep copy. * * @return the copy of the original expression */ public Expression copy() { return new InstanceOfExpression(getBaseExpression().copy(), SequenceType.makeSequenceType(targetType, targetCardinality)); } /** * Determine the data type of the result of the InstanceOf expression * @param th the type hierarchy cache */ public ItemType getItemType(TypeHierarchy th) { return BuiltInAtomicType.BOOLEAN; } /** * Evaluate the expression */ public Item evaluateItem(XPathContext context) throws XPathException { return BooleanValue.get(effectiveBooleanValue(context)); } /** * Evaluate the expression as a boolean */ public boolean effectiveBooleanValue(XPathContext context) throws XPathException { SequenceIterator iter = operand.iterate(context); int count = 0; while (true) { Item item = iter.next(); if (item == null) break; count++; if (!targetType.matchesItem(item, false, context.getConfiguration())) { return false; } if (count==2 && !Cardinality.allowsMany(targetCardinality)) { return false; } } return !(count == 0 && ((targetCardinality & StaticProperty.ALLOWS_ZERO) == 0)); } /** * Diagnostic print of expression structure. The abstract expression tree * is written to the supplied output destination. */ public void explain(ExpressionPresenter destination) { destination.startElement("instance"); destination.emitAttribute("of", targetType.toString(destination.getNamePool())); destination.emitAttribute("occurs", Cardinality.getOccurrenceIndicator(targetCardinality)); operand.explain(destination); destination.endElement(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/expr/VennExpression.java0000644000175000017500000004645311033112257022222 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.functions.SystemFunction; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.om.Axis; import net.sf.saxon.pattern.CombinedNodeTest; import net.sf.saxon.sort.DocumentOrderIterator; import net.sf.saxon.sort.GlobalOrderComparer; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.Type; import net.sf.saxon.type.TypeHierarchy; import net.sf.saxon.value.SequenceType; import net.sf.saxon.instruct.Block; import java.util.Set; import java.util.HashSet; /** * An expression representing a nodeset that is a union, difference, or * intersection of two other NodeSets */ public class VennExpression extends BinaryExpression { /** * Constructor * @param p1 the left-hand operand * @param op the operator (union, intersection, or difference) * @param p2 the right-hand operand */ public VennExpression(final Expression p1, final int op, final Expression p2) { super(p1, op, p2); } /** * Determine the data type of the items returned by this expression * @return the data type * @param th the type hierarchy cache */ public final ItemType getItemType(TypeHierarchy th) { final ItemType t1 = operand0.getItemType(th); final ItemType t2 = operand1.getItemType(th); return Type.getCommonSuperType(t1, t2, th); } /** * Determine the static cardinality of the expression */ public final int computeCardinality() { final int c1 = operand0.getCardinality(); final int c2 = operand1.getCardinality(); switch (operator) { case Token.UNION: if (Literal.isEmptySequence(operand0)) return c2; if (Literal.isEmptySequence(operand1)) return c1; return c1 | c2 | StaticProperty.ALLOWS_ONE | StaticProperty.ALLOWS_MANY; // allows ZERO only if one operand allows ZERO case Token.INTERSECT: if (Literal.isEmptySequence(operand0)) return StaticProperty.EMPTY; if (Literal.isEmptySequence(operand1)) return StaticProperty.EMPTY; return (c1 & c2) | StaticProperty.ALLOWS_ZERO | StaticProperty.ALLOWS_ONE; // allows MANY only if both operands allow MANY case Token.EXCEPT: if (Literal.isEmptySequence(operand0)) return StaticProperty.EMPTY; if (Literal.isEmptySequence(operand1)) return c1; return c1 | StaticProperty.ALLOWS_ZERO | StaticProperty.ALLOWS_ONE; // allows MANY only if first operand allows MANY } return StaticProperty.ALLOWS_ZERO_OR_MORE; } /** * Get the static properties of this expression (other than its type). The result is * bit-signficant. These properties are used for optimizations. In general, if * property bit is set, it is true, but if it is unset, the value is unknown. */ public int computeSpecialProperties() { final int prop0 = operand0.getSpecialProperties(); final int prop1 = operand1.getSpecialProperties(); int props = StaticProperty.ORDERED_NODESET; if (testContextDocumentNodeSet(prop0, prop1)) { props |= StaticProperty.CONTEXT_DOCUMENT_NODESET; } if (testSubTree(prop0, prop1)) { props |= StaticProperty.SUBTREE_NODESET; } if (!testCreative(prop0, prop1)) { props |= StaticProperty.NON_CREATIVE; } return props; } /** * Determine whether all the nodes in the node-set are guaranteed to * come from the same document as the context node. Used for optimization. * @param prop0 contains the Context Document Nodeset property of the first operand * @param prop1 contains the Context Document Nodeset property of the second operand * @return true if all the nodes come from the context document */ private boolean testContextDocumentNodeSet(final int prop0, final int prop1) { switch (operator) { case Token.UNION: return (prop0 & prop1 & StaticProperty.CONTEXT_DOCUMENT_NODESET) != 0; case Token.INTERSECT: return ((prop0 | prop1) & StaticProperty.CONTEXT_DOCUMENT_NODESET) != 0; case Token.EXCEPT: return (prop0 & StaticProperty.CONTEXT_DOCUMENT_NODESET) != 0; } return false; } /** * Gather the component operands of a union or intersect expression * @param operator union or intersect * @param set the set into which the components are to be gathered. If the operator * is union, this follows the tree gathering all operands of union expressions. Ditto, * mutatis mutandis, for intersect expressions. */ public void gatherComponents(int operator, Set set) { if (operand0 instanceof VennExpression && ((VennExpression)operand0).operator == operator) { ((VennExpression)operand0).gatherComponents(operator, set); } else { set.add(operand0); } if (operand1 instanceof VennExpression && ((VennExpression)operand1).operator == operator) { ((VennExpression)operand1).gatherComponents(operator, set); } else { set.add(operand1); } } /** * Determine whether all the nodes in the node-set are guaranteed to * come from a subtree rooted at the context node. Used for optimization. * @param prop0 contains the SubTree property of the first operand * @param prop1 contains the SubTree property of the second operand * @return true if all the nodes come from the tree rooted at the context node */ private boolean testSubTree(final int prop0, final int prop1) { switch (operator) { case Token.UNION: return (prop0 & prop1 & StaticProperty.SUBTREE_NODESET) != 0; case Token.INTERSECT: return ((prop0 | prop1) & StaticProperty.SUBTREE_NODESET) != 0; case Token.EXCEPT: return (prop0 & StaticProperty.SUBTREE_NODESET) != 0; } return false; } /** * Determine whether the expression can create new nodes * @param prop0 contains the noncreative property of the first operand * @param prop1 contains the noncreative property of the second operand * @return true if the expression can create new nodes */ private boolean testCreative(final int prop0, final int prop1) { return !(((prop0 & StaticProperty.NON_CREATIVE) != 0) && ((prop1 & StaticProperty.NON_CREATIVE) != 0)); } /** * Simplify the expression * @param visitor an expression visitor */ public Expression simplify(ExpressionVisitor visitor) throws XPathException { operand0 = visitor.simplify(operand0); operand1 = visitor.simplify(operand1); // If either operand is an empty sequence, simplify the expression. This can happen // after reduction with constructs of the form //a[condition] | //b[not(condition)], // common in XPath 1.0 because there were no conditional expressions. switch (operator) { case Token.UNION: if (Literal.isEmptySequence(operand0) && (operand1.getSpecialProperties() & StaticProperty.ORDERED_NODESET) != 0) return operand1; if (Literal.isEmptySequence(operand1) && (operand0.getSpecialProperties() & StaticProperty.ORDERED_NODESET) != 0) return operand0; break; case Token.INTERSECT: if (Literal.isEmptySequence(operand0)) return operand0; if (Literal.isEmptySequence(operand1)) return operand1; break; case Token.EXCEPT: if (Literal.isEmptySequence(operand0)) return operand0; if (Literal.isEmptySequence(operand1) && (operand0.getSpecialProperties() & StaticProperty.ORDERED_NODESET) != 0) return operand0; break; } // If both are axis expressions on the same axis, merge them // ie. rewrite (axis::test1 | axis::test2) as axis::(test1 | test2) if (operand0 instanceof AxisExpression && operand1 instanceof AxisExpression) { final AxisExpression a1 = (AxisExpression)operand0; final AxisExpression a2 = (AxisExpression)operand1; if (a1.getAxis() == a2.getAxis()) { AxisExpression ax = new AxisExpression(a1.getAxis(), new CombinedNodeTest(a1.getNodeTest(), operator, a2.getNodeTest())); ExpressionTool.copyLocationInfo(this, ax); return ax; } } // If both are path expressions starting the same way, merge them // i.e. rewrite (/X | /Y) as /(X|Y). This applies recursively, so that // /A/B/C | /A/B/D becomes /A/B/child::(C|D) // This optimization was previously done for all three operators. However, it's not safe for "except": // A//B except A//C//B cannot be rewritten as A/descendant-or-self::node()/(B except C//B). As a quick // fix, the optimization has been retained for "union" but dropped for "intersect" and "except". Need to // do a more rigorous analysis of the conditions under which it is safe. // TODO: generalize this code to handle all distributive operators if (operand0 instanceof PathExpression && operand1 instanceof PathExpression && operator==Token.UNION) { final PathExpression path1 = (PathExpression)operand0; final PathExpression path2 = (PathExpression)operand1; if (path1.getFirstStep().equals(path2.getFirstStep())) { final VennExpression venn = new VennExpression( path1.getRemainingSteps(), operator, path2.getRemainingSteps()); ExpressionTool.copyLocationInfo(this, venn); final PathExpression path = new PathExpression(path1.getFirstStep(), venn); ExpressionTool.copyLocationInfo(this, path); return visitor.simplify(path); } } // Try merging two non-positional filter expressions: // A[exp0] | A[exp1] becomes A[exp0 or exp1] if (operand0 instanceof FilterExpression && operand1 instanceof FilterExpression) { final FilterExpression exp0 = (FilterExpression)operand0; final FilterExpression exp1 = (FilterExpression)operand1; final TypeHierarchy th = visitor.getConfiguration().getTypeHierarchy(); if (!exp0.isPositional(th) && !exp1.isPositional(th) && exp0.getBaseExpression().equals(exp1.getBaseExpression())) { final Expression filter; switch (operator) { case Token.UNION: filter = new BooleanExpression(exp0.getFilter(), Token.OR, exp1.getFilter()); break; case Token.INTERSECT: filter = new BooleanExpression(exp0.getFilter(), Token.AND, exp1.getFilter()); break; case Token.EXCEPT: final FunctionCall negate2 = SystemFunction.makeSystemFunction( "not", new Expression[]{exp1.getFilter()}); filter = new BooleanExpression(exp0.getFilter(), Token.AND, negate2); break; default: throw new AssertionError("Unknown operator " + operator); } ExpressionTool.copyLocationInfo(this, filter); FilterExpression f = new FilterExpression(exp0.getBaseExpression(), filter); ExpressionTool.copyLocationInfo(this, f); return visitor.simplify(f); } } return this; } /** * Type-check the expression */ public Expression typeCheck(ExpressionVisitor visitor, final ItemType contextItemType) throws XPathException { operand0 = visitor.typeCheck(operand0, contextItemType); operand1 = visitor.typeCheck(operand1, contextItemType); final RoleLocator role0 = new RoleLocator(RoleLocator.BINARY_EXPR, Token.tokens[operator], 0); //role0.setSourceLocator(this); operand0 = TypeChecker.staticTypeCheck(operand0, SequenceType.NODE_SEQUENCE, false, role0, visitor); final RoleLocator role1 = new RoleLocator(RoleLocator.BINARY_EXPR, Token.tokens[operator], 1); //role1.setSourceLocator(this); operand1 = TypeChecker.staticTypeCheck(operand1, SequenceType.NODE_SEQUENCE, false, role1, visitor); return this; } /** * Perform optimisation of an expression and its subexpressions. *

    *

    This method is called after all references to functions and variables have been resolved * to the declaration of the function or variable, and after all type checking has been done.

    * * @param visitor an expression visitor * @param contextItemType the static type of "." at the point where this expression is invoked. * The parameter is set to null if it is known statically that the context item will be undefined. * If the type of the context item is not known statically, the argument is set to * {@link net.sf.saxon.type.Type#ITEM_TYPE} * @return the original expression, rewritten if appropriate to optimize execution * @throws net.sf.saxon.trans.XPathException * if an error is discovered during this phase * (typically a type error) */ public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { Expression e = super.optimize(visitor, contextItemType); if (e != this) { return e; } // Convert @*|node() into @*,node() to eliminate the sorted merge operation if (operator == Token.UNION && operand0 instanceof AxisExpression && operand1 instanceof AxisExpression) { AxisExpression a0 = (AxisExpression)operand0; AxisExpression a1 = (AxisExpression)operand1; if (a0.getAxis() == Axis.ATTRIBUTE && a1.getAxis() == Axis.CHILD) { Block b = new Block(); b.setChildren(new Expression[]{operand0, operand1}); return b; } else if (a1.getAxis() == Axis.ATTRIBUTE && a0.getAxis() == Axis.CHILD) { Block b = new Block(); b.setChildren(new Expression[]{operand1, operand0}); return b; } } return this; } /** * Copy an expression. This makes a deep copy. * * @return the copy of the original expression */ public Expression copy() { return new VennExpression(operand0.copy(), operator, operand1.copy()); } /** * Is this expression the same as another expression? */ public boolean equals(Object other) { // NOTE: it's possible that the method in the superclass is already adequate for this if (other instanceof VennExpression) { VennExpression b = (VennExpression)other; if (operator != b.operator) { return false; } if (operand0.equals(b.operand0) && operand1.equals(b.operand1)) { return true; } if (operator == Token.UNION || operator == Token.INTERSECT) { // These are commutative and associative, so for example (A|B)|C equals B|(A|C) Set s0 = new HashSet(10); gatherComponents(operator, s0); Set s1 = new HashSet(10); ((VennExpression)other).gatherComponents(operator, s1); return s0.equals(s1); } } return false; } public int hashCode() { return operand0.hashCode() ^ operand1.hashCode(); } /** * Iterate over the value of the expression. The result will always be sorted in document order, * with duplicates eliminated * @param c The context for evaluation * @return a SequenceIterator representing the union of the two operands */ public SequenceIterator iterate(final XPathContext c) throws XPathException { SequenceIterator i1 = operand0.iterate(c); //return Type.isNodeType(getItemType()) && isSingleton(); // this is a sufficient condition, but other expressions override this method if ((operand0.getSpecialProperties() & StaticProperty.ORDERED_NODESET) == 0) { i1 = new DocumentOrderIterator(i1, GlobalOrderComparer.getInstance()); } SequenceIterator i2 = operand1.iterate(c); //return Type.isNodeType(getItemType()) && isSingleton(); // this is a sufficient condition, but other expressions override this method if ((operand1.getSpecialProperties() & StaticProperty.ORDERED_NODESET) == 0) { i2 = new DocumentOrderIterator(i2, GlobalOrderComparer.getInstance()); } switch (operator) { case Token.UNION: return new UnionEnumeration(i1, i2, GlobalOrderComparer.getInstance()); case Token.INTERSECT: return new IntersectionEnumeration(i1, i2, GlobalOrderComparer.getInstance()); case Token.EXCEPT: return new DifferenceEnumeration(i1, i2, GlobalOrderComparer.getInstance()); } throw new UnsupportedOperationException("Unknown operator in Set Expression"); } /** * Get the effective boolean value. In the case of a union expression, this * is reduced to an OR expression, for efficiency */ public boolean effectiveBooleanValue(final XPathContext context) throws XPathException { if (operator == Token.UNION) { return operand0.effectiveBooleanValue(context) || operand1.effectiveBooleanValue(context); } else { return super.effectiveBooleanValue(context); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/expr/SingletonAtomizer.java0000644000175000017500000002400411111054261022672 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.Configuration; import net.sf.saxon.om.Item; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.pattern.EmptySequenceTest; import net.sf.saxon.pattern.NodeTest; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.BuiltInAtomicType; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.Type; import net.sf.saxon.type.TypeHierarchy; import net.sf.saxon.value.AtomicValue; import net.sf.saxon.value.Value; /** * A SingletonAtomizer combines the functions of an Atomizer and a CardinalityChecker: it is used to * atomize a sequence of nodes, checking that the result of the atomization contains zero or one atomic * values. Note that the input may be a sequence of nodes or atomic values, even though the result must * contain at most one atomic value. */ public final class SingletonAtomizer extends UnaryExpression { private boolean allowEmpty; private RoleLocator role; /** * Constructor * @param sequence the sequence to be atomized * @param role contains information about where the expression appears, for use in any error message * @param allowEmpty true if the result sequence is allowed to be empty. */ public SingletonAtomizer(Expression sequence, RoleLocator role, boolean allowEmpty) { super(sequence); this.allowEmpty = allowEmpty; this.role = role; } /** * Simplify an expression * @param visitor an expression visitor */ public Expression simplify(ExpressionVisitor visitor) throws XPathException { operand = visitor.simplify(operand); if (operand instanceof Literal && ((Literal)(operand)).getValue() instanceof AtomicValue) { return operand; } return this; } /** * Type-check the expression */ public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { operand = visitor.typeCheck(operand, contextItemType); visitor.resetStaticProperties(); if (Literal.isEmptySequence(operand)) { if (!allowEmpty) { typeError("An empty sequence is not allowed as the " + role.getMessage(), role.getErrorCode(), null); } return operand; } final TypeHierarchy th = visitor.getConfiguration().getTypeHierarchy(); if (operand.getItemType(th).isAtomicType()) { return operand; } return this; } public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { Expression exp = super.optimize(visitor, contextItemType); if (exp == this) { final TypeHierarchy th = visitor.getConfiguration().getTypeHierarchy(); if (operand.getItemType(th).isAtomicType()) { return operand; } return this; } else { return exp; } } /** * Determine the special properties of this expression * @return {@link StaticProperty#NON_CREATIVE}. */ public int computeSpecialProperties() { int p = super.computeSpecialProperties(); return p | StaticProperty.NON_CREATIVE; } /** * Copy an expression. This makes a deep copy. * * @return the copy of the original expression */ public Expression copy() { return new SingletonAtomizer(getBaseExpression().copy(), role, allowEmpty); } /** * Get the RoleLocator (used to construct error messages) * @return the role locator */ public RoleLocator getRole() { return role; } public PathMap.PathMapNodeSet addToPathMap(PathMap pathMap, PathMap.PathMapNodeSet pathMapNodeSet) { PathMap.PathMapNodeSet result = operand.addToPathMap(pathMap, pathMapNodeSet); if (result != null) { result.setAtomized(); } return null; } /** * Evaluate as an Item. This should only be called if a singleton or empty sequence is required; * it throws a type error if the underlying sequence is multi-valued. */ public Item evaluateItem(XPathContext context) throws XPathException { int found = 0; Item result = null; SequenceIterator iter = operand.iterate(context); while (true) { Item item = iter.next(); if (item == null) { break; } if (item instanceof AtomicValue) { if (found++ > 0) { typeError( "A sequence of more than one item is not allowed as the " + role.getMessage(), role.getErrorCode(), context); } result = item; } else { Value value = ((NodeInfo)item).atomize(); found += value.getLength(); if (found > 1) { typeError( "A sequence of more than one item is not allowed as the " + role.getMessage(), role.getErrorCode(), context); } result = value.itemAt(0); } } if (found == 0 && !allowEmpty) { typeError("An empty sequence is not allowed as the " + role.getMessage(), role.getErrorCode(), null); } return result; } /** * Determine the data type of the items returned by the expression, if possible * @return a value such as Type.STRING, Type.BOOLEAN, Type.NUMBER. For this class, the * result is always an atomic type, but it might be more specific. * @param th the type hierarchy cache */ public ItemType getItemType(TypeHierarchy th) { boolean isSchemaAware = true; //Executable exec = getExecutable(); if (!th.getConfiguration().isSchemaAware(Configuration.XML_SCHEMA)) { isSchemaAware = false; } ItemType in = operand.getItemType(th); if (in.isAtomicType()) { return in; } if (in instanceof NodeTest) { if (in instanceof EmptySequenceTest) { return in; } int kinds = ((NodeTest)in).getNodeKindMask(); if (!isSchemaAware) { // Some node-kinds always have a typed value that's a string if ((kinds | STRING_KINDS) == STRING_KINDS) { return BuiltInAtomicType.STRING; } // Some node-kinds are always untyped atomic; some are untypedAtomic provided that the configuration // is untyped if ((kinds | UNTYPED_IF_UNTYPED_KINDS) == UNTYPED_IF_UNTYPED_KINDS) { return BuiltInAtomicType.UNTYPED_ATOMIC; } } else { if ((kinds | UNTYPED_KINDS) == UNTYPED_KINDS) { return BuiltInAtomicType.UNTYPED_ATOMIC; } } return in.getAtomizedItemType(); // SchemaType schemaType = ((NodeTest)in).getContentType(); // if (schemaType instanceof SimpleType) { // return ((SimpleType)schemaType).getCommonAtomicType(); // } else if (((ComplexType)schemaType).isSimpleContent()) { // return ((ComplexType)schemaType).getSimpleContentType().getCommonAtomicType(); // } else if (schemaType instanceof AnyType) { // // AnyType includes AnySimpleType as a subtype, so the atomized value can be any atomic type // // including untypedAtomic // return BuiltInAtomicType.ANY_ATOMIC; // } else { // // if a complex type with complex content (other than AnyType) can be atomized at all, // // then it will return untypedAtomic values // return BuiltInAtomicType.UNTYPED_ATOMIC; // } } return BuiltInAtomicType.ANY_ATOMIC; } /** * Node kinds whose typed value is always a string */ private static final int STRING_KINDS = (1<" */ public static final int GT = 11; /** * Operator "<" */ public static final int LT = 12; /** * Operator ">=" */ public static final int GE = 13; /** * Operator "<=" */ public static final int LE = 14; /** * Operator "+" */ public static final int PLUS = 15; /** * Binary minus operator */ public static final int MINUS = 16; /** * Multiply operator, "*" when used in an operator context */ public static final int MULT = 17; /** * Operator "div" */ public static final int DIV = 18; /** * Operator "mod" */ public static final int MOD = 19; /** * Operator "is" */ public static final int IS = 20; /** * "$" symbol */ public static final int DOLLAR = 21; /** * Operator not-equals. That is, "!=" */ public static final int NE = 22; /** * Operator "intersect" */ public static final int INTERSECT = 23; /** * Operator "except" */ public static final int EXCEPT = 24; /** * Keyword "return" */ public static final int RETURN = 25; /** * Ketword "then" */ public static final int THEN = 26; /** * Keyword "else" */ public static final int ELSE = 27; /** * Keyword "where" */ public static final int WHERE = 28; /** * Operator "to" */ public static final int TO = 29; /** * Keyword "in" */ public static final int IN = 30; /** * Keyword "some" */ public static final int SOME = 31; /** * Keyword "every" */ public static final int EVERY = 32; /** * Keyword "satisfies" */ public static final int SATISFIES = 33; /** * Token representing the name of a function and the following "(" symbol */ public static final int FUNCTION = 34; /** * Token representing the name of an axis and the following "::" symbol */ public static final int AXIS = 35; /** * Keyword "if" */ public static final int IF = 36; /** * Operator "<<" */ public static final int PRECEDES = 37; /** * Operator ">>" */ public static final int FOLLOWS = 38; /** * "::" symbol */ public static final int COLONCOLON = 39; /** * ":*" symbol */ public static final int COLONSTAR = 40; /** * operator "instance of" */ public static final int INSTANCE_OF = 41; /** * operator "cast as" */ public static final int CAST_AS = 42; /** * operator "treat as" */ public static final int TREAT_AS = 43; /** * operator "eq" */ public static final int FEQ = 44; // "Fortran" style comparison operators eq, ne, etc /** * operator "ne" */ public static final int FNE = 45; /** * operator "gt" */ public static final int FGT = 46; /** * operator "lt" */ public static final int FLT = 47; /** * operator "ge" */ public static final int FGE = 48; /** * opeartor "le" */ public static final int FLE = 49; /** * operator "idiv" */ public static final int IDIV = 50; /** * operator "castable as" */ public static final int CASTABLE_AS = 51; /** * ":=" symbol (XQuery only) */ public static final int ASSIGN = 52; /** * "{" symbol (XQuery only) */ public static final int LCURLY = 53; /** * composite token: (XQuery only) */ public static final int KEYWORD_CURLY = 54; /** * composite token <'element' QNAME> (XQuery only) */ public static final int ELEMENT_QNAME = 55; /** * composite token <'attribute' QNAME> (XQuery only) */ public static final int ATTRIBUTE_QNAME = 56; /** * composite token <'pi' QNAME> (XQuery only) */ public static final int PI_QNAME = 57; /** * Keyword "typeswitch" */ public static final int TYPESWITCH = 58; /** * Keyword "case" */ public static final int CASE = 59; /** * Keyword "modify" */ public static final int MODIFY = 60; /** * Node kind, e.g. "node()" or "comment()" */ public static final int NODEKIND = 61; /** * "*:" token */ public static final int SUFFIX = 62; // e.g. *:suffix - the suffix is actually a separate token /** * "as" (in XQuery Update rename expression) */ public static final int AS = 63; // The following tokens are used only in the query prolog. They are categorized // as operators on the basis that a following name is treated as a name rather than // an operator. /** * "xquery version" */ public static final int XQUERY_VERSION = 70; /** * "declare namespace" */ public static final int DECLARE_NAMESPACE = 71; /** * "declare default" */ public static final int DECLARE_DEFAULT = 72; /** * "declare construction" */ public static final int DECLARE_CONSTRUCTION = 73; /** * "declare base-uri" */ public static final int DECLARE_BASEURI = 74; /** * "declare boundary-space" */ public static final int DECLARE_BOUNDARY_SPACE = 75; /** * "import schema" */ public static final int IMPORT_SCHEMA = 76; /** * "import module" */ public static final int IMPORT_MODULE = 77; /** * "define variable" */ public static final int DECLARE_VARIABLE = 78; /** * "declare function" */ public static final int DECLARE_FUNCTION = 79; /** * "module namespace" */ public static final int MODULE_NAMESPACE = 80; /** * Various compound symbols supporting XQuery validation expression */ public static final int VALIDATE = 81; public static final int VALIDATE_STRICT = 82; public static final int VALIDATE_LAX = 83; /** * "declare xmlspace" */ public static final int DECLARE_ORDERING = 84; /** * "declare copy-namespaces" */ public static final int DECLARE_COPY_NAMESPACES = 85; /** * "declare option" */ public static final int DECLARE_OPTION = 86; /** * "declare revalidation" */ public static final int DECLARE_REVALIDATION = 87; /** * "insert node/nodes" */ public static final int INSERT_NODE = 90; /** * "delete node/nodes" */ public static final int DELETE_NODE = 91; /** * "replace node/nodes" */ public static final int REPLACE_NODE = 92; /** * "replace value" */ public static final int REPLACE_VALUE = 93; /** * "rename node" */ public static final int RENAME_NODE = 94; /** * "as first" */ //public static final int AS_FIRST = 95; /** * "as last" */ //public static final int AS_LAST = 96; /** * "first into" */ public static final int FIRST_INTO = 95; /** * "last into" */ public static final int LAST_INTO = 96; /** * "after" */ public static final int AFTER = 97; /** * "before" */ public static final int BEFORE = 98; /** * "into" */ public static final int INTO = 99; /** * "with" */ public static final int WITH = 100; /** * "declare updating [function]" */ public static final int DECLARE_UPDATING = 101; /** * semicolon separator */ public static final int SEMICOLON = 149; /** * Constant identifying the token number of the last token to be classified as an operator */ static int LAST_OPERATOR = 150; // Tokens that set "operator" context, so an immediately following "div" is recognized // as an operator, not as an element name /** * Name token (a QName, in general) */ public static final int NAME = 201; /** * String literal */ public static final int STRING_LITERAL = 202; /** * Right square bracket */ public static final int RSQB = 203; /** * Right parenthesis */ public static final int RPAR = 204; /** * "." symbol */ public static final int DOT = 205; /** * ".." symbol */ public static final int DOTDOT = 206; /** * "*" symbol when used as a wildcard */ public static final int STAR = 207; /** * "prefix:*" token */ public static final int PREFIX = 208; // e.g. prefix:* /** * Numeric literal */ public static final int NUMBER = 209; /** * "for" keyword */ public static final int FOR = 211; /** * Keyword "default" */ public static final int DEFAULT = 212; /** * Question mark symbol. That is, "?" */ public static final int QMARK = 213; /** * "}" symbol (XQuery only) */ public static final int RCURLY = 215; /** * "let" keyword (XQuery only) */ public static final int LET = 216; /** * "<" at the start of a tag (XQuery only). The pseudo-XML syntax that * follows is read character-by-character by the XQuery parser */ public static final int TAG = 217; /** * A token representing an XQuery pragma. * This construct "(# .... #)" is regarded as a single token, for the QueryParser to sort out. */ public static final int PRAGMA = 218; /** * "copy" keyword */ public static final int COPY = 219; /** * Unary minus sign */ public static final int NEGATE = 299; // unary minus: not actually a token, but we // use token numbers to identify operators. /** * The following strings are used to represent tokens in error messages */ public static String[] tokens = new String[300]; static { tokens [ EOF ] = ""; tokens [ UNION ] = "|"; tokens [ SLASH ] = "/"; tokens [ AT ] = "@"; tokens [ LSQB ] = "["; tokens [ LPAR ] = "("; tokens [ EQUALS ] = "="; tokens [ COMMA ] = ","; tokens [ SLSL ] = "//"; tokens [ OR ] = "or"; tokens [ AND ] = "and"; tokens [ GT ] = ">"; tokens [ LT ] = "<"; tokens [ GE ] = ">="; tokens [ LE ] = "<="; tokens [ PLUS ] = "+"; tokens [ MINUS ] = "-"; tokens [ MULT ] = "*"; tokens [ DIV ] = "div"; tokens [ MOD ] = "mod"; tokens [ IS ] = "is"; tokens [ DOLLAR ] = "$"; tokens [ NE ] = "!="; tokens [ INTERSECT ] = "intersect"; tokens [ EXCEPT ] = "except"; tokens [ RETURN ] = "return"; tokens [ THEN ] = "then"; tokens [ ELSE ] = "else"; //tokens [ ISNOT ] = "isnot"; tokens [ TO ] = "to"; tokens [ IN ] = "in"; tokens [ SOME ] = "some"; tokens [ EVERY ] = "every"; tokens [ SATISFIES ] = "satisfies"; tokens [ FUNCTION ] = "("; tokens [ AXIS ] = ""; tokens [ IF ] = "if("; tokens [ PRECEDES ] = "<<"; tokens [ FOLLOWS ] = ">>"; tokens [ COLONCOLON ] = "::"; tokens [ COLONSTAR ] = ":*"; tokens [ INSTANCE_OF ] = "instance of"; tokens [ CAST_AS ] = "cast as"; tokens [ TREAT_AS ] = "treat as"; tokens [ FEQ ] = "eq"; tokens [ FNE ] = "ne"; tokens [ FGT ] = "gt"; tokens [ FGE ] = "ge"; tokens [ FLT ] = "lt"; tokens [ FLE ] = "le"; tokens [ IDIV ] = "idiv"; tokens [ CASTABLE_AS ] = "castable as"; tokens [ ASSIGN ] = ":="; tokens [ TYPESWITCH ] = "typeswitch"; tokens [ CASE ] = "case"; tokens [ DEFAULT ] = "default"; //tokens [ AS_FIRST ] = "as first"; //tokens [ AS_LAST ] = "as last"; tokens [ AFTER ] = "after"; tokens [ BEFORE ] = "before"; tokens [ INTO ] = "into"; tokens [ WITH ] = "with"; tokens [ MODIFY ] = "modify"; tokens [ AS ] = "as"; tokens [ NAME ] = ""; tokens [ STRING_LITERAL ] = ""; tokens [ RSQB ] = "]"; tokens [ RPAR ] = ")"; tokens [ DOT ] = "."; tokens [ DOTDOT ] = ".."; tokens [ STAR ] = "*"; tokens [ PREFIX ] = ""; tokens [ NUMBER ] = ""; tokens [ NODEKIND ] = "()"; tokens [ FOR ] = "for"; tokens [ SUFFIX ] = "<*:local-name>"; tokens [ QMARK ] = "?"; tokens [ LCURLY ] = "{"; tokens [ KEYWORD_CURLY ] = " {"; tokens [ RCURLY ] = "}"; tokens [ LET ] = "let"; tokens [ VALIDATE ] = "validate {"; tokens [ TAG ] = ""; tokens [ PRAGMA ] = "(# ... #)"; tokens [ SEMICOLON ] = ";"; tokens [ COPY ] = "copy"; tokens [ NEGATE ] = "-"; } /** * Lookup table for composite (two-keyword) tokens */ public static HashMap doubleKeywords = new HashMap(30); /** * Pseudo-token representing the start of the expression */ public static final int UNKNOWN = -1; private Token() { } static { mapDouble("instance of", INSTANCE_OF); mapDouble("cast as", CAST_AS); mapDouble("treat as", TREAT_AS); mapDouble("castable as", CASTABLE_AS); mapDouble("xquery version", XQUERY_VERSION); mapDouble("declare namespace", DECLARE_NAMESPACE); mapDouble("declare default", DECLARE_DEFAULT); mapDouble("declare construction", DECLARE_CONSTRUCTION); mapDouble("declare base-uri", DECLARE_BASEURI); mapDouble("declare boundary-space", DECLARE_BOUNDARY_SPACE); mapDouble("declare ordering", DECLARE_ORDERING); mapDouble("declare copy-namespaces", DECLARE_COPY_NAMESPACES); mapDouble("declare option", DECLARE_OPTION); mapDouble("declare revalidation", DECLARE_REVALIDATION); mapDouble("import schema", IMPORT_SCHEMA); mapDouble("import module", IMPORT_MODULE); mapDouble("declare variable", DECLARE_VARIABLE); mapDouble("declare function", DECLARE_FUNCTION); mapDouble("declare updating", DECLARE_UPDATING); mapDouble("module namespace", MODULE_NAMESPACE); mapDouble("validate strict", VALIDATE_STRICT); mapDouble("validate lax", VALIDATE_LAX); mapDouble("insert node", INSERT_NODE); mapDouble("insert nodes", INSERT_NODE); mapDouble("delete node", DELETE_NODE); mapDouble("delete nodes", DELETE_NODE); mapDouble("replace node", REPLACE_NODE); mapDouble("replace value", REPLACE_VALUE); mapDouble("rename node", RENAME_NODE); mapDouble("rename nodes", RENAME_NODE); mapDouble("first into", FIRST_INTO); mapDouble("last into", LAST_INTO); //mapDouble("as first", AS_FIRST); //mapDouble("as last", AS_LAST); } private static void mapDouble(String doubleKeyword, int token) { doubleKeywords.put(doubleKeyword, new Integer(token)); tokens[token] = doubleKeyword; } /** * Return the inverse of a relational operator, so that "a op b" can be * rewritten as "b inverse(op) a" */ public static int inverse(int operator) { switch(operator) { case LT: return GT; case LE: return GE; case GT: return LT; case GE: return LE; case FLT: return FGT; case FLE: return FGE; case FGT: return FLT; case FGE: return FLE; default: return operator; } } /** * Return the negation of a relational operator, so that "a op b" can be * rewritten as not(b op' a) */ public static int negate(int operator) { switch(operator) { case FEQ: return FNE; case FNE: return FEQ; case FLT: return FGE; case FLE: return FGT; case FGT: return FLE; case FGE: return FLT; default: throw new IllegalArgumentException("Invalid operator for negate()"); } } public static boolean isOrderedOperator(int operator) { return operator != FEQ && operator != FNE; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. //saxonb-9.1.0.8/bj/net/sf/saxon/expr/CollationMap.java0000644000175000017500000000763111033112257021611 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.Configuration; import net.sf.saxon.om.NamespaceConstant; import net.sf.saxon.sort.CodepointCollator; import net.sf.saxon.sort.StringCollator; import java.io.Serializable; import java.util.HashMap; /** * This object maps collation URIs to collations. Logically this function is part of the static * context, but it is often needed dynamically, so it is defined as a separate component that can * safely be retained at run-time. */ public class CollationMap implements Serializable { private Configuration config; private String defaultCollationName; private HashMap map; /** * Create a collation map * @param config the Saxon configuration */ public CollationMap(Configuration config) { this.config = config; this.defaultCollationName = NamespaceConstant.CODEPOINT_COLLATION_URI; } /** * Create a copy of a collation map * @param in the collation map to be copied */ public CollationMap(CollationMap in) { if (in.map != null) { map = new HashMap(in.map); } config = in.config; defaultCollationName = in.defaultCollationName; } /** * Set the name of the default collation * @param name the default collation name (should be a URI, but this is not enforced) */ public void setDefaultCollationName(String name) { defaultCollationName = name; } /** * Get the name of the default collation * @return the default collation name (should be a URI, but this is not enforced) */ public String getDefaultCollationName() { return defaultCollationName; } /** * Get the default collation * @return the default collation, as a StringCollator */ public StringCollator getDefaultCollation() { return getNamedCollation(defaultCollationName); } /** * Register a named collation * @param absoluteURI the name of the collation. This should be an absolute URI, but * this is not enforced * @param collator the StringCollator that implements the collating rules */ public void setNamedCollation(String absoluteURI, StringCollator collator) { if (map == null) { map = new HashMap(); } map.put(absoluteURI, collator); } /** * Get the collation with a given collation name. If the collation name has * not been registered in this CollationMap, the CollationURIResolver registered * with the Configuration is called. If this cannot resolve the collation name, * it should return null. * @param name the collation name (should be an absolute URI) * @return the StringCollator with this name if known, or null if not known */ public StringCollator getNamedCollation(String name) { if (name.equals(NamespaceConstant.CODEPOINT_COLLATION_URI)) { return CodepointCollator.getInstance(); } if (map != null) { StringCollator c = (StringCollator)map.get(name); if (c != null) { return c; } } return config.getCollationURIResolver().resolve(name, null, config); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/expr/CastableExpression.java0000644000175000017500000002141611033112257023022 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.om.Item; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.trace.ExpressionPresenter; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.*; import net.sf.saxon.value.AtomicValue; import net.sf.saxon.value.BooleanValue; import net.sf.saxon.value.Value; /** * Castable Expression: implements "Expr castable as atomic-type?". * The implementation simply wraps a cast expression with a try/catch. */ public final class CastableExpression extends UnaryExpression { AtomicType targetType; boolean allowEmpty; /** * Create a "castable" expression of the form "source castable as target" * @param source The source expression * @param target The type being tested against * @param allowEmpty true if an empty sequence is acceptable, that is if the expression * was written as "source castable as target?" */ public CastableExpression(Expression source, AtomicType target, boolean allowEmpty) { super(source); targetType = target; this.allowEmpty = allowEmpty; } /** * Get the target type * @return the target type */ public AtomicType getTargetType() { return targetType; } /** * Determine whether the empty sequence is allowed * @return true if an empty sequence is allowed */ public boolean allowsEmpty() { return allowEmpty; } /** * Simplify the expression * @return the simplified expression * @param visitor an expression visitor */ public Expression simplify(ExpressionVisitor visitor) throws XPathException { operand = visitor.simplify(operand); return preEvaluate(visitor); } private Expression preEvaluate(ExpressionVisitor visitor) throws XPathException { if (Literal.isAtomic(operand)) { return Literal.makeLiteral( BooleanValue.get(effectiveBooleanValue(visitor.getStaticContext().makeEarlyEvaluationContext()))); } if (Literal.isEmptySequence(operand)) { return new Literal(BooleanValue.get(allowEmpty)); } return this; } /** * Type-check the expression */ public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { operand = visitor.typeCheck(operand, contextItemType); // We need to take care here. The usual strategy of wrapping the operand in an expression that // does type-checking doesn't work here, because an error in the type checking should be caught, // while an error in evaluating the expression as written should not. // SequenceType atomicType = SequenceType.makeSequenceType( // BuiltInAtomicType.ANY_ATOMIC, // (allowEmpty ? StaticProperty.ALLOWS_ZERO_OR_ONE // : StaticProperty.EXACTLY_ONE)); // // RoleLocator role = new RoleLocator(RoleLocator.TYPE_OP, "castable as", 0, null); // role.setSourceLocator(this); // try { // operand = TypeChecker.staticTypeCheck(operand, atomicType, false, role, env); // } catch (XPathException err) { // return Literal.makeLiteral(BooleanValue.FALSE); // } final TypeHierarchy th = visitor.getConfiguration().getTypeHierarchy(); if (!CastExpression.isPossibleCast( operand.getItemType(th).getAtomizedItemType().getPrimitiveType(), targetType.getPrimitiveType())) { return Literal.makeLiteral(BooleanValue.FALSE); } return preEvaluate(visitor); } /** * Optimize the expression */ public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { operand = visitor.optimize(operand, contextItemType); return preEvaluate(visitor); } /** * Is this expression the same as another expression? */ public boolean equals(Object other) { return super.equals(other) && targetType == ((CastableExpression)other).targetType && allowEmpty == ((CastableExpression)other).allowEmpty; } /** * Determine the data type of the result of the Castable expression * @param th the type hierarchy cache */ public ItemType getItemType(TypeHierarchy th) { return BuiltInAtomicType.BOOLEAN; } public int computeCardinality() { return StaticProperty.EXACTLY_ONE; } /** * Determine the special properties of this expression * @return {@link StaticProperty#NON_CREATIVE}. */ public int computeSpecialProperties() { int p = super.computeSpecialProperties(); return p | StaticProperty.NON_CREATIVE; } /** * Copy an expression. This makes a deep copy. * * @return the copy of the original expression */ public Expression copy() { return new CastableExpression(getBaseExpression().copy(), targetType, allowEmpty); } /** * Evaluate the expression */ public Item evaluateItem(XPathContext context) throws XPathException { return BooleanValue.get(effectiveBooleanValue(context)); } public boolean effectiveBooleanValue(XPathContext context) throws XPathException { int count = 0; SequenceIterator iter = operand.iterate(context); while (true) { Item item = iter.next(); if (item == null) { break; } if (item instanceof NodeInfo) { Value atomizedValue = ((NodeInfo)item).atomize(); int length = atomizedValue.getLength(); count += length; if (count > 1) { return false; } if (length != 0) { AtomicValue av = (AtomicValue)atomizedValue.itemAt(0); if (!isCastable(av, targetType, context)) { return false; } } } else { AtomicValue av = (AtomicValue)item; count++; if (count > 1) { return false; } if (!isCastable(av, targetType, context)) { return false; } } } return count != 0 || allowEmpty; } /** * Determine whether a value is castable to a given type * @param value the value to be tested * @param targetType the type to be tested against * @param context XPath dynamic context * @return true if the value is castable to the required type */ public static boolean isCastable(AtomicValue value, AtomicType targetType, XPathContext context) { //if (targetType instanceof BuiltInAtomicType) { return !(value.convert(targetType, true, context) instanceof ValidationFailure); // } else { // ConversionResult result = // value.convert((AtomicType)targetType.getBuiltInBaseType(), context, true); // if (result instanceof ValidationFailure) { // return false; // } // AtomicValue val = (AtomicValue)result; // result = targetType.setDerivedTypeLabel(val.copy(null), val.getStringValueCS(), true); // return !(result instanceof ValidationFailure); // } } /** * Diagnostic print of expression structure. The abstract expression tree * is written to the supplied output destination. */ public void explain(ExpressionPresenter out) { out.startElement("castable"); out.emitAttribute("as", targetType.toString(out.getConfiguration().getNamePool())); operand.explain(out); out.endElement(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/expr/IntegerRangeTest.java0000644000175000017500000001606311056753600022450 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.trace.ExpressionPresenter; import net.sf.saxon.om.Item; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.BuiltInAtomicType; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.TypeHierarchy; import net.sf.saxon.value.AtomicValue; import net.sf.saxon.value.BooleanValue; import net.sf.saxon.value.NumericValue; import java.util.Arrays; import java.util.Iterator; /** * An IntegerRangeTest is an expression of the form * E = N to M * where E is numeric, and N and M are both expressions of type integer. */ public class IntegerRangeTest extends Expression { Expression value; Expression min; Expression max; /** * Construct a IntegerRangeTest * @param value the integer value to be tested to see if it is in the range min to max inclusive * @param min the lowest permitted value * @param max the highest permitted value */ public IntegerRangeTest(Expression value, Expression min, Expression max) { this.value = value; this.min = min; this.max = max; } /** * Get the value to be tested * @return the expression that evaluates to the value being tested */ public Expression getValueExpression() { return value; } /** * Get the expression denoting the start of the range * @return the expression denoting the minumum value */ public Expression getMinValueExpression() { return min; } /** * Get the expression denoting the end of the range * @return the expression denoting the maximum value */ public Expression getMaxValueExpression() { return max; } /** * Type-check the expression */ public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { // Already done, we only get one of these expressions after the operands have been analyzed return this; } /** * Perform optimisation of an expression and its subexpressions. *

    *

    This method is called after all references to functions and variables have been resolved * to the declaration of the function or variable, and after all type checking has been done.

    * * @param visitor an expression visitor * @param contextItemType the static type of "." at the point where this expression is invoked. * The parameter is set to null if it is known statically that the context item will be undefined. * If the type of the context item is not known statically, the argument is set to * {@link net.sf.saxon.type.Type#ITEM_TYPE} * @return the original expression, rewritten if appropriate to optimize execution * @throws XPathException if an error is discovered during this phase * (typically a type error) */ public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { return this; } /** * Get the data type of the items returned * @param th the type hierarchy cache */ public ItemType getItemType(TypeHierarchy th) { return BuiltInAtomicType.BOOLEAN; } /** * Determine the static cardinality */ public int computeCardinality() { return StaticProperty.EXACTLY_ONE; } /** * Copy an expression. This makes a deep copy. * * @return the copy of the original expression */ public Expression copy() { return new IntegerRangeTest(value.copy(), min.copy(), max.copy()); } /** * Get the immediate sub-expressions of this expression. Default implementation * returns a zero-length array, appropriate for an expression that has no * sub-expressions. * * @return an iterator containing the sub-expressions of this expression */ public Iterator iterateSubExpressions() { Expression[] e = {value, min, max}; return Arrays.asList(e).iterator(); } /** * Replace one subexpression by a replacement subexpression * @param original the original subexpression * @param replacement the replacement subexpression * @return true if the original subexpression is found */ public boolean replaceSubExpression(Expression original, Expression replacement) { boolean found = false; if (value == original) { value = replacement; found = true; } if (min == original) { min = replacement; found = true; } if (max == original) { max = replacement; found = true; } return found; } /** * Promote this expression if possible */ public Expression promote(PromotionOffer offer) throws XPathException { Expression exp = offer.accept(this); if (exp != null) { return exp; } else { if (offer.action != PromotionOffer.UNORDERED) { value = doPromotion(value, offer); min = doPromotion(min, offer); max = doPromotion(max, offer); } return this; } } /** * Evaluate the expression */ public Item evaluateItem(XPathContext c) throws XPathException { AtomicValue av = (AtomicValue)value.evaluateItem(c); if (av==null) { return BooleanValue.FALSE; } NumericValue v = (NumericValue)av; if (!v.isWholeNumber()) { return BooleanValue.FALSE; } AtomicValue av2 = (AtomicValue)min.evaluateItem(c); NumericValue v2 = (NumericValue)av2; if (v.compareTo(v2) < 0) { return BooleanValue.FALSE; } AtomicValue av3 = (AtomicValue)max.evaluateItem(c); NumericValue v3 = (NumericValue)av3; return BooleanValue.get(v.compareTo(v3) <= 0); } /** * Diagnostic print of expression structure. The abstract expression tree * is written to the supplied output destination. */ public void explain(ExpressionPresenter destination) { destination.startElement("integerRangeTest"); value.explain(destination); min.explain(destination); max.explain(destination); destination.endElement(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/expr/XPathContextMajor.java0000644000175000017500000003473311033112257022614 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.Configuration; import net.sf.saxon.Controller; import net.sf.saxon.trace.InstructionInfo; import net.sf.saxon.instruct.*; import net.sf.saxon.om.*; import net.sf.saxon.regex.RegexIterator; import net.sf.saxon.sort.GroupIterator; import net.sf.saxon.trans.Mode; import net.sf.saxon.trans.Rule; import net.sf.saxon.trans.XPathException; import java.util.Arrays; /** * This class represents a "major context" in which an XPath expression is evaluated: * a "major context" object allows all aspects of the dynamic context to change, whereas * a "minor context" only allows changes to the focus and the destination for push output. */ public class XPathContextMajor extends XPathContextMinor { private ParameterSet localParameters; private ParameterSet tunnelParameters; private UserFunction tailCallFunction; private Mode currentMode; private Rule currentTemplate; private GroupIterator currentGroupIterator; private RegexIterator currentRegexIterator; /** * Constructor should only be called by the Controller, * which acts as a XPathContext factory. * @param controller the Controller */ public XPathContextMajor(Controller controller) { this.controller = controller; stackFrame = StackFrame.EMPTY; origin = controller; } /** * Private Constructor */ private XPathContextMajor() { } /** * Constructor for use in free-standing Java applications. * @param item the item to use as the initial context item. If this is null, * the comtext item is initially undefined (which will cause a dynamic error * if it is referenced). * @param exec the Executable */ public XPathContextMajor(Item item, Executable exec) { controller = new Controller(exec.getConfiguration(), exec); if (item != null) { UnfailingIterator iter = SingletonIterator.makeIterator(item); iter.next(); currentIterator = iter; } origin = controller; } /** * Constructor for use in free-standing Java applications. * @param item the item to use as the initial context item. If this is null, * the comtext item is initially undefined (which will cause a dynamic error * if it is referenced). * @param config the Saxon Configuration * @deprecated since 9.0 - use {@link #XPathContextMajor(Item, Executable)} */ public XPathContextMajor(Item item, Configuration config) { // No longer used internally but retained for backwards compatibility (8.8) Executable exec = new Executable(config); exec.setHostLanguage(Configuration.JAVA_APPLICATION); controller = new Controller(config, exec); if (item != null) { UnfailingIterator iter = SingletonIterator.makeIterator(item); iter.next(); currentIterator = iter; } origin = controller; } /** * Construct a new context as a copy of another. The new context is effectively added * to the top of a stack, and contains a pointer to the previous context */ public XPathContextMajor newContext() { XPathContextMajor c = new XPathContextMajor(); c.controller = controller; c.currentIterator = currentIterator; c.stackFrame = stackFrame; c.localParameters = localParameters; c.tunnelParameters = tunnelParameters; c.last = last; c.currentReceiver = currentReceiver; c.isTemporaryDestination = isTemporaryDestination; c.currentMode = currentMode; c.currentTemplate = currentTemplate; c.currentRegexIterator = currentRegexIterator; c.currentGroupIterator = currentGroupIterator; c.caller = this; c.tailCallFunction = null; return c; } /** * Create a new "major" context (one that is capable of holding a stack frame with local variables * @param prev the previous context (the one causing the new context to be created) * @return the new major context */ public static XPathContextMajor newContext(XPathContextMinor prev) { XPathContextMajor c = new XPathContextMajor(); XPathContext p = prev; while (!(p instanceof XPathContextMajor)) { p = p.getCaller(); } c.controller = p.getController(); c.currentIterator = prev.getCurrentIterator(); c.stackFrame = prev.getStackFrame(); c.localParameters = p.getLocalParameters(); c.tunnelParameters = p.getTunnelParameters(); c.last = prev.last; c.currentReceiver = prev.currentReceiver; c.isTemporaryDestination = prev.isTemporaryDestination; c.currentMode = p.getCurrentMode(); c.currentTemplate = p.getCurrentTemplateRule(); c.currentRegexIterator = p.getCurrentRegexIterator(); c.currentGroupIterator = p.getCurrentGroupIterator(); c.caller = prev; c.tailCallFunction = null; return c; } /** * Get the local parameters for the current template call. * @return the supplied parameters */ public ParameterSet getLocalParameters() { return localParameters; } /** * Set the local parameters for the current template call. * @param localParameters the supplied parameters */ public void setLocalParameters(ParameterSet localParameters) { this.localParameters = localParameters; } /** * Get the tunnel parameters for the current template call. * @return the supplied tunnel parameters */ public ParameterSet getTunnelParameters() { return tunnelParameters; } /** * Set the tunnel parameters for the current template call. * @param tunnelParameters the supplied tunnel parameters */ public void setTunnelParameters(ParameterSet tunnelParameters) { this.tunnelParameters = tunnelParameters; } /** * Set the creating expression (for use in diagnostics). The origin is generally set to "this" by the * object that creates the new context. It's up to the debugger to determine whether this information * is useful. The object will either be an {@link Expression}, allowing information * about the calling instruction to be obtained, or null. */ public void setOrigin(InstructionInfo expr) { origin = expr; } /** * Set the local stack frame. This method is used when creating a Closure to support * delayed evaluation of expressions. The "stack frame" is actually on the Java heap, which * means it can survive function returns and the like. * @param map the SlotManager, which holds static details of the allocation of variables to slots * @param variables the array of "slots" to hold the actual variable values. This array will be * copied if it is too small to hold all the variables defined in the SlotManager */ public void setStackFrame(SlotManager map, ValueRepresentation[] variables) { stackFrame = new StackFrame(map, variables); if (map != null && variables.length != map.getNumberOfVariables()) { if (variables.length > map.getNumberOfVariables()) { throw new IllegalStateException("Attempting to set more local variables than the stackframe can accommodate"); } stackFrame.slots = new ValueRepresentation[map.getNumberOfVariables()]; System.arraycopy(variables, 0, stackFrame.slots, 0, variables.length); } } /** * Reset the stack frame variable map, while reusing the StackFrame object itself. This * is done on a tail call to a different function * @param map the SlotManager representing the stack frame contents * @param numberOfParams the number of parameters required on the new stack frame */ public void resetStackFrameMap(SlotManager map, int numberOfParams) { stackFrame.map = map; if (stackFrame.slots.length != map.getNumberOfVariables()) { ValueRepresentation[] v2 = new ValueRepresentation[map.getNumberOfVariables()]; System.arraycopy(stackFrame.slots, 0, v2, 0, numberOfParams); stackFrame.slots = v2; } else { // not strictly necessary Arrays.fill(stackFrame.slots, numberOfParams, stackFrame.slots.length, null); } } /** * Reset the local stack frame. This method is used when processing a tail-recursive function. * Instead of the function being called recursively, the parameters are set to new values and the * function body is evaluated repeatedly * @param fn the user function being called using tail recursion * @param variables the parameter to be supplied to the user function */ public void requestTailCall(UserFunction fn, ValueRepresentation[] variables) { if (variables.length > stackFrame.slots.length) { ValueRepresentation[] v2 = new ValueRepresentation[fn.getStackFrameMap().getNumberOfVariables()]; System.arraycopy(variables, 0, v2, 0, variables.length); stackFrame.slots = v2; } else { System.arraycopy(variables, 0, stackFrame.slots, 0, variables.length); } tailCallFunction = fn; } /** * Determine whether the body of a function is to be repeated, due to tail-recursive function calls * @return null if no tail call has been requested, or the name of the function to be called otherwise */ public UserFunction getTailCallFunction() { UserFunction fn = tailCallFunction; tailCallFunction = null; return fn; } /** * Create a new stack frame for local variables, using the supplied SlotManager to * define the allocation of slots to individual variables * @param map the SlotManager for the new stack frame */ public void openStackFrame(SlotManager map) { int numberOfSlots = map.getNumberOfVariables(); if (numberOfSlots == 0) { stackFrame = StackFrame.EMPTY; } else { stackFrame = new StackFrame(map, new ValueRepresentation[numberOfSlots]); } } /** * Create a new stack frame large enough to hold a given number of local variables, * for which no stack frame map is available. This is used in particular when evaluating * match patterns of template rules. * @param numberOfVariables The number of local variables to be accommodated. */ public void openStackFrame(int numberOfVariables) { stackFrame = new StackFrame(new SlotManager(numberOfVariables), new ValueRepresentation[numberOfVariables]); } /** * Set the current mode. * @param mode the new current mode */ public void setCurrentMode(Mode mode) { this.currentMode = mode; } /** * Get the current mode. * @return the current mode. May return null if the current mode is the default mode. */ public Mode getCurrentMode() { return currentMode; } /** * Set the current template. This is used to support xsl:apply-imports. The caller * is responsible for remembering the previous current template and resetting it * after use. * * @param rule the current template rule */ public void setCurrentTemplateRule(Rule rule) { this.currentTemplate = rule; } /** * Get the current template. This is used to support xsl:apply-imports * * @return the current template */ public Rule getCurrentTemplateRule() { return currentTemplate; } /** * Set the current grouping iterator. This supports the current-group() and * current-grouping-key() functions in XSLT 2.0 * @param iterator the new current GroupIterator */ public void setCurrentGroupIterator(GroupIterator iterator) { this.currentGroupIterator = iterator; } /** * Get the current group iterator. This supports the current-group() and * current-grouping-key() functions in XSLT 2.0 * @return the current grouped collection */ public GroupIterator getCurrentGroupIterator() { return currentGroupIterator; } /** * Set the current regex iterator. This supports the functionality of the regex-group() * function in XSLT 2.0. * @param currentRegexIterator the current regex iterator */ public void setCurrentRegexIterator(RegexIterator currentRegexIterator) { this.currentRegexIterator = currentRegexIterator; } /** * Get the current regex iterator. This supports the functionality of the regex-group() * function in XSLT 2.0. * @return the current regular expressions iterator */ public RegexIterator getCurrentRegexIterator() { return currentRegexIterator; } /** * Use local parameter. This is called when a local xsl:param element is processed. * If a parameter of the relevant name was supplied, it is bound to the xsl:param element. * Otherwise the method returns false, so the xsl:param default will be evaluated * @param qName The fingerprint of the parameter name * @param binding The XSLParam element to bind its value to * @param isTunnel True if a tunnel parameter is required, else false * @return true if a parameter of this name was supplied, false if not */ public boolean useLocalParameter(StructuredQName qName, LocalParam binding, boolean isTunnel) throws XPathException { ParameterSet params = (isTunnel ? getTunnelParameters() : localParameters); if (params==null) return false; ValueRepresentation val = params.get(binding.getParameterId()); stackFrame.slots[binding.getSlotNumber()] = val; return (val != null); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/expr/EveryItemMappingIterator.java0000644000175000017500000000616211033112257024164 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.om.Item; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.trans.XPathException; /** * EveryItemMappingIterator applies a mapping function to each item in a sequence. * The mapping function always returns a single item (never null) *

    * This is a specialization of the more general MappingIterator class, for use * in cases where a single input item always maps to exactly one output item */ public final class EveryItemMappingIterator implements SequenceIterator { private SequenceIterator base; private ItemMappingFunction action; private Item current = null; /** * Construct an ItemMappingIterator that will apply a specified ItemMappingFunction to * each Item returned by the base iterator. * * @param base the base iterator * @param action the mapping function to be applied */ public EveryItemMappingIterator(SequenceIterator base, ItemMappingFunction action) { this.base = base; this.action = action; } public Item next() throws XPathException { Item nextSource = base.next(); if (nextSource == null) { current = null; return null; } // Call the supplied mapping function current = action.map(nextSource); return current; } public Item current() { return current; } public int position() { return base.position(); } public void close() { base.close(); } public SequenceIterator getAnother() throws XPathException { return new EveryItemMappingIterator(base.getAnother(), action); } /** * Get properties of this iterator, as a bit-significant integer. * * @return the properties of this iterator. This will be some combination of * properties such as {@link net.sf.saxon.om.SequenceIterator#GROUNDED}, * {@link net.sf.saxon.om.SequenceIterator#LAST_POSITION_FINDER}, * and {@link net.sf.saxon.om.SequenceIterator#LOOKAHEAD}. It is always * acceptable to return the value zero, indicating that there are no known special properties. * It is acceptable for the properties of the iterator to change depending on its state. */ public int getProperties() { return 0; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/expr/AppendIterator.java0000644000175000017500000000623011033112257022142 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.om.Item; import net.sf.saxon.trans.XPathException; /** * Iterator that concatenates the results of two supplied iterators */ public class AppendIterator implements SequenceIterator { private SequenceIterator first; private SequenceIterable second; private XPathContext context; private SequenceIterator currentIterator; private int position = 0; /** * This form of constructor is designed to delay getting an iterator for the second * expression until it is actually needed. This gives savings in cases where the * iteration is aborted prematurely. * @param first Iterator over the first operand * @param second The second operand * @param context The dynamic context for evaluation of the second operand */ public AppendIterator(SequenceIterator first, SequenceIterable second, XPathContext context) { this.first = first; this.second = second; this.context = context; this.currentIterator = first; } public Item next() throws XPathException { Item n = currentIterator.next(); if (n == null && currentIterator==first) { currentIterator = second.iterate(context); n = currentIterator.next(); } if (n == null) { position = -1; } else { position++; } return n; } public Item current() { return currentIterator.current(); } public int position() { return position; } public void close() { } public SequenceIterator getAnother() throws XPathException { return new AppendIterator(first.getAnother(), second, context); } /** * Get properties of this iterator, as a bit-significant integer. * * @return the properties of this iterator. This will be some combination of * properties such as {@link SequenceIterator#GROUNDED}, {@link SequenceIterator#LAST_POSITION_FINDER}, * and {@link SequenceIterator#LOOKAHEAD}. It is always * acceptable to return the value zero, indicating that there are no known special properties. * It is acceptable for the properties of the iterator to change depending on its state. */ public int getProperties() { return 0; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/expr/ItemChecker.java0000644000175000017500000002440011041242325021402 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.event.SequenceReceiver; import net.sf.saxon.event.TypeCheckingFilter; import net.sf.saxon.om.Item; import net.sf.saxon.om.NamePool; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.pattern.DocumentNodeTest; import net.sf.saxon.pattern.NodeTest; import net.sf.saxon.pattern.CombinedNodeTest; import net.sf.saxon.trace.ExpressionPresenter; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.*; import net.sf.saxon.value.Cardinality; import net.sf.saxon.value.Value; /** * A ItemChecker implements the item type checking of "treat as": that is, * it returns the supplied sequence, checking that all its items are of the correct type */ public final class ItemChecker extends UnaryExpression { private ItemType requiredItemType; private RoleLocator role; /** * Constructor * @param sequence the expression whose value we are checking * @param itemType the required type of the items in the sequence * @param role information used in constructing an error message */ public ItemChecker(Expression sequence, ItemType itemType, RoleLocator role) { super(sequence); requiredItemType = itemType; this.role = role; adoptChildExpression(sequence); } /** * Get the required type * @return the required type of the items in the sequence */ public ItemType getRequiredType() { return requiredItemType; } /** * Get the RoleLocator (used to construct error messages) * @return the RoleLocator */ public RoleLocator getRoleLocator() { return role; } /** * Simplify an expression * @param visitor an expression visitor */ public Expression simplify(ExpressionVisitor visitor) throws XPathException { operand = visitor.simplify(operand); if (requiredItemType instanceof AnyItemType) { return operand; } return this; } /** * Type-check the expression */ public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { operand = visitor.typeCheck(operand, contextItemType); // When typeCheck is called a second time, we might have more information... final TypeHierarchy th = visitor.getConfiguration().getTypeHierarchy(); int card = operand.getCardinality(); if (card == StaticProperty.EMPTY) { //value is always empty, so no item checking needed return operand; } ItemType supplied = operand.getItemType(th); int relation = th.relationship(requiredItemType, supplied); if (relation == TypeHierarchy.SAME_TYPE || relation == TypeHierarchy.SUBSUMES) { return operand; } else if (relation == TypeHierarchy.DISJOINT) { final NamePool namePool = visitor.getConfiguration().getNamePool(); if (Cardinality.allowsZero(card)) { String message = role.composeErrorMessage( requiredItemType, operand.getItemType(th), namePool); visitor.getStaticContext().issueWarning("The only value that can pass type-checking is an empty sequence. " + message, this); } else if (requiredItemType.equals(BuiltInAtomicType.STRING) && th.isSubType(supplied, BuiltInAtomicType.ANY_URI)) { // URI promotion will take care of this at run-time return operand; } else { String message = role.composeErrorMessage(requiredItemType, operand.getItemType(th), namePool); XPathException err = new XPathException(message); err.setErrorCode(role.getErrorCode()); err.setLocator(this); err.setIsTypeError(true); throw err; } } return this; } /** * An implementation of Expression must provide at least one of the methods evaluateItem(), iterate(), or process(). * This method indicates which of these methods is provided. This implementation provides both iterate() and * process() methods natively. */ public int getImplementationMethod() { int m = ITERATE_METHOD | PROCESS_METHOD; if (!Cardinality.allowsMany(getCardinality())) { m |= EVALUATE_METHOD; } return m; } /** * Iterate over the sequence of values */ public SequenceIterator iterate(XPathContext context) throws XPathException { SequenceIterator base = operand.iterate(context); ItemCheckMappingFunction map = new ItemCheckMappingFunction(); map.externalContext = context; return new ItemMappingIterator(base, map); } /** * Mapping function: this is used only if the expression does not allow a sequence of more than * one item. */ private class ItemCheckMappingFunction implements ItemMappingFunction { public XPathContext externalContext; public Item map(Item item) throws XPathException { testConformance(item, externalContext); return item; } } /** * Evaluate as an Item. */ public Item evaluateItem(XPathContext context) throws XPathException { Item item = operand.evaluateItem(context); if (item==null) return null; testConformance(item, context); return item; } /** * Process the instruction, without returning any tail calls * * @param context The dynamic context, giving access to the current node, * the current variables, etc. */ public void process(XPathContext context) throws XPathException { Expression next = operand; int card = StaticProperty.ALLOWS_ZERO_OR_MORE; if (next instanceof CardinalityChecker) { card = ((CardinalityChecker)next).getRequiredCardinality(); next = ((CardinalityChecker)next).getBaseExpression(); } if ((next.getImplementationMethod() & PROCESS_METHOD) != 0 && !(requiredItemType instanceof DocumentNodeTest)) { SequenceReceiver out = context.getReceiver(); TypeCheckingFilter filter = new TypeCheckingFilter(); filter.setUnderlyingReceiver(out); filter.setPipelineConfiguration(out.getPipelineConfiguration()); filter.setRequiredType(requiredItemType, card, role); context.setReceiver(filter); next.process(context); filter.close(); context.setReceiver(out); } else { super.process(context); } } /** * Copy an expression. This makes a deep copy. * * @return the copy of the original expression */ public Expression copy() { return new ItemChecker(getBaseExpression().copy(), requiredItemType, role); } private void testConformance(Item item, XPathContext context) throws XPathException { if (!requiredItemType.matchesItem(item, true, (context == null ? null : context.getConfiguration()))) { String message; if (context == null) { // no name pool available message = "Supplied value of type " + Type.displayTypeName(item) + " does not match the required type of " + role.getMessage(); } else { final NamePool pool = context.getNamePool(); final TypeHierarchy th = context.getConfiguration().getTypeHierarchy(); message = role.composeErrorMessage(requiredItemType, Value.asValue(item).getItemType(th), pool); } String errorCode = role.getErrorCode(); if ("XPDY0050".equals(errorCode)) { // error in "treat as" assertion dynamicError(message, errorCode, context); } else { typeError(message, errorCode, context); } } } /** * Determine the data type of the items returned by the expression * @param th the type hierarchy cache */ public ItemType getItemType(TypeHierarchy th) { ItemType operandType = operand.getItemType(th); int relationship = th.relationship(requiredItemType, operandType); switch (relationship) { case TypeHierarchy.OVERLAPS: if (requiredItemType instanceof NodeTest && operandType instanceof NodeTest) { return new CombinedNodeTest((NodeTest)requiredItemType, Token.INTERSECT, (NodeTest)operandType); } else { // we don't know how to intersect atomic types, it doesn't actually happen return requiredItemType; } case TypeHierarchy.SUBSUMES: case TypeHierarchy.SAME_TYPE: // shouldn't happen, but it doesn't matter return operandType; case TypeHierarchy.SUBSUMED_BY: default: return requiredItemType; } } /** * Is this expression the same as another expression? */ public boolean equals(Object other) { return super.equals(other) && requiredItemType == ((ItemChecker)other).requiredItemType; } /** * Diagnostic print of expression structure. The abstract expression tree * is written to the supplied output destination. */ public void explain(ExpressionPresenter out) { out.startElement("treat"); out.emitAttribute("as", requiredItemType.toString(out.getConfiguration().getNamePool())); operand.explain(out); out.endElement(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/expr/ParentNodeExpression.java0000644000175000017500000001003611033112257023337 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.trace.ExpressionPresenter; import net.sf.saxon.om.Item; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.om.Axis; import net.sf.saxon.trans.XPathException; import net.sf.saxon.pattern.AnyNodeTest; /** * Class ParentNodeExpression represents the XPath expression ".." or "parent::node()" */ public class ParentNodeExpression extends SingleNodeExpression { /** * Return the node selected by this SingleNodeExpression * @param context The context for the evaluation * @return the parent of the current node defined by the context */ public NodeInfo getNode(XPathContext context) throws XPathException { Item item = context.getContextItem(); if (item==null) { dynamicError("The context item is not set", "XPDY0002", context); } if (item instanceof NodeInfo) { return ((NodeInfo)item).getParent(); } else { dynamicError("The context item for the parent axis (..) is not a node", "XPTY0020", context); return null; } } /** * Copy an expression. This makes a deep copy. * * @return the copy of the original expression */ public Expression copy() { return new ParentNodeExpression(); } /** * Add a representation of this expression to a PathMap. The PathMap captures a map of the nodes visited * by an expression in a source tree. * * @param pathMap the PathMap to which the expression should be added * @param pathMapNodeSet * @return the pathMapNode representing the focus established by this expression, in the case where this * expression is the first operand of a path expression or filter expression */ public PathMap.PathMapNodeSet addToPathMap(PathMap pathMap, PathMap.PathMapNodeSet pathMapNodeSet) { AxisExpression parent = new AxisExpression(Axis.PARENT, AnyNodeTest.getInstance()); parent.setContainer(getContainer()); return parent.addToPathMap(pathMap, pathMapNodeSet); } /** * Determine which aspects of the context the expression depends on. The result is * a bitwise-or'ed value composed from constants such as XPathContext.VARIABLES and * XPathContext.CURRENT_NODE */ /* public int getDependencies() { return StaticProperty.CONTEXT_ITEM; } */ /** * Is this expression the same as another expression? */ public boolean equals(Object other) { return (other instanceof ParentNodeExpression); } /** * get HashCode for comparing two expressions */ public int hashCode() { return "ParentNodeExpression".hashCode(); } /** * The toString() method for an expression attempts to give a representation of the expression * in an XPath-like form, but there is no guarantee that the syntax will actually be true XPath. * In the case of XSLT instructions, the toString() method gives an abstracted view of the syntax */ public String toString() { return ".."; } /** * Diagnostic print of expression structure. The abstract expression tree * is written to the supplied output destination. */ public void explain(ExpressionPresenter destination) { destination.startElement("parent"); destination.endElement(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/expr/ItemMappingFunction.java0000644000175000017500000000243611033112257023145 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.om.Item; import net.sf.saxon.trans.XPathException; /** * ItemMappingFunction is an interface that must be satisfied by an object passed to a * ItemMappingIterator. It represents an object which, given an Item, can return either * another Item, or null. */ public interface ItemMappingFunction { /** * Map one item to another item. * @param item The input item to be mapped. * @return either the output item, or null. */ public Item map(Item item) throws XPathException; } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/expr/Container.java0000644000175000017500000000433111033112257021143 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.instruct.Executable; import net.sf.saxon.event.LocationProvider; import javax.xml.transform.SourceLocator; import java.io.Serializable; /** * A Container is something other than an expression that can act as the container of an expression. * It is typically an object such as a function, a global variable, or in XSLT a template, or an attribute set. * When free-standing XPath expressions are compiled, the static context for the expression acts as its * container. */ public interface Container extends SourceLocator, Serializable { /** * Get the Executable (representing a complete stylesheet or query) of which this Container forms part * @return the executable */ public Executable getExecutable(); /** * Get the LocationProvider allowing location identifiers to be resolved. * @return the location provider */ public LocationProvider getLocationProvider(); /** * Get the host language (XSLT, XQuery, XPath) used to implement the code in this container * @return typically {@link net.sf.saxon.Configuration#XSLT} or {@link net.sf.saxon.Configuration#XQUERY} */ public int getHostLanguage(); /** * Replace one subexpression by a replacement subexpression * @param original the original subexpression * @param replacement the replacement subexpression * @return true if the original subexpression was found */ public boolean replaceSubExpression(Expression original, Expression replacement); } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): Michael Kay // saxonb-9.1.0.8/bj/net/sf/saxon/expr/EagerLetExpression.java0000644000175000017500000000316311033112257022773 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ItemType; /** * An EagerLetExpression is the same as a LetExpression except that the variable is evaluated using * eager evaluation rather than lazy evaluation. This is used when performing diagnostic tracing. */ public class EagerLetExpression extends LetExpression { public EagerLetExpression() {} public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { Expression e = super.optimize(visitor, contextItemType); if (e == this) { evaluationMode = ExpressionTool.eagerEvaluationMode(sequence); } return e; } /** * Evaluate the variable. */ // protected ValueRepresentation eval(XPathContext context) throws XPathException { // return ExpressionTool.eagerEvaluate(sequence, context); // } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/expr/RoleLocator.java0000644000175000017500000001747711033112257021465 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.om.NamePool; import net.sf.saxon.om.StructuredQName; import net.sf.saxon.type.ItemType; import java.io.Serializable; /** * A RoleLocator identifies the role in which an expression is used, for example as * the third argument of the concat() function. This information is stored in an * ItemChecker or CardinalityChecker so that good diagnostics can be * achieved when run-time type errors are detected. */ public class RoleLocator implements Serializable { private int kind; private Serializable operation; // always either a String or a StructuredQName private int operand; private String errorCode = "XPTY0004"; // default error code for type errors public static final int FUNCTION = 0; public static final int BINARY_EXPR = 1; public static final int TYPE_OP = 2; public static final int VARIABLE = 3; public static final int INSTRUCTION = 4; public static final int FUNCTION_RESULT = 5; public static final int ORDER_BY = 6; public static final int TEMPLATE_RESULT = 7; public static final int PARAM = 8; public static final int UNARY_EXPR = 9; public static final int UPDATING_EXPR = 10; /** * Create information about the role of a subexpression within its parent expression * @param kind the kind of parent expression, e.g. a function call or a variable reference * @param operation the name of the object in the parent expression, e.g. a function name or * instruction name. May be expressed either as a String or as a {@link net.sf.saxon.om.StructuredQName}. * For a string, the special format element/attribute is recognized, for example xsl:for-each/select, * to identify the role of an XPath expression in a stylesheet. * @param operand Ordinal position of this subexpression, e.g. the position of an argument in */ public RoleLocator(int kind, Serializable operation, int operand) { if (!(operation instanceof String || operation instanceof StructuredQName)) { throw new IllegalArgumentException("operation"); } this.kind = kind; this.operation = operation; this.operand = operand; } /** * Set the error code to be produced if a type error is detected * @param code The error code */ public void setErrorCode(String code) { if (code != null) { this.errorCode = code; } } /** * Get the error code to be produced if a type error is detected * @return code The error code */ public String getErrorCode() { return errorCode; } /** * Set the source location */ // public void setSourceLocator(SourceLocator locator) { // // this is currently used only when type-checking literals, // // which don't have any location information of their own // if (locator instanceof ExpressionLocation) { // this.sourceLocator = locator; // } else { // this.sourceLocator = new ExpressionLocation(locator); // } // // the supplied value isn't saved because the locator may be an expression that // // contains links back to the containing stylesheet, which causes the stylesheet // // to remain in memory at run-time (and prevents stylesheet compilation) // } /** * Get the source location (if known - return null if not known) */ // public SourceLocator getSourceLocator() { // return sourceLocator; // } /** * Construct and return the error message indicating a type error * @return the constructed error message */ public String getMessage() { String name; if (operation instanceof String) { name = (String)operation; } else { name = ((StructuredQName)operation).getDisplayName(); } switch (kind) { case FUNCTION: return ordinal(operand+1) + " argument of " + name + "()"; case BINARY_EXPR: return ordinal(operand+1) + " operand of '" + name + '\''; case UNARY_EXPR: return "operand of '-'"; case TYPE_OP: return "value in '" + name + "' expression"; case VARIABLE: return "value of variable $" + name; case INSTRUCTION: int slash = name.indexOf('/'); String attributeName = ""; if (slash >= 0) { attributeName = name.substring(slash+1); name = name.substring(0, slash); } return '@' + attributeName + " attribute of " + name; case FUNCTION_RESULT: return "result of function " + name + "()"; case TEMPLATE_RESULT: return "result of template " + name; case ORDER_BY: return ordinal(operand+1) + " sort key"; case PARAM: return "value of parameter $" + name; case UPDATING_EXPR: return "value of " + ordinal(operand+1) + " operand of " + name + " expression"; default: return ""; } } /** * Construct the part of the message giving the required item type * @param requiredItemType the item type required by the context of a particular expression * @param pool the name pool * @return a message of the form "Required item type of X is Y" */ public String composeRequiredMessage(ItemType requiredItemType, NamePool pool) { return "Required item type of " + getMessage() + " is " + requiredItemType.toString(pool); } /** * Construct a full error message * @param requiredItemType the item type required by the context of a particular expression * @param suppliedItemType the item type inferred by static analysis of an expression * @param pool the name pool * @return a message of the form "Required item type of A is R; supplied value has item type S" */ public String composeErrorMessage(ItemType requiredItemType, ItemType suppliedItemType, NamePool pool) { return "Required item type of " + getMessage() + " is " + requiredItemType.toString(pool) + "; supplied value has item type " + suppliedItemType.toString(pool); } /** * Get the ordinal representation of a number (used to identify which argument of a function * is in error) * @param n the cardinal number * @return the ordinal representation */ private static String ordinal(int n) { switch(n) { case 1: return "first"; case 2: return "second"; case 3: return "third"; default: // we can live with 21th, 22th... How many functions have >20 arguments? return n + "th"; } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. //saxonb-9.1.0.8/bj/net/sf/saxon/expr/ContextMappingIterator.java0000644000175000017500000001204611033112257023675 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.om.Item; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.trans.XPathException; /** * ContextMappingIterator merges a sequence of sequences into a single flat * sequence. It takes as inputs an iteration, and a mapping function to be * applied to each Item returned by that iteration. The mapping function itself * returns another iteration. The result is an iteration of the concatenation of all * the iterations returned by the mapping function.

    * * This is a specialization of the MappingIterator class: it differs in that it * sets each item being processed as the context item */ public final class ContextMappingIterator implements SequenceIterator { private SequenceIterator base; private ContextMappingFunction action; private XPathContext context; private SequenceIterator stepIterator = null; private Item current = null; private int position = 0; /** * Construct a ContextMappingIterator that will apply a specified ContextMappingFunction to * each Item returned by the base iterator. * @param action the mapping function to be applied * @param context the processing context. The mapping function is applied to each item returned * by context.getCurrentIterator() in turn. */ public ContextMappingIterator(ContextMappingFunction action, XPathContext context) { base = context.getCurrentIterator(); this.action = action; this.context = context; } public Item next() throws XPathException { Item nextItem; while (true) { if (stepIterator != null) { nextItem = stepIterator.next(); if (nextItem != null) { break; } else { stepIterator = null; } } if (base.next() != null) { // Call the supplied mapping function stepIterator = action.map(context); nextItem = stepIterator.next(); if (nextItem == null) { stepIterator = null; } else { break; } } else { stepIterator = null; current = null; position = -1; return null; } } current = nextItem; position++; return nextItem; } public Item current() { return current; } public int position() { return position; } public void close() { base.close(); } public SequenceIterator getAnother() throws XPathException { SequenceIterator newBase = base.getAnother(); XPathContext c2 = context; if (c2!=null) { c2 = c2.newMinorContext(); c2.setCurrentIterator(newBase); c2.setOrigin(context.getOrigin()); } return new ContextMappingIterator(action, c2); } /** * Get properties of this iterator, as a bit-significant integer. * * @return the properties of this iterator. This will be some combination of * properties such as {@link net.sf.saxon.om.SequenceIterator#GROUNDED}, {@link net.sf.saxon.om.SequenceIterator#LAST_POSITION_FINDER}, * and {@link net.sf.saxon.om.SequenceIterator#LOOKAHEAD}. It is always * acceptable to return the value zero, indicating that there are no known special properties. * It is acceptable for the properties of the iterator to change depending on its state. */ public int getProperties() { return 0; } /** * Indicate that any nodes returned in the sequence will be atomized. This * means that if it wishes to do so, the implementation can return the typed * values of the nodes rather than the nodes themselves. The implementation * is free to ignore this hint. * @param atomizing true if the caller of this iterator will atomize any * nodes that are returned, and is therefore willing to accept the typed * value of the nodes instead of the nodes themselves. */ // public void setIsAtomizing(boolean atomizing) { // this.atomizing = atomizing; // } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/expr/UnaryExpression.java0000644000175000017500000002115211033112257022377 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.Configuration; import net.sf.saxon.trace.ExpressionPresenter; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.TypeHierarchy; import net.sf.saxon.value.SequenceExtent; import net.sf.saxon.value.Value; import java.util.Iterator; /** * Unary Expression: an expression taking a single operand expression */ public abstract class UnaryExpression extends Expression { protected Expression operand; public UnaryExpression(Expression p0) { operand = p0; adoptChildExpression(p0); } public Expression getBaseExpression() { return operand; } /** * Simplify an expression * @return the simplified expression * @param visitor an expression visitor */ public Expression simplify(ExpressionVisitor visitor) throws XPathException { operand = visitor.simplify(operand); return this; } /** * Type-check the expression. Default implementation for unary operators that accept * any kind of operand */ public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { operand = visitor.typeCheck(operand, contextItemType); // if the operand value is known, pre-evaluate the expression try { if (operand instanceof Literal) { return Literal.makeLiteral(Value.asValue( SequenceExtent.makeSequenceExtent( iterate(visitor.getStaticContext().makeEarlyEvaluationContext())))); } //return (Value)ExpressionTool.eagerEvaluate(this, env.makeEarlyEvaluationContext()); } catch (XPathException err) { // if early evaluation fails, suppress the error: the value might // not be needed at run-time } return this; } /** * Perform optimisation of an expression and its subexpressions. *

    *

    This method is called after all references to functions and variables have been resolved * to the declaration of the function or variable, and after all type checking has been done.

    * * @param visitor an expression visitor * @param contextItemType the static type of "." at the point where this expression is invoked. * The parameter is set to null if it is known statically that the context item will be undefined. * If the type of the context item is not known statically, the argument is set to * {@link net.sf.saxon.type.Type#ITEM_TYPE} * @return the original expression, rewritten if appropriate to optimize execution * @throws XPathException if an error is discovered during this phase * (typically a type error) */ public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { operand = visitor.optimize(operand, contextItemType); // if the operand value is known, pre-evaluate the expression try { if (operand instanceof Literal) { return Literal.makeLiteral(Value.asValue( SequenceExtent.makeSequenceExtent( iterate(visitor.getStaticContext().makeEarlyEvaluationContext())))); } } catch (XPathException err) { // if early evaluation fails, suppress the error: the value might // not be needed at run-time } return this; } /** * Promote this expression if possible */ public Expression promote(PromotionOffer offer) throws XPathException { Expression exp = offer.accept(this); if (exp != null) { return exp; } else { operand = doPromotion(operand, offer); return this; } } /** * Get the immediate subexpressions of this expression */ public Iterator iterateSubExpressions() { return new MonoIterator(operand); } /** * Replace one subexpression by a replacement subexpression * @param original the original subexpression * @param replacement the replacement subexpression * @return true if the original subexpression is found */ public boolean replaceSubExpression(Expression original, Expression replacement) { boolean found = false; if (operand == original) { operand = replacement; found = true; } return found; } /** * Get the static properties of this expression (other than its type). The result is * bit-signficant. These properties are used for optimizations. In general, if * property bit is set, it is true, but if it is unset, the value is unknown. */ public int computeSpecialProperties() { return operand.getSpecialProperties(); } /** * Determine the static cardinality. Default implementation returns the cardinality of the operand */ public int computeCardinality() { return operand.getCardinality(); } /** * Determine the data type of the expression, if possible. The default * implementation for unary expressions returns the item type of the operand * @return the item type of the items in the result sequence, insofar as this * is known statically. * @param th the type hierarchy cache */ public ItemType getItemType(TypeHierarchy th) { return operand.getItemType(th); } /** * Is this expression the same as another expression? */ public boolean equals(Object other) { return this.getClass().equals(other.getClass()) && this.operand.equals(((UnaryExpression)other).operand); } /** * get HashCode for comparing two expressions. Note that this hashcode gives the same * result for (A op B) and for (B op A), whether or not the operator is commutative. */ public int hashCode() { return ("UnaryExpression " + getClass()).hashCode() ^ operand.hashCode(); } /** * The toString() method for an expression attempts to give a representation of the expression * in an XPath-like form, but there is no guarantee that the syntax will actually be true XPath. * In the case of XSLT instructions, the toString() method gives an abstracted view of the syntax */ public String toString() { String className = getClass().getName(); String simpleName = className.substring(className.lastIndexOf(".")+1); return simpleName + "(" + operand.toString() + ")"; // TODO:JDK1.5 - use getClass().getSimpleName() } /** * Diagnostic print of expression structure. The abstract expression tree * is written to the supplied output destination. */ public void explain(ExpressionPresenter out) { String name = displayExpressionName(); if (name == null) { out.startElement("unaryOperator"); String op = displayOperator(out.getConfiguration()); if (op != null) { out.emitAttribute("op", op); } } else { out.startElement(name); } operand.explain(out); out.endElement(); } /** * Give a string representation of the operator for use in diagnostics * @return the operator, as a string * @param config */ protected String displayOperator(Configuration config) { return null; } /** * Return the element name to use in the expression tree */ protected String displayExpressionName() { return null; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/expr/BinaryExpression.java0000644000175000017500000003461211033112257022532 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.trace.ExpressionPresenter; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ItemType; import net.sf.saxon.value.Cardinality; import net.sf.saxon.value.Value; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /** * Binary Expression: a numeric or boolean expression consisting of the * two operands and an operator */ public abstract class BinaryExpression extends Expression { protected Expression operand0; protected Expression operand1; protected int operator; // represented by the token number from class Tokenizer /** * Create a binary expression identifying the two operands and the operator * @param p0 the left-hand operand * @param op the operator, as a token returned by the Tokenizer (e.g. Token.AND) * @param p1 the right-hand operand */ public BinaryExpression(Expression p0, int op, Expression p1) { operator = op; operand0 = p0; operand1 = p1; adoptChildExpression(p0); adoptChildExpression(p1); } /** * Simplify an expression * @return the simplified expression * @param visitor an expression visitor */ public Expression simplify(ExpressionVisitor visitor) throws XPathException { operand0 = visitor.simplify(operand0); operand1 = visitor.simplify(operand1); return this; } /** * Type-check the expression. Default implementation for binary operators that accept * any kind of operand */ public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { operand0 = visitor.typeCheck(operand0, contextItemType); operand1 = visitor.typeCheck(operand1, contextItemType); // if both operands are known, pre-evaluate the expression try { if ((operand0 instanceof Literal) && (operand1 instanceof Literal)) { Value v = Value.asValue(evaluateItem(visitor.getStaticContext().makeEarlyEvaluationContext())); return Literal.makeLiteral(v); } } catch (XPathException err) { // if early evaluation fails, suppress the error: the value might // not be needed at run-time } return this; } /** * Perform optimisation of an expression and its subexpressions. *

    *

    This method is called after all references to functions and variables have been resolved * to the declaration of the function or variable, and after all type checking has been done.

    * * @param visitor an expression visitor * @param contextItemType the static type of "." at the point where this expression is invoked. * The parameter is set to null if it is known statically that the context item will be undefined. * If the type of the context item is not known statically, the argument is set to * {@link net.sf.saxon.type.Type#ITEM_TYPE} * @return the original expression, rewritten if appropriate to optimize execution * @throws XPathException if an error is discovered during this phase * (typically a type error) */ public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { operand0 = visitor.optimize(operand0, contextItemType); operand1 = visitor.optimize(operand1, contextItemType); // if both operands are known, pre-evaluate the expression try { if ((operand0 instanceof Literal) && (operand1 instanceof Literal)) { Value v = Value.asValue(evaluateItem(visitor.getStaticContext().makeEarlyEvaluationContext())); return Literal.makeLiteral(v); } } catch (XPathException err) { // if early evaluation fails, suppress the error: the value might // not be needed at run-time } return this; } /** * Mark an expression as being "flattened". This is a collective term that includes extracting the * string value or typed value, or operations such as simple value construction that concatenate text * nodes before atomizing. The implication of all of these is that although the expression might * return nodes, the identity of the nodes has no significance. This is called during type checking * of the parent expression. * * @param flattened set to true if the result of the expression is atomized or otherwise turned into * an atomic value */ public void setFlattened(boolean flattened) { operand0.setFlattened(flattened); operand1.setFlattened(flattened); } /** * Promote this expression if possible */ public Expression promote(PromotionOffer offer) throws XPathException { Expression exp = offer.accept(this); if (exp != null) { return exp; } else { if (offer.action != PromotionOffer.UNORDERED) { operand0 = doPromotion(operand0, offer); operand1 = doPromotion(operand1, offer); } return this; } } /** * Get the immediate subexpressions of this expression */ public Iterator iterateSubExpressions() { return new PairIterator(operand0, operand1); } /** * Replace one subexpression by a replacement subexpression * @param original the original subexpression * @param replacement the replacement subexpression * @return true if the original subexpression is found */ public boolean replaceSubExpression(Expression original, Expression replacement) { boolean found = false; if (operand0 == original) { operand0 = replacement; found = true; } if (operand1 == original) { operand1 = replacement; found = true; } return found; } /** * Get the operator * @return the operator, for example {@link Token#PLUS} */ public int getOperator() { return operator; } /** * Get the operands * @return the two operands of the binary expression, as an array of length 2 */ public Expression[] getOperands() { return new Expression[] {operand0, operand1}; } /** * Determine the static cardinality. Default implementation returns [0..1] if either operand * can be empty, or [1..1] otherwise. */ public int computeCardinality() { if (Cardinality.allowsZero(operand0.getCardinality()) || Cardinality.allowsZero(operand1.getCardinality())) { return StaticProperty.ALLOWS_ZERO_OR_ONE; } else { return StaticProperty.EXACTLY_ONE; } } /** * Determine the special properties of this expression * @return {@link StaticProperty#NON_CREATIVE}. This is overridden * for some subclasses. */ public int computeSpecialProperties() { int p = super.computeSpecialProperties(); return p | StaticProperty.NON_CREATIVE; } /** * Determine whether a binary operator is commutative, that is, A op B = B op A. * @param operator the operator, for example {@link Token#PLUS} * @return true if the operator is commutative */ protected static boolean isCommutative(int operator) { return (operator == Token.AND || operator == Token.OR || operator == Token.UNION || operator == Token.INTERSECT || operator == Token.PLUS || operator == Token.MULT || operator == Token.EQUALS || operator == Token.FEQ || operator == Token.NE || operator == Token.FNE ); } /** * Determine whether an operator is associative, that is, ((a^b)^c) = (a^(b^c)) * @param operator the operator, for example {@link Token#PLUS} * @return true if the operator is associative */ protected static boolean isAssociative(int operator) { return (operator == Token.AND || operator == Token.OR || operator == Token.UNION || operator == Token.INTERSECT || operator == Token.PLUS || operator == Token.MULT ); } /** * Test if one operator is the inverse of another, so that (A op1 B) is * equivalent to (B op2 A). Commutative operators are the inverse of themselves * and are therefore not listed here. * @param op1 the first operator * @param op2 the second operator * @return true if the operators are the inverse of each other */ protected static boolean isInverse(int op1, int op2) { return op1 != op2 && op1 == Token.inverse(op2); } /** * Is this expression the same as another expression? */ public boolean equals(Object other) { if (other instanceof BinaryExpression) { BinaryExpression b = (BinaryExpression)other; if (operator == b.operator) { if (operand0.equals(b.operand0) && operand1.equals(b.operand1)) { return true; } if (isCommutative(operator) && operand0.equals(b.operand1) && operand1.equals(b.operand0)) { return true; } if (isAssociative(operator) && pairwiseEqual(flattenExpression(new ArrayList(4)), b.flattenExpression(new ArrayList(4)))) { return true; } } if (isInverse(operator, b.operator) && operand0.equals(b.operand1) && operand1.equals(b.operand0)) { return true; } } return false; } /** * Flatten an expression with respect to an associative operator: for example * the expression (a+b) + (c+d) becomes list(a,b,c,d), with the list in canonical * order (sorted by hashCode) * @param list a list provided by the caller to contain the result * @return the list of expressions */ private List flattenExpression(List list) { if (operand0 instanceof BinaryExpression && ((BinaryExpression)operand0).operator == operator) { ((BinaryExpression)operand0).flattenExpression(list); } else { int h = operand0.hashCode(); list.add(operand0); int i = list.size()-1; while (i > 0 && h > list.get(i-1).hashCode()) { list.set(i, list.get(i-1)); list.set(i-1, operand0); i--; } } if (operand1 instanceof BinaryExpression && ((BinaryExpression)operand1).operator == operator) { ((BinaryExpression)operand1).flattenExpression(list); } else { int h = operand1.hashCode(); list.add(operand1); int i = list.size()-1; while (i > 0 && h > list.get(i-1).hashCode()) { list.set(i, list.get(i-1)); list.set(i-1, operand1); i--; } } return list; } /** * Compare whether two lists of expressions are pairwise equal * @param a the first list of expressions * @param b the second list of expressions * @return true if the two lists are equal */ private boolean pairwiseEqual(List a, List b) { if (a.size() != b.size()) { return false; } for (int i=0; iThis class inherits from SlashExpression; it is used in the common case where the SlashExpression * is known to return nodes rather than atomic values.

    * *

    This class is not responsible for sorting the results into document order or removing duplicates. * That is done by a DocumentSorter expression which is wrapped around the path expression. However, this * class does contain the logic for deciding statically whether the DocumentSorter is needed or not.

    */ public final class PathExpression extends SlashExpression implements ContextMappingFunction { private transient int state = 0; // 0 = raw, 1 = simplified, 2 = analyzed, 3 = optimized /** * Constructor * @param start A node-set expression denoting the absolute or relative set of nodes from which the * navigation path should start. * @param step The step to be followed from each node in the start expression to yield a new * node-set */ public PathExpression(Expression start, Expression step) { super(start, step); // If start is a path expression such as a, and step is b/c, then // instead of a/(b/c) we construct (a/b)/c. This is because it often avoids // a sort. // The "/" operator in XPath 2.0 is not always associative. Problems // can occur if position() and last() are used on the rhs, or if node-constructors // appear, e.g. //b/../. So we only do this rewrite if the step is a path // expression in which both operands are axis expressions optionally with predicates if (step instanceof PathExpression) { PathExpression stepPath = (PathExpression) step; if (isFilteredAxisPath(stepPath.getStartExpression()) && isFilteredAxisPath(stepPath.getStepExpression())) { setStartExpression(new PathExpression(start, stepPath.start)); setStepExpression(stepPath.step); } } } public boolean isHybrid() { return false; } /** * Add a document sorting node to the expression tree, if needed */ Expression addDocumentSorter() { int props = getSpecialProperties(); if ((props & StaticProperty.ORDERED_NODESET) != 0) { return this; } else if ((props & StaticProperty.REVERSE_DOCUMENT_ORDER) != 0) { return SystemFunction.makeSystemFunction("reverse", new Expression[]{this}); } else { return new DocumentSorter(this); } } /** * Determine whether an expression is an * axis step with optional filter predicates. * @param exp the expression to be examined * @return true if the supplied expression is an AxisExpression, or an AxisExpression wrapped by one * or more filter expressions */ private static boolean isFilteredAxisPath(Expression exp) { if (exp instanceof AxisExpression) { return true; } else { while (exp instanceof FilterExpression) { exp = ((FilterExpression) exp).getBaseExpression(); } return exp instanceof AxisExpression; } } /** * Simplify an expression * @return the simplified expression * @param visitor the expression visitor */ public Expression simplify(ExpressionVisitor visitor) throws XPathException { if (state > 0) { return this; } state = 1; Expression e2 = super.simplify(visitor); if (e2 != this) { return e2; } // Remove a redundant "." from the path // TODO: can we move this logic to the superclass? Does it destroy type-checking? if (start instanceof ContextItemExpression) { return step; } if (step instanceof ContextItemExpression) { return start; } return this; } // Simplify an expression of the form a//b, where b has no positional filters. // This comes out of the contructor above as (a/descendent-or-self::node())/child::b, // but it is equivalent to a/descendant::b; and the latter is better as it // doesn't require sorting. Note that we can't do this until type information is available, // as we need to know whether any filters are positional or not. private PathExpression simplifyDescendantPath(StaticContext env) { Expression st = start; // detect .//x as a special case; this will appear as descendant-or-self::node()/x if (start instanceof AxisExpression) { AxisExpression stax = (AxisExpression) start; if (stax.getAxis() != Axis.DESCENDANT_OR_SELF) { return null; } ContextItemExpression cie = new ContextItemExpression(); ExpressionTool.copyLocationInfo(this, cie); st = new PathExpression(cie, stax); ExpressionTool.copyLocationInfo(this, st); } if (!(st instanceof PathExpression)) { return null; } PathExpression startPath = (PathExpression) st; if (!(startPath.step instanceof AxisExpression)) { return null; } AxisExpression mid = (AxisExpression) startPath.step; if (mid.getAxis() != Axis.DESCENDANT_OR_SELF) { return null; } NodeTest test = mid.getNodeTest(); if (!(test == null || test instanceof AnyNodeTest)) { return null; } Expression underlyingStep = step; while (underlyingStep instanceof FilterExpression) { if (((FilterExpression) underlyingStep).isPositional(env.getConfiguration().getTypeHierarchy())) { return null; } underlyingStep = ((FilterExpression) underlyingStep).getBaseExpression(); } if (!(underlyingStep instanceof AxisExpression)) { return null; } AxisExpression underlyingAxis = (AxisExpression) underlyingStep; if (underlyingAxis.getAxis() == Axis.CHILD) { Expression newStep = new AxisExpression(Axis.DESCENDANT, ((AxisExpression) underlyingStep).getNodeTest()); ExpressionTool.copyLocationInfo(this, newStep); underlyingStep = step; while (underlyingStep instanceof FilterExpression) { // Add any filters to the new expression. We know they aren't // positional, so the order of the filters doesn't matter. newStep = new FilterExpression(newStep, ((FilterExpression) underlyingStep).getFilter()); ExpressionTool.copyLocationInfo(underlyingStep, newStep); underlyingStep = ((FilterExpression) underlyingStep).getBaseExpression(); } //System.err.println("Simplified this:"); // display(10); //System.err.println("as this:"); // new PathExpression(startPath.start, newStep).display(10); PathExpression newPath = new PathExpression(startPath.start, newStep); ExpressionTool.copyLocationInfo(this, newPath); return newPath; } if (underlyingAxis.getAxis() == Axis.ATTRIBUTE) { // turn the expression a//@b into a/descendant-or-self::*/@b Expression newStep = new AxisExpression(Axis.DESCENDANT_OR_SELF, NodeKindTest.ELEMENT); ExpressionTool.copyLocationInfo(this, newStep); PathExpression newPath = new PathExpression( new PathExpression(startPath.start, newStep), step); ExpressionTool.copyLocationInfo(this, newPath); return newPath; } return null; } /** * Perform type analysis */ public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { final TypeHierarchy th = visitor.getConfiguration().getTypeHierarchy(); if (state >= 2) { // we've already done the main analysis, and we don't want to do it again because // decisions on sorting get upset. But we have new information, namely the contextItemType, // so we use that to check that it's a node setStartExpression(visitor.typeCheck(start, contextItemType)); setStepExpression(visitor.typeCheck(step, start.getItemType(th))); return this; } state = 2; setStartExpression(visitor.typeCheck(start, contextItemType)); // The first operand must be of type node()* RoleLocator role0 = new RoleLocator(RoleLocator.BINARY_EXPR, "/", 0); //role0.setSourceLocator(this); role0.setErrorCode("XPTY0019"); setStartExpression( TypeChecker.staticTypeCheck(start, SequenceType.NODE_SEQUENCE, false, role0, visitor)); // Now check the second operand setStepExpression(visitor.typeCheck(step, start.getItemType(th))); if ((step.getSpecialProperties() & StaticProperty.NON_CREATIVE) != 0) { // A traditional path expression // We don't need the operands to be sorted; any sorting that's needed // will be done at the top level Optimizer opt = visitor.getConfiguration().getOptimizer(); setStartExpression(ExpressionTool.unsorted(opt, start, false)); setStepExpression(ExpressionTool.unsorted(opt, step, false)); // Try to simplify expressions such as a//b PathExpression p = simplifyDescendantPath(visitor.getStaticContext()); if (p != null) { ExpressionTool.copyLocationInfo(this, p); return visitor.typeCheck(visitor.simplify(p), contextItemType); } else { // a failed attempt to simplify the expression may corrupt the parent pointers adoptChildExpression(start); adoptChildExpression(step); } } return this; } /** * Optimize the expression and perform type analysis */ public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { Optimizer opt = visitor.getConfiguration().getOptimizer(); // TODO: recognize explosive path expressions such as ..//../..//.. : eliminate duplicates early to contain the size // Mainly for benchmarks, but one sees following-sibling::p/preceding-sibling::h2. We could define an expression as // explosive if it contains two adjacent steps with opposite directions (except where both are singletons). final TypeHierarchy th = visitor.getConfiguration().getTypeHierarchy(); if (state >= 3) { // we've already done the main analysis, and we don't want to do it again because // decisions on sorting get upset. But we have new information, namely the contextItemType, // so we use that to check that it's a node setStartExpression(visitor.optimize(start, contextItemType)); setStepExpression(step.optimize(visitor, start.getItemType(th))); return this; } state = 3; // Rewrite a/b[filter] as (a/b)[filter] to improve the chance of indexing Expression lastStep = getLastStep(); if (lastStep instanceof FilterExpression && !((FilterExpression)lastStep).isPositional(th)) { Expression leading = getLeadingSteps(); Expression p2 = new PathExpression(leading, ((FilterExpression)lastStep).getBaseExpression()); Expression f2 = new FilterExpression(p2, ((FilterExpression)lastStep).getFilter()); return f2.optimize(visitor, contextItemType); } Expression k = opt.convertPathExpressionToKey(this, visitor); if (k != null) { return k.typeCheck(visitor, contextItemType).optimize(visitor, contextItemType); } setStartExpression(visitor.optimize(start, contextItemType)); setStepExpression(step.optimize(visitor, start.getItemType(th))); // If any subexpressions within the step are not dependent on the focus, // and if they are not "creative" expressions (expressions that can create new nodes), then // promote them: this causes them to be evaluated once, outside the path expression return promoteFocusIndependentSubexpressions(visitor, contextItemType); } /** * Promote this expression if possible */ public Expression promote(PromotionOffer offer) throws XPathException { Expression p = this; if (offer.action == PromotionOffer.RANGE_INDEPENDENT) { // try converting the expression first from a/b/c[pred] to (a/b/c)[pred] so that a/b/c can be promoted final Optimizer optimizer = offer.getOptimizer(); FilterExpression p2 = optimizer.convertToFilterExpression( this, optimizer.getConfiguration().getTypeHierarchy()); if (p2 != null) { return p2.promote(offer); } } Expression exp = offer.accept(p); if (exp != null) { return exp; } else { setStartExpression(doPromotion(start, offer)); if (offer.action == PromotionOffer.INLINE_VARIABLE_REFERENCES || offer.action == PromotionOffer.REPLACE_CURRENT) { // Don't pass on other requests. We could pass them on, but only after augmenting // them to say we are interested in subexpressions that don't depend on either the // outer context or the inner context. setStepExpression(doPromotion(step, offer)); } return this; } } /** * Copy an expression. This makes a deep copy. * * @return the copy of the original expression */ public Expression copy() { return new PathExpression(start.copy(), step.copy()); } /** * Get the static properties of this expression (other than its type). The result is * bit-signficant. These properties are used for optimizations. In general, if * property bit is set, it is true, but if it is unset, the value is unknown. */ public int computeSpecialProperties() { int startProperties = start.getSpecialProperties(); int stepProperties = step.getSpecialProperties(); int p = 0; if (!Cardinality.allowsMany(start.getCardinality())) { startProperties |= StaticProperty.ORDERED_NODESET | StaticProperty.PEER_NODESET; } if (!Cardinality.allowsMany(step.getCardinality())) { stepProperties |= StaticProperty.ORDERED_NODESET | StaticProperty.PEER_NODESET; } if ((startProperties & stepProperties & StaticProperty.CONTEXT_DOCUMENT_NODESET) != 0) { p |= StaticProperty.CONTEXT_DOCUMENT_NODESET; } if (((startProperties & StaticProperty.SINGLE_DOCUMENT_NODESET) != 0) && ((stepProperties & StaticProperty.CONTEXT_DOCUMENT_NODESET) != 0)) { p |= StaticProperty.SINGLE_DOCUMENT_NODESET; } if ((startProperties & stepProperties & StaticProperty.PEER_NODESET) != 0) { p |= StaticProperty.PEER_NODESET; } if ((startProperties & stepProperties & StaticProperty.SUBTREE_NODESET) != 0) { p |= StaticProperty.SUBTREE_NODESET; } if (testNaturallySorted(startProperties, stepProperties)) { p |= StaticProperty.ORDERED_NODESET; } if (testNaturallyReverseSorted()) { p |= StaticProperty.REVERSE_DOCUMENT_ORDER; } if ((startProperties & stepProperties & StaticProperty.NON_CREATIVE) != 0) { p |= StaticProperty.NON_CREATIVE; } return p; } /** * Determine if we can guarantee that the nodes are delivered in document order. * This is true if the start nodes are sorted peer nodes * and the step is based on an Axis within the subtree rooted at each node. * It is also true if the start is a singleton node and the axis is sorted. * @param startProperties the properties of the left-hand expression * @param stepProperties the properties of the right-hand expression * @return true if the natural nested-loop evaluation strategy for the expression * is known to deliver results with no duplicates and in document order, that is, * if no additional sort is required */ private boolean testNaturallySorted(int startProperties, int stepProperties) { // System.err.println("**** Testing pathExpression.isNaturallySorted()"); // display(20); // System.err.println("Start is ordered node-set? " + start.isOrderedNodeSet()); // System.err.println("Start is naturally sorted? " + start.isNaturallySorted()); // System.err.println("Start is singleton? " + start.isSingleton()); if ((stepProperties & StaticProperty.ORDERED_NODESET) == 0) { return false; } if (Cardinality.allowsMany(start.getCardinality())) { if ((startProperties & StaticProperty.ORDERED_NODESET) == 0) { return false; } } else { //if ((stepProperties & StaticProperty.ORDERED_NODESET) != 0) { return true; //} } // We know now that both the start and the step are sorted. But this does // not necessarily mean that the combination is sorted. // The result is sorted if the start is sorted and the step selects attributes // or namespaces if ((stepProperties & StaticProperty.ATTRIBUTE_NS_NODESET) != 0) { return true; } // The result is sorted if the start selects "peer nodes" (that is, a node-set in which // no node is an ancestor of another) and the step selects within the subtree rooted // at the context node return ((startProperties & StaticProperty.PEER_NODESET) != 0) && ((stepProperties & StaticProperty.SUBTREE_NODESET) != 0); } /** * Determine if the path expression naturally returns nodes in reverse document order * @return true if the natural nested-loop evaluation strategy returns nodes in reverse * document order */ private boolean testNaturallyReverseSorted() { // Some examples of path expressions that are naturally reverse sorted: // ancestor::*/@x // ../preceding-sibling::x // $x[1]/preceding-sibling::node() // This information is used to do a simple reversal of the nodes // instead of a full sort, which is significantly cheaper, especially // when using tree models (such as DOM and JDOM) in which comparing // nodes in document order is an expensive operation. if (!Cardinality.allowsMany(start.getCardinality()) && (step instanceof AxisExpression)) { return !Axis.isForwards[((AxisExpression) step).getAxis()]; } return !Cardinality.allowsMany(step.getCardinality()) && (start instanceof AxisExpression) && !Axis.isForwards[((AxisExpression)start).getAxis()]; } /** * Get the first step in this expression. A path expression A/B/C is represented as (A/B)/C, but * the first step is A * @return the first step in the expression, after expanding any nested path expressions */ public Expression getFirstStep() { if (start instanceof PathExpression) { return ((PathExpression) start).getFirstStep(); } else { return start; } } /** * Get all steps after the first. * This is complicated by the fact that A/B/C is represented as ((A/B)/C; we are required * to return B/C * @return a path expression containing all steps in this path expression other than the first, * after expanding any nested path expressions */ public Expression getRemainingSteps() { if (start instanceof PathExpression) { PathExpression rem = new PathExpression(((PathExpression) start).getRemainingSteps(), step); ExpressionTool.copyLocationInfo(start, rem); return rem; } else { return step; } } /** * Get the last step of the path expression * @return the last step in the expression, after expanding any nested path expressions */ public Expression getLastStep() { if (step instanceof PathExpression) { return ((PathExpression)step).getLastStep(); } else { return step; } } /** * Get a path expression consisting of all steps except the last * @return a path expression containing all steps in this path expression other than the last, * after expanding any nested path expressions */ public Expression getLeadingSteps() { if (step instanceof PathExpression) { PathExpression rem = new PathExpression(start, ((PathExpression) step).getLeadingSteps()); ExpressionTool.copyLocationInfo(start, rem); return rem; } else { return start; } } /** * Test whether a path expression is an absolute path - that is, a path whose first step selects a * document node * @param th the type hierarchy cache * @return true if the first step in this path expression selects a document node */ public boolean isAbsolute(TypeHierarchy th) { Expression first = getFirstStep(); if (first.getItemType(th).getPrimitiveType() == Type.DOCUMENT) { return true; } // This second test allows keys to be built. See XMark q9. // if (first instanceof AxisExpression && ((AxisExpression)first).getContextItemType().getPrimitiveType() == Type.DOCUMENT) { // return true; // }; return false; } /** * Test whether a path expression is an absolute path - that is, a path whose first step selects a * document node; if not, see if it can be converted to an absolute path. This is possible in cases where * the path expression has the form a/b/c and it is known that the context item is a document node; in this * case it is safe to change the path expression to /a/b/c * @param th the type hierarchy cache * @return the path expression if it is absolute; the converted path expression if it can be made absolute; * or null if neither condition applies. */ public PathExpression tryToMakeAbsolute(TypeHierarchy th) { Expression first = getFirstStep(); if (first.getItemType(th).getPrimitiveType() == Type.DOCUMENT) { return this; } // This second test allows keys to be built. See XMark q9. if (first instanceof AxisExpression && ((AxisExpression)first).getContextItemType().getPrimitiveType() == Type.DOCUMENT) { RootExpression root = new RootExpression(); ExpressionTool.copyLocationInfo(this, root); PathExpression path = new PathExpression(root, this); ExpressionTool.copyLocationInfo(this, path); return path; } return null; } /** * Add a representation of this expression to a PathMap. The PathMap captures a map of the nodes visited * by an expression in a source tree. * * @param pathMap the PathMap to which the expression should be added * @param pathMapNodeSet * @return the pathMapNode representing the focus established by this expression, in the case where this * expression is the first operand of a path expression or filter expression */ public PathMap.PathMapNodeSet addToPathMap(PathMap pathMap, PathMap.PathMapNodeSet pathMapNodeSet) { // TODO: not clear why this differs from the superclass method PathMap.PathMapNodeSet target = start.addToPathMap(pathMap, pathMapNodeSet); return step.addToPathMap(pathMap, target); } /** * Iterate the path-expression in a given context * @param context the evaluation context */ public SequenceIterator iterate(XPathContext context) throws XPathException { // This class delivers the result of the path expression in unsorted order, // without removal of duplicates. If sorting and deduplication are needed, // this is achieved by wrapping the path expression in a DocumentSorter SequenceIterator master = start.iterate(context); XPathContext context2 = context.newMinorContext(); context2.setCurrentIterator(master); context2.setOrigin(this); //context2.setOriginatingConstructType(Location.PATH_EXPRESSION); return new ContextMappingIterator(this, context2); } /** * The toString() method for an expression attempts to give a representation of the expression * in an XPath-like form, but there is no guarantee that the syntax will actually be true XPath. * In the case of XSLT instructions, the toString() method gives an abstracted view of the syntax */ public String toString() { return "(" + start.toString() + "/" + step.toString() + ")"; } /** * Diagnostic print of expression structure. The abstract expression tree * is written to the supplied output destination. */ public void explain(ExpressionPresenter destination) { destination.startElement("path"); start.explain(destination); step.explain(destination); destination.endElement(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/expr/AtomicSequenceConverter.java0000644000175000017500000001431711033112257024023 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.om.Item; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.om.ValueRepresentation; import net.sf.saxon.trace.ExpressionPresenter; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.AtomicType; import net.sf.saxon.type.BuiltInAtomicType; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.TypeHierarchy; import net.sf.saxon.value.AtomicValue; import net.sf.saxon.value.Cardinality; import net.sf.saxon.value.SequenceExtent; import net.sf.saxon.value.Value; /** * An AtomicSequenceConverter is an expression that performs a cast on each member of * a supplied sequence */ public final class AtomicSequenceConverter extends UnaryExpression { private AtomicType requiredItemType; private BuiltInAtomicType requiredPrimitiveType; /** * Constructor * @param sequence this must be a sequence of atomic values. This is not checked; a ClassCastException * will occur if the precondition is not satisfied. * @param requiredItemType the item type to which all items in the sequence should be converted, * using the rules for "cast as". */ public AtomicSequenceConverter(Expression sequence, AtomicType requiredItemType) { super(sequence); this.requiredItemType = requiredItemType; requiredPrimitiveType = (BuiltInAtomicType)requiredItemType.getPrimitiveItemType(); ExpressionTool.copyLocationInfo(sequence, this); } /** * Get the required (target) primitive type * @return the required primitive type */ public AtomicType getRequiredPrimitiveType() { return requiredPrimitiveType; } /** * Simplify an expression * @param visitor an expression visitor */ public Expression simplify(ExpressionVisitor visitor) throws XPathException { operand = visitor.simplify(operand); if (operand instanceof Literal) { ValueRepresentation val = SequenceExtent.makeSequenceExtent( iterate(visitor.getStaticContext().makeEarlyEvaluationContext())); return Literal.makeLiteral(Value.asValue(val)); } return this; } /** * Type-check the expression */ public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { operand = visitor.typeCheck(operand, contextItemType); final TypeHierarchy th = visitor.getConfiguration().getTypeHierarchy(); if (th.isSubType(operand.getItemType(th), requiredItemType)) { return operand; } else if (!Cardinality.allowsMany(operand.getCardinality())) { CastExpression cast = new CastExpression(operand, requiredItemType, (operand.getCardinality() & StaticProperty.ALLOWS_ZERO) != 0); ExpressionTool.copyLocationInfo(this, cast); return cast; } else { return this; } } /** * Determine the special properties of this expression * @return {@link StaticProperty#NON_CREATIVE}. */ public int computeSpecialProperties() { int p = super.computeSpecialProperties(); return p | StaticProperty.NON_CREATIVE; } /** * Copy an expression. This makes a deep copy. * * @return the copy of the original expression */ public Expression copy() { return new AtomicSequenceConverter(getBaseExpression().copy(), requiredItemType); } /** * Iterate over the sequence of values */ public SequenceIterator iterate(final XPathContext context) throws XPathException { SequenceIterator base = operand.iterate(context); ItemMappingFunction converter = new ItemMappingFunction() { public Item map(Item item) throws XPathException { return ((AtomicValue)item).convert(requiredPrimitiveType, true, context).asAtomic(); } }; return new ItemMappingIterator(base, converter); } /** * Evaluate as an Item. This should only be called if the AtomicSequenceConverter has cardinality zero-or-one */ public Item evaluateItem(XPathContext context) throws XPathException { Item item = operand.evaluateItem(context); if (item==null) return null; return ((AtomicValue)item).convert(requiredPrimitiveType, true, context).asAtomic(); } /** * Determine the data type of the items returned by the expression, if possible * @return a value such as Type.STRING, Type.BOOLEAN, Type.NUMBER, Type.NODE, * or Type.ITEM (meaning not known in advance) * @param th the type hierarchy cache */ public ItemType getItemType(TypeHierarchy th) { return requiredItemType; } /** * Determine the static cardinality of the expression */ public int computeCardinality() { return operand.getCardinality(); } /** * Is this expression the same as another expression? */ public boolean equals(Object other) { return super.equals(other) && requiredPrimitiveType == ((AtomicSequenceConverter)other).requiredPrimitiveType; } /** * Diagnostic print of expression structure. The abstract expression tree * is written to the supplied output destination. */ public void explain(ExpressionPresenter destination) { destination.startElement("convertItems"); destination.emitAttribute("to", requiredItemType.toString(destination.getNamePool())); operand.explain(destination); destination.endElement(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/expr/StackFrame.java0000644000175000017500000000277011033112257021246 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.instruct.SlotManager; import net.sf.saxon.om.ValueRepresentation; /** * This class represents a stack frame holding details of the variables used in a function or in * an XSLT template. */ public class StackFrame { protected SlotManager map; protected ValueRepresentation[] slots; public StackFrame (SlotManager map, ValueRepresentation[] slots) { this.map = map; this.slots = slots; } public SlotManager getStackFrameMap() { return map; } public ValueRepresentation[] getStackFrameValues() { return slots; } public static final StackFrame EMPTY = new StackFrame(SlotManager.EMPTY, ValueRepresentation.EMPTY_VALUE_ARRAY); } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. //saxonb-9.1.0.8/bj/net/sf/saxon/expr/ArithmeticExpression10.java0000644000175000017500000002775611041224444023554 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.functions.NumberFn; import net.sf.saxon.functions.SystemFunction; import net.sf.saxon.om.Item; import net.sf.saxon.om.StructuredQName; import net.sf.saxon.om.NamespaceConstant; import net.sf.saxon.pattern.EmptySequenceTest; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.AtomicType; import net.sf.saxon.type.BuiltInAtomicType; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.TypeHierarchy; import net.sf.saxon.value.*; import net.sf.saxon.instruct.Choose; /** * Arithmetic Expression: an expression using one of the operators * plus, minus, multiply, div, idiv, mod, in backwards * compatibility mode: see {@link ArithmeticExpression} for the non-backwards * compatible case. */ public class ArithmeticExpression10 extends BinaryExpression { private Calculator calculator; /** * Create an arithmetic expression to be evaluated in XPath 1.0 mode * @param p0 the first operand * @param operator the operator, for example {@link Token#PLUS} * @param p1 the second operand */ public ArithmeticExpression10(Expression p0, int operator, Expression p1) { super(p0, operator, p1); } /** * Determine whether the expression is to be evaluated in backwards-compatible mode * @return true, always */ public boolean isBackwardsCompatible() { return true; } /** * Type-check the expression statically. We try to work out which particular * arithmetic function to use if the types of operands are known an compile time. */ public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { final TypeHierarchy th = visitor.getConfiguration().getTypeHierarchy(); if (Literal.isEmptySequence(operand0)) { return new Literal(DoubleValue.NaN); } if (Literal.isEmptySequence(operand1)) { return new Literal(DoubleValue.NaN); } Expression oldOp0 = operand0; Expression oldOp1 = operand1; operand0 = visitor.typeCheck(operand0, contextItemType); operand1 = visitor.typeCheck(operand1, contextItemType); SequenceType atomicType = SequenceType.OPTIONAL_ATOMIC; RoleLocator role0 = new RoleLocator(RoleLocator.BINARY_EXPR, Token.tokens[operator], 0); //role0.setSourceLocator(this); operand0 = TypeChecker.staticTypeCheck(operand0, atomicType, true, role0, visitor); final ItemType itemType0 = operand0.getItemType(th); if (itemType0 instanceof EmptySequenceTest) { return Literal.makeLiteral(DoubleValue.NaN); } AtomicType type0 = (AtomicType) itemType0.getPrimitiveItemType(); if (calculator == null) { operand0 = createConversionCode(operand0, th, type0); } type0 = (AtomicType) operand0.getItemType(th).getPrimitiveItemType(); // System.err.println("First operand"); operand0.display(10); RoleLocator role1 = new RoleLocator(RoleLocator.BINARY_EXPR, Token.tokens[operator], 1); //role1.setSourceLocator(this); operand1 = TypeChecker.staticTypeCheck(operand1, atomicType, true, role1, visitor); final ItemType itemType1 = operand1.getItemType(th); if (itemType1 instanceof EmptySequenceTest) { return Literal.makeLiteral(DoubleValue.NaN); } AtomicType type1 = (AtomicType)itemType1.getPrimitiveItemType(); if (calculator == null) { operand1 = createConversionCode(operand1, th, type1); } type1 = (AtomicType) operand1.getItemType(th).getPrimitiveItemType(); if (operand0 != oldOp0) { adoptChildExpression(operand0); } if (operand1 != oldOp1) { adoptChildExpression(operand1); } if (operator == Token.NEGATE) { if (operand1 instanceof Literal) { Value v = ((Literal)operand1).getValue(); if (v instanceof NumericValue) { return Literal.makeLiteral(((NumericValue)v).negate()); } } NegateExpression ne = new NegateExpression(operand1); ne.setBackwardsCompatible(true); return visitor.typeCheck(ne, contextItemType); } // Get a calculator to implement the arithmetic operation. If the types are not yet specifically known, // we allow this to return an "ANY" calculator which defers the decision. However, we only allow this if // at least one of the operand types is AnyAtomicType. boolean mustResolve = !(type0.equals(BuiltInAtomicType.ANY_ATOMIC) || type1.equals(BuiltInAtomicType.ANY_ATOMIC) || type0.equals(BuiltInAtomicType.NUMERIC) || type1.equals(BuiltInAtomicType.NUMERIC)); calculator = Calculator.getCalculator(type0.getFingerprint(), type1.getFingerprint(), ArithmeticExpression.mapOpCode(operator), mustResolve); if (calculator == null) { XPathException de = new XPathException("Arithmetic operator is not defined for arguments of types (" + type0.getDescription() + ", " + type1.getDescription() + ")"); de.setLocator(this); de.setErrorCode("XPTY0004"); throw de; } try { if ((operand0 instanceof Literal) && (operand1 instanceof Literal)) { return Literal.makeLiteral( Value.asValue(evaluateItem(visitor.getStaticContext().makeEarlyEvaluationContext()))); } } catch (XPathException err) { // if early evaluation fails, suppress the error: the value might // not be needed at run-time } return this; } private Expression createConversionCode( Expression operand, final TypeHierarchy th, AtomicType type) { if (Cardinality.allowsMany(operand.getCardinality())) { FirstItemExpression fie = new FirstItemExpression(operand); ExpressionTool.copyLocationInfo(this, fie); operand = fie; } if (th.isSubType(type, BuiltInAtomicType.DOUBLE) || th.isSubType(type, BuiltInAtomicType.DATE) || th.isSubType(type, BuiltInAtomicType.TIME) || th.isSubType(type, BuiltInAtomicType.DATE_TIME) || th.isSubType(type, BuiltInAtomicType.DURATION)) { return operand; } if (th.isSubType(type, BuiltInAtomicType.BOOLEAN) || th.isSubType(type, BuiltInAtomicType.STRING) || th.isSubType(type, BuiltInAtomicType.UNTYPED_ATOMIC) || th.isSubType(type, BuiltInAtomicType.FLOAT) || th.isSubType(type, BuiltInAtomicType.DECIMAL)) { if (operand instanceof Literal) { Value val = ((Literal)operand).getValue(); return new Literal(NumberFn.convert((AtomicValue)val)); } else { return SystemFunction.makeSystemFunction("number", new Expression[]{operand}); } } // If we can't determine the primitive type at compile time, we generate a run-time typeswitch LetExpression let = new LetExpression(); let.setRequiredType(SequenceType.OPTIONAL_ATOMIC); let.setVariableQName(new StructuredQName("nn", NamespaceConstant.SAXON, "nn" + let.hashCode())); let.setSequence(operand); LocalVariableReference var = new LocalVariableReference(let); Expression isDouble = new InstanceOfExpression( var, SequenceType.makeSequenceType(BuiltInAtomicType.DOUBLE, StaticProperty.ALLOWS_ZERO_OR_ONE)); var = new LocalVariableReference(let); Expression isDecimal = new InstanceOfExpression( var, SequenceType.makeSequenceType(BuiltInAtomicType.DECIMAL, StaticProperty.ALLOWS_ZERO_OR_ONE)); var = new LocalVariableReference(let); Expression isFloat = new InstanceOfExpression( var, SequenceType.makeSequenceType(BuiltInAtomicType.FLOAT, StaticProperty.ALLOWS_ZERO_OR_ONE)); var = new LocalVariableReference(let); Expression isString = new InstanceOfExpression( var, SequenceType.makeSequenceType(BuiltInAtomicType.STRING, StaticProperty.ALLOWS_ZERO_OR_ONE)); var = new LocalVariableReference(let); Expression isUntypedAtomic = new InstanceOfExpression( var, SequenceType.makeSequenceType(BuiltInAtomicType.UNTYPED_ATOMIC, StaticProperty.ALLOWS_ZERO_OR_ONE)); var = new LocalVariableReference(let); Expression isBoolean = new InstanceOfExpression( var, SequenceType.makeSequenceType(BuiltInAtomicType.BOOLEAN, StaticProperty.ALLOWS_ZERO_OR_ONE)); Expression condition = new BooleanExpression(isDouble, Token.OR, isDecimal); condition = new BooleanExpression(condition, Token.OR, isFloat); condition = new BooleanExpression(condition, Token.OR, isString); condition = new BooleanExpression(condition, Token.OR, isUntypedAtomic); condition = new BooleanExpression(condition, Token.OR, isBoolean); var = new LocalVariableReference(let); NumberFn fn = (NumberFn)SystemFunction.makeSystemFunction("number", new Expression[]{var}); var = new LocalVariableReference(let); var.setStaticType(SequenceType.SINGLE_ATOMIC, null, 0); Expression action = Choose.makeConditional(condition, fn, var); let.setAction(action); return let; } /** * Determine the data type of the expression, if this is known statically */ public ItemType getItemType(TypeHierarchy th) { if (calculator == null) { return BuiltInAtomicType.ANY_ATOMIC; // type is not known statically } else { ItemType t1 = operand0.getItemType(th); if (!(t1 instanceof AtomicType)) { t1 = t1.getAtomizedItemType(); } ItemType t2 = operand1.getItemType(th); if (!(t2 instanceof AtomicType)) { t2 = t2.getAtomizedItemType(); } return calculator.getResultType((AtomicType) t1.getPrimitiveItemType(), (AtomicType) t2.getPrimitiveItemType()); } } /** * Copy an expression. This makes a deep copy. * * @return the copy of the original expression */ public Expression copy() { ArithmeticExpression10 a2 = new ArithmeticExpression10(operand0.copy(), operator, operand1.copy()); a2.calculator = calculator; return a2; } /** * Evaluate the expression. */ public Item evaluateItem(XPathContext context) throws XPathException { AtomicValue v1 = (AtomicValue) operand0.evaluateItem(context); if (v1 == null) { return DoubleValue.NaN; } AtomicValue v2 = (AtomicValue) operand1.evaluateItem(context); if (v2 == null) { return DoubleValue.NaN; } return calculator.compute(v1, v2, context); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/expr/ExpressionVisitor.java0000644000175000017500000002056311033112257022745 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.Configuration; import net.sf.saxon.instruct.Executable; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ItemType; import java.util.Iterator; import java.util.Stack; /** * The ExpressionVisitor supports the various phases of processing of an expression tree which require * a recursive walk of the tree structure visiting each node in turn. In maintains a stack holding the * ancestor nodes of the node currently being visited. */ public class ExpressionVisitor { private Stack stack; private Container container; private Executable executable; private StaticContext staticContext; private Configuration configuration; /** * Create an ExpressionVisitor */ public ExpressionVisitor() { stack = new Stack(); } /** * Get the Saxon configuration * @return the Saxon configuration */ public Configuration getConfiguration() { return configuration; } /** * Set the Saxon configuration * @param configuration the Saxon configuration */ public void setConfiguration(Configuration configuration) { this.configuration = configuration; } /** * Get the container of the expressions being visited * @return the container */ public Container getContainer() { return container; } /** * Set the container of the expressions being visited * @param container the container */ public void setContainer(Container container) { this.container = container; } /** * Get the Executable containing the expressions being visited * @return the Executable */ public Executable getExecutable() { return executable; } /** * Set the Executable containing the expressions being visited * @param executable the Executable */ public void setExecutable(Executable executable) { this.executable = executable; } /** * Get the stack containing all the expressions currently being visited * @return the expression stack holding all the containing expressions of the current expression; * the objects on this Stack are instances of {@link Expression} */ public Stack getStack() { return stack; } /** * Set the stack used to hold the expressions being visited * @param stack the expression stack */ public void setStack(Stack stack) { this.stack = stack; } /** * Get the static context for the expressions being visited. Note: this may not reflect all changes * in static context (e.g. namespace context, base URI) applying to nested expressions * @return the static context */ public StaticContext getStaticContext() { return staticContext; } /** * Set the static context for the expressions being visited. Note: this may not reflect all changes * in static context (e.g. namespace context, base URI) applying to nested expressions * @param staticContext the static context */ public void setStaticContext(StaticContext staticContext) { this.staticContext = staticContext; } /** * Get the current expression, the one being visited * @return the current expression */ public Expression getCurrentExpression() { return (Expression)stack.peek(); } /** * Factory method: make an expression visitor * @param env the static context * @return the new expression visitor */ public static ExpressionVisitor make(StaticContext env) { ExpressionVisitor visitor = new ExpressionVisitor(); visitor.setStaticContext(env); visitor.setConfiguration(env.getConfiguration()); return visitor; } /** * Simplify an expression, via the ExpressionVisitor * @param exp the expression to be simplified * @return the simplified expression * @throws XPathException */ public Expression simplify(Expression exp) throws XPathException { if (exp != null) { stack.push(exp); Expression exp2 = exp.simplify(this); stack.pop(); return exp2; } else { return null; } } /** * Type check an expression, via the ExpressionVisitor * @param exp the expression to be typechecked * @param contextItemType the static type of the context item for this expression * @return the expression that results from type checking (this may be wrapped in expressions that * perform dynamic checking of the item type or cardinality, or that perform atomization or numeric * promotion) * @throws XPathException if static type checking fails, that is, if the expression cannot possibly * deliver a value of the required type */ public Expression typeCheck(Expression exp, ItemType contextItemType) throws XPathException { if (exp != null) { stack.push(exp); Expression exp2 = exp.typeCheck(this, contextItemType); stack.pop(); return exp2; } else { return null; } } /** * Optimize an expression, via the ExpressionVisitor * @param exp the expression to be typechecked * @param contextItemType the static type of the context item for this expression * @return the rewritten expression * @throws XPathException */ public Expression optimize(Expression exp, ItemType contextItemType) throws XPathException { if (exp != null) { stack.push(exp); Expression exp2 = exp.optimize(this, contextItemType); stack.pop(); return exp2; } else { return null; } } /** * Get the parent expression of the current expression in the expression tree * @return the parent of the current expression (or null if this is the root) */ public Expression getParentExpression() { int pos = stack.size() - 2; if (pos > 0) { return (Expression)stack.get(pos); } else { return null; } } /** * Return true if the current expression at the top of the visitor's stack is evaluated repeatedly * when a given ancestor expression is evaluated once * @param ancestor the ancestor expression. May be null, in which case the search goes all the way * to the base of the stack. * @return true if the current expression is evaluated repeatedly */ public boolean isLoopingSubexpression(Expression ancestor) { int top = stack.size()-1; while (true) { if (top <= 0) { return false; } Expression parent = (Expression)stack.get(top - 1); if (parent.hasLoopingSubexpression(((Expression)stack.get(top)))) { return true; } if (parent == ancestor) { return false; } top--; } } /** * Reset the static properties for the current expression and for all its containing expressions. * This should be done whenever the expression is changed in a way that might * affect the properties. It causes the properties to be recomputed next time they are needed. */ public final void resetStaticProperties() { Iterator up = stack.iterator(); while (up.hasNext()) { Expression exp = (Expression)up.next(); exp.resetLocalStaticProperties(); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/expr/ArithmeticExpression.java0000644000175000017500000003170611033112257023400 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.om.Item; import net.sf.saxon.om.StandardNames; import net.sf.saxon.pattern.EmptySequenceTest; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.AtomicType; import net.sf.saxon.type.BuiltInAtomicType; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.TypeHierarchy; import net.sf.saxon.value.*; /** * Arithmetic Expression: an expression using one of the operators * plus, minus, multiply, div, idiv, mod. Note that this code does not handle backwards * compatibility mode: see {@link ArithmeticExpression10} */ public class ArithmeticExpression extends BinaryExpression { private Calculator calculator; private boolean simplified = false; /** * Create an arithmetic expression * @param p0 the first operand * @param operator the operator, for example {@link Token#PLUS} * @param p1 the second operand */ public ArithmeticExpression(Expression p0, int operator, Expression p1) { super(p0, operator, p1); } public Expression simplify(ExpressionVisitor visitor) throws XPathException { if (simplified) { // Don't simplify more than once; because in XSLT the static context on subsequent calls // might not know whether backwards compatibility is in force or not return this; } simplified = true; Expression e = super.simplify(visitor); if (e == this && visitor.getStaticContext().isInBackwardsCompatibleMode()) { return new ArithmeticExpression10(operand0, operator, operand1); } else { if (operator == Token.NEGATE && Literal.isAtomic(operand1)) { // very early evaluation of expressions like "-1", so they are treated as numeric literals AtomicValue val = (AtomicValue)((Literal)operand1).getValue(); if (val instanceof NumericValue) { return new Literal(((NumericValue)val).negate()); } } return e; } } /** * Get the calculator allocated to evaluate this expression * @return the calculator, a helper object that does the actual calculation */ public Calculator getCalculator() { return calculator; } /** * Type-check the expression statically. We try to work out which particular * arithmetic function to use if the types of operands are known an compile time. */ public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { final TypeHierarchy th = visitor.getConfiguration().getTypeHierarchy(); Expression oldOp0 = operand0; Expression oldOp1 = operand1; operand0 = visitor.typeCheck(operand0, contextItemType); operand1 = visitor.typeCheck(operand1, contextItemType); SequenceType atomicType = SequenceType.OPTIONAL_ATOMIC; RoleLocator role0 = new RoleLocator(RoleLocator.BINARY_EXPR, Token.tokens[operator], 0); //role0.setSourceLocator(this); operand0 = TypeChecker.staticTypeCheck(operand0, atomicType, false, role0, visitor); final ItemType itemType0 = operand0.getItemType(th); if (itemType0 instanceof EmptySequenceTest) { return new Literal(EmptySequence.getInstance()); } AtomicType type0 = (AtomicType) itemType0.getPrimitiveItemType(); if (type0.getFingerprint() == StandardNames.XS_UNTYPED_ATOMIC) { operand0 = new UntypedAtomicConverter(operand0, BuiltInAtomicType.DOUBLE, true); type0 = BuiltInAtomicType.DOUBLE; } else if (/*!(operand0 instanceof UntypedAtomicConverter)*/ (operand0.getSpecialProperties()&StaticProperty.NOT_UNTYPED) == 0 && th.relationship(type0, BuiltInAtomicType.UNTYPED_ATOMIC) != TypeHierarchy.DISJOINT) { operand0 = new UntypedAtomicConverter(operand0, BuiltInAtomicType.DOUBLE, false); type0 = (AtomicType)operand0.getItemType(th); } // System.err.println("First operand"); operand0.display(10); RoleLocator role1 = new RoleLocator(RoleLocator.BINARY_EXPR, Token.tokens[operator], 1); //role1.setSourceLocator(this); operand1 = TypeChecker.staticTypeCheck(operand1, atomicType, false, role1, visitor); final ItemType itemType1 = operand1.getItemType(th); if (itemType1 instanceof EmptySequenceTest) { return new Literal(EmptySequence.getInstance()); } AtomicType type1 = (AtomicType)itemType1.getPrimitiveItemType(); if (type1.getFingerprint() == StandardNames.XS_UNTYPED_ATOMIC) { operand1 = new UntypedAtomicConverter(operand1, BuiltInAtomicType.DOUBLE, true); type1 = BuiltInAtomicType.DOUBLE; } else if (/*!(operand1 instanceof UntypedAtomicConverter) &&*/ (operand1.getSpecialProperties()&StaticProperty.NOT_UNTYPED) == 0 && th.relationship(type1, BuiltInAtomicType.UNTYPED_ATOMIC) != TypeHierarchy.DISJOINT) { operand1 = new UntypedAtomicConverter(operand1, BuiltInAtomicType.DOUBLE, false); type1 = (AtomicType)operand1.getItemType(th); } if (operand0 != oldOp0) { adoptChildExpression(operand0); } if (operand1 != oldOp1) { adoptChildExpression(operand1); } if (Literal.isEmptySequence(operand0) || Literal.isEmptySequence(operand1)) { return new Literal(EmptySequence.getInstance()); } if (type0.isExternalType() || type1.isExternalType()) { XPathException de = new XPathException("Arithmetic operators are not defined for external objects"); de.setLocator(this); de.setErrorCode("XPTY0004"); throw de; } if (operator == Token.NEGATE) { if (operand1 instanceof Literal && ((Literal)operand1).getValue() instanceof NumericValue) { NumericValue nv = (NumericValue)((Literal)operand1).getValue(); return new Literal(nv.negate()); } else { NegateExpression ne = new NegateExpression(operand1); ne.setBackwardsCompatible(false); return visitor.typeCheck(ne, contextItemType); } } // Get a calculator to implement the arithmetic operation. If the types are not yet specifically known, // we allow this to return an "ANY" calculator which defers the decision. However, we only allow this if // at least one of the operand types is AnyAtomicType or (otherwise unspecified) numeric. boolean mustResolve = !(type0.equals(BuiltInAtomicType.ANY_ATOMIC) || type1.equals(BuiltInAtomicType.ANY_ATOMIC) || type0.equals(BuiltInAtomicType.NUMERIC) || type1.equals(BuiltInAtomicType.NUMERIC)); calculator = Calculator.getCalculator( type0.getFingerprint(), type1.getFingerprint(), mapOpCode(operator), mustResolve); if (calculator == null) { XPathException de = new XPathException("Arithmetic operator is not defined for arguments of types (" + type0.getDescription() + ", " + type1.getDescription() + ")"); de.setLocator(this); de.setErrorCode("XPTY0004"); throw de; } try { if ((operand0 instanceof Literal) && (operand1 instanceof Literal)) { return new Literal(Value.asValue(evaluateItem(visitor.getStaticContext().makeEarlyEvaluationContext()))); } } catch (XPathException err) { // if early evaluation fails, suppress the error: the value might // not be needed at run-time, or it might be due to context such as the implicit timezone // not being available yet } return this; } /** * Copy an expression. This makes a deep copy. * * @return the copy of the original expression */ public Expression copy() { ArithmeticExpression ae = new ArithmeticExpression(operand0.copy(), operator, operand1.copy()); ae.calculator = calculator; return ae; } /** * Static method to apply arithmetic to two values * @param value0 the first value * @param operator the operator as denoted in the Calculator class, for example {@link Calculator#PLUS} * @param value1 the second value * @param context the XPath dynamic evaluation context * @return the result of the arithmetic operation */ public static AtomicValue compute(AtomicValue value0, int operator, AtomicValue value1, XPathContext context) throws XPathException { int p0 = value0.getPrimitiveType().getFingerprint(); int p1 = value1.getPrimitiveType().getFingerprint(); Calculator calculator = Calculator.getCalculator(p0, p1, operator, false); return calculator.compute(value0, value1, context); } /** * Map operator codes from those in the Token class to those in the Calculator class * @param op an operator denoted by a constant in the {@link Token} class, for example {@link Token#PLUS} * @return an operator denoted by a constant defined in the {@link Calculator} class, for example * {@link Calculator#PLUS} */ public static int mapOpCode(int op) { switch (op) { case Token.PLUS: return Calculator.PLUS; case Token.MINUS: case Token.NEGATE: return Calculator.MINUS; case Token.MULT: return Calculator.TIMES; case Token.DIV: return Calculator.DIV; case Token.IDIV: return Calculator.IDIV; case Token.MOD: return Calculator.MOD; default: throw new IllegalArgumentException(); } } /** * Determine the data type of the expression, insofar as this is known statically * @param th the type hierarchy cache * @return the atomic type of the result of this arithmetic expression */ public ItemType getItemType(TypeHierarchy th) { if (calculator == null) { return BuiltInAtomicType.ANY_ATOMIC; // type is not known statically } else { ItemType t1 = operand0.getItemType(th); if (!(t1 instanceof AtomicType)) { t1 = t1.getAtomizedItemType(); } ItemType t2 = operand1.getItemType(th); if (!(t2 instanceof AtomicType)) { t2 = t2.getAtomizedItemType(); } ItemType resultType = calculator.getResultType((AtomicType) t1.getPrimitiveItemType(), (AtomicType) t2.getPrimitiveItemType()); if (resultType.equals(BuiltInAtomicType.ANY_ATOMIC)) { // there are a few special cases where we can do better. For example, given X+1, where the type of X // is unknown, we can still infer that the result is numeric. (Not so for X*2, however, where it could // be a duration) if ((operator == Token.PLUS || operator == Token.MINUS) && (th.isSubType(t2, BuiltInAtomicType.NUMERIC) || th.isSubType(t1, BuiltInAtomicType.NUMERIC))) { resultType = BuiltInAtomicType.NUMERIC; } } return resultType; } } /** * Evaluate the expression. */ public Item evaluateItem(XPathContext context) throws XPathException { AtomicValue v0 = (AtomicValue) operand0.evaluateItem(context); if (v0 == null) { return null; } AtomicValue v1 = (AtomicValue) operand1.evaluateItem(context); if (v1 == null) { return null; } try { return calculator.compute(v0, v1, context); } catch (XPathException e) { e.maybeSetLocation(this); e.maybeSetContext(context); throw e; } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/expr/SimpleExpression.java0000644000175000017500000002735611033112257022546 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.Controller; import net.sf.saxon.trace.ExpressionPresenter; import net.sf.saxon.value.Value; import net.sf.saxon.event.SequenceOutputter; import net.sf.saxon.event.PipelineConfiguration; import net.sf.saxon.om.*; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.Type; import net.sf.saxon.type.TypeHierarchy; import java.util.Arrays; import java.util.Iterator; /** * An abstract implementation of Expression designed to make it easy to implement new expressions, * in particular, expressions to support extension instructions. */ public abstract class SimpleExpression extends Expression { public static final Expression[] NO_ARGUMENTS = new Expression[0]; protected Expression[] arguments = NO_ARGUMENTS; /** * Constructor */ public SimpleExpression() { } /** * Set the immediate sub-expressions of this expression. * @param sub an array containing the sub-expressions of this expression */ public void setArguments(Expression[] sub) { arguments = sub; for (int i=0; i *

    This method is called after all references to functions and variables have been resolved * to the declaration of the function or variable, and after all type checking has been done.

    * * @param visitor an expression visitor * @param contextItemType the static type of "." at the point where this expression is invoked. * The parameter is set to null if it is known statically that the context item will be undefined. * If the type of the context item is not known statically, the argument is set to * {@link net.sf.saxon.type.Type#ITEM_TYPE} * @return the original expression, rewritten if appropriate to optimize execution * @throws XPathException if an error is discovered during this phase * (typically a type error) */ public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { Optimizer opt = visitor.getConfiguration().getOptimizer(); TypeHierarchy th = visitor.getConfiguration().getTypeHierarchy(); operand0 = visitor.optimize(operand0, contextItemType); operand1 = visitor.optimize(operand1, contextItemType); Value value0 = null; Value value1 = null; if (operand0 instanceof Literal) { value0 = ((Literal)operand0).getValue(); } if (operand1 instanceof Literal) { value1 = ((Literal)operand1).getValue(); } // evaluate the expression now if both arguments are constant if ((value0 != null) && (value1 != null)) { try { AtomicValue r = (AtomicValue)evaluateItem(visitor.getStaticContext().makeEarlyEvaluationContext()); //noinspection RedundantCast return Literal.makeLiteral(r == null ? (Value)EmptySequence.getInstance() : (Value)r); } catch (NoDynamicContextException e) { // early evaluation failed, typically because the implicit context isn't available. // Try again at run-time return this; } } // optimise count(x) eq 0 (or gt 0, ne 0, eq 0, etc) if (Aggregate.isCountFunction(operand0) && Literal.isAtomic(operand1)) { if (isZero(value1)) { if (operator == Token.FEQ || operator == Token.FLE) { // rewrite count(x)=0 as empty(x) Expression result = SystemFunction.makeSystemFunction( "empty", new Expression[]{((FunctionCall) operand0).argument[0]}); opt.trace("Rewrite count()=0 as:", result); return result; } else if (operator == Token.FNE || operator == Token.FGT) { // rewrite count(x)!=0, count(x)>0 as exists(x) Expression arg = ExpressionTool.unsorted(opt, ((FunctionCall)operand0).argument[0], false); Expression result = SystemFunction.makeSystemFunction("exists", new Expression[] {arg}); opt.trace("Rewrite count()>0 as:", result); return result; } else if (operator == Token.FGE) { // rewrite count(x)>=0 as true() return Literal.makeLiteral(BooleanValue.TRUE); } else { // singletonOperator == Token.FLT // rewrite count(x)<0 as false() return Literal.makeLiteral(BooleanValue.FALSE); } } else if (value1 instanceof Int64Value && (operator == Token.FGT || operator == Token.FGE)) { // rewrite count(x) gt n as exists(x[n+1]) // and count(x) ge n as exists(x[n]) long val = ((Int64Value) value1).longValue(); if (operator == Token.FGT) { val++; } FilterExpression filter = new FilterExpression(((FunctionCall) operand0).argument[0], Literal.makeLiteral(Int64Value.makeIntegerValue(val))); ExpressionTool.copyLocationInfo(this, filter); Expression result = SystemFunction.makeSystemFunction("exists", new Expression[]{filter}); opt.trace("Rewrite count()>=N as:", result); return result; } } // optimise (0 eq count(x)), etc if (Aggregate.isCountFunction(operand1) && isZero(value0)) { ValueComparison vc = new ValueComparison(operand1, Token.inverse(operator), operand0); ExpressionTool.copyLocationInfo(this, vc); return visitor.optimize(visitor.typeCheck(vc, contextItemType), contextItemType); } // optimise string-length(x) = 0, >0, !=0 etc if ((operand0 instanceof StringLength) && (((StringLength) operand0).getNumberOfArguments() == 1) && isZero(value1)) { Expression arg = (((StringLength)operand0).getArguments()[0]); switch (operator) { case Token.FEQ: case Token.FLE: return SystemFunction.makeSystemFunction("not", new Expression[]{arg}); case Token.FNE: case Token.FGT: return SystemFunction.makeSystemFunction("boolean", new Expression[]{arg}); case Token.FGE: return Literal.makeLiteral(BooleanValue.TRUE); case Token.FLT: return Literal.makeLiteral(BooleanValue.FALSE); } } // optimise (0 = string-length(x)), etc if ((operand1 instanceof StringLength) && (((StringLength) operand1).getNumberOfArguments() == 1) && isZero(value0)) { Expression arg = (((StringLength)operand1).getArguments()[0]); switch (operator) { case Token.FEQ: case Token.FGE: return SystemFunction.makeSystemFunction("not", new Expression[]{arg}); case Token.FNE: case Token.FLT: return SystemFunction.makeSystemFunction("boolean", new Expression[]{arg}); case Token.FLE: return Literal.makeLiteral(BooleanValue.TRUE); case Token.FGT: return Literal.makeLiteral(BooleanValue.FALSE); } } // optimise string="" etc // Note we can change S!="" to boolean(S) for cardinality zero-or-one, but we can only // change S="" to not(S) for cardinality exactly-one. int p0 = operand0.getItemType(th).getPrimitiveType(); if ((p0 == StandardNames.XS_STRING || p0 == StandardNames.XS_ANY_URI || p0 == StandardNames.XS_UNTYPED_ATOMIC) && operand1 instanceof Literal && ((Literal)operand1).getValue() instanceof StringValue && ((StringValue)((Literal)operand1).getValue()).isZeroLength() && comparer instanceof CodepointCollatingComparer) { switch (operator) { case Token.FNE: case Token.FGT: return SystemFunction.makeSystemFunction("boolean", new Expression[]{operand0}); case Token.FEQ: case Token.FLE: if (operand0.getCardinality() == StaticProperty.EXACTLY_ONE) { return SystemFunction.makeSystemFunction("not", new Expression[]{operand0}); } } } // optimize "" = string etc int p1 = operand1.getItemType(th).getPrimitiveType(); if ((p1 == StandardNames.XS_STRING || p1 == StandardNames.XS_ANY_URI || p1 == StandardNames.XS_UNTYPED_ATOMIC) && operand0 instanceof Literal && ((Literal)operand0).getValue() instanceof StringValue && ((StringValue)((Literal)operand0).getValue()).isZeroLength() && comparer instanceof CodepointCollatingComparer) { switch (operator) { case Token.FNE: case Token.FLT: return SystemFunction.makeSystemFunction("boolean", new Expression[]{operand1}); case Token.FEQ: case Token.FGE: if (operand1.getCardinality() == StaticProperty.EXACTLY_ONE) { return SystemFunction.makeSystemFunction("not", new Expression[]{operand1}); } } } // optimise [position()=last()] etc if ((operand0 instanceof Position) && (operand1 instanceof Last)) { switch (operator) { case Token.FEQ: case Token.FGE: IsLastExpression iletrue = new IsLastExpression(true); ExpressionTool.copyLocationInfo(this, iletrue); return iletrue; case Token.FNE: case Token.FLT: IsLastExpression ilefalse = new IsLastExpression(false); ExpressionTool.copyLocationInfo(this, ilefalse); return ilefalse; case Token.FGT: return Literal.makeLiteral(BooleanValue.FALSE); case Token.FLE: return Literal.makeLiteral(BooleanValue.TRUE); } } if ((operand0 instanceof Last) && (operand1 instanceof Position)) { switch (operator) { case Token.FEQ: case Token.FLE: IsLastExpression iletrue = new IsLastExpression(true); ExpressionTool.copyLocationInfo(this, iletrue); return iletrue; case Token.FNE: case Token.FGT: IsLastExpression ilefalse = new IsLastExpression(false); ExpressionTool.copyLocationInfo(this, ilefalse); return ilefalse; case Token.FLT: return Literal.makeLiteral(BooleanValue.FALSE); case Token.FGE: return Literal.makeLiteral(BooleanValue.TRUE); } } // optimize comparison against an integer constant if (value1 instanceof Int64Value && operand0.getCardinality() == StaticProperty.EXACTLY_ONE && th.isSubType(operand0.getItemType(th), BuiltInAtomicType.NUMERIC)) { return new CompareToIntegerConstant(operand0, operator, ((Int64Value)value1).longValue()); } if (value0 instanceof Int64Value && operand1.getCardinality() == StaticProperty.EXACTLY_ONE && th.isSubType(operand1.getItemType(th), BuiltInAtomicType.NUMERIC)) { return new CompareToIntegerConstant(operand1, Token.inverse(operator), ((Int64Value) value0).longValue()); } // optimize generate-id(X) = generate-id(Y) as "X is Y" // This construct is often used in XSLT 1.0 stylesheets. // Only do this if we know the arguments are singletons, because "is" doesn't // do first-value extraction. if (NamePart.isGenerateIdFunction(operand0) && NamePart.isGenerateIdFunction(operand1)) { FunctionCall f0 = (FunctionCall) operand0; FunctionCall f1 = (FunctionCall) operand1; if (!Cardinality.allowsMany(f0.argument[0].getCardinality()) && !Cardinality.allowsMany(f1.argument[0].getCardinality()) && (operator == Token.FEQ)) { IdentityComparison id = new IdentityComparison(f0.argument[0], Token.IS, f1.argument[0]); id.setGenerateIdEmulation(true); ExpressionTool.copyLocationInfo(this, id); return visitor.optimize(visitor.typeCheck(visitor.simplify(id), contextItemType), contextItemType); } } return this; } /** * Check whether this specific instance of the expression is negatable * * @return true if it is */ public boolean isNegatable(ExpressionVisitor visitor) { // Expression is not negatable if it might involve NaN TypeHierarchy th = visitor.getConfiguration().getTypeHierarchy(); return !maybeNaN(operand0, th) && !maybeNaN(operand1, th); } private boolean maybeNaN(Expression exp, TypeHierarchy th) { return th.relationship(exp.getItemType(th), BuiltInAtomicType.DOUBLE) != TypeHierarchy.DISJOINT || th.relationship(exp.getItemType(th), BuiltInAtomicType.FLOAT) != TypeHierarchy.DISJOINT; } /** * Return the negation of this value comparison: that is, a value comparison that returns true() * if and only if the original returns false(). The result must be the same as not(this) even in the * case where one of the operands is (). * @return the inverted comparison */ public Expression negate() { ValueComparison vc = new ValueComparison(operand0, Token.negate(operator), operand1); vc.comparer = comparer; if (resultWhenEmpty == null || resultWhenEmpty == BooleanValue.FALSE) { vc.resultWhenEmpty = BooleanValue.TRUE; } else { vc.resultWhenEmpty = BooleanValue.FALSE; } ExpressionTool.copyLocationInfo(this, vc); return vc; } /** * Test whether an expression is constant zero * @param v the value to be tested * @return true if the operand is the constant zero (of any numeric data type) */ private static boolean isZero(Value v) { return v instanceof NumericValue && ((NumericValue)v).compareTo(0) == 0; } /** * Copy an expression. This makes a deep copy. * * @return the copy of the original expression */ public Expression copy() { ValueComparison vc = new ValueComparison(operand0.copy(), operator, operand1.copy()); vc.comparer = comparer; vc.resultWhenEmpty = resultWhenEmpty; //vc.operand0MaybeUntyped = operand0MaybeUntyped; //vc.operand1MaybeUntyped = operand1MaybeUntyped; vc.needsRuntimeComparabilityCheck = needsRuntimeComparabilityCheck; return vc; } /** * Evaluate the effective boolean value of the expression * * @param context the given context for evaluation * @return a boolean representing the result of the comparison of the two operands */ public boolean effectiveBooleanValue(XPathContext context) throws XPathException { try { AtomicValue v0 = ((AtomicValue) operand0.evaluateItem(context)); if (v0 == null) { return (resultWhenEmpty == BooleanValue.TRUE); // normally false } // if (operand0MaybeUntyped && v0 instanceof UntypedAtomicValue) { // // commmented out 2007-12-03 - not really necessary? If not, can lose the untyped0MaybeUntyped variables // v0 = new StringValue(v0.getStringValueCS()); // } AtomicValue v1 = ((AtomicValue) operand1.evaluateItem(context)); if (v1 == null) { return (resultWhenEmpty == BooleanValue.TRUE); // normally false } // if (operand1MaybeUntyped && v1 instanceof UntypedAtomicValue) { // v1 = new StringValue(v1.getStringValueCS()); // } if (needsRuntimeComparabilityCheck && !Type.isComparable(v0.getPrimitiveType(), v1.getPrimitiveType(), Token.isOrderedOperator(operator))) { XPathException e2 = new XPathException("Cannot compare " + Type.displayTypeName(v0) + " to " + Type.displayTypeName(v1)); e2.setErrorCode("XPTY0004"); e2.setIsTypeError(true); throw e2; } return compare(v0, operator, v1, comparer.provideContext(context)); } catch (XPathException e) { // re-throw the exception with location information added e.maybeSetLocation(this); e.maybeSetContext(context); throw e; } catch (ClassCastException err) { throw new XPathException("CCE", this); } } /** * Compare two atomic values, using a specified operator and collation * * @param v0 the first operand * @param op the operator, as defined by constants such as {@link Token#FEQ} or * {@link Token#FLT} * @param v1 the second operand * @param collator the Collator to be used when comparing strings * @return the result of the comparison: -1 for LT, 0 for EQ, +1 for GT * @throws XPathException if the values are not comparable */ static boolean compare(AtomicValue v0, int op, AtomicValue v1, AtomicComparer collator) throws XPathException { if (v0.isNaN() || v1.isNaN()) { return (op == Token.FNE); } try { switch (op) { case Token.FEQ: return collator.comparesEqual(v0, v1); case Token.FNE: return !collator.comparesEqual(v0, v1); case Token.FGT: return collator.compareAtomicValues(v0, v1) > 0; case Token.FLT: return collator.compareAtomicValues(v0, v1) < 0; case Token.FGE: return collator.compareAtomicValues(v0, v1) >= 0; case Token.FLE: return collator.compareAtomicValues(v0, v1) <= 0; default: throw new UnsupportedOperationException("Unknown operator " + op); } } catch (ClassCastException err) { XPathException e2 = new XPathException("Cannot compare " + Type.displayTypeName(v0) + " to " + Type.displayTypeName(v1)); e2.setErrorCode("XPTY0004"); e2.setIsTypeError(true); throw e2; } } /** * Evaluate the expression in a given context * * @param context the given context for evaluation * @return a BooleanValue representing the result of the numeric comparison of the two operands, * or null representing the empty sequence */ public Item evaluateItem(XPathContext context) throws XPathException { try { AtomicValue v0 = (AtomicValue) operand0.evaluateItem(context); if (v0 == null) { return resultWhenEmpty; } // if (v0 instanceof UntypedAtomicValue) { // v0 = v0.convert(BuiltInAtomicType.STRING, true, context).asAtomic(); // } AtomicValue v1 = (AtomicValue) operand1.evaluateItem(context); if (v1 == null) { return resultWhenEmpty; } // if (v1 instanceof UntypedAtomicValue) { // v1 = v1.convert(BuiltInAtomicType.STRING, true, context).asAtomic(); // } if (needsRuntimeComparabilityCheck && !Type.isComparable(v0.getPrimitiveType(), v1.getPrimitiveType(), Token.isOrderedOperator(operator))) { XPathException e2 = new XPathException("Cannot compare " + Type.displayTypeName(v0) + " to " + Type.displayTypeName(v1)); e2.setErrorCode("XPTY0004"); e2.setIsTypeError(true); throw e2; } return BooleanValue.get(compare(v0, operator, v1, comparer.provideContext(context))); } catch (XPathException e) { // re-throw the exception with location information added e.maybeSetLocation(this); e.maybeSetContext(context); throw e; } } /** * Determine the data type of the expression * * @param th the type hierarchy cache * @return Type.BOOLEAN */ public ItemType getItemType(TypeHierarchy th) { return BuiltInAtomicType.BOOLEAN; } /** * Determine the static cardinality. */ public int computeCardinality() { if (resultWhenEmpty != null) { return StaticProperty.EXACTLY_ONE; } else { return super.computeCardinality(); } } protected String displayOperator() { return Token.tokens[operator] + (resultWhenEmpty == null ? "" : " (on empty return " + resultWhenEmpty + ')'); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/expr/LetExpression.java0000644000175000017500000006060511203037636022041 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.evpull.EventIterator; import net.sf.saxon.instruct.DocumentInstr; import net.sf.saxon.instruct.GlobalVariable; import net.sf.saxon.instruct.TailCall; import net.sf.saxon.instruct.TailCallReturner; import net.sf.saxon.om.Item; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.om.StructuredQName; import net.sf.saxon.om.ValueRepresentation; import net.sf.saxon.trace.ExpressionPresenter; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.SchemaType; import net.sf.saxon.type.TypeHierarchy; import net.sf.saxon.value.Cardinality; import net.sf.saxon.value.SequenceType; import java.util.List; import java.util.ArrayList; /** * A LetExpression is modelled on the XQuery syntax let $x := expr return expr. This syntax * is not available in the surface XPath language, but it is used internally in an optimized * expression tree. */ public class LetExpression extends Assignation implements TailCallReturner { // This integer holds an approximation to the number of times that the declared variable is referenced. // The value 1 means there is only one reference and it is not in a loop, which means that the value will // not be retained in memory. If there are multiple references or references within a loop, the value will // be a small integer > 1. The special value FILTERED indicates that there is a reference within a loop // in the form $x[predicate], which indicates that the value should potentially be indexable. int refCount; int evaluationMode = ExpressionTool.UNDECIDED; /** * Create a LetExpression */ public LetExpression() { //System.err.println("let"); } /** * Indicate that the variable bound by this let expression should be indexable * (because it is used in an appropriate filter expression) */ public void setIndexedVariable() { refCount = FilterExpression.FILTERED; } /** * Test whether the variable bound by this let expression should be indexable * @return true if the variable should be indexable */ public boolean isIndexedVariable() { return (refCount == FilterExpression.FILTERED); } /** * Get the (nominal) count of the number of references to this variable * @return zero if there are no references, one if there is a single reference that is not in * a loop, some higher number if there are multiple references (or a single reference in a loop), * or the special value @link RangeVariable#FILTERED} if there are any references * in filter expressions that require searching. */ public int getNominalReferenceCount() { return refCount; } /** * Register a variable reference that refers to the variable bound in this let expression * @param v the variable reference */ public void addReference(VariableReference v) { refCount++; } /** * Type-check the expression */ public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { // The order of events is critical here. First we ensure that the type of the // sequence expression is established. This is used to establish the type of the variable, // which in turn is required when type-checking the action part. sequence = visitor.typeCheck(sequence, contextItemType); RoleLocator role = new RoleLocator(RoleLocator.VARIABLE, getVariableQName(), 0); //role.setSourceLocator(this); sequence = TypeChecker.strictTypeCheck( sequence, requiredType, role, visitor.getStaticContext()); final TypeHierarchy th = visitor.getConfiguration().getTypeHierarchy(); final ItemType actualItemType = sequence.getItemType(th); refineTypeInformation(actualItemType, sequence.getCardinality(), (sequence instanceof Literal ? ((Literal) sequence).getValue() : null), sequence.getSpecialProperties(), visitor, this); action = visitor.typeCheck(action, contextItemType); return this; } /** * Determine whether this expression implements its own method for static type checking * * @return true - this expression has a non-trivial implementation of the staticTypeCheck() * method */ public boolean implementsStaticTypeCheck() { return true; } /** * Static type checking for let expressions is delegated to the expression itself, * and is performed on the "action" expression, to allow further delegation to the branches * of a conditional * @param req the required type * @param backwardsCompatible true if backwards compatibility mode applies * @param role the role of the expression in relation to the required type * @param visitor an expression visitor * @return the expression after type checking (perhaps augmented with dynamic type checking code) * @throws XPathException if failures occur, for example if the static type of one branch of the conditional * is incompatible with the required type */ public Expression staticTypeCheck(SequenceType req, boolean backwardsCompatible, RoleLocator role, ExpressionVisitor visitor) throws XPathException { action = TypeChecker.staticTypeCheck(action, req, backwardsCompatible, role, visitor); return this; } /** * Perform optimisation of an expression and its subexpressions. *

    *

    This method is called after all references to functions and variables have been resolved * to the declaration of the function or variable, and after all type checking has been done.

    * * @param visitor an expression visitor * @param contextItemType the static type of "." at the point where this expression is invoked. * The parameter is set to null if it is known statically that the context item will be undefined. * If the type of the context item is not known statically, the argument is set to * {@link net.sf.saxon.type.Type#ITEM_TYPE} * @return the original expression, rewritten if appropriate to optimize execution * @throws XPathException if an error is discovered during this phase * (typically a type error) */ public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { StaticContext env = visitor.getStaticContext(); Optimizer opt = visitor.getConfiguration().getOptimizer(); // if this is a construct of the form "let $j := EXP return $j" replace it with EXP // Remarkably, people do write this, and it can also be produced by previous rewrites // Note that type checks will already have been added to the sequence expression if (action instanceof VariableReference && ((VariableReference) action).getBinding() == this) { return visitor.optimize(sequence, contextItemType); } /** * Unless this has already been done, find and count the references to this variable */ // if this is an XSLT construct of the form text, try to replace // it by . This can be done if all the references to the variable use // its value as a string (rather than, say, as a node or as a boolean) if (sequence instanceof DocumentInstr && ((DocumentInstr) sequence).isTextOnly()) { if (allReferencesAreFlattened()) { sequence = ((DocumentInstr) sequence).getStringValueExpression(env); adoptChildExpression(sequence); } } if (!isIndexedVariable()) { refCount = ExpressionTool.getReferenceCount(action, this, false); } if (refCount == 0) { // variable is not used - no need to evaluate it Expression a = visitor.optimize(action, contextItemType); ExpressionTool.copyLocationInfo(this, a); return a; } if (refCount == 1 || sequence instanceof Literal) { // Either there's only one reference, and it's not in a loop. // Or the variable is bound to a constant value. // In these two cases we can inline the reference. // That is, we replace "let $x := SEQ return f($x)" by "f(SEQ)". Note, we rely on the fact // that any context-changing expression is treated as a loop, and generates a refCount greater // than one. replaceVariable(opt, sequence); return visitor.optimize(action, contextItemType); } int tries = 0; while (tries++ < 5) { Expression seq2 = visitor.optimize(sequence, contextItemType); if (seq2 == sequence) { break; } sequence = seq2; adoptChildExpression(sequence); visitor.resetStaticProperties(); } tries = 0; while (tries++ < 5) { Expression act2 = visitor.optimize(action, contextItemType); if (act2 == action) { break; } action = act2; adoptChildExpression(action); visitor.resetStaticProperties(); } // Try to promote any WHERE clause appearing within the LET expression Expression p = promoteWhereClause(null); if (p != null) { return p; } evaluationMode = (isIndexedVariable() ? ExpressionTool.MAKE_CLOSURE : ExpressionTool.lazyEvaluationMode(sequence)); return this; } /** * Determine whether all references to this variable are using the value either * (a) by atomizing it, or (b) by taking its string value. (This excludes usages * such as testing the existence of a node or taking the effective boolean value). * @return true if all references are known to atomize (or stringify) the value, * false otherwise. The value false may indicate "not known". */ private boolean allReferencesAreFlattened() { List references = new ArrayList(); ExpressionTool.gatherVariableReferences(action, this, references); for (int i=references.size()-1; i>=0; i--) { BindingReference bref = (BindingReference)references.get(i); if (bref instanceof VariableReference) { VariableReference ref = (VariableReference)bref; if (ref.isFlattened()) { // OK, it's a string context } else { return false; } } else { // it must be saxon:assign return false; } } return true; } /** * Check that any elements and attributes constructed or returned by this expression are acceptable * in the content model of a given complex type. It's always OK to say yes, since the check will be * repeated at run-time. The process of checking element and attribute constructors against the content * model of a complex type also registers the type of content expected of those constructors, so the * static validation can continue recursively. */ public void checkPermittedContents(SchemaType parentType, StaticContext env, boolean whole) throws XPathException { action.checkPermittedContents(parentType, env, whole); } /** * Iterate over the result of the expression to return a sequence of items */ public SequenceIterator iterate(XPathContext context) throws XPathException { // minimize stack consumption by evaluating nested LET expressions iteratively LetExpression let = this; while (true) { ValueRepresentation val = let.eval(context); context.setLocalVariable(let.getLocalSlotNumber(), val); if (let.action instanceof LetExpression) { let = (LetExpression) let.action; } else { break; } } return let.action.iterate(context); } /** * Iterate over the result of the expression to return a sequence of events */ public EventIterator iterateEvents(XPathContext context) throws XPathException { // minimize stack consumption by evaluating nested LET expressions iteratively LetExpression let = this; while (true) { ValueRepresentation val = let.eval(context); context.setLocalVariable(let.getLocalSlotNumber(), val); if (let.action instanceof LetExpression) { let = (LetExpression) let.action; } else { break; } } return let.action.iterateEvents(context); } /** * Evaluate the variable. * @param context the dynamic evaluation context * @return the result of evaluating the expression that is bound to the variable */ protected ValueRepresentation eval(XPathContext context) throws XPathException { if (evaluationMode == ExpressionTool.UNDECIDED) { evaluationMode = ExpressionTool.lazyEvaluationMode(sequence); } return ExpressionTool.evaluate(sequence, evaluationMode, context, refCount); } /** * Evaluate the expression as a singleton */ public Item evaluateItem(XPathContext context) throws XPathException { // minimize stack consumption by evaluating nested LET expressions iteratively LetExpression let = this; while (true) { ValueRepresentation val = let.eval(context); context.setLocalVariable(let.getLocalSlotNumber(), val); if (let.action instanceof LetExpression) { let = (LetExpression) let.action; } else { break; } } return let.action.evaluateItem(context); } /** * Process this expression as an instruction, writing results to the current * outputter */ public void process(XPathContext context) throws XPathException { // minimize stack consumption by evaluating nested LET expressions iteratively LetExpression let = this; while (true) { ValueRepresentation val = let.eval(context); context.setLocalVariable(let.getLocalSlotNumber(), val); if (let.action instanceof LetExpression) { let = (LetExpression) let.action; } else { break; } } let.action.process(context); } /** * Determine the data type of the items returned by the expression, if possible * * @param th the type hierarchy cache * @return one of the values Type.STRING, Type.BOOLEAN, Type.NUMBER, Type.NODE, * or Type.ITEM (meaning not known in advance) */ public ItemType getItemType(TypeHierarchy th) { return action.getItemType(th); } /** * Determine the static cardinality of the expression */ public int computeCardinality() { return action.getCardinality(); } /** * Get the static properties of this expression (other than its type). The result is * bit-signficant. These properties are used for optimizations. In general, if * property bit is set, it is true, but if it is unset, the value is unknown. */ public int computeSpecialProperties() { int props = action.getSpecialProperties(); int seqProps = sequence.getSpecialProperties(); if ((seqProps & StaticProperty.NON_CREATIVE) == 0) { props &= ~StaticProperty.NON_CREATIVE; } return props; } /** * Mark tail function calls */ public int markTailFunctionCalls(StructuredQName qName, int arity) { return ExpressionTool.markTailFunctionCalls(action, qName, arity); } /** * Promote this expression if possible */ public Expression promote(PromotionOffer offer) throws XPathException { Expression exp = offer.accept(this); if (exp != null) { return exp; } else { // pass the offer on to the sequence expression Expression seq2 = doPromotion(sequence, offer); if (seq2 != sequence) { // if we've extracted a global variable, it may need to be marked indexable if (seq2 instanceof VariableReference) { Binding b = ((VariableReference)seq2).getBinding(); if (b instanceof GlobalVariable) { ((GlobalVariable)b).setReferenceCount(refCount < 10 ? 10 : refCount); } } sequence = seq2; } if (offer.action == PromotionOffer.INLINE_VARIABLE_REFERENCES || offer.action == PromotionOffer.UNORDERED || offer.action == PromotionOffer.REPLACE_CURRENT || offer.action == PromotionOffer.EXTRACT_GLOBAL_VARIABLES) { action = doPromotion(action, offer); } else if (offer.action == PromotionOffer.RANGE_INDEPENDENT || offer.action == PromotionOffer.FOCUS_INDEPENDENT) { // Pass the offer to the action expression after adding the variable bound by this let expression, // so that a subexpression must depend on neither variable if it is to be promoted Binding[] savedBindingList = offer.bindingList; offer.bindingList = extendBindingList(offer.bindingList); action = doPromotion(action, offer); offer.bindingList = savedBindingList; } // if this results in the expression (let $x := $y return Z), replace all references to // to $x by references to $y in the Z part, and eliminate this LetExpression by // returning the action part. if (sequence instanceof VariableReference) { Binding b = ((VariableReference)sequence).getBinding(); if (b != null && !b.isAssignable()) { replaceVariable(offer.getOptimizer(), sequence); return action; } } // similarly, for (let $x := lazy($y) return Z) if (sequence instanceof LazyExpression && ((LazyExpression) sequence).getBaseExpression() instanceof VariableReference && !((VariableReference)((LazyExpression) sequence).getBaseExpression()).getBinding().isAssignable()) { replaceVariable(offer.getOptimizer(), ((LazyExpression) sequence).getBaseExpression()); return action; } return this; } } /** * Copy an expression. This makes a deep copy. * @return the copy of the original expression */ public Expression copy() { LetExpression let = new LetExpression(); let.setVariableQName(variableName); let.setRequiredType(requiredType); let.setSequence(sequence.copy()); Expression newAction = action.copy(); let.setAction(newAction); ExpressionTool.rebindVariableReferences(newAction, this, let); return let; } /** * Replace all references to the variable bound by this let expression, * that occur within the action expression, with the given expression * * @param opt The optimizer * @param seq the expression * @throws XPathException */ private void replaceVariable(Optimizer opt, Expression seq) throws XPathException { PromotionOffer offer2 = new PromotionOffer(opt); offer2.action = PromotionOffer.INLINE_VARIABLE_REFERENCES; offer2.bindingList = new Binding[] {this}; offer2.containingExpression = seq; action = doPromotion(action, offer2); if (offer2.accepted) { // there might be further references to the variable offer2.accepted = false; replaceVariable(opt, seq); } if (isIndexedVariable()) { if (seq instanceof VariableReference) { Binding newBinding = ((VariableReference) seq).getBinding(); if (newBinding instanceof LetExpression) { ((LetExpression) newBinding).setIndexedVariable(); } } else { // can happen as a result of other rewrites refCount = 10; } } } /** * ProcessLeavingTail: called to do the real work of this instruction. * The results of the instruction are written * to the current Receiver, which can be obtained via the Controller. * * @param context The dynamic context of the transformation, giving access to the current node, * the current variables, etc. * @return null if the instruction has completed execution; or a TailCall indicating * a function call or template call that is delegated to the caller, to be made after the stack has * been unwound so as to save stack space. */ public TailCall processLeavingTail(XPathContext context) throws XPathException { // minimize stack consumption by evaluating nested LET expressions iteratively LetExpression let = this; while (true) { ValueRepresentation val = let.eval(context); context.setLocalVariable(let.getLocalSlotNumber(), val); if (let.action instanceof LetExpression) { let = (LetExpression) let.action; } else { break; } } if (let.action instanceof TailCallReturner) { return ((TailCallReturner) let.action).processLeavingTail(context); } else { let.action.process(context); return null; } } /** * Evaluate an updating expression, adding the results to a Pending Update List. * The default implementation of this method, which is used for non-updating expressions, * throws an UnsupportedOperationException * * @param context the XPath dynamic evaluation context * @param pul the pending update list to which the results should be written */ public void evaluatePendingUpdates(XPathContext context, PendingUpdateList pul) throws XPathException { // minimize stack consumption by evaluating nested LET expressions iteratively LetExpression let = this; while (true) { ValueRepresentation val = let.eval(context); context.setLocalVariable(let.getLocalSlotNumber(), val); if (let.action instanceof LetExpression) { let = (LetExpression) let.action; } else { break; } } let.action.evaluatePendingUpdates(context, pul); } /** * Diagnostic print of expression structure. The abstract expression tree * is written to the supplied output destination. */ public void explain(ExpressionPresenter out) { out.startElement("let"); out.emitAttribute("variable", getVariableName()); out.emitAttribute("as", sequence.getItemType(out.getTypeHierarchy()).toString(out.getNamePool()) + Cardinality.getOccurrenceIndicator(sequence.getCardinality())); if (isIndexedVariable()) { out.emitAttribute("indexable", "true"); } out.startSubsidiaryElement("be"); sequence.explain(out); out.endSubsidiaryElement(); out.startSubsidiaryElement("return"); action.explain(out); out.endSubsidiaryElement(); out.endElement(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/expr/StaticProperty.java0000644000175000017500000002363011033112257022220 0ustar eugeneeugenepackage net.sf.saxon.expr; /** * This class contains constants identifying dependencies that an XPath expression * might have on its context. */ public abstract class StaticProperty { /** * Bit setting: Expression depends on current() item */ public static final int DEPENDS_ON_CURRENT_ITEM = 1; /** * Bit setting: Expression depends on context item */ public static final int DEPENDS_ON_CONTEXT_ITEM = 1<<1; /** * Bit setting: Expression depends on position() */ public static final int DEPENDS_ON_POSITION = 1<<2; /** * Bit setting: Expression depends on last() */ public static final int DEPENDS_ON_LAST = 1<<3; /** * Bit setting: Expression depends on the document containing the context node */ public static final int DEPENDS_ON_CONTEXT_DOCUMENT = 1<<4; /** * Bit setting: Expression depends on current-group() and/or current-grouping-key() */ public static final int DEPENDS_ON_CURRENT_GROUP = 1<<5; /** * Bit setting: Expression depends on regex-group() */ public static final int DEPENDS_ON_REGEX_GROUP = 1<<6; /** * Bit setting: Expression depends on local variables */ public static final int DEPENDS_ON_LOCAL_VARIABLES = 1<<7; /** * Bit setting: Expression depends on user-defined functions */ public static final int DEPENDS_ON_USER_FUNCTIONS = 1<<8; /** * Bit setting: Expression depends on assignable global variables */ public static final int DEPENDS_ON_ASSIGNABLE_GLOBALS = 1<<9; /** * Bit setting: Expression can't be evaluated at compile time for reasons other than the above */ public static final int DEPENDS_ON_RUNTIME_ENVIRONMENT = 1<<10; /** * Combination of bits representing dependencies on the XSLT context */ public static final int DEPENDS_ON_XSLT_CONTEXT = DEPENDS_ON_CURRENT_ITEM | DEPENDS_ON_CURRENT_GROUP | DEPENDS_ON_REGEX_GROUP | DEPENDS_ON_ASSIGNABLE_GLOBALS; /** * Combination of bits representing dependencies on the focus */ public static final int DEPENDS_ON_FOCUS = DEPENDS_ON_CONTEXT_ITEM | DEPENDS_ON_POSITION | DEPENDS_ON_LAST | DEPENDS_ON_CONTEXT_DOCUMENT; /** * Combination of bits representing dependencies on the focus, but excluding dependencies * on the current document */ public static final int DEPENDS_ON_NON_DOCUMENT_FOCUS = DEPENDS_ON_CONTEXT_ITEM | DEPENDS_ON_POSITION | DEPENDS_ON_LAST; /* * Bit set if an empty sequence is allowed */ public static final int ALLOWS_ZERO = 1<<13; /** * Bit set if a single value is allowed */ public static final int ALLOWS_ONE = 1<<14; /** * Bit set if multiple values are allowed */ public static final int ALLOWS_MANY = 1<<15; /** * Mask for all cardinality bits */ public static final int CARDINALITY_MASK = ALLOWS_ZERO | ALLOWS_ONE | ALLOWS_MANY; /** * Occurence indicator for "one or more" (+) */ public static final int ALLOWS_ONE_OR_MORE = ALLOWS_ONE | ALLOWS_MANY; /** * Occurence indicator for "zero or more" (*) */ public static final int ALLOWS_ZERO_OR_MORE = ALLOWS_ZERO | ALLOWS_ONE | ALLOWS_MANY; /** * Occurence indicator for "zero or one" (?) */ public static final int ALLOWS_ZERO_OR_ONE = ALLOWS_ZERO | ALLOWS_ONE; /** * Occurence indicator for "exactly one" (default occurrence indicator) */ public static final int EXACTLY_ONE = ALLOWS_ONE; /** * Occurence indicator when an empty sequence is required */ public static final int EMPTY = ALLOWS_ZERO; /** * Reduce the cardinality value to an integer in the range 0-7 * @param cardinality the result of calling getCardinality() on an expression * @return the cardinality code */ public static int getCardinalityCode(int cardinality) { return (cardinality & CARDINALITY_MASK) >> 13; } /** * Display the cardinality value as a string (used for diagnostics) * @param cardinality the cardinality as returned by getCardinality() applied to an expression * @return a string describing the cardinality */ public static String getCardinalityDescription(int cardinality) { int code = getCardinalityCode(cardinality); String[] names = { "not allowed", "exactly zero", "exactly one", "zero or one", "many", "zero or many", "one or more", "zero or more" }; return names[code]; } /** * Expression property: this bit is set by getProperties() in the case of * an expression whose item type is node, when the nodes in the result are * guaranteed all to be in the same document as the context node. For * expressions that return values other than nodes, the setting is undefined. */ public static final int CONTEXT_DOCUMENT_NODESET = 1<<16; /** * Expression property: this bit is set by getProperties() in the case of * an expression whose item type is node, when the nodes in the result are * in document order. */ public static final int ORDERED_NODESET = 1<<17; /** * Expression property: this bit is set by getProperties() in the case of * an expression that delivers items in the reverse of the correct order, when unordered * retrieval is requested. */ public static final int REVERSE_DOCUMENT_ORDER = 1<<18; /** * Expression property: this bit is set by getProperties() in the case of * an expression that delivers a set of nodes with the guarantee that no node in the * set will be an ancestor of any other. This property is useful in deciding whether the * results of a path expression are pre-sorted. The property is only used in the case where * the NATURALLY_SORTED property is true, so there is no point in setting it in other cases. */ public static final int PEER_NODESET = 1<<19; /** * Expression property: this bit is set by getProperties() in the case of * an expression that delivers a set of nodes with the guarantee that every node in the * result will be a descendant or self, or attribute or namespace, of the context node */ public static final int SUBTREE_NODESET = 1<<20; /** * Expression property: this bit is set by getProperties() in the case of * an expression that delivers a set of nodes with the guarantee that every node in the * result will be an attribute or namespace of the context node */ public static final int ATTRIBUTE_NS_NODESET = 1<<21; /** * Expression property: this bit is set in the case of an expression that will * never return newly created nodes, nor a value that depends on the identity * of newly created nodes (for example generate-id(new-node())). Expressions * that do create new nodes cannot be moved out of loops as this could cause * too few nodes to be created: for example if f() creates a new node, then * count(for $i in 1 to 5 return f()) must be 5. */ public static final int NON_CREATIVE = 1<<22; /** * Expression property: this bit is set in the case of an expression that delivers * a set of nodes that are all in the same document (not necessarily the same * document as the context node). */ public static final int SINGLE_DOCUMENT_NODESET = 1<<23; /** * Expression property: this bit indicates that an expression has (or might have) * side-effects. This property is applied to calls on extension functions and to * certain instructions such as xsl:result-document and xsl:message. */ public static final int HAS_SIDE_EFFECTS = 1<<24; /** * Expression property: this bit indicates that although the static type of the expression * permits untyped values, it is known that the value will not be untyped. */ public static final int NOT_UNTYPED = 1<<25; /** * Mask to select all the dependency bits */ public static final int DEPENDENCY_MASK = DEPENDS_ON_CONTEXT_DOCUMENT | DEPENDS_ON_CONTEXT_ITEM | DEPENDS_ON_CURRENT_GROUP | DEPENDS_ON_REGEX_GROUP | DEPENDS_ON_CURRENT_ITEM | DEPENDS_ON_FOCUS | DEPENDS_ON_LOCAL_VARIABLES | DEPENDS_ON_USER_FUNCTIONS | DEPENDS_ON_ASSIGNABLE_GLOBALS | DEPENDS_ON_RUNTIME_ENVIRONMENT | HAS_SIDE_EFFECTS; /** * Mask for "special properties": that is, all properties other than cardinality * and dependencies */ public static final int SPECIAL_PROPERTY_MASK = CONTEXT_DOCUMENT_NODESET | ORDERED_NODESET | REVERSE_DOCUMENT_ORDER | PEER_NODESET | SUBTREE_NODESET | ATTRIBUTE_NS_NODESET | SINGLE_DOCUMENT_NODESET | NON_CREATIVE | HAS_SIDE_EFFECTS | NOT_UNTYPED; // This class is not instantiated private StaticProperty() {} } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/expr/ItemMappingIterator.java0000644000175000017500000000667311033112257023160 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.om.Item; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.trans.XPathException; /** * ItemMappingIterator applies a mapping function to each item in a sequence. * The mapping function either returns a single item, or null (representing an * empty sequence). *

    * This is a specialization of the more general MappingIterator class, for use * in cases where a single input item never maps to a sequence of more than one * output item. */ public final class ItemMappingIterator implements SequenceIterator { private SequenceIterator base; private ItemMappingFunction action; private Item current = null; private int position = 0; /** * Construct an ItemMappingIterator that will apply a specified ItemMappingFunction to * each Item returned by the base iterator. * * @param base the base iterator * @param action the mapping function to be applied */ public ItemMappingIterator(SequenceIterator base, ItemMappingFunction action) { this.base = base; this.action = action; } public Item next() throws XPathException { while (true) { Item nextSource = base.next(); if (nextSource == null) { current = null; position = -1; return null; } // Call the supplied mapping function current = action.map(nextSource); if (current != null) { position++; return current; } // otherwise go round the loop to get the next item from the base sequence } } public Item current() { return current; } public int position() { return position; } public void close() { base.close(); } public SequenceIterator getAnother() throws XPathException { return new ItemMappingIterator(base.getAnother(), action); } /** * Get properties of this iterator, as a bit-significant integer. * * @return the properties of this iterator. This will be some combination of * properties such as {@link net.sf.saxon.om.SequenceIterator#GROUNDED}, * {@link net.sf.saxon.om.SequenceIterator#LAST_POSITION_FINDER}, * and {@link net.sf.saxon.om.SequenceIterator#LOOKAHEAD}. It is always * acceptable to return the value zero, indicating that there are no known special properties. * It is acceptable for the properties of the iterator to change depending on its state. */ public int getProperties() { return 0; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/expr/FilterIterator.java0000644000175000017500000002210311033112257022155 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.om.Item; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.trace.Location; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.*; /** * A FilterIterator filters an input sequence using a filter expression. Note that a FilterIterator * is not used where the filter is a constant number (PositionFilter is used for this purpose instead), * so this class does no optimizations for numeric predicates. */ public class FilterIterator implements SequenceIterator { protected SequenceIterator base; protected Expression filter; private int position = 0; private Item current = null; protected XPathContext filterContext; /** * Constructor * @param base An iteration of the items to be filtered * @param filter The expression defining the filter predicate * @param context The context in which the expression is being evaluated */ public FilterIterator(SequenceIterator base, Expression filter, XPathContext context) { this.base = base; this.filter = filter; filterContext = context.newMinorContext(); filterContext.setCurrentIterator(base); filterContext.setOriginatingConstructType(Location.FILTER_EXPRESSION); } /** * Get the next item if there is one */ public Item next() throws XPathException { current = getNextMatchingItem(); if (current == null) { position = -1; } else { position++; } return current; } /** * Get the next item in the base sequence that matches the filter predicate * if there is such an item, or null if not. * @return the next item that matches the predicate */ protected Item getNextMatchingItem() throws XPathException { while (true) { Item next = base.next(); if (next == null) { return null; } if (matches()) { return next; } } } /** * Determine whether the context item matches the filter predicate * @return true if the context item matches */ protected boolean matches() throws XPathException { // This code is carefully designed to avoid reading more items from the // iteration of the filter expression than are absolutely essential. // The code is almost identical to the code in ExpressionTool#effectiveBooleanValue // except for the handling of a numeric result SequenceIterator iterator = filter.iterate(filterContext); Item first = iterator.next(); if (first == null) { return false; } if (first instanceof NodeInfo) { return true; } else { if (first instanceof BooleanValue) { if (iterator.next() != null) { ExpressionTool.ebvError("sequence of two or more items starting with a boolean"); } return ((BooleanValue)first).getBooleanValue(); } else if (first instanceof StringValue) { if (iterator.next() != null) { ExpressionTool.ebvError("sequence of two or more items starting with a string"); } return (first.getStringValueCS().length()!=0); } else if (first instanceof Int64Value) { if (iterator.next() != null) { ExpressionTool.ebvError("sequence of two or more items starting with a numeric value"); } return ((Int64Value)first).longValue() == base.position(); } else if (first instanceof NumericValue) { if (iterator.next() != null) { ExpressionTool.ebvError("sequence of two or more items starting with a numeric value"); } return ((NumericValue)first).compareTo(base.position()) == 0; } else { ExpressionTool.ebvError("sequence starting with an atomic value other than a boolean, number, or string"); return false; } } } public Item current() { return current; } public int position() { return position; } public void close() { base.close(); } /** * Get another iterator to return the same nodes */ public SequenceIterator getAnother() throws XPathException { return new FilterIterator(base.getAnother(), filter, filterContext); } /** * Get properties of this iterator, as a bit-significant integer. * * @return the properties of this iterator. This will be some combination of * properties such as {@link SequenceIterator#GROUNDED}, {@link SequenceIterator#LAST_POSITION_FINDER}, * and {@link SequenceIterator#LOOKAHEAD}. It is always * acceptable to return the value zero, indicating that there are no known special properties. * It is acceptable for the properties of the iterator to change depending on its state. */ public int getProperties() { return 0; } /** * Subclass to handle the common special case where it is statically known * that the filter cannot return a numeric value */ public static final class NonNumeric extends FilterIterator { /** * Create a FilterIterator for the situation where it is known that the filter * expression will never evaluate to a number value. For this case we can simply * use the effective boolean value of the predicate * @param base iterator over the sequence to be filtered * @param filter the filter expression * @param context the current context (for evaluating the filter expression as a whole). * A new context will be created to evaluate the predicate. */ public NonNumeric(SequenceIterator base, Expression filter, XPathContext context) { super(base, filter, context); } /** * Determine whether the context item matches the filter predicate */ protected boolean matches() throws XPathException { return filter.effectiveBooleanValue(filterContext); } /** * Get another iterator to return the same nodes */ public SequenceIterator getAnother() throws XPathException { return new FilterIterator.NonNumeric(base.getAnother(), filter, filterContext); } } /** * Subclass to support the extension function saxon:leading, which terminates * the iteration at the first item whose predicate is false */ public static final class Leading extends FilterIterator { /** * Create a FilterIterate that terminates at the first item for which the predicate * evaluates to false * @param base iterator over the sequence to be filtered * @param filter the filter expression - always evaluated as a boolean * @param context the outer context for the filter expression as a whole; a new * context will be created for evaluating the predicate */ public Leading(SequenceIterator base, Expression filter, XPathContext context) { super(base, filter, context); } /** * Determine whether the context item matches the filter predicate */ protected boolean matches() throws XPathException { return filter.effectiveBooleanValue(filterContext); } /** * Get the next node that matches the filter predicate if there is one */ protected Item getNextMatchingItem() throws XPathException { Item next = base.next(); if (next == null) { return null; } if (matches()) { return next; } else { // terminate the iteration on the first non-match return null; } } /** * Get another iterator to return the same nodes */ public SequenceIterator getAnother() throws XPathException { return new FilterIterator.Leading(base.getAnother(), filter, filterContext); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/expr/Negatable.java0000644000175000017500000000240711033112257021105 0ustar eugeneeugenepackage net.sf.saxon.expr; /** * This interface is implemented by expressions that returns a boolean value, and returns an expression * whose result is the negated boolean value */ public interface Negatable { /** * Check whether this specific instance of the expression is negatable * @return true if it is */ public boolean isNegatable(ExpressionVisitor visitor); /** * Create an expression that returns the negation of this expression * @return the negated expression * @throws IllegalOperationException if isNegatable() returns false */ public Expression negate(); } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/expr/PendingUpdateList.java0000644000175000017500000000327311033112257022610 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.trans.XPathException; import java.util.Set; /** * A PendingUpdateList is created by updating expressions in XQuery Update. * *

    The implementation of this interface is in Saxon-SA.

    */ public interface PendingUpdateList { /** * Apply the pending updates * @param context the XPath dynamic evaluation context * @param validationMode the revalidation mode from the static context * @throws XPathException */ void apply(XPathContext context, int validationMode) throws XPathException; /** * Get the root nodes of the trees that are affected by updates in the pending update list * @return the root nodes of affected trees, as a Set */ Set getAffectedTrees(); /** * Add a put() action to the pending update list * @param node (the first argument of put()) * @param uri (the second argument of put()) */ void addPutAction(NodeInfo node, String uri) throws XPathException; } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/expr/ErrorIterator.java0000644000175000017500000001174711033112257022035 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.om.Item; import net.sf.saxon.trans.XPathException; /** * A SequenceIterator that throws an exception as soon as its next() method is called. Used when * the method that returns the iterator isn't allowed to throw a checked exception itself. */ public class ErrorIterator implements SequenceIterator { private XPathException exception; public ErrorIterator(XPathException exception) { this.exception = exception; } /** * Get the next item in the sequence. This method changes the state of the * iterator, in particular it affects the result of subsequent calls of * position() and current(). * * @return the next item, or null if there are no more items. Once a call * on next() has returned null, no further calls should be made. The preferred * action for an iterator if subsequent calls on next() are made is to return * null again, and all implementations within Saxon follow this rule. * @throws net.sf.saxon.trans.XPathException * if an error occurs retrieving the next item * @since 8.4 */ public Item next() throws XPathException { throw exception; } /** * Get the current value in the sequence (the one returned by the * most recent call on next()). This will be null before the first * call of next(). This method does not change the state of the iterator. * * @return the current item, the one most recently returned by a call on * next(). Returns null if next() has not been called, or if the end * of the sequence has been reached. * @since 8.4 */ public Item current() { return null; } /** * Get the current position. This will usually be zero before the first call * on next(), otherwise it will be the number of times that next() has * been called. Once next() has returned null, the preferred action is * for subsequent calls on position() to return -1, but not all existing * implementations follow this practice. (In particular, the EmptyIterator * is stateless, and always returns 0 as the value of position(), whether * or not next() has been called.) *

    * This method does not change the state of the iterator. * * @return the current position, the position of the item returned by the * most recent call of next(). This is 1 after next() has been successfully * called once, 2 after it has been called twice, and so on. If next() has * never been called, the method returns zero. If the end of the sequence * has been reached, the value returned will always be <= 0; the preferred * value is -1. * @since 8.4 */ public int position() { return 0; } public void close() { } /** * Get another SequenceIterator that iterates over the same items as the original, * but which is repositioned at the start of the sequence. *

    * This method allows access to all the items in the sequence without disturbing the * current position of the iterator. Internally, its main use is in evaluating the last() * function. *

    * This method does not change the state of the iterator. * * @return a SequenceIterator that iterates over the same items, * positioned before the first item * @throws net.sf.saxon.trans.XPathException * if any error occurs * @since 8.4 */ public SequenceIterator getAnother() throws XPathException { return this; } /** * Get properties of this iterator, as a bit-significant integer. * * @return the properties of this iterator. This will be some combination of * properties such as {@link #GROUNDED}, {@link #LAST_POSITION_FINDER}, * and {@link #LOOKAHEAD}. It is always * acceptable to return the value zero, indicating that there are no known special properties. * It is acceptable for the properties of the iterator to change depending on its state. * @since 8.6 */ public int getProperties() { return 0; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/expr/RangeExpression.java0000644000175000017500000001433111253655466022360 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.om.EmptyIterator; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.BuiltInAtomicType; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.TypeHierarchy; import net.sf.saxon.value.*; /** * A RangeExpression is an expression that represents an integer sequence as * a pair of end-points (for example "x to y"). * If the end-points are equal, the sequence is of length one. *

    From Saxon 7.8, the sequence must be ascending; if the end-point is less * than the start-point, an empty sequence is returned. This is to allow * expressions of the form "for $i in 1 to count($seq) return ...."

    */ public class RangeExpression extends BinaryExpression { /** * Construct a RangeExpression * @param start expression that computes the start of the range * @param op represents the operator "to", needed only because this class is a subclass of * BinaryExpression which needs an operator * @param end expression that computes the end of the range */ public RangeExpression(Expression start, int op, Expression end) { super(start, op, end); } /** * Type-check the expression */ public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { operand0 = visitor.typeCheck(operand0, contextItemType); operand1 = visitor.typeCheck(operand1, contextItemType); boolean backCompat = visitor.getStaticContext().isInBackwardsCompatibleMode(); RoleLocator role0 = new RoleLocator(RoleLocator.BINARY_EXPR, "to", 0); //role0.setSourceLocator(this); operand0 = TypeChecker.staticTypeCheck( operand0, SequenceType.OPTIONAL_INTEGER, backCompat, role0, visitor); RoleLocator role1 = new RoleLocator(RoleLocator.BINARY_EXPR, "to", 1); //role1.setSourceLocator(this); operand1 = TypeChecker.staticTypeCheck( operand1, SequenceType.OPTIONAL_INTEGER, backCompat, role1, visitor); return makeConstantRange(); } /** * Perform optimisation of an expression and its subexpressions. *

    *

    This method is called after all references to functions and variables have been resolved * to the declaration of the function or variable, and after all type checking has been done.

    * * @param visitor an expression visitor * @param contextItemType the static type of "." at the point where this expression is invoked. * The parameter is set to null if it is known statically that the context item will be undefined. * If the type of the context item is not known statically, the argument is set to * {@link net.sf.saxon.type.Type#ITEM_TYPE} * @return the original expression, rewritten if appropriate to optimize execution * @throws XPathException if an error is discovered during this phase * (typically a type error) */ public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { operand0 = visitor.optimize(operand0, contextItemType); operand1 = visitor.optimize(operand1, contextItemType); return makeConstantRange(); } private Expression makeConstantRange() { if (operand0 instanceof Literal && operand1 instanceof Literal) { Value v0 = ((Literal)operand0).getValue(); Value v1 = ((Literal)operand1).getValue(); if (v0 instanceof Int64Value && v1 instanceof Int64Value) { long i0 = ((Int64Value)v0).longValue(); long i1 = ((Int64Value)v1).longValue(); Literal result; if (i0 > i1) { result = Literal.makeEmptySequence(); } else if (i0 == i1) { result = Literal.makeLiteral(Int64Value.makeIntegerValue(i0)); } else { result = Literal.makeLiteral(new IntegerRange(i0, i1)); } ExpressionTool.copyLocationInfo(this, result); return result; } } return this; } /** * Get the data type of the items returned * @param th the type hierarchy cache */ public ItemType getItemType(TypeHierarchy th) { return BuiltInAtomicType.INTEGER; } /** * Determine the static cardinality */ public int computeCardinality() { return StaticProperty.ALLOWS_ZERO_OR_MORE; } /** * Copy an expression. This makes a deep copy. * * @return the copy of the original expression */ public Expression copy() { return new RangeExpression(operand0.copy(), operator, operand1.copy()); } /** * Return an iteration over the sequence */ public SequenceIterator iterate(XPathContext context) throws XPathException { AtomicValue av1 = (AtomicValue)operand0.evaluateItem(context); if (av1 == null) { return EmptyIterator.getInstance(); } NumericValue v1 = (NumericValue)av1; AtomicValue av2 = (AtomicValue)operand1.evaluateItem(context); if (av2 == null) { return EmptyIterator.getInstance(); } NumericValue v2 = (NumericValue)av2; if (v1.compareTo(v2) > 0) { return EmptyIterator.getInstance(); } return new RangeIterator(v1.longValue(), v2.longValue()); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/expr/ComparisonExpression.java0000644000175000017500000000330111033112257023407 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.sort.AtomicComparer; /** * Interface implemented by expressions that perform a comparison */ public interface ComparisonExpression { /** * Get the AtomicComparer used to compare atomic values. This encapsulates any collation that is used */ public AtomicComparer getAtomicComparer(); /** * Get the primitive (singleton) operator used: one of Token.FEQ, Token.FNE, Token.FLT, Token.FGT, * Token.FLE, Token.FGE */ public int getSingletonOperator(); /** * Get the two operands of the comparison */ public Expression[] getOperands(); /** * Determine whether untyped atomic values should be converted to the type of the other operand * @return true if untyped values should be converted to the type of the other operand, false if they * should be converted to strings. */ public boolean convertsUntypedToOther(); } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. //saxonb-9.1.0.8/bj/net/sf/saxon/expr/SlashExpression.java0000644000175000017500000004430611033112257022361 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.functions.SystemFunction; import net.sf.saxon.om.EmptyIterator; import net.sf.saxon.om.Item; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.pattern.AnyNodeTest; import net.sf.saxon.sort.DocumentOrderIterator; import net.sf.saxon.sort.DocumentSorter; import net.sf.saxon.sort.GlobalOrderComparer; import net.sf.saxon.trace.ExpressionPresenter; import net.sf.saxon.trace.Location; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.BuiltInAtomicType; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.Type; import net.sf.saxon.type.TypeHierarchy; import net.sf.saxon.value.AtomicValue; import net.sf.saxon.value.Cardinality; import net.sf.saxon.value.SequenceType; import javax.xml.transform.SourceLocator; import java.util.Iterator; /** * A slash expression is any expression using the binary slash operator "/". The parser initially generates a slash * expression for all occurrences of the binary "/" operator. Subsequently, as a result of type inferencing, the * majority of slash expressions will be rewritten as instances of PathExpression (returning nodes) or * AtomicMappingExpressions (returning atomic values). However, in the rare case where it is not possible to determine * statically whether the rh operand returns nodes or atomic values, instances of this class may need to be interpreted * directly at run time. */ public class SlashExpression extends Expression implements ContextMappingFunction { Expression start; Expression step; /** * Constructor * @param start The left hand operand (which must always select a sequence of nodes). * @param step The step to be followed from each node in the start expression to yield a new * sequence; this may return either nodes or atomic values (but not a mixture of the two) */ public SlashExpression(Expression start, Expression step) { this.start = start; this.step = step; setStartExpression(start); setStepExpression(step); } protected void setStartExpression(Expression start2) { if (start != start2) { start = start2; adoptChildExpression(start); } } protected void setStepExpression(Expression step2) { if (step != step2) { step = step2; adoptChildExpression(step); } } /** * Static factory method, allowing early instantiation of a subclass if the type of the step expression * is already known */ public static SlashExpression makeSlashExpression(Expression start, Expression step, TypeHierarchy th) { ItemType itemType = step.getItemType(th); if (th.isSubType(itemType, AnyNodeTest.getInstance())) { return new PathExpression(start, step); } else if (th.isSubType(itemType, BuiltInAtomicType.ANY_ATOMIC)) { return new AtomicMappingExpression(start, step); } else { return new SlashExpression(start, step); } } /** * Get the start expression (the left-hand operand) * @return the first operand */ public Expression getStartExpression() { return start; } /** * Get the step expression (the right-hand operand) * @return the second operand */ public Expression getStepExpression() { return step; } /** * Determine whether this expression is capable (as far as static analysis is concerned) * of returning a mixture of nodes and atomic values. If so, this needs to be prevented * at run time * @return true if the static type allows both nodes and atomic values */ public boolean isHybrid() { return true; } /** * Simplify an expression * @return the simplified expression * @param visitor the expression visitor */ public Expression simplify(ExpressionVisitor visitor) throws XPathException { setStartExpression(visitor.simplify(start)); setStepExpression(visitor.simplify(step)); // if the start expression is an empty sequence, then the whole PathExpression is empty if (Literal.isEmptySequence(start)) { return start; } // if the simplified Step is an empty sequence, then the whole PathExpression is empty if (Literal.isEmptySequence(step)) { return step; } // the expression /.. is sometimes used to represent the empty node-set. Applying this simplification // now avoids generating warnings for this case. if (start instanceof RootExpression && step instanceof ParentNodeExpression) { return Literal.makeEmptySequence(); } return this; } /** * Determine the data type of the items returned by this exprssion * @return the type of the step * @param th the type hierarchy cache */ public final ItemType getItemType(TypeHierarchy th) { return step.getItemType(th); } /** * Type-check the expression */ public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { final TypeHierarchy th = visitor.getConfiguration().getTypeHierarchy(); Expression start2 = visitor.typeCheck(start, contextItemType); // The first operand must be of type node()* RoleLocator role0 = new RoleLocator(RoleLocator.BINARY_EXPR, "/", 0); role0.setErrorCode("XPTY0019"); setStartExpression( TypeChecker.staticTypeCheck(start2, SequenceType.NODE_SEQUENCE, false, role0, visitor)); // Now check the second operand setStepExpression(visitor.typeCheck(step, start.getItemType(th))); // We distinguish three cases for the second operand: either it is known statically to deliver // nodes only (a traditional path expression), or it is known statically to deliver atomic values // only (a simple mapping expression), or we don't yet know. ItemType stepType = step.getItemType(th); if (th.isSubType(stepType, Type.NODE_TYPE)) { if ((step.getSpecialProperties() & StaticProperty.NON_CREATIVE) != 0) { // A traditional path expression // We don't need the operands to be sorted; any sorting that's needed // will be done at the top level Optimizer opt = visitor.getConfiguration().getOptimizer(); start2 = ExpressionTool.unsorted(opt, start, false); Expression step2 = ExpressionTool.unsorted(opt, step, false); PathExpression path = new PathExpression(start2, step2); ExpressionTool.copyLocationInfo(this, path); Expression sortedPath = path.addDocumentSorter(); ExpressionTool.copyLocationInfo(this, sortedPath); sortedPath = sortedPath.simplify(visitor); return sortedPath.typeCheck(visitor, contextItemType); } // Decide whether the result needs to be wrapped in a sorting // expression to deliver the results in document order int props = getSpecialProperties(); if ((props & StaticProperty.ORDERED_NODESET) != 0) { return this; } else if ((props & StaticProperty.REVERSE_DOCUMENT_ORDER) != 0) { return SystemFunction.makeSystemFunction("reverse", new Expression[]{this}); } else { return new DocumentSorter(this); } } else if (stepType.isAtomicType()) { // This is a simple mapping expression: a/b where b returns atomic values AtomicMappingExpression ame = new AtomicMappingExpression(start, step); ExpressionTool.copyLocationInfo(this, ame); return visitor.typeCheck(visitor.simplify(ame), contextItemType); } else { // This is a hybrid mapping expression, one where we don't know the type of the step // (and therefore, we don't know whether sorting into document order is required) until run-time return this; } } public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { TypeHierarchy th = visitor.getConfiguration().getTypeHierarchy(); setStartExpression(visitor.optimize(start, contextItemType)); setStepExpression(step.optimize(visitor, start.getItemType(th))); return promoteFocusIndependentSubexpressions(visitor, contextItemType); } /** * If any subexpressions within the step are not dependent on the focus, * and if they are not "creative" expressions (expressions that can create new nodes), then * promote them: this causes them to be evaluated once, outside the path expression * @param visitor the expression visitor * @param contextItemType the type of the context item for evaluating the start expression * @return the rewritten expression, or the original expression if no rewrite was possible */ protected Expression promoteFocusIndependentSubexpressions( ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { Optimizer opt = visitor.getConfiguration().getOptimizer(); PromotionOffer offer = new PromotionOffer(opt); offer.action = PromotionOffer.FOCUS_INDEPENDENT; offer.promoteDocumentDependent = (start.getSpecialProperties() & StaticProperty.CONTEXT_DOCUMENT_NODESET) != 0; offer.containingExpression = this; setStepExpression(doPromotion(step, offer)); visitor.resetStaticProperties(); if (offer.containingExpression != this) { offer.containingExpression = visitor.optimize(visitor.typeCheck(offer.containingExpression, contextItemType), contextItemType); return offer.containingExpression; } return this; } /** * Promote this expression if possible */ public Expression promote(PromotionOffer offer) throws XPathException { Expression exp = offer.accept(this); if (exp != null) { return exp; } else { setStartExpression(doPromotion(start, offer)); if (offer.action == PromotionOffer.INLINE_VARIABLE_REFERENCES || offer.action == PromotionOffer.REPLACE_CURRENT) { // Don't pass on other requests. We could pass them on, but only after augmenting // them to say we are interested in subexpressions that don't depend on either the // outer context or the inner context. setStepExpression(doPromotion(step, offer)); } return this; } } /** * Get the immediate subexpressions of this expression */ public Iterator iterateSubExpressions() { return new PairIterator(start, step); } /** * Given an expression that is an immediate child of this expression, test whether * the evaluation of the parent expression causes the child expression to be * evaluated repeatedly * @param child the immediate subexpression * @return true if the child expression is evaluated repeatedly */ public boolean hasLoopingSubexpression(Expression child) { return child == step; } /** * Replace one subexpression by a replacement subexpression * @param original the original subexpression * @param replacement the replacement subexpression * @return true if the original subexpression is found */ public boolean replaceSubExpression(Expression original, Expression replacement) { boolean found = false; if (start == original) { setStartExpression(replacement); found = true; } if (step == original) { setStepExpression(replacement); found = true; } return found; } /** * Determine which aspects of the context the expression depends on. The result is * a bitwise-or'ed value composed from constants such as XPathContext.VARIABLES and * XPathContext.CURRENT_NODE */ public int computeDependencies() { return start.getDependencies() | // not all dependencies in the step matter, because the context node, etc, // are not those of the outer expression (step.getDependencies() & (StaticProperty.DEPENDS_ON_XSLT_CONTEXT | StaticProperty.DEPENDS_ON_LOCAL_VARIABLES | StaticProperty.DEPENDS_ON_USER_FUNCTIONS)); } /** * Copy an expression. This makes a deep copy. * * @return the copy of the original expression */ public Expression copy() { return new SlashExpression(start.copy(), step.copy()); } /** * Get the static properties of this expression (other than its type). The result is * bit-signficant. These properties are used for optimizations. In general, if * property bit is set, it is true, but if it is unset, the value is unknown. */ public int computeSpecialProperties() { int p = super.computeSpecialProperties(); if ((start.getSpecialProperties() & step.getSpecialProperties() & StaticProperty.NON_CREATIVE) != 0) { p |= StaticProperty.NON_CREATIVE; } return p; } /** * Determine the static cardinality of the expression */ public int computeCardinality() { int c1 = start.getCardinality(); int c2 = step.getCardinality(); return Cardinality.multiply(c1, c2); } /** * Is this expression the same as another expression? */ public boolean equals(Object other) { if (!(other instanceof SlashExpression)) { return false; } SlashExpression p = (SlashExpression) other; return (start.equals(p.start) && step.equals(p.step)); } /** * get HashCode for comparing two expressions */ public int hashCode() { return "SlashExpression".hashCode() + start.hashCode() + step.hashCode(); } /** * Iterate the path-expression in a given context * @param context the evaluation context */ public SequenceIterator iterate(final XPathContext context) throws XPathException { // This class delivers the result of the path expression in unsorted order, // without removal of duplicates. If sorting and deduplication are needed, // this is achieved by wrapping the path expression in a DocumentSorter SequenceIterator result = start.iterate(context); XPathContext context2 = context.newMinorContext(); context2.setCurrentIterator(result); context2.setOrigin(this); context2.setOriginatingConstructType(Location.PATH_EXPRESSION); result = new ContextMappingIterator(this, context2); // Peek at the first item, and depending on its type, check that all the items // are atomic values or that all are nodes. final SourceLocator loc = this; Item first = result.next(); if (first == null) { return EmptyIterator.getInstance(); } else if (first instanceof AtomicValue) { ItemMappingFunction atomicValueChecker = new ItemMappingFunction() { public Item map(Item item) throws XPathException { if (item instanceof AtomicValue) { return item; } else { throw reportMixedItems(loc, context); } } }; return new ItemMappingIterator(result.getAnother(), atomicValueChecker); } else { ItemMappingFunction nodeChecker = new ItemMappingFunction() { public Item map(Item item) throws XPathException { if (item instanceof NodeInfo) { return item; } else { throw reportMixedItems(loc, context); } } }; return new DocumentOrderIterator( new ItemMappingIterator(result.getAnother(), nodeChecker), GlobalOrderComparer.getInstance()); } } private XPathException reportMixedItems(SourceLocator loc, XPathContext context) { XPathException err = new XPathException("Cannot mix nodes and atomic values in the result of a path expression"); err.setErrorCode("XPTY0018"); err.setLocator(loc); err.setXPathContext(context); return err; } /** * Mapping function, from a node returned by the start iteration, to a sequence * returned by the child. */ public final SequenceIterator map(XPathContext context) throws XPathException { return step.iterate(context); } /** * Diagnostic print of expression structure. The abstract expression tree * is written to the supplied output destination. */ public void explain(ExpressionPresenter destination) { destination.startElement("slash"); start.explain(destination); step.explain(destination); destination.endElement(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/expr/ExpressionTool.java0000644000175000017500000012302011202260605022212 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.Configuration; import net.sf.saxon.Controller; import net.sf.saxon.event.PipelineConfiguration; import net.sf.saxon.event.SequenceOutputter; import net.sf.saxon.functions.Current; import net.sf.saxon.functions.ExtensionFunctionCall; import net.sf.saxon.functions.Put; import net.sf.saxon.instruct.Block; import net.sf.saxon.instruct.SlotManager; import net.sf.saxon.instruct.UserFunction; import net.sf.saxon.om.*; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.AnyItemType; import net.sf.saxon.value.*; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.List; /** * This class, ExpressionTool, contains a number of useful static methods * for manipulating expressions. Most importantly, it provides the factory * method make() for constructing a new expression */ public class ExpressionTool { public static final int UNDECIDED = -1; public static final int NO_EVALUATION_NEEDED = 0; public static final int EVALUATE_VARIABLE = 1; public static final int MAKE_CLOSURE = 3; public static final int MAKE_MEMO_CLOSURE = 4; public static final int RETURN_EMPTY_SEQUENCE = 5; public static final int EVALUATE_AND_MATERIALIZE_VARIABLE = 6; public static final int CALL_EVALUATE_ITEM = 7; public static final int ITERATE_AND_MATERIALIZE = 8; public static final int PROCESS = 9; public static final int LAZY_TAIL_EXPRESSION = 10; public static final int SHARED_APPEND_EXPRESSION = 11; public static final int MAKE_INDEXED_VARIABLE = 12; public static final int MAKE_SINGLETON_CLOSURE = 13; private ExpressionTool() {} /** * Parse an expression. This performs the basic analysis of the expression against the * grammar, it binds variable references and function calls to variable definitions and * function definitions, and it performs context-independent expression rewriting for * optimization purposes. * * @param expression The expression (as a character string) * @param env An object giving information about the compile-time * context of the expression * @param start position of the first significant character in the expression * @param terminator The token that marks the end of this expression; typically * Tokenizer.EOF, but may for example be a right curly brace * @param lineNumber the line number of the start of the expression * @param compileWithTracing true if diagnostic tracing during expression parsing is required * @return an object of type Expression * @throws XPathException if the expression contains a static error */ public static Expression make(String expression, StaticContext env, int start, int terminator, int lineNumber, boolean compileWithTracing) throws XPathException { ExpressionParser parser = new ExpressionParser(); parser.setCompileWithTracing(compileWithTracing); if (terminator == -1) { terminator = Token.EOF; } Expression exp = parser.parse(expression, start, terminator, lineNumber, env); exp = ExpressionVisitor.make(env).simplify(exp); return exp; } /** * Copy location information (the line number and reference to the container) from one expression * to another * @param from the expression containing the location information * @param to the expression to which the information is to be copied */ public static void copyLocationInfo(Expression from, Expression to) { if (from != null && to != null) { to.setLocationId(from.getLocationId()); to.setContainer(from.getContainer()); } } /** * Remove unwanted sorting from an expression, at compile time * @param opt the expression optimizer * @param exp the expression to be optimized * @param retainAllNodes true if there is a need to retain exactly those nodes returned by exp * even if there are duplicates; false if the caller doesn't mind whether duplicate nodes * are retained or eliminated * @return the expression after rewriting */ public static Expression unsorted(Optimizer opt, Expression exp, boolean retainAllNodes) throws XPathException { if (exp instanceof Literal) { return exp; // fast exit } PromotionOffer offer = new PromotionOffer(opt); offer.action = PromotionOffer.UNORDERED; offer.retainAllNodes = retainAllNodes; return exp.promote(offer); } /** * Remove unwanted sorting from an expression, at compile time, if and only if it is known * that the result of the expression will be homogeneous (all nodes, or all atomic values). * This is done when we need the effective boolean value of a sequence: the EBV of a * homogenous sequence does not depend on its order, but this is not true when atomic * values and nodes are mixed: (N, AV) is true, but (AV, N) is an error. * @param opt the expression optimizer * @param exp the expression to be optimized * @return the expression after rewriting */ public static Expression unsortedIfHomogeneous(Optimizer opt, Expression exp) throws XPathException { if (exp instanceof Literal) { return exp; // fast exit } if (exp.getItemType(opt.getConfiguration().getTypeHierarchy()) instanceof AnyItemType) { return exp; } else { PromotionOffer offer = new PromotionOffer(opt); offer.action = PromotionOffer.UNORDERED; offer.retainAllNodes = false; // TODO: redundant code. All callers set this to false return exp.promote(offer); } } /** * Determine the method of evaluation to be used when lazy evaluation of an expression is * preferred. This method is called at compile time, after all optimizations have been done, * to determine the preferred strategy for lazy evaluation, depending on the type of expression. * * @param exp the expression to be evaluated * @return an integer constant identifying the evaluation mode */ public static int lazyEvaluationMode(Expression exp) { if (exp instanceof Literal) { return NO_EVALUATION_NEEDED; } else if (exp instanceof VariableReference) { return EVALUATE_VARIABLE; } else if ((exp.getDependencies() & ( StaticProperty.DEPENDS_ON_POSITION | StaticProperty.DEPENDS_ON_LAST | StaticProperty.DEPENDS_ON_CURRENT_ITEM | StaticProperty.DEPENDS_ON_CURRENT_GROUP | StaticProperty.DEPENDS_ON_REGEX_GROUP )) != 0) { // we can't save these values in the closure, so we evaluate // the expression now if they are needed return eagerEvaluationMode(exp); } else if (exp instanceof ErrorExpression) { return CALL_EVALUATE_ITEM; // evaluateItem() on an error expression throws the latent exception } else if (exp instanceof LazyExpression) { // A LazyExpression is always evaluated lazily (if at all possible) to // prevent spurious errors (see opt017) if (Cardinality.allowsMany(exp.getCardinality())) { return MAKE_MEMO_CLOSURE; } else { return MAKE_SINGLETON_CLOSURE; } } else if (!Cardinality.allowsMany(exp.getCardinality())) { // singleton expressions are always evaluated eagerly return eagerEvaluationMode(exp); } else if (exp instanceof TailExpression) { // Treat tail recursion as a special case, to avoid creating a deeply-nested // tree of Closures. If this expression is a TailExpression, and its first // argument is also a TailExpression, we combine the two TailExpressions into // one and return a closure over that. TailExpression tail = (TailExpression)exp; Expression base = tail.getBaseExpression(); if (base instanceof VariableReference) { return LAZY_TAIL_EXPRESSION; } else { return MAKE_CLOSURE; } } else if (exp instanceof Block && ((Block)exp).getChildren().length == 2 && (((Block)exp).getChildren()[0] instanceof VariableReference || ((Block)exp).getChildren()[0] instanceof Literal)) { // If the expression is a Block, that is, it is appending a value to a sequence, // then we have the opportunity to use a shared list underpinning the old value and // the new. This takes precedence over lazy evaluation (it would be possible to do this // lazily, but more difficult). We currently only do this for the common case of a two-argument // append expression, in the case where the first argument is either a value, or a variable // reference identifying a value. The most common case is that the first argument is a reference // to an argument of recursive function, where the recursive function returns the result of // appending to the sequence. return SHARED_APPEND_EXPRESSION; } else { // create a Closure, a wrapper for the expression and its context return MAKE_CLOSURE; } } /** * Determine the method of evaluation to be used when lazy evaluation of an expression is * preferred. This method is called at compile time, after all optimizations have been done, * to determine the preferred strategy for lazy evaluation, depending on the type of expression. * * @param exp the expression to be evaluated * @return an integer constant identifying the evaluation mode */ public static int eagerEvaluationMode(Expression exp) { if (exp instanceof Literal && !(((Literal)exp).getValue() instanceof Closure)) { return NO_EVALUATION_NEEDED; } if (exp instanceof VariableReference) { return EVALUATE_AND_MATERIALIZE_VARIABLE; } int m = exp.getImplementationMethod(); if ((m & Expression.EVALUATE_METHOD) != 0) { return CALL_EVALUATE_ITEM; } else if ((m & Expression.ITERATE_METHOD) != 0) { return ITERATE_AND_MATERIALIZE; } else { return PROCESS; } } /** * Do lazy evaluation of an expression. This will return a value, which may optionally * be a SequenceIntent, which is a wrapper around an iterator over the value of the expression. * @param exp the expression to be evaluated * @param evaluationMode the evaluation mode for this expression * @param context the run-time evaluation context for the expression. If * the expression is not evaluated immediately, then parts of the * context on which the expression depends need to be saved as part of * the Closure * @param ref an indication of how the value will be used. The value 1 indicates that the value * is only expected to be used once, so that there is no need to keep it in memory. A small value >1 * indicates multiple references, so the value will be saved when first evaluated. The special value * FILTERED indicates a reference within a loop of the form $x[predicate], indicating that the value * should be saved in a way that permits indexing. * @exception XPathException if any error occurs in evaluating the * expression * @return a value: either the actual value obtained by evaluating the * expression, or a Closure containing all the information needed to * evaluate it later */ public static ValueRepresentation evaluate(Expression exp, int evaluationMode, XPathContext context, int ref) throws XPathException { switch (evaluationMode) { case NO_EVALUATION_NEEDED: return ((Literal)exp).getValue(); case EVALUATE_VARIABLE: return ((VariableReference)exp).evaluateVariable(context); case MAKE_CLOSURE: return Closure.make(exp, context, ref); //return new SequenceExtent(exp.iterate(context)); case MAKE_MEMO_CLOSURE: return Closure.make(exp, context, (ref==1 ? 10 : ref)); case MAKE_SINGLETON_CLOSURE: return new SingletonClosure(exp, context); case RETURN_EMPTY_SEQUENCE: return EmptySequence.getInstance(); case EVALUATE_AND_MATERIALIZE_VARIABLE: ValueRepresentation v = ((VariableReference)exp).evaluateVariable(context); if (v instanceof Closure) { return SequenceExtent.makeSequenceExtent(((Closure)v).iterate()); } else { return v; } case CALL_EVALUATE_ITEM: Item item = exp.evaluateItem(context); if (item == null) { return EmptySequence.getInstance(); } else { return item; } case UNDECIDED: case ITERATE_AND_MATERIALIZE: if (ref == FilterExpression.FILTERED) { return context.getConfiguration().getOptimizer().makeSequenceExtent(exp, ref, context); } else { return SequenceExtent.makeSequenceExtent(exp.iterate(context)); } case PROCESS: Controller controller = context.getController(); XPathContext c2 = context.newMinorContext(); c2.setOrigin(exp); SequenceOutputter seq = controller.allocateSequenceOutputter(20); PipelineConfiguration pipe = controller.makePipelineConfiguration(); pipe.setHostLanguage(exp.getHostLanguage()); seq.setPipelineConfiguration(pipe); c2.setTemporaryReceiver(seq); seq.open(); exp.process(c2); seq.close(); ValueRepresentation val = seq.getSequence(); seq.reset(); return val; case LAZY_TAIL_EXPRESSION: { TailExpression tail = (TailExpression)exp; VariableReference vr = (VariableReference)tail.getBaseExpression(); ValueRepresentation base = evaluate(vr, EVALUATE_VARIABLE, context, ref); if (base instanceof MemoClosure) { SequenceIterator it = ((MemoClosure)base).iterate(); base = ((GroundedIterator)it).materialize(); } if (base instanceof IntegerRange) { long start = ((IntegerRange)base).getStart() + 1; long end = ((IntegerRange)base).getEnd(); if (start == end) { return Int64Value.makeIntegerValue(end); } else { return new IntegerRange(start, end); } } if (base instanceof SequenceExtent) { return new SequenceExtent( (SequenceExtent)base, tail.getStart() - 1, ((SequenceExtent)base).getLength() - tail.getStart() + 1); } return Closure.make(tail, context, ref); } case SHARED_APPEND_EXPRESSION: { if (exp instanceof Block) { Block block = (Block)exp; Expression base = block.getChildren()[0]; Value baseVal; if (base instanceof Literal) { baseVal = ((Literal)base).getValue(); } else if (base instanceof VariableReference) { baseVal = Value.asValue(evaluate(base, EVALUATE_VARIABLE, context, ref)); if (baseVal instanceof MemoClosure && ((MemoClosure)baseVal).isFullyRead()) { baseVal = ((MemoClosure)baseVal).materialize(); } } else { throw new AssertionError("base of shared append expression is of class " + base.getClass()); } if (baseVal instanceof ShareableSequence && ((ShareableSequence)baseVal).isShareable()) { List list = ((ShareableSequence)baseVal).getList(); SequenceIterator iter = block.getChildren()[1].iterate(context); while (true) { Item i = iter.next(); if (i == null) { break; } list.add(i); } return new ShareableSequence(list); } else { List list = new ArrayList(20); SequenceIterator iter = baseVal.iterate(); while (true) { Item i = iter.next(); if (i == null) { break; } list.add(i); } iter = block.getChildren()[1].iterate(context); while (true) { Item i = iter.next(); if (i == null) { break; } list.add(i); } return new ShareableSequence(list); } } else { // it's not a Block: it must have been rewritten after deciding to use this evaluation mode return SequenceExtent.makeSequenceExtent(exp.iterate(context)); } } case MAKE_INDEXED_VARIABLE: return context.getConfiguration().getOptimizer().makeIndexedValue(exp.iterate(context)); default: throw new IllegalArgumentException("Unknown evaluation mode " + evaluationMode); } } /** * Do lazy evaluation of an expression. This will return a value, which may optionally * be a SequenceIntent, which is a wrapper around an iterator over the value of the expression. * @param exp the expression to be evaluated * @param context the run-time evaluation context for the expression. If * the expression is not evaluated immediately, then parts of the * context on which the expression depends need to be saved as part of * the Closure * @param ref an indication of how the value will be used. The value 1 indicates that the value * is only expected to be used once, so that there is no need to keep it in memory. A small value >1 * indicates multiple references, so the value will be saved when first evaluated. The special value * FILTERED indicates a reference within a loop of the form $x[predicate], indicating that the value * should be saved in a way that permits indexing. * @return a value: either the actual value obtained by evaluating the * expression, or a Closure containing all the information needed to * evaluate it later * @throws XPathException if any error occurs in evaluating the * expression */ public static ValueRepresentation lazyEvaluate(Expression exp, XPathContext context, int ref) throws XPathException { final int evaluationMode = lazyEvaluationMode(exp); return evaluate(exp, evaluationMode, context, ref); } /** * Evaluate an expression now; lazy evaluation is not permitted in this case * @param exp the expression to be evaluated * @param context the run-time evaluation context * @exception net.sf.saxon.trans.XPathException if any dynamic error occurs evaluating the * expression * @return the result of evaluating the expression */ public static ValueRepresentation eagerEvaluate(Expression exp, XPathContext context) throws XPathException { final int evaluationMode = eagerEvaluationMode(exp); return evaluate(exp, evaluationMode, context, 10); } /** * Scan an expression to find and mark any recursive tail function calls * @param exp the expression to be analyzed * @param qName the name of the containing function * @param arity the arity of the containing function * @return 0 if no tail call was found; 1 if a tail call to a different function was found; * 2 if a tail call to the specified function was found. In this case the * UserFunctionCall object representing the tail function call will also have been marked as * a tail call. */ public static int markTailFunctionCalls(Expression exp, StructuredQName qName, int arity) { return exp.markTailFunctionCalls(qName, arity); } /** * Construct indent string, for diagnostic output * * @param level the indentation level (the number of spaces to return) * @return a string of "level*2" spaces */ public static String indent(int level) { String s = ""; for (int i=0; i1), and the special value FILTERED, which indicates that there are * multiple references and one or more of them is of the form $x[....] indicating that an * index might be useful. */ public static int getReferenceCount(Expression exp, Binding binding, boolean inLoop) { int rcount = 0; if (exp instanceof VariableReference && ((VariableReference)exp).getBinding() == binding) { if (((VariableReference)exp).isFiltered()) { return FilterExpression.FILTERED; } else { rcount += (inLoop ? 10 : 1); } } else { for (Iterator iter = exp.iterateSubExpressions(); iter.hasNext(); ) { Expression child = (Expression)iter.next(); boolean childLoop = inLoop || (exp.hasLoopingSubexpression(child)); rcount += getReferenceCount(child, binding, childLoop); if (rcount >= FilterExpression.FILTERED) { break; } } } return rcount; } /** * Gather the set of all the subexpressions of an expression (the transitive closure) * @param exp the parent expression * @param set the set to be populated; on return it will contain all the subexpressions. * Beware that testing for membership of a set of expressions relies on the equals() comparison, * which does not test identity. */ public static void gatherAllSubExpressions(Expression exp, HashSet set) { set.add(exp); for (Iterator iter = exp.iterateSubExpressions(); iter.hasNext(); ) { gatherAllSubExpressions((Expression)iter.next(), set); } } /** * Get the size of an expression tree (the number of subexpressions it contains) * @param exp the expression whose size is required * @return the size of the expression tree, as the number of nodes */ public static int expressionSize(Expression exp) { int total = 1; for (Iterator iter = exp.iterateSubExpressions(); iter.hasNext(); ) { total += expressionSize((Expression)iter.next()); } return total; } /** * Rebind all variable references to a binding * @param exp the expression whose contained variable references are to be rebound * @param oldBinding the old binding for the variable references * @param newBinding the new binding to which the variables should be rebound */ public static void rebindVariableReferences( Expression exp, Binding oldBinding, Binding newBinding) { if (exp instanceof VariableReference) { if (((VariableReference)exp).getBinding() == oldBinding) { ((VariableReference)exp).fixup(newBinding); } } else { Iterator iter = exp.iterateSubExpressions(); while (iter.hasNext()) { Expression e = (Expression)iter.next(); rebindVariableReferences(e, oldBinding, newBinding); } } } /** * Determine whether the expression is either an updating expression, or an expression that is permitted * in a context where updating expressions are allowed * @param exp the expression under test * @return true if the expression is an updating expression, or an empty sequence, or a call on error() */ public static boolean isAllowedInUpdatingContext(Expression exp) { return Literal.isEmptySequence(exp) || exp instanceof net.sf.saxon.functions.Error || exp.isUpdatingExpression() || exp instanceof Put || (exp instanceof LetExpression && isAllowedInUpdatingContext(((LetExpression)exp).getAction())); // The last condition is stretching the rules in the XQuery update specification. We need the rule because // the branches of a typeswitch get turned into let expressions before we can check them. } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/expr/SingleNodeExpression.java0000644000175000017500000001156611033112257023340 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.om.Item; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.om.SingletonIterator; import net.sf.saxon.pattern.AnyNodeTest; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.TypeHierarchy; /** * A node set expression that will always return zero or one nodes */ public abstract class SingleNodeExpression extends Expression { /** * Type-check the expression. */ public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { if (contextItemType == null) { XPathException err = new XPathException("Cannot select a node here: the context item is undefined"); err.setErrorCode("XPDY0002"); err.setIsTypeError(true); err.setLocator(this); throw err; } if (contextItemType.isAtomicType()) { XPathException err = new XPathException("Cannot select a node here: the context item is an atomic value"); err.setErrorCode("XPTY0020"); err.setIsTypeError(true); err.setLocator(this); throw err; } return this; } /** * Perform optimisation of an expression and its subexpressions. *

    *

    This method is called after all references to functions and variables have been resolved * to the declaration of the function or variable, and after all type checking has been done.

    * * @param visitor an expression visitor * @param contextItemType the static type of "." at the point where this expression is invoked. * The parameter is set to null if it is known statically that the context item will be undefined. * If the type of the context item is not known statically, the argument is set to * {@link net.sf.saxon.type.Type#ITEM_TYPE} * @return the original expression, rewritten if appropriate to optimize execution * @throws XPathException if an error is discovered during this phase * (typically a type error) */ public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { // repeat the check: in XSLT insufficient information is available the first time return typeCheck(visitor, contextItemType); } /** * Specify that the expression returns a singleton */ public int computeCardinality() { return StaticProperty.ALLOWS_ZERO_OR_ONE; } /** * Determine the data type of the items returned by this expression * @return Type.NODE * @param th the type hierarchy cache */ public ItemType getItemType(TypeHierarchy th) { return AnyNodeTest.getInstance(); } /** * Determine which aspects of the context the expression depends on. The result is * a bitwise-or'ed value composed from constants such as StaticProperty.VARIABLES and * StaticProperty.CURRENT_NODE */ public int getIntrinsicDependencies() { return StaticProperty.DEPENDS_ON_CONTEXT_ITEM; } public int computeSpecialProperties() { return StaticProperty.ORDERED_NODESET | StaticProperty.CONTEXT_DOCUMENT_NODESET | StaticProperty.SINGLE_DOCUMENT_NODESET | StaticProperty.NON_CREATIVE; } /** * Get the single node to which this expression refers. Returns null if the node-set is empty */ public abstract NodeInfo getNode(XPathContext context) throws XPathException; /** * Evaluate the expression in a given context to return an iterator * @param context the evaluation context */ public SequenceIterator iterate(XPathContext context) throws XPathException { return SingletonIterator.makeIterator(getNode(context)); } public Item evaluateItem(XPathContext context) throws XPathException { return getNode(context); } public boolean effectiveBooleanValue(XPathContext context) throws XPathException { return getNode(context) != null; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/expr/ReverseRangeIterator.java0000644000175000017500000000677611033112257023342 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.om.Item; import net.sf.saxon.om.LookaheadIterator; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.Int64Value; /** * Iterator that produces numeric values in a monotonic sequence, * ascending or descending. Although a range expression (N to M) is always * in ascending order, applying the reverse() function will produce * a RangeIterator that works in descending order. */ public class ReverseRangeIterator implements SequenceIterator, ReversibleIterator, LastPositionFinder, LookaheadIterator { long start; long currentValue; long limit; /** * Create an iterator over a range of integers in monotonic descending order * @param start the first integer to be delivered (the highest in the range) * @param end the last integer to be delivered (the lowest in the range). Must be <= start */ public ReverseRangeIterator(long start, long end) { this.start = start; currentValue = start + 1; limit = end; } public boolean hasNext() { return currentValue > limit; } public Item next() { if (--currentValue < limit) { return null; } return Int64Value.makeIntegerValue(currentValue); } public Item current() { if (currentValue < limit) { return null; } else { return Int64Value.makeIntegerValue(currentValue); } } public int position() { if (currentValue < limit) { return -1; } else { return (int)(start - currentValue + 1); } } public void close() { } public int getLastPosition() { return (int)((start - limit) + 1); } public SequenceIterator getAnother() throws XPathException { return new ReverseRangeIterator(start, limit); } /** * Get properties of this iterator, as a bit-significant integer. * * @return the properties of this iterator. This will be some combination of * properties such as {@link net.sf.saxon.om.SequenceIterator#GROUNDED}, {@link net.sf.saxon.om.SequenceIterator#LAST_POSITION_FINDER}, * and {@link net.sf.saxon.om.SequenceIterator#LOOKAHEAD}. It is always * acceptable to return the value zero, indicating that there are no known special properties. * It is acceptable for the properties of the iterator to change depending on its state. */ public int getProperties() { return LOOKAHEAD | LAST_POSITION_FINDER; } public SequenceIterator getReverseIterator() { return new RangeIterator(limit, start); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/expr/CardinalityChecker.java0000644000175000017500000003372011033112257022755 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.trans.Err; import net.sf.saxon.event.SequenceReceiver; import net.sf.saxon.event.TypeCheckingFilter; import net.sf.saxon.om.FastStringBuffer; import net.sf.saxon.om.Item; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.pattern.DocumentNodeTest; import net.sf.saxon.trace.ExpressionPresenter; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.Type; import net.sf.saxon.type.TypeHierarchy; import net.sf.saxon.value.Cardinality; /** * A CardinalityChecker implements the cardinality checking of "treat as": that is, * it returns the supplied sequence, checking that its cardinality is correct */ public final class CardinalityChecker extends UnaryExpression { private int requiredCardinality = -1; private RoleLocator role; /** * Private Constructor: use factory method * @param sequence the base sequence whose cardinality is to be checked * @param cardinality the required cardinality * @param role information to be used in error reporting */ private CardinalityChecker(Expression sequence, int cardinality, RoleLocator role) { super(sequence); requiredCardinality = cardinality; this.role = role; computeStaticProperties(); adoptChildExpression(sequence); } /** * Factory method to construct a CardinalityChecker. The method may create an expression that combines * the cardinality checking with the functionality of the underlying expression class * @param sequence the base sequence whose cardinality is to be checked * @param cardinality the required cardinality * @param role information to be used in error reporting * @return a new Expression that does the CardinalityChecking (not necessarily a CardinalityChecker) */ public static Expression makeCardinalityChecker(Expression sequence, int cardinality, RoleLocator role) { Expression result; if (sequence instanceof Atomizer && !Cardinality.allowsMany(cardinality)) { Expression base = ((Atomizer)sequence).getBaseExpression(); result = new SingletonAtomizer(base, role, Cardinality.allowsZero(cardinality)); } else { result = new CardinalityChecker(sequence, cardinality, role); } ExpressionTool.copyLocationInfo(sequence, result); return result; } /** * Get the required cardinality * @return the cardinality required by this checker */ public int getRequiredCardinality() { return requiredCardinality; } /** * Type-check the expression */ public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { operand = visitor.typeCheck(operand, contextItemType); if (requiredCardinality == StaticProperty.ALLOWS_ZERO_OR_MORE || Cardinality.subsumes(requiredCardinality, operand.getCardinality())) { return operand; } return this; } /** * Perform optimisation of an expression and its subexpressions. *

    *

    This method is called after all references to functions and variables have been resolved * to the declaration of the function or variable, and after all type checking has been done.

    * * @param visitor an expression visitor * @param contextItemType the static type of "." at the point where this expression is invoked. * The parameter is set to null if it is known statically that the context item will be undefined. * If the type of the context item is not known statically, the argument is set to * {@link net.sf.saxon.type.Type#ITEM_TYPE} * @return the original expression, rewritten if appropriate to optimize execution * @throws XPathException if an error is discovered during this phase * (typically a type error) */ public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { operand = visitor.optimize(operand, contextItemType); if (requiredCardinality == StaticProperty.ALLOWS_ZERO_OR_MORE || Cardinality.subsumes(requiredCardinality, operand.getCardinality())) { return operand; } return this; } /** * Set the error code to be returned (this is used when evaluating the functions such * as exactly-one() which have their own error codes) * @param code the error code to be used */ public void setErrorCode(String code) { role.setErrorCode(code); } /** * Get the RoleLocator, which contains diagnostic information for use if the cardinality check fails * @return the diagnostic information */ public RoleLocator getRoleLocator() { return role; } /** * An implementation of Expression must provide at least one of the methods evaluateItem(), iterate(), or process(). * This method indicates which of these methods is provided. This implementation provides both iterate() and * process() methods natively. */ public int getImplementationMethod() { int m = ITERATE_METHOD | PROCESS_METHOD; if (!Cardinality.allowsMany(requiredCardinality)) { m |= EVALUATE_METHOD; } return m; } /** * Iterate over the sequence of values */ public SequenceIterator iterate(XPathContext context) throws XPathException { SequenceIterator base = operand.iterate(context); // If the base iterator knows how many items there are, then check it now rather than wasting time if ((base.getProperties() & SequenceIterator.LAST_POSITION_FINDER) != 0) { int count = ((LastPositionFinder)base).getLastPosition(); if (count == 0 && !Cardinality.allowsZero(requiredCardinality)) { typeError("An empty sequence is not allowed as the " + role.getMessage(), role.getErrorCode(), context); } else if (count == 1 && requiredCardinality == StaticProperty.EMPTY) { typeError("The only value allowed for the " + role.getMessage() + " is an empty sequence", role.getErrorCode(), context); } else if (count > 1 && !Cardinality.allowsMany(requiredCardinality)) { typeError("A sequence of more than one item is not allowed as the " + role.getMessage() + depictSequenceStart(base.getAnother(), 2), role.getErrorCode(), context); } return base; } // Otherwise return an iterator that does the checking on the fly return new CardinalityCheckingIterator(base, requiredCardinality, role, this); } /** * Show the first couple of items in a sequence in an error message * @param seq iterator over the sequence * @param max maximum number of items to be shown * @return a message display of the contents of the sequence */ public static String depictSequenceStart(SequenceIterator seq, int max) { try { FastStringBuffer sb = new FastStringBuffer(100); int count = 0; sb.append(" ("); while (true) { Item next = seq.next(); if (next == null) { sb.append(") "); return sb.toString(); } if (count++ > 0) { sb.append(", "); } if (count > max) { sb.append("...) "); return sb.toString(); } sb.append(Err.depict(next)); } } catch (XPathException e) { return ""; } } /** * Mapping function used to check for sequences of length > 1 when this is not permitted */ // private class CardinalityCheckingFunction implements ItemMappingFunction { // // public SequenceIterator iterator; // public XPathContext context; // // public CardinalityCheckingFunction(XPathContext context) { // this.context = context; // } // // public Item map(Item item) throws XPathException { // if (iterator.position()==2) { // typeError( // "A sequence of more than one item is not allowed as the " + // role.getMessage() + depictSequenceStart(iterator.getAnother(), 2), // role.getErrorCode(), context); // return null; // } // return item; // } // } /** * Mapping function used to check that a sequence is empty */ // private class EmptyCheckingFunction implements ItemMappingFunction { // // public SequenceIterator iterator; // public XPathContext context; // // public EmptyCheckingFunction(XPathContext context) { // this.context = context; // } // // public Item map(Item item) throws XPathException { // typeError("An empty sequence is required as the " + // role.getMessage(), role.getErrorCode(), context); // return null; // } // } /** * Evaluate as an Item. */ public Item evaluateItem(XPathContext context) throws XPathException { SequenceIterator iter = operand.iterate(context); Item item = null; while (true) { Item nextItem = iter.next(); if (nextItem == null) break; if (requiredCardinality == StaticProperty.EMPTY) { typeError("An empty sequence is required as the " + role.getMessage(), role.getErrorCode(), context); return null; } if (item != null) { typeError("A sequence of more than one item is not allowed as the " + role.getMessage() + depictSequenceStart(iter.getAnother(), 2), role.getErrorCode(), context); return null; } item = nextItem; } if (item == null && !Cardinality.allowsZero(requiredCardinality)) { typeError("An empty sequence is not allowed as the " + role.getMessage(), role.getErrorCode(), context); return null; } return item; } /** * Process the instruction, without returning any tail calls * * @param context The dynamic context, giving access to the current node, * the current variables, etc. */ public void process(XPathContext context) throws XPathException { Expression next = operand; ItemType type = Type.ITEM_TYPE; if (next instanceof ItemChecker) { type = ((ItemChecker)next).getRequiredType(); next = ((ItemChecker)next).getBaseExpression(); } if ((next.getImplementationMethod() & PROCESS_METHOD) != 0 && !(type instanceof DocumentNodeTest)) { SequenceReceiver out = context.getReceiver(); TypeCheckingFilter filter = new TypeCheckingFilter(); filter.setUnderlyingReceiver(out); filter.setPipelineConfiguration(out.getPipelineConfiguration()); filter.setRequiredType(type, requiredCardinality, role); context.setReceiver(filter); next.process(context); filter.close(); context.setReceiver(out); } else { super.process(context); } } /** * Determine the data type of the items returned by the expression, if possible * @return a value such as Type.STRING, Type.BOOLEAN, Type.NUMBER, Type.NODE, * or Type.ITEM (meaning not known in advance) * @param th the type hierarchy cache */ public ItemType getItemType(TypeHierarchy th) { return operand.getItemType(th); } /** * Determine the static cardinality of the expression */ public int computeCardinality() { return requiredCardinality; } /** * Get the static properties of this expression (other than its type). The result is * bit-signficant. These properties are used for optimizations. In general, if * property bit is set, it is true, but if it is unset, the value is unknown. */ public int computeSpecialProperties() { return operand.getSpecialProperties(); } /** * Copy an expression. This makes a deep copy. * * @return the copy of the original expression */ public Expression copy() { return new CardinalityChecker(getBaseExpression().copy(), requiredCardinality, role); } /** * Is this expression the same as another expression? */ public boolean equals(Object other) { return super.equals(other) && requiredCardinality == ((CardinalityChecker)other).requiredCardinality; } /** * Diagnostic print of expression structure. The abstract expression tree * is written to the supplied output destination. */ public void explain(ExpressionPresenter out) { out.startElement("checkCardinality"); out.emitAttribute("occurs", Cardinality.toString(requiredCardinality)); operand.explain(out); out.endElement(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/expr/PromotionOffer.java0000644000175000017500000003343111111054261022171 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.functions.Current; import net.sf.saxon.functions.Reverse; import net.sf.saxon.instruct.Block; import net.sf.saxon.instruct.LocalParam; import net.sf.saxon.om.NamespaceConstant; import net.sf.saxon.om.StructuredQName; import net.sf.saxon.sort.DocumentSorter; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.TypeHierarchy; import net.sf.saxon.value.SequenceType; /** * PromotionOffer is an object used transiently during compilation of an expression. It contains * information passed by a containing expression to its subexpressions, when looking for subexpressions * that can be promoted to a higher level because they are not dependent on the context established * by the containing expression. The object is also used to pass back return information when the * promotion actually takes place. */ public class PromotionOffer { /** * FOCUS_INDEPENDENT requests promotion of all non-trivial subexpressions that don't depend on the * focus. This is typically used to extract subexpressions from a filter predicate. The offer is * optional - each subexpression can decide whether it's worth the trouble of promoting itself. * The offer is normally passed on to subexpressions, except subexpressions that are evaluated * with a different focus */ public static final int FOCUS_INDEPENDENT = 10; /** * RANGE_INDEPENDENT requests promotion of all non-trivial subexpressions that don't depend on a * specified range variable. This is typically used to extract subexpressions from the action of * a for expression or the condition of a some/every quantified expression. The offer is * optional - each subexpression can decide whether it's worth the trouble of promoting itself. * The offer is normally passed on to subexpressions, except subexpressions that are evaluated * with a different focus or a different range variable, because these may have other dependencies * that prevent their promotion. */ public static final int RANGE_INDEPENDENT = 11; /** * Inline variable references causes all references to a variable V to be replaced by the * expression E. The variable is supplied in the "binding" property; the replacement expression * in the containingExpression property. A special case is where the replacement expression is * a ContextItemExpression; in this case the offer is not passed on to subexpressions where * the context is different. */ public static final int INLINE_VARIABLE_REFERENCES = 12; // Note: After inlining variable references, it is possible for an expression to appear at more // than one place in the expression tree. This seems dangerous, since a rewrite applied to one // branch might be inappropriate in another branch. We get away with it because the only expressions // that we are inline are very simple ones: (a) a ContextItemExpression, and (b) another VariableReference, // or because we only inline an expression where there is a single variable reference /** * UNORDERED indicates that the containing expression does not require the results * to be delivered in any particular order. The boolean mustEliminateDuplicates * is set if duplicate items in the result are not allowed. */ public static final int UNORDERED = 13; /** * REPLACE_CURRENT causes calls to the XSLT current() function to be replaced by * reference to a variable. The variable binding is the single member of the array bindingList */ public static final int REPLACE_CURRENT = 14; /** * EXTRACT_GLOBAL_VARIABLES identifies subexpressions that are not constant, but have no dependencies * other than on global variables or parameters (they must also be non-creative). Such expressions can * be extracted from a function or template and converted into global variables. This optimization is done * in Saxon-SA only. */ public static final int EXTRACT_GLOBAL_VARIABLES = 15; /** * The optimizer in use */ private Optimizer optimizer; /** * The expression visitor in use */ public ExpressionVisitor visitor; /** * action is one of the possible promotion actions, FOCUS_INDEPENDENT, RANGE_INDEPENDENT, * INLINE_VARIABLE_REFERENCES, UNORDERED, EXTRACT_GLOBAL_VARIABLES */ public int action; /** * In the case of FOCUS_INDEPENDENT, "promoteDocumentDependent" is a boolean that, when set to * true, indicates that it is safe to promote a subexpression that depends on the context document * but not on other aspects of the focus. This is the case, for example, in a filter expression when * it is known that all the nodes selected by the expression will be in the same document - as happens * when the filter is applied to a path expression. This allows subexpressions such as key() to be * promoted */ public boolean promoteDocumentDependent = false; /** * In the case of FOCUS_INDEPENDENT, "promoteXSLTFunctions" is a boolean that, when set to true, indicates * that it is safe to promote XSLT functions such as current(). This flag is set when rewriting XPath expressions * and is unset when rewriting XSLT templates. */ public boolean promoteXSLTFunctions = true; /** * In the case of UNORDERED, "retainAllNodes" is a boolean that is set to * true if the nodes can be delivered in any order so long as the right number of nodes * are delivered. If this boolean is false, the caller doesn't care whether duplicate nodes * are retained or whether they are eliminated. */ public boolean retainAllNodes = true; /** * In the case of RANGE_INDEPENDENT, "binding" identifies the range variables whose dependencies * we are looking for. For INLINE_VARIABLE_REFERENCES it is a single Binding that we are aiming to inline */ public Binding[] bindingList; /** * When a promotion offer is made, containingExpression identifies the level to which the promotion * should occur. When a subexpression is promoted, an expression of the form let $VAR := SUB return ORIG * is created, and this replaces the original containingExpression within the PromotionOffer. */ public Expression containingExpression; /** * Flag that is set if the offer has been accepted, that is, if the expression has changed */ public boolean accepted = false; /** * Create a PromotionOffer for use with a particular Optimizer * @param optimizer the optimizer */ public PromotionOffer(Optimizer optimizer) { this.optimizer = optimizer; } /** * Get the optimizer in use * @return the optimizer */ public Optimizer getOptimizer() { return optimizer; } /** * Method to test whether a subexpression qualifies for promotion, and if so, to * accept the promotion. * @param child the subexpression in question * @return if promotion was done, returns the expression that should be used in place * of the child expression. If no promotion was done, returns null. If promotion is * determined not to be necessary for this subtree, returns the supplied child expression * unchanged */ public Expression accept(Expression child) throws XPathException { switch (action) { case RANGE_INDEPENDENT: { int properties = child.getSpecialProperties(); if (((properties & StaticProperty.NON_CREATIVE) != 0) && !ExpressionTool.dependsOnVariable(child, bindingList) && (child.getDependencies() & (StaticProperty.HAS_SIDE_EFFECTS | StaticProperty.DEPENDS_ON_ASSIGNABLE_GLOBALS)) == 0) { return promote(child); } break; } case FOCUS_INDEPENDENT: { int dependencies = child.getDependencies(); int properties = child.getSpecialProperties(); if (!promoteXSLTFunctions && ((dependencies & StaticProperty.DEPENDS_ON_XSLT_CONTEXT) != 0)) { break; } if (ExpressionTool.dependsOnVariable(child, bindingList)) { break; } if ((dependencies & (StaticProperty.HAS_SIDE_EFFECTS | StaticProperty.DEPENDS_ON_ASSIGNABLE_GLOBALS)) != 0) { break; } if ((dependencies & StaticProperty.DEPENDS_ON_FOCUS) == 0 && (properties & StaticProperty.NON_CREATIVE) != 0) { return promote(child); } else if (promoteDocumentDependent && (dependencies & StaticProperty.DEPENDS_ON_NON_DOCUMENT_FOCUS) == 0 && (properties & StaticProperty.NON_CREATIVE) != 0) { return promote(child); } break; } case REPLACE_CURRENT: { if (child instanceof Current) { LocalVariableReference var = new LocalVariableReference((Assignation)containingExpression); ExpressionTool.copyLocationInfo(child, var); return var; } else if (!ExpressionTool.callsFunction(child, Current.FN_CURRENT)) { return child; } break; } case INLINE_VARIABLE_REFERENCES: { if (child instanceof VariableReference && ((VariableReference)child).getBinding() == bindingList[0]) { try { Expression copy = containingExpression.copy(); ExpressionTool.copyLocationInfo(child, copy); return copy; } catch (UnsupportedOperationException err) { // If we can't make a copy, return the original. This is safer than it seems, // because on the paths where this happens, we are merely moving the expression from // one place to another, not replicating it return containingExpression; } } break; } case UNORDERED: { if (child instanceof Reverse) { return ((Reverse)child).getArguments()[0]; } else if (child instanceof DocumentSorter && !retainAllNodes) { return ((DocumentSorter)child).getBaseExpression(); } break; } case EXTRACT_GLOBAL_VARIABLES: if (!(child instanceof Literal || child instanceof LocalParam || (child instanceof Block && ((Block)child).containsLocalParam())) && (child.getDependencies()&~StaticProperty.DEPENDS_ON_RUNTIME_ENVIRONMENT) == 0 && (child.getSpecialProperties() & StaticProperty.NON_CREATIVE) != 0) { return optimizer.extractGlobalVariables(child, visitor); } break; default: throw new UnsupportedOperationException("Unknown promotion action " + action); } return null; } /** * Method to promote a subexpression. A LetExpression is created which binds the child expression * to a system-created variable, and then returns the original expression, with the child expression * replaced by a reference to the variable. * @param child the expression to be promoted * @return the expression that results from the promotion, if any took place */ private Expression promote(Expression child) { final TypeHierarchy th = optimizer.getConfiguration().getTypeHierarchy(); // if the expression being promoted is an operand of "=", make the variable an indexed variable boolean indexed = false; Expression parent = containingExpression.findParentOf(child); if (parent instanceof GeneralComparison && ((GeneralComparison)parent).getOperator() == Token.EQUALS) { indexed = true; } LetExpression let = new LetExpression(); let.setVariableQName(new StructuredQName("zz", NamespaceConstant.SAXON, "zz" + let.hashCode())); SequenceType type = SequenceType.makeSequenceType(child.getItemType(th), child.getCardinality()); let.setRequiredType(type); ExpressionTool.copyLocationInfo(containingExpression, let); let.setSequence(LazyExpression.makeLazyExpression(child)); let.setAction(containingExpression); let.adoptChildExpression(containingExpression); if (indexed) { let.setIndexedVariable(); } containingExpression = let; accepted = true; LocalVariableReference var = new LocalVariableReference(let); int properties = child.getSpecialProperties()&StaticProperty.NOT_UNTYPED; var.setStaticType(type, null, properties); ExpressionTool.copyLocationInfo(containingExpression, var); return var; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/expr/ContinueInstr.java0000644000175000017500000000543511033112257022033 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.instruct.*; import net.sf.saxon.om.NamespaceConstant; import net.sf.saxon.om.StructuredQName; import net.sf.saxon.om.ValueRepresentation; import net.sf.saxon.trace.ExpressionPresenter; import net.sf.saxon.trans.XPathException; import java.util.Iterator; import java.util.ArrayList; /** * */ public class ContinueInstr extends Instruction { private WithParam[] actualParams = null; private IterateInstr iterateInstr; private UserFunction continueFunction; static ValueRepresentation[] emptyArgs = new ValueRepresentation[0]; public static StructuredQName SAXON_CONTINUE = new StructuredQName("saxon", NamespaceConstant.SAXON, "continue"); public ContinueInstr(IterateInstr iterateInstr) { this.iterateInstr = iterateInstr; continueFunction = new UserFunction(); continueFunction.setFunctionName(SAXON_CONTINUE); } public void setParameters(WithParam[] actualParams) { this.actualParams = actualParams; } public Iterator iterateSubExpressions() { ArrayList list = new ArrayList(10); WithParam.getXPathExpressions(actualParams, list); return list.iterator(); } public TailCall processLeavingTail(XPathContext context) throws XPathException { XPathContextMajor cm = (XPathContextMajor)context; ParameterSet params = assembleParams(context, actualParams); cm.setLocalParameters(params); cm.requestTailCall(continueFunction, emptyArgs); return null; } public Expression simplify(ExpressionVisitor visitor) throws XPathException { WithParam.simplify(actualParams, visitor); return this; } public Expression copy() { return this; } public void explain(ExpressionPresenter out) { out.startElement("saxonContinue"); if (actualParams != null && actualParams.length > 0) { out.startSubsidiaryElement("withParams"); WithParam.displayExpressions(actualParams, out); out.endSubsidiaryElement(); } out.endElement(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/expr/GeneralComparison.java0000644000175000017500000006445511116213433022646 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.functions.Minimax; import net.sf.saxon.functions.SystemFunction; import net.sf.saxon.om.*; import net.sf.saxon.pattern.EmptySequenceTest; import net.sf.saxon.sort.AtomicComparer; import net.sf.saxon.sort.CodepointCollator; import net.sf.saxon.sort.GenericAtomicComparer; import net.sf.saxon.sort.StringCollator; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.*; import net.sf.saxon.value.*; /** * GeneralComparison: a boolean expression that compares two expressions * for equals, not-equals, greater-than or less-than. This implements the operators * =, !=, <, >, etc. This implementation is not used when in backwards-compatible mode */ public class GeneralComparison extends BinaryExpression implements ComparisonExpression { protected int singletonOperator; protected AtomicComparer comparer; /** * Create a relational expression identifying the two operands and the operator * * @param p0 the left-hand operand * @param op the operator, as a token returned by the Tokenizer (e.g. Token.LT) * @param p1 the right-hand operand */ public GeneralComparison(Expression p0, int op, Expression p1) { super(p0, op, p1); singletonOperator = getSingletonOperator(op); } /** * Get the AtomicComparer used to compare atomic values. This encapsulates any collation that is used */ public AtomicComparer getAtomicComparer() { return comparer; } /** * Get the primitive (singleton) operator used: one of Token.FEQ, Token.FNE, Token.FLT, Token.FGT, * Token.FLE, Token.FGE */ public int getSingletonOperator() { return singletonOperator; } /** * Determine whether untyped atomic values should be converted to the type of the other operand * @return true if untyped values should be converted to the type of the other operand, false if they * should be converted to strings. */ public boolean convertsUntypedToOther() { return true; } /** * Determine the static cardinality. Returns [1..1] */ public int computeCardinality() { return StaticProperty.EXACTLY_ONE; } /** * Type-check the expression * * @return the checked expression */ public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { final TypeHierarchy th = visitor.getConfiguration().getTypeHierarchy(); Expression oldOp0 = operand0; Expression oldOp1 = operand1; operand0 = visitor.typeCheck(operand0, contextItemType); operand1 = visitor.typeCheck(operand1, contextItemType); // If either operand is statically empty, return false if (Literal.isEmptySequence(operand0) || Literal.isEmptySequence(operand1)) { return Literal.makeLiteral(BooleanValue.FALSE); } // Neither operand needs to be sorted Optimizer opt = visitor.getConfiguration().getOptimizer(); operand0 = ExpressionTool.unsorted(opt, operand0, false); operand1 = ExpressionTool.unsorted(opt, operand1, false); SequenceType atomicType = SequenceType.ATOMIC_SEQUENCE; RoleLocator role0 = new RoleLocator(RoleLocator.BINARY_EXPR, Token.tokens[operator], 0); //role0.setSourceLocator(this); operand0 = TypeChecker.staticTypeCheck(operand0, atomicType, false, role0, visitor); RoleLocator role1 = new RoleLocator(RoleLocator.BINARY_EXPR, Token.tokens[operator], 1); //role1.setSourceLocator(this); operand1 = TypeChecker.staticTypeCheck(operand1, atomicType, false, role1, visitor); if (operand0 != oldOp0) { adoptChildExpression(operand0); } if (operand1 != oldOp1) { adoptChildExpression(operand1); } ItemType t0 = operand0.getItemType(th); // this is always an atomic type or empty-sequence() ItemType t1 = operand1.getItemType(th); // this is always an atomic type or empty-sequence() if (t0 instanceof EmptySequenceTest || t1 instanceof EmptySequenceTest) { return Literal.makeLiteral(BooleanValue.FALSE); } if (((AtomicType)t0).isExternalType() || ((AtomicType)t1).isExternalType()) { XPathException err = new XPathException("Cannot perform comparisons involving external objects"); err.setIsTypeError(true); err.setErrorCode("XPTY0004"); err.setLocator(this); throw err; } BuiltInAtomicType pt0 = (BuiltInAtomicType)t0.getPrimitiveItemType(); BuiltInAtomicType pt1 = (BuiltInAtomicType)t1.getPrimitiveItemType(); int c0 = operand0.getCardinality(); int c1 = operand1.getCardinality(); if (c0 == StaticProperty.EMPTY || c1 == StaticProperty.EMPTY) { return Literal.makeLiteral(BooleanValue.FALSE); } if (t0.equals(BuiltInAtomicType.ANY_ATOMIC) || t0.equals(BuiltInAtomicType.UNTYPED_ATOMIC) || t1.equals(BuiltInAtomicType.ANY_ATOMIC) || t1.equals(BuiltInAtomicType.UNTYPED_ATOMIC)) { // then no static type checking is possible } else { if (!Type.isComparable(pt0, pt1, Token.isOrderedOperator(singletonOperator))) { final NamePool namePool = visitor.getConfiguration().getNamePool(); XPathException err = new XPathException("Cannot compare " + t0.toString(namePool) + " to " + t1.toString(namePool)); err.setErrorCode("XPTY0004"); err.setIsTypeError(true); err.setLocator(this); throw err; } } if (c0 == StaticProperty.EXACTLY_ONE && c1 == StaticProperty.EXACTLY_ONE && !t0.equals(BuiltInAtomicType.ANY_ATOMIC) && !t1.equals(BuiltInAtomicType.ANY_ATOMIC)) { // Use a value comparison if both arguments are singletons, and if the comparison operator to // be used can be determined. Expression e0 = operand0; Expression e1 = operand1; if (t0.equals(BuiltInAtomicType.UNTYPED_ATOMIC)) { if (t1.equals(BuiltInAtomicType.UNTYPED_ATOMIC)) { e0 = new CastExpression(operand0, BuiltInAtomicType.STRING, false); adoptChildExpression(e0); e1 = new CastExpression(operand1, BuiltInAtomicType.STRING, false); adoptChildExpression(e1); } else if (th.isSubType(t1, BuiltInAtomicType.NUMERIC)) { e0 = new CastExpression(operand0, BuiltInAtomicType.DOUBLE, false); adoptChildExpression(e0); } else { e0 = new CastExpression(operand0, (AtomicType) t1, false); adoptChildExpression(e0); } } else if (t1.equals(BuiltInAtomicType.UNTYPED_ATOMIC)) { if (th.isSubType(t0, BuiltInAtomicType.NUMERIC)) { e1 = new CastExpression(operand1, BuiltInAtomicType.DOUBLE, false); adoptChildExpression(e1); } else { e1 = new CastExpression(operand1, (AtomicType) t0, false); adoptChildExpression(e1); } } ValueComparison vc = new ValueComparison(e0, singletonOperator, e1); vc.setAtomicComparer(comparer); ExpressionTool.copyLocationInfo(this, vc); return visitor.typeCheck(visitor.simplify(vc), contextItemType); } StaticContext env = visitor.getStaticContext(); if (comparer == null) { final String defaultCollationName = env.getDefaultCollationName(); StringCollator collation = env.getCollation(defaultCollationName); if (collation == null) { collation = CodepointCollator.getInstance(); } comparer = GenericAtomicComparer.makeAtomicComparer( pt0, pt1, collation, visitor.getConfiguration().getConversionContext()); } // evaluate the expression now if both arguments are constant if ((operand0 instanceof Literal) && (operand1 instanceof Literal)) { return Literal.makeLiteral((AtomicValue)evaluateItem(env.makeEarlyEvaluationContext())); } return this; } private static Expression makeMinOrMax(Expression exp, String function) { FunctionCall fn = SystemFunction.makeSystemFunction(function, new Expression[]{exp}); ((Minimax)fn).setIgnoreNaN(true); return fn; } /** * Optimize the expression * * @return the checked expression */ public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { final TypeHierarchy th = visitor.getConfiguration().getTypeHierarchy(); final StaticContext env = visitor.getStaticContext(); final Optimizer opt = visitor.getConfiguration().getOptimizer(); operand0 = visitor.optimize(operand0, contextItemType); operand1 = visitor.optimize(operand1, contextItemType); Value value0 = null; if (operand0 instanceof Literal) { value0 = ((Literal)operand0).getValue(); } // If either operand is statically empty, return false if (Literal.isEmptySequence(operand0) || Literal.isEmptySequence(operand1)) { return Literal.makeLiteral(BooleanValue.FALSE); } // Neither operand needs to be sorted operand0 = ExpressionTool.unsorted(opt, operand0, false); operand1 = ExpressionTool.unsorted(opt, operand1, false); ItemType t0 = operand0.getItemType(th); ItemType t1 = operand1.getItemType(th); int c0 = operand0.getCardinality(); int c1 = operand1.getCardinality(); // Check if neither argument allows a sequence of >1 if (!Cardinality.allowsMany(c0) && !Cardinality.allowsMany(c1)) { // Use a singleton comparison if both arguments are singletons SingletonComparison sc = new SingletonComparison(operand0, singletonOperator, operand1); ExpressionTool.copyLocationInfo(this, sc); sc.setAtomicComparer(comparer); return visitor.optimize(sc, contextItemType); } // if first argument is a singleton, reverse the arguments if (Cardinality.expectsMany(operand1) && !Cardinality.expectsMany(operand0)) { GeneralComparison mc = getInverseComparison(); ExpressionTool.copyLocationInfo(this, mc); mc.comparer = comparer; return visitor.optimize(mc, contextItemType); } // see if both arguments are singletons... if (c0 == StaticProperty.EXACTLY_ONE && c1 == StaticProperty.EXACTLY_ONE && !t0.equals(BuiltInAtomicType.ANY_ATOMIC) && !t1.equals(BuiltInAtomicType.ANY_ATOMIC)) { // Use a value comparison if both arguments are singletons, and if the comparison operator to // be used can be determined. Expression e0 = operand0; Expression e1 = operand1; if (t0.equals(BuiltInAtomicType.UNTYPED_ATOMIC)) { if (t1.equals(BuiltInAtomicType.UNTYPED_ATOMIC)) { e0 = new CastExpression(operand0, BuiltInAtomicType.STRING, false); adoptChildExpression(e0); e1 = new CastExpression(operand1, BuiltInAtomicType.STRING, false); adoptChildExpression(e1); } else if (th.isSubType(t1, BuiltInAtomicType.NUMERIC)) { e0 = new CastExpression(operand0, BuiltInAtomicType.DOUBLE, false); adoptChildExpression(e0); } else { e0 = new CastExpression(operand0, (AtomicType) t1, false); adoptChildExpression(e0); } } else if (t1.equals(BuiltInAtomicType.UNTYPED_ATOMIC)) { if (th.isSubType(t0, BuiltInAtomicType.NUMERIC)) { e1 = new CastExpression(operand1, BuiltInAtomicType.DOUBLE, false); adoptChildExpression(e1); } else { e1 = new CastExpression(operand1, (AtomicType) t0, false); adoptChildExpression(e1); } } ValueComparison vc = new ValueComparison(e0, singletonOperator, e1); vc.setAtomicComparer(comparer); ExpressionTool.copyLocationInfo(this, vc); return visitor.optimize(visitor.typeCheck(visitor.simplify(vc), contextItemType), contextItemType); } final String defaultCollationName = env.getDefaultCollationName(); StringCollator comp = env.getCollation(defaultCollationName); if (comp == null) { comp = CodepointCollator.getInstance(); } BuiltInAtomicType pt0 = (BuiltInAtomicType)t0.getPrimitiveItemType(); BuiltInAtomicType pt1 = (BuiltInAtomicType)t1.getPrimitiveItemType(); comparer = GenericAtomicComparer.makeAtomicComparer(pt0, pt1, comp, env.getConfiguration().getConversionContext()); // If one operand is numeric, then construct code // to force the other operand to numeric // TODO: shouldn't this happen during type checking? Expression e0 = operand0; Expression e1 = operand1; // if (operator != Token.EQUALS && operator != Token.NE && // (th.isSubType(t0, BuiltInAtomicType.NUMERIC) || th.isSubType(t1, BuiltInAtomicType.NUMERIC))) { boolean numeric0 = th.isSubType(t0, BuiltInAtomicType.NUMERIC); boolean numeric1 = th.isSubType(t1, BuiltInAtomicType.NUMERIC); if (numeric1 && !numeric0) { RoleLocator role = new RoleLocator(RoleLocator.BINARY_EXPR, Token.tokens[operator], 0); //role.setSourceLocator(this); e0 = TypeChecker.staticTypeCheck(e0, SequenceType.NUMERIC_SEQUENCE, false, role, visitor); } if (numeric0 && !numeric1) { RoleLocator role = new RoleLocator(RoleLocator.BINARY_EXPR, Token.tokens[operator], 1); //role.setSourceLocator(this); e1 = TypeChecker.staticTypeCheck(e1, SequenceType.NUMERIC_SEQUENCE, false, role, visitor); } // look for (N to M = I) // First a variable range... if (operand0 instanceof RangeExpression && th.isSubType(operand1.getItemType(th), BuiltInAtomicType.NUMERIC) && operator == Token.EQUALS && !Cardinality.allowsMany(operand1.getCardinality())) { Expression min = ((RangeExpression)operand0).operand0; Expression max = ((RangeExpression)operand0).operand1; // if (operand1 instanceof Position) { // PositionRange pr = new PositionRange(min, max, PositionRange.GE_MIN_LE_MAX); // ExpressionTool.copyLocationInfo(this, pr); // return pr; // } else { IntegerRangeTest ir = new IntegerRangeTest(operand1, min, max); ExpressionTool.copyLocationInfo(this, ir); return ir; // } } // Now a fixed range... if (value0 instanceof IntegerRange && th.isSubType(operand1.getItemType(th), BuiltInAtomicType.NUMERIC) && operator == Token.EQUALS && !Cardinality.allowsMany(operand1.getCardinality())) { long min = ((IntegerRange)value0).getStart(); long max = ((IntegerRange)value0).getEnd(); // if (operand1 instanceof Position) { // PositionRange pr = new PositionRange( // Literal.makeLiteral(Int64Value.makeIntegerValue(min)), // Literal.makeLiteral(Int64Value.makeIntegerValue(max)), PositionRange.GE_MIN_LE_MAX); // ExpressionTool.copyLocationInfo(this, pr); // return pr; // } else { IntegerRangeTest ir = new IntegerRangeTest(operand1, Literal.makeLiteral(Int64Value.makeIntegerValue(min)), Literal.makeLiteral(Int64Value.makeIntegerValue(max))); ExpressionTool.copyLocationInfo(this, ir); return ir; // } } // If second operand is a singleton, rewrite as // some $x in E0 satisfies $x op E1 // TODO: this works, but it doesn't invariably produce benefits, eg. XMark Q11. // Make it more selective. if (!Cardinality.allowsMany(c1)) { // System.err.println("** using quantified optimization R **"); QuantifiedExpression qe = new QuantifiedExpression(); qe.setOperator(Token.SOME); qe.setVariableQName(new StructuredQName("qq", NamespaceConstant.SAXON, "qq" + qe.hashCode())); SequenceType type = SequenceType.makeSequenceType(e0.getItemType(th), StaticProperty.EXACTLY_ONE); qe.setRequiredType(type); qe.setSequence(e0); ExpressionTool.copyLocationInfo(this, qe); LocalVariableReference var = new LocalVariableReference(qe); SingletonComparison vc = new SingletonComparison(var, singletonOperator, e1); vc.setAtomicComparer(comparer); qe.setAction(vc); return visitor.optimize(visitor.typeCheck(qe, contextItemType), contextItemType); } // If the operator is gt, ge, lt, le then replace X < Y by min(X) < max(Y) // This optimization is done only in the case where at least one of the // sequences is known to be purely numeric. It isn't safe if both sequences // contain untyped atomic values, because in that case, the type of the // comparison isn't known in advance. For example [(1, U1) < ("fred", U2)] // involves both string and numeric comparisons. if (operator != Token.EQUALS && operator != Token.NE && (th.isSubType(t0, BuiltInAtomicType.NUMERIC) || th.isSubType(t1, BuiltInAtomicType.NUMERIC))) { // System.err.println("** using minimax optimization **"); ValueComparison vc; switch(operator) { case Token.LT: case Token.LE: vc = new ValueComparison(makeMinOrMax(e0, "min"), singletonOperator, makeMinOrMax(e1, "max")); vc.setResultWhenEmpty(BooleanValue.FALSE); vc.setAtomicComparer(comparer); break; case Token.GT: case Token.GE: vc = new ValueComparison(makeMinOrMax(e0, "max"), singletonOperator, makeMinOrMax(e1, "min")); vc.setResultWhenEmpty(BooleanValue.FALSE); vc.setAtomicComparer(comparer); break; default: throw new UnsupportedOperationException("Unknown operator " + operator); } ExpressionTool.copyLocationInfo(this, vc); return visitor.typeCheck(vc, contextItemType); } // evaluate the expression now if both arguments are constant if ((operand0 instanceof Literal) && (operand1 instanceof Literal)) { return Literal.makeLiteral((AtomicValue)evaluateItem(env.makeEarlyEvaluationContext())); } return this; } /** * Copy an expression. This makes a deep copy. * * @return the copy of the original expression */ public Expression copy() { GeneralComparison gc = new GeneralComparison(operand0.copy(), operator, operand1.copy()); gc.comparer = comparer; gc.singletonOperator = singletonOperator; return gc; } /** * Evaluate the expression in a given context * * @param context the given context for evaluation * @return a BooleanValue representing the result of the numeric comparison of the two operands */ public Item evaluateItem(XPathContext context) throws XPathException { return BooleanValue.get(effectiveBooleanValue(context)); } /** * Evaluate the expression in a boolean context * * @param context the given context for evaluation * @return a boolean representing the result of the numeric comparison of the two operands */ public boolean effectiveBooleanValue(XPathContext context) throws XPathException { try { SequenceIterator iter1 = operand0.iterate(context); SequenceIterator iter2 = operand1.iterate(context); Value seq2 = (Value)SequenceExtent.makeSequenceExtent(iter2); // we choose seq2 because it's more likely to be a singleton int count2 = seq2.getLength(); if (count2 == 0) { return false; } if (count2 == 1) { AtomicValue s2 = (AtomicValue)seq2.itemAt(0); while (true) { AtomicValue s1 = (AtomicValue)iter1.next(); if (s1 == null) { break; } if (compare(s1, singletonOperator, s2, comparer, context)) { iter1.close(); return true; } } return false; } while (true) { AtomicValue s1 = (AtomicValue)iter1.next(); if (s1 == null) { break; } SequenceIterator e2 = seq2.iterate(); while (true) { AtomicValue s2 = (AtomicValue)e2.next(); if (s2 == null) { break; } if (compare(s1, singletonOperator, s2, comparer, context)) { iter1.close(); e2.close(); return true; } } } return false; } catch (ValidationException e) { XPathException err = new XPathException(e); err.setXPathContext(context); if (e.getLineNumber() == -1) { err.setLocator(this); } else { err.setLocator(e); } err.setErrorCode(e.getErrorCodeLocalPart()); throw err; } catch (XPathException e) { // re-throw the exception with location information added e.maybeSetLocation(this); e.maybeSetContext(context); throw e; } } /** * Compare two atomic values * @param a1 the first value * @param operator the operator, for example {@link Token#EQUALS} * @param a2 the second value * @param comparer the comparer to be used to perform the comparison * @param context the XPath evaluation context * @return true if the comparison succeeds */ protected static boolean compare(AtomicValue a1, int operator, AtomicValue a2, AtomicComparer comparer, XPathContext context) throws XPathException { AtomicValue v1 = a1; AtomicValue v2 = a2; if (a1 instanceof UntypedAtomicValue) { if (a2 instanceof NumericValue) { v1 = a1.convert(BuiltInAtomicType.DOUBLE, true, context).asAtomic(); } else if (a2 instanceof UntypedAtomicValue) { // the spec says convert it to a string, but this doesn't affect the outcome } else { v1 = a1.convert(a2.getPrimitiveType(), true, context).asAtomic(); } } if (a2 instanceof UntypedAtomicValue) { if (a1 instanceof NumericValue) { v2 = a2.convert(BuiltInAtomicType.DOUBLE, true, context).asAtomic(); } else if (a1 instanceof UntypedAtomicValue) { // the spec says convert it to a string, but this doesn't affect the outcome } else { v2 = a2.convert(a1.getPrimitiveType(), true, context).asAtomic(); } } return ValueComparison.compare(v1, operator, v2, comparer.provideContext(context)); } /** * Determine the data type of the expression * @param th the type hierarchy cache * @return the value BuiltInAtomicType.BOOLEAN */ public ItemType getItemType(TypeHierarchy th) { return BuiltInAtomicType.BOOLEAN; } /** * Return the singleton form of the comparison operator, e.g. FEQ for EQUALS, FGT for GT * @param op the many-to-many form of the operator, for example {@link Token#LE} * @return the corresponding singleton operator, for example {@link Token#FLE} */ private static int getSingletonOperator(int op) { switch (op) { case Token.EQUALS: return Token.FEQ; case Token.GE: return Token.FGE; case Token.NE: return Token.FNE; case Token.LT: return Token.FLT; case Token.GT: return Token.FGT; case Token.LE: return Token.FLE; default: return op; } } protected GeneralComparison getInverseComparison() { return new GeneralComparison(operand1, Token.inverse(operator), operand0); } protected String displayOperator() { return "many-to-many " + super.displayOperator(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/expr/MappingFunction.java0000644000175000017500000000274311033112257022327 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.om.Item; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.trans.XPathException; /** * MappingFunction is an interface that must be satisfied by an object passed to a * MappingIterator. It represents an object which, given an Item, can return a * SequenceIterator that delivers a sequence of zero or more Items. */ public interface MappingFunction { /** * Map one item to a sequence. * @param item The item to be mapped. * @return one of the following: (a) a SequenceIterator over the sequence of items that the supplied input * item maps to, or (b) null if it maps to an empty sequence. */ public SequenceIterator map(Item item) throws XPathException; } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/expr/Atomizer.java0000644000175000017500000003514411033112257021021 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.Configuration; import net.sf.saxon.event.ReceiverOptions; import net.sf.saxon.instruct.ValueOf; import net.sf.saxon.om.*; import net.sf.saxon.pattern.EmptySequenceTest; import net.sf.saxon.pattern.NodeTest; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.*; import net.sf.saxon.value.AtomicValue; import net.sf.saxon.value.Cardinality; import net.sf.saxon.value.Value; /** * An Atomizer is an expression corresponding essentially to the fn:data() function: it * maps a sequence by replacing nodes with their typed values */ public final class Atomizer extends UnaryExpression { private boolean untyped; //set to true if it is known that the nodes being atomized will be untyped private boolean singleValued; // set to true if all atomized nodes will atomize to a single atomic value private Configuration config; /** * Constructor * @param sequence the sequence to be atomized * @param config the Configuration. Used only for optimization, may be null. Atomization is faster if * it is known in advance that all nodes will be untyped. */ public Atomizer(Expression sequence, Configuration config) { super(sequence); this.config = config; if (config != null) { untyped = (config.areAllNodesUntyped()); computeSingleValued(config.getTypeHierarchy()); } sequence.setFlattened(true); } /** * Simplify an expression * @param visitor an expression visitor */ public Expression simplify(ExpressionVisitor visitor) throws XPathException { config = visitor.getConfiguration(); untyped = config.areAllNodesUntyped(); operand = visitor.simplify(operand); if (operand instanceof Literal) { Value val = ((Literal)operand).getValue(); if (val instanceof AtomicValue) { return operand; } SequenceIterator iter = val.iterate(); while (true) { // if all items in the sequence are atomic (they generally will be, since this is // done at compile time), then return the sequence Item i = iter.next(); if (i == null) { return operand; } if (i instanceof NodeInfo) { return this; } } } else if (operand instanceof ValueOf && (((ValueOf)operand).getOptions()& ReceiverOptions.DISABLE_ESCAPING) == 0) { // XSLT users tend to use ValueOf unnecessarily return ((ValueOf)operand).convertToStringJoin(visitor.getStaticContext()); } return this; } /** * Type-check the expression */ public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { operand = visitor.typeCheck(operand, contextItemType); // If the configuration allows typed data, check whether the content type of these particular nodes is untyped final TypeHierarchy th = visitor.getConfiguration().getTypeHierarchy(); computeSingleValued(th); visitor.resetStaticProperties(); if (th.isSubType(operand.getItemType(th), BuiltInAtomicType.ANY_ATOMIC)) { return operand; } operand.setFlattened(true); return this; } private void computeSingleValued(TypeHierarchy th) { singleValued = untyped; if (!singleValued) { ItemType nodeType = operand.getItemType(th); if (nodeType instanceof NodeTest) { SchemaType st = ((NodeTest)nodeType).getContentType(); if (st == AnyType.getInstance() || st.isAtomicType()) { singleValued = true; } } } } /** * Perform optimisation of an expression and its subexpressions. *

    *

    This method is called after all references to functions and variables have been resolved * to the declaration of the function or variable, and after all type checking has been done.

    * * @param visitor an expression visitor * @param contextItemType the static type of "." at the point where this expression is invoked. * The parameter is set to null if it is known statically that the context item will be undefined. * If the type of the context item is not known statically, the argument is set to * {@link net.sf.saxon.type.Type#ITEM_TYPE} * @return the original expression, rewritten if appropriate to optimize execution * @throws net.sf.saxon.trans.XPathException * if an error is discovered during this phase * (typically a type error) */ public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { Expression exp = super.optimize(visitor, contextItemType); if (exp == this) { final TypeHierarchy th = visitor.getConfiguration().getTypeHierarchy(); if (th.isSubType(operand.getItemType(th), BuiltInAtomicType.ANY_ATOMIC)) { return operand; } if (operand instanceof ValueOf && (((ValueOf)operand).getOptions()& ReceiverOptions.DISABLE_ESCAPING) == 0) { // XSLT users tend to use ValueOf unnecessarily return ((ValueOf)operand).convertToStringJoin(visitor.getStaticContext()); } } return exp; } /** * Determine the special properties of this expression * @return {@link StaticProperty#NON_CREATIVE}. */ public int computeSpecialProperties() { int p = super.computeSpecialProperties(); return p | StaticProperty.NON_CREATIVE; } /** * Copy an expression. This makes a deep copy. * * @return the copy of the original expression */ public Expression copy() { return new Atomizer(getBaseExpression().copy(), config); } /** * Iterate over the sequence of values */ public SequenceIterator iterate(XPathContext context) throws XPathException { SequenceIterator base = operand.iterate(context); return getAtomizingIterator(base); } /** * Evaluate as an Item. This should only be called if the Atomizer has cardinality zero-or-one, * which will only be the case if the underlying expression has cardinality zero-or-one. */ public Item evaluateItem(XPathContext context) throws XPathException { Item i = operand.evaluateItem(context); if (i==null) { return null; } if (i instanceof NodeInfo) { SequenceIterator it = i.getTypedValue(); return it.next(); } else { return i; } } /** * Determine the data type of the items returned by the expression, if possible * @return a value such as Type.STRING, Type.BOOLEAN, Type.NUMBER. For this class, the * result is always an atomic type, but it might be more specific. * @param th the type hierarchy cache */ public ItemType getItemType(TypeHierarchy th) { return getAtomizedItemType(operand, untyped, th); } /** * Compute the type that will result from atomizing the result of a given expression * @param operand the given expression * @param alwaysUntyped true if it is known that nodes will always be untyped * @param th the type hierarchy cache * @return the item type of the result of evaluating the operand expression, after atomization */ public static ItemType getAtomizedItemType(Expression operand, boolean alwaysUntyped, TypeHierarchy th) { ItemType in = operand.getItemType(th); if (in.isAtomicType()) { return in; } if (in instanceof NodeTest) { if (in instanceof EmptySequenceTest) { return in; } int kinds = ((NodeTest)in).getNodeKindMask(); if (alwaysUntyped) { // Some node-kinds always have a typed value that's a string if ((kinds | STRING_KINDS) == STRING_KINDS) { return BuiltInAtomicType.STRING; } // Some node-kinds are always untyped atomic; some are untypedAtomic provided that the configuration // is untyped if ((kinds | UNTYPED_IF_UNTYPED_KINDS) == UNTYPED_IF_UNTYPED_KINDS) { return BuiltInAtomicType.UNTYPED_ATOMIC; } } else { if ((kinds | UNTYPED_KINDS) == UNTYPED_KINDS) { return BuiltInAtomicType.UNTYPED_ATOMIC; } } return in.getAtomizedItemType(); } return BuiltInAtomicType.ANY_ATOMIC; } /** * Node kinds whose typed value is always a string */ private static final int STRING_KINDS = (1< *

    The default implementation of this method assumes that an expression does no navigation other than * the navigation done by evaluating its subexpressions, and that the subexpressions are evaluated in the * same context as the containing expression. The method must be overridden for any expression * where these assumptions do not hold. For example, implementations exist for AxisExpression, ParentExpression, * and RootExpression (because they perform navigation), and for the doc(), document(), and collection() * functions because they create a new navigation root. Implementations also exist for PathExpression and * FilterExpression because they have subexpressions that are evaluated in a different context from the * calling expression.

    * * @param pathMap the PathMap to which the expression should be added * @param pathMapNodeSet the PathMapNodeSet to which the paths embodied in this expression should be added * @return the pathMapNodeSet representing the points in the source document that are both reachable by this * expression, and that represent possible results of this expression. For an expression that does * navigation, it represents the end of the arc in the path map that describes the navigation route. For other * expressions, it is the same as the input pathMapNode. */ public PathMap.PathMapNodeSet addToPathMap(PathMap pathMap, PathMap.PathMapNodeSet pathMapNodeSet) { PathMap.PathMapNodeSet result = operand.addToPathMap(pathMap, pathMapNodeSet); if (result != null) { result.setAtomized(); } return null; } /** * Get an iterator that returns the result of atomizing the sequence delivered by the supplied * iterator * @param base the supplied iterator, the input to atomization * @return an iterator that returns atomic values, the result of the atomization */ public static SequenceIterator getAtomizingIterator(SequenceIterator base) { if (base instanceof AxisIterator) { return new AxisAtomizingIterator((AxisIterator)base); } return new MappingIterator(base, AtomizingFunction.getInstance()); } /** * Diagnostic print of expression structure. The abstract expression tree * is written to the supplied output destination. */ public String displayExpressionName() { return "atomize"; } /** * Implement the mapping function. This is stateless, so there is a singleton instance. */ public static class AtomizingFunction implements MappingFunction { /** * Private constructor, ensuring that everyone uses the singleton instance */ private AtomizingFunction(){} private static final AtomizingFunction theInstance = new AtomizingFunction(); /** * Get the singleton instance * @return the singleton instance of this mapping function */ public static AtomizingFunction getInstance() { return theInstance; } public SequenceIterator map(Item item) throws XPathException { if (item instanceof NodeInfo) { return item.getTypedValue(); } else { return SingletonIterator.makeIterator(item); } } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/expr/LocalVariableReference.java0000644000175000017500000000740511033112257023545 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.om.ValueRepresentation; import net.sf.saxon.trans.XPathException; /** * Variable reference: a reference to a local variable. This subclass of VariableReference * bypasses the Binding object to get the value directly from the relevant slot in the local * stackframe. */ public class LocalVariableReference extends VariableReference { int slotNumber = -999; /** * Create a local variable reference. The binding and slot number will be supplied later */ public LocalVariableReference() { } /** * Create a LocalVariableReference bound to a given Binding * @param binding the binding (that is, the declaration of this local variable) */ public LocalVariableReference(Binding binding) { super(binding); } /** * Create a clone copy of this VariableReference * @return the cloned copy */ public Expression copy() { if (binding == null) { throw new UnsupportedOperationException("Cannot copy a variable reference whose binding is unknown"); } LocalVariableReference ref = new LocalVariableReference(); ref.binding = binding; ref.staticType = staticType; ref.slotNumber = slotNumber; ref.constantValue = constantValue; ref.displayName = displayName; ExpressionTool.copyLocationInfo(this, ref); return ref; } /** * Set the slot number for this local variable, that is, its position in the local stack frame * @param slotNumber the slot number to be used */ public void setSlotNumber(int slotNumber) { this.slotNumber = slotNumber; } /** * Get the slot number allocated to this local variable * @return the slot number */ public int getSlotNumber() { return slotNumber; } /** * Return the value of the variable * @param c the XPath dynamic context * @return the value of the variable * @throws XPathException if any dynamic error occurs while evaluating the variable */ public ValueRepresentation evaluateVariable(XPathContext c) throws XPathException { try { return c.getStackFrame().slots[slotNumber]; } catch (ArrayIndexOutOfBoundsException err) { if (slotNumber == -999) { throw new ArrayIndexOutOfBoundsException("Local variable has not been allocated a stack frame slot"); } throw err; } } /** * Replace this VariableReference where appropriate by a more efficient implementation. This * can only be done after all slot numbers are allocated. The efficiency is gained by binding the * VariableReference directly to a local or global slot, rather than going via the Binding object * * @param parent the parent expression of this variable reference */ // public void refineVariableReference(Expression parent) { // // no-op // } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/expr/FunctionCall.java0000644000175000017500000003704711033112257021614 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.om.FastStringBuffer; import net.sf.saxon.om.StructuredQName; import net.sf.saxon.trace.ExpressionPresenter; import net.sf.saxon.trans.NoDynamicContextException; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ItemType; import net.sf.saxon.value.SequenceExtent; import net.sf.saxon.value.Value; import java.util.Arrays; import java.util.Iterator; /** * Abstract superclass for calls to system-defined and user-defined functions */ public abstract class FunctionCall extends Expression { /** * The name of the function */ private StructuredQName name; /** * The array of expressions representing the actual parameters * to the function call */ protected Expression[] argument; /** * Set the name of the function being called * @param name the name of the function */ public final void setFunctionName(StructuredQName name) { this.name = name; } /** * Get the qualified of the function being called * @return the qualified name */ public StructuredQName getFunctionName() { return name; } /** * Determine the number of actual arguments supplied in the function call * @return the arity (the number of arguments) */ public final int getNumberOfArguments() { return argument.length; } /** * Method called by the expression parser when all arguments have been supplied * @param args the expressions contained in the argument list of the function call */ public void setArguments(Expression[] args) { argument = args; for (int a=0; a *

    This method is called after all references to functions and variables have been resolved * to the declaration of the function or variable, and after all type checking has been done.

    * * @param visitor an expression visitor * @param contextItemType the static type of "." at the point where this expression is invoked. * The parameter is set to null if it is known statically that the context item will be undefined. * If the type of the context item is not known statically, the argument is set to * {@link net.sf.saxon.type.Type#ITEM_TYPE} * @return the original expression, rewritten if appropriate to optimize execution * @throws XPathException if an error is discovered during this phase * (typically a type error) */ public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { boolean fixed = true; for (int i=0; i * A convenience routine for use in subclasses. * @param min the minimum number of arguments allowed * @param max the maximum number of arguments allowed * @param visitor an expression visitor * @return the actual number of arguments * @throws net.sf.saxon.trans.XPathException if the number of arguments is out of range */ protected int checkArgumentCount(int min, int max, ExpressionVisitor visitor) throws XPathException { int numArgs = argument.length; if (min==max && numArgs != min) { throw new XPathException("Function " + getDisplayName() + " must have " + min + pluralArguments(min), this); } if (numArgs < min) { throw new XPathException("Function " + getDisplayName() + " must have at least " + min + pluralArguments(min), this); } if (numArgs > max) { throw new XPathException("Function " + getDisplayName() + " must have no more than " + max + pluralArguments(max), this); } return numArgs; } /** * Utility routine used in constructing error messages: get the word "argument" or "arguments" * @param num the number of arguments * @return the singular or plural word */ private static String pluralArguments(int num) { if (num==1) return " argument"; return " arguments"; } /** * Get the immediate subexpressions of this expression */ public Iterator iterateSubExpressions() { try { return Arrays.asList(argument).iterator(); } catch (NullPointerException err) { // typically caused by doing CopyLocationInfo after creating the function // but before creating its arguments throw err; } } /** * Replace one subexpression by a replacement subexpression * @param original the original subexpression * @param replacement the replacement subexpression * @return true if the original subexpression is found */ public boolean replaceSubExpression(Expression original, Expression replacement) { boolean found = false; for (int i=0; i *

    The default implementation of this method assumes that an expression does no navigation other than * the navigation done by evaluating its subexpressions, and that the subexpressions are evaluated in the * same context as the containing expression. The method must be overridden for any expression * where these assumptions do not hold. For example, implementations exist for AxisExpression, ParentExpression, * and RootExpression (because they perform navigation), and for the doc(), document(), and collection() * functions because they create a new navigation root. Implementations also exist for PathExpression and * FilterExpression because they have subexpressions that are evaluated in a different context from the * calling expression.

    * * @param pathMap the PathMap to which the expression should be added * @param pathMapNodes the node in the PathMap representing the focus at the point where this expression * is called. Set to null if this expression appears at the top level, in which case the expression, if it * is registered in the path map at all, must create a new path map root. * @return the pathMapNode representing the focus established by this expression, in the case where this * expression is the first operand of a path expression or filter expression. For an expression that does * navigation, it represents the end of the arc in the path map that describes the navigation route. For other * expressions, it is the same as the input pathMapNode. */ public PathMap.PathMapNodeSet addExternalFunctionCallToPathMap(PathMap pathMap, PathMap.PathMapNodeSet pathMapNodes) { // Except in the case of system functions, we have no idea where a function call might // navigate, so we assume the worst, and register that the path has unknown dependencies PathMap.PathMapNodeSet result = new PathMap.PathMapNodeSet(); for (Iterator iter = iterateSubExpressions(); iter.hasNext(); ) { Expression child = (Expression)iter.next(); result.addNodeSet(child.addToPathMap(pathMap, pathMapNodes)); } result.setHasUnknownDependencies(); return result; // AxisExpression axis = new AxisExpression(Axis.ANCESTOR_OR_SELF, AnyNodeTest.getInstance()); // axis.setContainer(getContainer()); // PathMap.PathMapNodeSet target = axis.addToPathMap(pathMap, pathMapNodes); // axis = new AxisExpression(Axis.ANCESTOR_OR_SELF, AnyNodeTest.getInstance()); // axis.setContainer(getContainer()); // return axis.addToPathMap(pathMap, target); } /** * Get the name of the function for display in messages * @return the name of the function as a lexical QName */ public final String getDisplayName() { return getFunctionName().getDisplayName(); } /** * The toString() method for an expression attempts to give a representation of the expression * in an XPath-like form, but there is no guarantee that the syntax will actually be true XPath. * In the case of XSLT instructions, the toString() method gives an abstracted view of the syntax */ public String toString() { FastStringBuffer buff = new FastStringBuffer(120); buff.append(getDisplayName()); Iterator iter = iterateSubExpressions(); boolean first = true; while (iter.hasNext()) { buff.append(first ? "(" : ", "); buff.append(iter.next().toString()); first = false; } buff.append(first ? "()" : ")"); return buff.toString(); } /** * Diagnostic print of expression structure. The abstract expression tree * is written to the supplied output destination. */ public void explain(ExpressionPresenter out) { out.startElement("functionCall"); out.emitAttribute("name", getDisplayName()); for (int a=0; a0) { // p1 is higher nextNode2 = next(p2); if (nextNode2 == null) { return deliver(); } } else { // keys are equal nextNode2 = next(p2); nextNode1 = next(p1); } } } /** * Deliver the next node from the first node-set, advancing the iterator to * look-ahead for the next item, and setting the current and position variables. * @return the next node from the first node-set * @throws XPathException */ private NodeInfo deliver() throws XPathException { current = nextNode1; nextNode1 = next(p1); position++; return current; } public Item current() { return current; } public int position() { return position; } public void close() { p1.close(); p2.close(); } public SequenceIterator getAnother() throws XPathException { return new DifferenceEnumeration(p1.getAnother(), p2.getAnother(), comparer); } /** * Get properties of this iterator, as a bit-significant integer. * * @return the properties of this iterator. This will be some combination of * properties such as {@link SequenceIterator#GROUNDED}, {@link SequenceIterator#LAST_POSITION_FINDER}, * and {@link SequenceIterator#LOOKAHEAD}. It is always * acceptable to return the value zero, indicating that there are no known special properties. * It is acceptable for the properties of the iterator to change depending on its state. */ public int getProperties() { return 0; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/expr/AxisAtomizingIterator.java0000644000175000017500000001010611033112257023516 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.om.Item; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.om.AxisIterator; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.Value; import net.sf.saxon.value.AtomicValue; /** * This iterator returns a sequence of atomic values, the result of atomizing the sequence * of nodes returned by an underlying AxisIterator. */ public final class AxisAtomizingIterator implements SequenceIterator { private AxisIterator base; private SequenceIterator results = null; private AtomicValue current = null; private int position = 0; /** * Construct an atomizing iterator * @param base the base iterator (whose nodes are to be atomized) */ public AxisAtomizingIterator(AxisIterator base) { this.base = base; } public Item next() throws XPathException { AtomicValue nextItem; while (true) { if (results != null) { nextItem = (AtomicValue)results.next(); if (nextItem != null) { break; } else { results = null; } } // Avoid calling next() to materialize the NodeInfo object if (base.moveNext()) { Value atomized = base.atomize(); if (atomized instanceof AtomicValue) { // common case (the atomized value of the node is a single atomic value) results = null; nextItem = (AtomicValue)atomized; break; } else { results = atomized.iterate(); nextItem = (AtomicValue)results.next(); if (nextItem == null) { results = null; } else { break; } } // now go round the loop to get the next item from the base sequence } else { results = null; current = null; position = -1; return null; } } current = nextItem; position++; return nextItem; } public Item current() { return current; } public int position() { return position; } public void close() { base.close(); } public SequenceIterator getAnother() { // System.err.println(this + " getAnother() "); AxisIterator newBase = (AxisIterator)base.getAnother(); return new AxisAtomizingIterator(newBase); } /** * Get properties of this iterator, as a bit-significant integer. * * @return the properties of this iterator. This will be some combination of * properties such as {@link net.sf.saxon.om.SequenceIterator#GROUNDED}, {@link net.sf.saxon.om.SequenceIterator#LAST_POSITION_FINDER}, * and {@link net.sf.saxon.om.SequenceIterator#LOOKAHEAD}. It is always * acceptable to return the value zero, indicating that there are no known special properties. * It is acceptable for the properties of the iterator to change depending on its state. */ public int getProperties() { return 0; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/expr/ForExpression.java0000644000175000017500000011451611100053577022042 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.evpull.EventIterator; import net.sf.saxon.evpull.EventMappingFunction; import net.sf.saxon.evpull.EventMappingIterator; import net.sf.saxon.functions.KeyFn; import net.sf.saxon.functions.SystemFunction; import net.sf.saxon.instruct.Choose; import net.sf.saxon.om.Item; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.om.StructuredQName; import net.sf.saxon.om.ValueRepresentation; import net.sf.saxon.trace.ExpressionPresenter; import net.sf.saxon.trace.Location; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.SchemaType; import net.sf.saxon.type.TypeHierarchy; import net.sf.saxon.value.Cardinality; import net.sf.saxon.value.Int64Value; import net.sf.saxon.value.SequenceType; import java.util.ArrayList; import java.util.List; /** * A ForExpression maps an expression over a sequence. * This version works with range variables, it doesn't change the context information */ public class ForExpression extends Assignation { private PositionVariable positionVariable = null; /** * Create a "for" expression (for $x at $p in SEQUENCE return ACTION) */ public ForExpression() { } /** * Set the reference to the position variable (XQuery only) * @param decl the range variable declaration for the position variable */ public void setPositionVariable (PositionVariable decl) { positionVariable = decl; } /** * Get the name of the position variable * @return the name of the position variable ("at $p") if there is one, or null if not */ public StructuredQName getPositionVariableName() { if (positionVariable == null) { return null; } else { return positionVariable.getVariableQName(); } } /** * Set the slot number for the range variable * @param nr the slot number allocated to the range variable on the local stack frame. * This implicitly allocates the next slot number to the position variable if there is one. */ public void setSlotNumber(int nr) { super.setSlotNumber(nr); if (positionVariable != null) { positionVariable.setSlotNumber(nr+1); } } /** * Get the number of slots required. * @return normally 1, except for a FOR expression with an AT clause, where it is 2. */ public int getRequiredSlots() { return (positionVariable == null ? 1 : 2); } /** * Type-check the expression */ public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { // The order of events is critical here. First we ensure that the type of the // sequence expression is established. This is used to establish the type of the variable, // which in turn is required when type-checking the action part. sequence = visitor.typeCheck(sequence, contextItemType); if (Literal.isEmptySequence(sequence)) { return sequence; } if (requiredType != null) { // if declaration is null, we've already done the type checking in a previous pass final TypeHierarchy th = visitor.getConfiguration().getTypeHierarchy(); SequenceType decl = requiredType; SequenceType sequenceType = SequenceType.makeSequenceType( decl.getPrimaryType(), StaticProperty.ALLOWS_ZERO_OR_MORE); RoleLocator role = new RoleLocator(RoleLocator.VARIABLE, variableName, 0 ); //role.setSourceLocator(this); sequence = TypeChecker.strictTypeCheck( sequence, sequenceType, role, visitor.getStaticContext()); ItemType actualItemType = sequence.getItemType(th); refineTypeInformation(actualItemType, StaticProperty.EXACTLY_ONE, null, sequence.getSpecialProperties(), visitor, this); } action = visitor.typeCheck(action, contextItemType); if (Literal.isEmptySequence(action)) { return action; } return this; } /** * Optimize the expression */ public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { Optimizer opt = visitor.getConfiguration().getOptimizer(); boolean debug = opt.getConfiguration().isOptimizerTracing(); // Try to promote any WHERE clause appearing immediately within the FOR expression Expression p = promoteWhereClause(positionVariable); if (p != null) { if (debug) { opt.trace("Promoted where clause in for $" + getVariableName(), p); } return visitor.optimize(p, contextItemType); } // See if there is a simple "where" condition that can be turned into a predicate Expression pred = convertWhereToPredicate(visitor, contextItemType); if (pred != null && pred != this) { if (debug) { opt.trace("Converted where clause in for $" + getVariableName() + " to predicate", pred); } return visitor.optimize(pred, contextItemType); } Expression seq2 = visitor.optimize(sequence, contextItemType); if (seq2 != sequence) { sequence = seq2; adoptChildExpression(sequence); visitor.resetStaticProperties(); return optimize(visitor, contextItemType); } if (Literal.isEmptySequence(sequence)) { return sequence; } Expression act2 = visitor.optimize(action, contextItemType); if (act2 != action) { action = act2; adoptChildExpression(action); visitor.resetStaticProperties(); // it's now worth re-attempting the "where" clause optimizations return optimize(visitor, contextItemType); } if (Literal.isEmptySequence(action)) { return action; } Expression e2 = extractLoopInvariants(visitor, contextItemType); if (e2 != null && e2 != this) { if (debug) { opt.trace("Extracted invariant in 'for $" + getVariableName() + "' loop", e2); } return visitor.optimize(e2, contextItemType); } // Simplify an expression of the form "for $b in a/b/c return $b/d". // (XQuery users seem to write these a lot!) if (positionVariable==null && sequence instanceof SlashExpression && action instanceof SlashExpression) { int count = ExpressionTool.getReferenceCount(action, this, false); SlashExpression path2 = (SlashExpression)action; Expression s2 = path2.getStartExpression(); Expression step2 = path2.getStepExpression(); if (count == 1 && s2 instanceof VariableReference && ((VariableReference)s2).getBinding() == this && ((step2.getDependencies() & (StaticProperty.DEPENDS_ON_POSITION | StaticProperty.DEPENDS_ON_LAST)) == 0)) { Expression newPath = new SlashExpression(sequence, path2.getStepExpression()); ExpressionTool.copyLocationInfo(this, newPath); newPath = visitor.typeCheck(visitor.simplify(newPath), contextItemType); if (newPath instanceof SlashExpression) { // if not, it has been wrapped in a DocumentSorter or Reverser, which makes it ineligible. // see test qxmp299, where this condition isn't satisfied if (debug) { opt.trace("Collapsed return clause of for $" + getVariableName() + " into path expression", newPath); } return visitor.optimize(newPath, contextItemType); } } } // Simplify an expression of the form "for $x in EXPR return $x". These sometimes // arise as a result of previous optimization steps. if (action instanceof VariableReference && ((VariableReference)action).getBinding() == this) { if (debug) { opt.trace("Collapsed redundant for expression $" + getVariableName(), sequence); } return sequence; } // Rewrite an expression of the form "for $x at $p in EXPR return $p" as "1 to count(EXPR)" if (action instanceof VariableReference && ((VariableReference)action).getBinding() == positionVariable) { FunctionCall count = SystemFunction.makeSystemFunction("count", new Expression[]{sequence}); RangeExpression range = new RangeExpression(new Literal(Int64Value.PLUS_ONE), Token.TO, count); if (debug) { opt.trace("Replaced 'for $x at $p in EXP return $p' by '1 to count(EXP)'", range); } return range.optimize(visitor, contextItemType); } // If the cardinality of the sequence is exactly one, rewrite as a LET expression if (sequence.getCardinality() == StaticProperty.EXACTLY_ONE && positionVariable == null) { LetExpression let = new LetExpression(); let.setVariableQName(variableName); let.setRequiredType(SequenceType.makeSequenceType( sequence.getItemType(visitor.getConfiguration().getTypeHierarchy()), StaticProperty.EXACTLY_ONE)); let.setSequence(sequence); let.setAction(action); let.setSlotNumber(slotNumber); ExpressionTool.rebindVariableReferences(action, this, let); return let.optimize(visitor, contextItemType); } //declaration = null; // let the garbage collector take it return this; } /** * Given an expression that is an immediate child of this expression, test whether * the evaluation of the parent expression causes the child expression to be * evaluated repeatedly * @param child the immediate subexpression * @return true if the child expression is evaluated repeatedly */ public boolean hasLoopingSubexpression(Expression child) { return child == action; } /** * Extract subexpressions in the action part that don't depend on the range variable * @param visitor the expression visitor * @param contextItemType the item type of the context item * @return the optimized expression if it has changed, or null if no optimization was possible */ private Expression extractLoopInvariants(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { // Extract subexpressions that don't depend on the range variable or the position variable // If a subexpression is (or might be) creative, this is, if it creates new nodes, we don't // extract it from the loop, but we do extract its non-creative subexpressions //if (positionVariable == null) { PromotionOffer offer = new PromotionOffer(visitor.getConfiguration().getOptimizer()); offer.containingExpression = this; offer.action = PromotionOffer.RANGE_INDEPENDENT; if (positionVariable == null) { offer.bindingList = new Binding[] {this}; } else { offer.bindingList = new Binding[] {this, positionVariable}; } action = doPromotion(action, offer); if (offer.containingExpression instanceof LetExpression) { // a subexpression has been promoted //offer.containingExpression.setParentExpression(container); // try again: there may be further subexpressions to promote offer.containingExpression = visitor.optimize(offer.containingExpression, contextItemType); } return offer.containingExpression; //} //return null; } /** * Convert where clause, if possible, to a predicate. * @param visitor the expression visitor * @param contextItemType the item type of the context item * @return the converted expression if modified, or null otherwise */ public Expression convertWhereToPredicate(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { if (Choose.isSingleBranchChoice(action)) { final TypeHierarchy th = visitor.getConfiguration().getTypeHierarchy(); final Optimizer opt = visitor.getConfiguration().getOptimizer(); Expression head = null; Expression selection = sequence; ItemType selectionContextItemType = contextItemType; if (sequence instanceof PathExpression) { if (((PathExpression)sequence).isAbsolute(th)) { head = ((PathExpression)sequence).getFirstStep(); selection = ((PathExpression)sequence).getRemainingSteps(); selectionContextItemType = head.getItemType(th); } else { PathExpression p = ((PathExpression)sequence).tryToMakeAbsolute(th); if (p != null) { sequence = p; adoptChildExpression(p); head = ((PathExpression)sequence).getFirstStep(); selection = ((PathExpression)sequence).getRemainingSteps(); selectionContextItemType = head.getItemType(th); } } } boolean changed = false; Expression condition = ((Choose)action).getConditions()[0]; List list = new ArrayList(4); BooleanExpression.listAndComponents(condition, list); for (int t=list.size()-1; t>=0; t--) { // Process each term in the where clause independently Expression term = (Expression)list.get(t); // TODO: following code should be generalized so it works on any kind of expression. if (term instanceof ValueComparison || term instanceof SingletonComparison) { BinaryExpression comp = (BinaryExpression)term; Expression[] operands = comp.getOperands(); for (int op=0; op<2; op++) { // If the where clause is a simple test on the position variable, for example // for $x at $p in EXPR where $p = 5 return A // then absorb the where condition into a predicate, rewriting it as // for $x in EXPR[position() = 5] return A // This takes advantage of the optimizations applied to positional filter expressions // Only do this if the sequence expression has not yet been changed, because // the position in a predicate after the first is different. Binding[] thisVar = {this}; if (positionVariable != null && operands[op] instanceof VariableReference && !changed) { List varRefs = new ArrayList(); ExpressionTool.gatherVariableReferences(action, positionVariable, varRefs); if (varRefs.size() == 1 && varRefs.get(0) == operands[op] && (operands[1-op].getDependencies() & StaticProperty.DEPENDS_ON_FOCUS) == 0 && !ExpressionTool.dependsOnVariable(operands[1-op], thisVar)) { FunctionCall position = SystemFunction.makeSystemFunction("position", SimpleExpression.NO_ARGUMENTS); Expression predicate; if (term instanceof ValueComparison) { if (op==0) { predicate = new ValueComparison(position, comp.getOperator(), operands[1]); } else { predicate = new ValueComparison(operands[0], comp.getOperator(), position); } } else { // term instanceof SingletonComparison if (op==0) { predicate = new SingletonComparison(position, comp.getOperator(), operands[1]); } else { predicate = new SingletonComparison(operands[0], comp.getOperator(), position); } } selection = new FilterExpression(selection, predicate); ExpressionTool.copyLocationInfo(this, selection); selection = visitor.typeCheck(selection, selectionContextItemType); //action = condAction.getThenExpression(); positionVariable = null; //positionBinding = null; list.remove(t); changed = true; break; //return simplify(env).typeCheck(env, contextItemType).optimize(opt, env, contextItemType); } } // If the where clause is a simple test on the value of the range variable, or a path // expression starting with the range variable, then rewrite it as a predicate. // For example, rewrite // for $x in EXPR where $x/a/b eq "z" return A // as // for $x in EXPR[a/b eq "z"] return A if ( positionVariable == null && opt.isVariableReplaceableByDot(term, thisVar) && (term.getDependencies() & StaticProperty.DEPENDS_ON_FOCUS) == 0 && ExpressionTool.dependsOnVariable(operands[op], thisVar) && !ExpressionTool.dependsOnVariable(operands[1-op], thisVar)) { PromotionOffer offer = new PromotionOffer(visitor.getConfiguration().getOptimizer()); offer.action = PromotionOffer.INLINE_VARIABLE_REFERENCES; offer.bindingList = thisVar; offer.containingExpression = new ContextItemExpression(); Expression newOperand = operands[op].promote(offer); if (newOperand != null && offer.accepted) { Expression predicate; if (op==0) { predicate = new ValueComparison(newOperand, comp.getOperator(), operands[1]); } else { predicate = new ValueComparison(operands[0], comp.getOperator(), newOperand); } predicate = visitor.typeCheck(predicate, sequence.getItemType(th)); selection = new FilterExpression(selection, predicate); ExpressionTool.copyLocationInfo(this, selection); selection = visitor.typeCheck(selection, selectionContextItemType); changed = true; positionVariable = null; //positionBinding = null; list.remove(t); } } } } else if (term instanceof GeneralComparison) { GeneralComparison comp = (GeneralComparison)term; Expression[] operands = comp.getOperands(); for (int op=0; op<2; op++) { // If the where clause is a simple test on the value of the range variable, or a path // expression starting with the range variable, then rewrite it as a predicate. // For example, rewrite // for $x in EXPR where $x/a/b = "z" return A // as // for $x in EXPR[a/b = "z"] return A Binding[] thisVar = {this}; if (positionVariable == null && opt.isVariableReplaceableByDot(term, thisVar) && (term.getDependencies() & StaticProperty.DEPENDS_ON_FOCUS) == 0 && ExpressionTool.dependsOnVariable(operands[op], thisVar) && !ExpressionTool.dependsOnVariable(operands[1-op], thisVar)) { PromotionOffer offer = new PromotionOffer(visitor.getConfiguration().getOptimizer()); offer.action = PromotionOffer.INLINE_VARIABLE_REFERENCES; offer.bindingList = thisVar; offer.containingExpression = new ContextItemExpression(); Expression newOperand = operands[op].promote(offer); if (newOperand != null && !ExpressionTool.dependsOnVariable(newOperand, thisVar)) { //newOperand.resetStaticProperties(); Expression predicate; //newOperand = new Atomizer(newOperand, env.getConfiguration()); if (op==0) { // TODO: make GeneralComparisonSA where appropriate predicate = new GeneralComparison(newOperand, comp.getOperator(), operands[1]); } else { predicate = new GeneralComparison(operands[0], comp.getOperator(), newOperand); } selection = new FilterExpression(selection, predicate); ExpressionTool.copyLocationInfo(this, selection); selection = visitor.typeCheck(selection, selectionContextItemType); selection = selection.optimize(visitor, selectionContextItemType); visitor.resetStaticProperties(); //action = condAction.getThenExpression(); positionVariable = null; //positionBinding = null; //return simplify(env).typeCheck(env, contextItemType).optimize(opt, env, contextItemType); list.remove(t); changed = true; break; } } } } else if (term instanceof QuantifiedExpression) { QuantifiedExpression q0 = (QuantifiedExpression)term; Expression sequence = q0.getSequence(); Expression action = q0.getAction(); Binding[] thisVar = {this}; if (positionVariable == null && opt.isVariableReplaceableByDot(term, thisVar) && (term.getDependencies() & StaticProperty.DEPENDS_ON_FOCUS) == 0 && ExpressionTool.dependsOnVariable(sequence, thisVar) && !ExpressionTool.dependsOnVariable(action, thisVar)) { PromotionOffer offer = new PromotionOffer(visitor.getConfiguration().getOptimizer()); offer.action = PromotionOffer.INLINE_VARIABLE_REFERENCES; offer.bindingList = thisVar; offer.containingExpression = new ContextItemExpression(); Expression newSequence = sequence.promote(offer); if (newSequence != null) { if (ExpressionTool.dependsOnVariable(newSequence, thisVar)) { throw new IllegalStateException("We have a problem..."); // we've partially rewritten the expression but we haven't got rid of all // dependencies on the variable. We can't go back and we can't go forward... } q0.setSequence(newSequence); selection = new FilterExpression(selection, q0); ExpressionTool.copyLocationInfo(this, selection); selection = visitor.typeCheck(selection, selectionContextItemType); selection = selection.optimize(visitor, selectionContextItemType); visitor.resetStaticProperties(); positionVariable = null; list.remove(t); changed = true; break; } } } } if (changed) { if (list.isEmpty()) { action = ((Choose)action).getActions()[0]; adoptChildExpression(action); } else { Expression term = (Expression)list.get(0); for (int t=1; t= 0) { context.setLocalVariable(pslot, Int64Value.makeIntegerValue(position++)); } action.process(context); } } /** * Evaluate an updating expression, adding the results to a Pending Update List. * The default implementation of this method, which is used for non-updating expressions, * throws an UnsupportedOperationException * * @param context the XPath dynamic evaluation context * @param pul the pending update list to which the results should be written */ public void evaluatePendingUpdates(XPathContext context, PendingUpdateList pul) throws XPathException { SequenceIterator iter = sequence.iterate(context); int position = 1; int slot = getLocalSlotNumber(); int pslot = -1; if (positionVariable != null) { pslot = positionVariable.getLocalSlotNumber(); } while (true) { Item item = iter.next(); if (item == null) break; context.setLocalVariable(slot, item); if (pslot >= 0) { context.setLocalVariable(pslot, Int64Value.makeIntegerValue(position++)); } action.evaluatePendingUpdates(context, pul); } } /** * Determine the data type of the items returned by the expression, if possible * @return one of the values Type.STRING, Type.BOOLEAN, Type.NUMBER, Type.NODE, * or Type.ITEM (meaning not known in advance) * @param th the type hierarchy cache */ public ItemType getItemType(TypeHierarchy th) { return action.getItemType(th); } /** * Determine the static cardinality of the expression */ public int computeCardinality() { int c1 = sequence.getCardinality(); int c2 = action.getCardinality(); return Cardinality.multiply(c1, c2); } /** * Diagnostic print of expression structure. The abstract expression tree * is written to the supplied output destination. */ public void explain(ExpressionPresenter out) { out.startElement("for"); out.emitAttribute("variable", getVariableName()); out.emitAttribute("as", sequence.getItemType(out.getTypeHierarchy()).toString(out.getNamePool())); if (positionVariable != null) { out.emitAttribute("at", positionVariable.getVariableQName().getDisplayName()); } out.startSubsidiaryElement("in"); sequence.explain(out); out.endSubsidiaryElement(); out.startSubsidiaryElement("return"); action.explain(out); out.endSubsidiaryElement(); out.endElement(); } /** * The MappingAction represents the action to be taken for each item in the * source sequence. It acts as the MappingFunction for the mapping iterator, and * also as the Binding of the position variable (at $n) in XQuery, if used. */ private static class MappingAction implements StatefulMappingFunction { private XPathContext context; private int slotNumber; private Expression action; private int pslot = -1; private int position = 1; public MappingAction(XPathContext context, int slotNumber, int pslot, Expression action) { this.context = context; this.slotNumber = slotNumber; this.pslot = pslot; this.action = action; } public SequenceIterator map(Item item) throws XPathException { context.setLocalVariable(slotNumber, item); if (pslot >= 0) { context.setLocalVariable(pslot, Int64Value.makeIntegerValue(position++)); } return action.iterate(context); } public StatefulMappingFunction getAnother() { // Create a copy of the stack frame, so that changes made to local variables by the cloned // iterator are not seen by the original iterator XPathContextMajor c2 = context.newContext(); StackFrame oldstack = context.getStackFrame(); ValueRepresentation[] vars = oldstack.getStackFrameValues(); ValueRepresentation[] newvars = new ValueRepresentation[vars.length]; System.arraycopy(vars, 0, newvars, 0, vars.length); c2.setStackFrame(oldstack.getStackFrameMap(), newvars); return new MappingAction(c2, slotNumber, pslot, action); } } /** * The EventMappingAction represents the action to be taken for each item in the * source sequence. It acts as the EventMappingFunction for the mapping iterator, and * also provides the Binding of the position variable (at $n) in XQuery, if used. */ private static class EventMappingAction implements EventMappingFunction { private XPathContext context; private int slotNumber; private Expression action; private int position = 1; private int pslot = -1; public EventMappingAction(XPathContext context, int slotNumber, PositionVariable positionBinding, Expression action) { this.context = context; this.slotNumber = slotNumber; if (positionBinding != null) { pslot = positionBinding.getLocalSlotNumber(); } this.action = action; } public EventIterator map(Item item) throws XPathException { context.setLocalVariable(slotNumber, item); if (pslot >= 0) { context.setLocalVariable(pslot, Int64Value.makeIntegerValue(position++)); } return action.iterateEvents(context); } } /** * Get the type of this expression for use in tracing and diagnostics * @return the type of expression, as enumerated in class {@link net.sf.saxon.trace.Location} */ public int getConstructType() { return Location.FOR_EXPRESSION; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/expr/QuantifiedExpression.java0000644000175000017500000002317311033112257023377 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.trace.ExpressionPresenter; import net.sf.saxon.om.Item; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.BuiltInAtomicType; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.TypeHierarchy; import net.sf.saxon.value.BooleanValue; import net.sf.saxon.value.SequenceType; import net.sf.saxon.functions.BooleanFn; /** * A QuantifiedExpression tests whether some/all items in a sequence satisfy * some condition. */ public class QuantifiedExpression extends Assignation { private int operator; // Token.SOME or Token.EVERY /** * Set the operator, either {@link Token#SOME} or {@link Token#EVERY} * @param operator the operator */ public void setOperator(int operator) { this.operator = operator; } /** * Get the operator, either {@link Token#SOME} or {@link Token#EVERY} * @return the operator */ public int getOperator() { return operator; } /** * Determine the static cardinality */ public int computeCardinality() { return StaticProperty.EXACTLY_ONE; } /** * Type-check the expression */ public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { final TypeHierarchy th = visitor.getConfiguration().getTypeHierarchy(); // The order of events is critical here. First we ensure that the type of the // sequence expression is established. This is used to establish the type of the variable, // which in turn is required when type-checking the action part. sequence = visitor.typeCheck(sequence, contextItemType); if (Literal.isEmptySequence(sequence)) { return Literal.makeLiteral(BooleanValue.get(operator != Token.SOME)); } // "some" and "every" have no ordering constraints Optimizer opt = visitor.getConfiguration().getOptimizer(); sequence = ExpressionTool.unsorted(opt, sequence, false); SequenceType decl = getRequiredType(); SequenceType sequenceType = SequenceType.makeSequenceType(decl.getPrimaryType(), StaticProperty.ALLOWS_ZERO_OR_MORE); RoleLocator role = new RoleLocator(RoleLocator.VARIABLE, getVariableQName(), 0); //role.setSourceLocator(this); sequence = TypeChecker.strictTypeCheck( sequence, sequenceType, role, visitor.getStaticContext()); ItemType actualItemType = sequence.getItemType(th); refineTypeInformation(actualItemType, StaticProperty.EXACTLY_ONE, null, sequence.getSpecialProperties(), visitor, this); //declaration = null; // let the garbage collector take it action = visitor.typeCheck(action, contextItemType); XPathException err = TypeChecker.ebvError(action, visitor.getConfiguration().getTypeHierarchy()); if (err != null) { err.setLocator(this); throw err; } return this; } /** * Perform optimisation of an expression and its subexpressions. *

    *

    This method is called after all references to functions and variables have been resolved * to the declaration of the function or variable, and after all type checking has been done.

    * * @param visitor an expression visitor * @param contextItemType the static type of "." at the point where this expression is invoked. * The parameter is set to null if it is known statically that the context item will be undefined. * If the type of the context item is not known statically, the argument is set to * {@link net.sf.saxon.type.Type#ITEM_TYPE} * @return the original expression, rewritten if appropriate to optimize execution * @throws XPathException if an error is discovered during this phase * (typically a type error) */ public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { Optimizer opt = visitor.getConfiguration().getOptimizer(); sequence = visitor.optimize(sequence, contextItemType); action = visitor.optimize(action, contextItemType); Expression ebv = BooleanFn.rewriteEffectiveBooleanValue(action, visitor, contextItemType); if (ebv != null) { action = ebv; adoptChildExpression(ebv); } PromotionOffer offer = new PromotionOffer(opt); offer.containingExpression = this; offer.action = PromotionOffer.RANGE_INDEPENDENT; offer.bindingList = new Binding[] {this}; action = doPromotion(action, offer); if (offer.containingExpression instanceof LetExpression) { offer.containingExpression = visitor.optimize(visitor.typeCheck(offer.containingExpression, contextItemType), contextItemType); } return offer.containingExpression; } /** * Check to ensure that this expression does not contain any updating subexpressions. * This check is overridden for those expressions that permit updating subexpressions. * * @throws net.sf.saxon.trans.XPathException * if the expression has a non-permitted updateing subexpression */ public void checkForUpdatingSubexpressions() throws XPathException { sequence.checkForUpdatingSubexpressions(); action.checkForUpdatingSubexpressions(); } /** * Determine whether this is an updating expression as defined in the XQuery update specification * @return true if this is an updating expression */ public boolean isUpdatingExpression() { return false; } /** * Copy an expression. This makes a deep copy. * @return the copy of the original expression */ public Expression copy() { QuantifiedExpression qe = new QuantifiedExpression(); qe.setOperator(operator); qe.setVariableQName(variableName); qe.setRequiredType(requiredType); qe.setSequence(sequence.copy()); Expression newAction = action.copy(); qe.setAction(newAction); qe.variableName = variableName; ExpressionTool.rebindVariableReferences(newAction, this, qe); return qe; } /** * Given an expression that is an immediate child of this expression, test whether * the evaluation of the parent expression causes the child expression to be * evaluated repeatedly * @param child the immediate subexpression * @return true if the child expression is evaluated repeatedly */ public boolean hasLoopingSubexpression(Expression child) { return child == action; } /** * Determine the special properties of this expression * @return {@link StaticProperty#NON_CREATIVE}. */ public int computeSpecialProperties() { int p = super.computeSpecialProperties(); return p | StaticProperty.NON_CREATIVE; } /** * Evaluate the expression to return a singleton value */ public Item evaluateItem(XPathContext context) throws XPathException { return BooleanValue.get(effectiveBooleanValue(context)); } /** * Get the result as a boolean */ public boolean effectiveBooleanValue(XPathContext context) throws XPathException { // First create an iteration of the base sequence. SequenceIterator base = sequence.iterate(context); // Now test to see if some or all of the tests are true. The same // logic is used for the SOME and EVERY operators final boolean some = (operator==Token.SOME); int slot = getLocalSlotNumber(); while (true) { final Item it = base.next(); if (it == null) { break; } context.setLocalVariable(slot, it); if (some == action.effectiveBooleanValue(context)) { base.close(); return some; } } return !some; } /** * Determine the data type of the items returned by the expression * @return Type.BOOLEAN * @param th the type hierarchy cache */ public ItemType getItemType(TypeHierarchy th) { return BuiltInAtomicType.BOOLEAN; } /** * Diagnostic print of expression structure. The abstract expression tree * is written to the supplied output destination. */ public void explain(ExpressionPresenter out) { out.startElement(Token.tokens[operator]); out.emitAttribute("variable", getVariableName()); out.startSubsidiaryElement("in"); sequence.explain(out); out.endSubsidiaryElement(); out.startSubsidiaryElement("satisfies"); action.explain(out); out.endSubsidiaryElement(); out.endElement(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/expr/Assignation.java0000644000175000017500000004243211033112257021504 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.instruct.Choose; import net.sf.saxon.om.StructuredQName; import net.sf.saxon.om.ValueRepresentation; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.SequenceType; import net.sf.saxon.value.MemoClosure; import net.sf.saxon.value.Value; import net.sf.saxon.type.ItemType; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /** * Assignation is an abstract superclass for the kinds of expression * that declare range variables: for, some, and every. */ public abstract class Assignation extends Expression implements Binding { protected int slotNumber = -999; // slot number for range variable // (initialized to ensure a crash if no real slot is allocated) protected Expression sequence; // the expression over which the variable ranges protected Expression action; // the action performed for each value of the variable protected StructuredQName variableName; protected SequenceType requiredType; //protected RangeVariable declaration; /** * Set the required type (declared type) of the variable * @param requiredType the required type */ public void setRequiredType(SequenceType requiredType) { this.requiredType = requiredType; } /** * Set the name of the variable * @param variableName the name of the variable */ public void setVariableQName(StructuredQName variableName) { this.variableName = variableName; } /** * Get the name of the variable * @return the variable name, as a QName */ public StructuredQName getVariableQName() { return variableName; } public StructuredQName getObjectName() { return variableName; } /** * Get the declared type of the variable * * @return the declared type */ public SequenceType getRequiredType() { return requiredType; } /** * If this is a local variable held on the local stack frame, return the corresponding slot number. * In other cases, return -1. */ public int getLocalSlotNumber() { return slotNumber; } /** * Get the value of the range variable */ public ValueRepresentation evaluateVariable(XPathContext context) throws XPathException { ValueRepresentation actual = context.evaluateLocalVariable(slotNumber); if (actual instanceof MemoClosure && ((MemoClosure)actual).isFullyRead()) { actual = ((MemoClosure)actual).materialize(); context.setLocalVariable(slotNumber, actual); } return actual; } /** * Add the "return" or "satisfies" expression, and fix up all references to the * range variable that occur within that expression * @param action the expression that occurs after the "return" keyword of a "for" * expression, the "satisfies" keyword of "some/every", or the ":=" operator of * a "let" expression. * * */ public void setAction(Expression action) { this.action = action; adoptChildExpression(action); } /** * Indicate whether the binding is local or global. A global binding is one that has a fixed * value for the life of a query or transformation; any other binding is local. */ public final boolean isGlobal() { return false; } /** * Test whether it is permitted to assign to the variable using the saxon:assign * extension element. This will only be for an XSLT global variable where the extra * attribute saxon:assignable="yes" is present. */ public final boolean isAssignable() { return false; } /** * Check to ensure that this expression does not contain any inappropriate updating subexpressions. * This check is overridden for those expressions that permit updating subexpressions. * * @throws net.sf.saxon.trans.XPathException * if the expression has a non-permitted updateing subexpression */ public void checkForUpdatingSubexpressions() throws XPathException { sequence.checkForUpdatingSubexpressions(); if (sequence.isUpdatingExpression()) { XPathException err = new XPathException( "Updating expression appears in a context where it is not permitted", "XUST0001"); err.setLocator(sequence); throw err; } action.checkForUpdatingSubexpressions(); } /** * Determine whether this is an updating expression as defined in the XQuery update specification * @return true if this is an updating expression */ public boolean isUpdatingExpression() { return action.isUpdatingExpression(); } /** * Get the action expression * @return the action expression (introduced by "return" or "satisfies") */ public Expression getAction() { return action; } /** * Set the "sequence" expression - the one to which the variable is bound * @param sequence the expression to which the variable is bound */ public void setSequence(Expression sequence) { this.sequence = sequence; adoptChildExpression(sequence); } /** * Get the "sequence" expression - the one to which the variable is bound * @return the expression to which the variable is bound */ public Expression getSequence() { return sequence; } /** * Set the slot number for the range variable * @param nr the slot number to be used */ public void setSlotNumber(int nr) { slotNumber = nr; } /** * Get the number of slots required. Normally 1, except for a FOR expression with an AT clause, where it is 2. * @return the number of slots required */ public int getRequiredSlots() { return 1; } /** * Simplify the expression * @param visitor an expression visitor */ public Expression simplify(ExpressionVisitor visitor) throws XPathException { sequence = visitor.simplify(sequence); action = visitor.simplify(action); return this; } /** * Promote this expression if possible */ public Expression promote(PromotionOffer offer) throws XPathException { Expression exp = offer.accept(this); if (exp != null) { return exp; } else { sequence = doPromotion(sequence, offer); if (offer.action == PromotionOffer.INLINE_VARIABLE_REFERENCES || offer.action == PromotionOffer.UNORDERED || offer.action == PromotionOffer.REPLACE_CURRENT) { action = doPromotion(action, offer); } else if (offer.action == PromotionOffer.RANGE_INDEPENDENT || offer.action == PromotionOffer.FOCUS_INDEPENDENT) { // Pass the offer to the action expression only if the action isn't dependent on the // variable bound by this assignation Binding[] savedBindingList = offer.bindingList; offer.bindingList = extendBindingList(offer.bindingList); action = doPromotion(action, offer); offer.bindingList = savedBindingList; } return this; } } /** * Suppress validation on contained element constructors, on the grounds that the parent element * is already performing validation. The default implementation does nothing. */ public void suppressValidation(int validationMode) { action.suppressValidation(validationMode); } /** * Extend an array of variable bindings to include the binding(s) defined in this expression * @param in a set of variable bindings * @return a set of variable bindings including all those supplied plus this one */ protected Binding[] extendBindingList(Binding[] in) { Binding[] newBindingList; if (in == null) { newBindingList = new Binding[1]; } else { newBindingList = new Binding[in.length + 1]; System.arraycopy(in, 0, newBindingList, 0, in.length); } newBindingList[newBindingList.length - 1] = this; return newBindingList; } /** * Promote a WHERE clause whose condition doesn't depend on the variable being bound. * This rewrites an expression of the form * *

    let $i := SEQ return if (C) then R else ()

    *

    to the form:

    *

    if (C) then (let $i := SEQ return R) else ()

    * * @param positionBinding the binding of the position variable if any * @return an expression in which terms from the WHERE clause that can be extracted have been extracted */ protected Expression promoteWhereClause(Binding positionBinding) { if (Choose.isSingleBranchChoice(action)) { //IfExpression ifex = (IfExpression)action; Expression condition = ((Choose)action).getConditions()[0]; Binding[] bindingList; if (positionBinding == null) { bindingList = new Binding[] {this}; } else { bindingList = new Binding[] {this, positionBinding}; } List list = new ArrayList(5); Expression promotedCondition = null; BooleanExpression.listAndComponents(condition, list); for (int i = list.size() - 1; i >= 0; i--) { Expression term = (Expression) list.get(i); if (!ExpressionTool.dependsOnVariable(term, bindingList)) { if (promotedCondition == null) { promotedCondition = term; } else { promotedCondition = new BooleanExpression(term, Token.AND, promotedCondition); } list.remove(i); } } if (promotedCondition != null) { if (list.isEmpty()) { // the whole if() condition has been promoted Expression oldThen = ((Choose)action).getActions()[0]; setAction(oldThen); return Choose.makeConditional(condition, this); } else { // one or more terms of the if() condition have been promoted Expression retainedCondition = (Expression) list.get(0); for (int i = 1; i < list.size(); i++) { retainedCondition = new BooleanExpression(retainedCondition, Token.AND, (Expression) list.get(i)); } ((Choose)action).getConditions()[0] = retainedCondition; Expression newIf = Choose.makeConditional( promotedCondition, this, Literal.makeEmptySequence()); ExpressionTool.copyLocationInfo(this, newIf); return newIf; } } } return null; } /** * Get the immediate subexpressions of this expression */ public Iterator iterateSubExpressions() { return new PairIterator(sequence, action); } /** * Replace one subexpression by a replacement subexpression * @param original the original subexpression * @param replacement the replacement subexpression * @return true if the original subexpression is found */ public boolean replaceSubExpression(Expression original, Expression replacement) { boolean found = false; if (sequence == original) { sequence = replacement; found = true; } if (action == original) { action = replacement; found = true; } return found; } /** * Add a representation of this expression to a PathMap. The PathMap captures a map of the nodes visited * by an expression in a source tree. *

    *

    The default implementation of this method assumes that an expression does no navigation other than * the navigation done by evaluating its subexpressions, and that the subexpressions are evaluated in the * same context as the containing expression. The method must be overridden for any expression * where these assumptions do not hold. For example, implementations exist for AxisExpression, ParentExpression, * and RootExpression (because they perform navigation), and for the doc(), document(), and collection() * functions because they create a new navigation root. Implementations also exist for PathExpression and * FilterExpression because they have subexpressions that are evaluated in a different context from the * calling expression.

    * * @param pathMap the PathMap to which the expression should be added * @param pathMapNodeSet the PathMapNodeSet to which the paths embodied in this expression should be added * @return the pathMapNodeSet representing the points in the source document that are both reachable by this * expression, and that represent possible results of this expression. For an expression that does * navigation, it represents the end of the arc in the path map that describes the navigation route. For other * expressions, it is the same as the input pathMapNode. */ public PathMap.PathMapNodeSet addToPathMap(PathMap pathMap, PathMap.PathMapNodeSet pathMapNodeSet) { PathMap.PathMapNodeSet varPath = sequence.addToPathMap(pathMap, pathMapNodeSet); pathMap.registerPathForVariable(this, varPath); return action.addToPathMap(pathMap, pathMapNodeSet); } // Following methods implement the VariableDeclaration interface, in relation to the range // variable // public int getVariableNameCode() { // return nameCode; // } // public int getVariableFingerprint() { // return nameCode & 0xfffff; // } /** * Get the display name of the range variable, for diagnostics only * @return the lexical QName of the range variable */ public String getVariableName() { if (variableName == null) { return "zz:var" + hashCode(); } else { return variableName.getDisplayName(); } } /** * Refine the type information associated with this variable declaration. This is useful when the * type of the variable has not been explicitly declared (which is common); the variable then takes * a static type based on the type of the expression to which it is bound. The effect of this call * is to update the static expression type for all references to this variable. * @param type the inferred item type of the expression to which the variable is bound * @param cardinality the inferred cardinality of the expression to which the variable is bound * @param constantValue the constant value to which the variable is bound (null if there is no constant value) * @param properties other static properties of the expression to which the variable is bound * @param visitor an expression visitor to provide context information * @param currentExpression the expression that binds the variable */ public void refineTypeInformation(ItemType type, int cardinality, Value constantValue, int properties, ExpressionVisitor visitor, Assignation currentExpression) { List references = new ArrayList(); ExpressionTool.gatherVariableReferences(currentExpression.getAction(), this, references); for (Iterator iter=references.iterator(); iter.hasNext();) { BindingReference ref = (BindingReference)iter.next(); if (ref instanceof VariableReference) { ((VariableReference)ref).refineVariableType(type, cardinality, constantValue, properties, visitor); visitor.resetStaticProperties(); ExpressionTool.resetPropertiesWithinSubtree(currentExpression); } } } /** * Get the value of the range variable */ // public ValueRepresentation evaluateVariable(XPathContext context) throws XPathException { //// if (slotNumber == -999) { //// display(10, context.getController().getNamePool(), System.err); //// } // ValueRepresentation actual = context.evaluateLocalVariable(slotNumber); // if (actual instanceof MemoClosure && ((MemoClosure)actual).isFullyRead()) { // actual = ((MemoClosure)actual).materialize(); // context.setLocalVariable(slotNumber, actual); // } // return actual; // } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/expr/FilterExpression.java0000644000175000017500000014045511033112257022536 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.Configuration; import net.sf.saxon.functions.*; import net.sf.saxon.instruct.Choose; import net.sf.saxon.om.*; import net.sf.saxon.trace.ExpressionPresenter; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.*; import net.sf.saxon.value.*; import java.util.Iterator; /** * A FilterExpression contains a base expression and a filter predicate, which may be an * integer expression (positional filter), or a boolean expression (qualifier) */ public final class FilterExpression extends Expression { private Expression start; private Expression filter; private boolean filterIsPositional; // true if the value of the filter might depend on // the context position private boolean filterIsSingletonBoolean; // true if the filter expression always returns a single boolean private boolean filterIsIndependentNumeric; // true if the filter expression returns a number that doesn't public static final int FILTERED = 10000; // depend on the context item or position //private int isIndexable = 0; /** * Constructor * * @param start A node-set expression denoting the absolute or relative set of nodes from which the * navigation path should start. * @param filter An expression defining the filter predicate */ public FilterExpression(Expression start, Expression filter) { this.start = start; this.filter = filter; adoptChildExpression(start); adoptChildExpression(filter); start.setFiltered(true); } /** * Get the data type of the items returned * * @param th the type hierarchy cache * @return an integer representing the data type */ public ItemType getItemType(TypeHierarchy th) { // special case the filter [. instance of x] if (filter instanceof InstanceOfExpression && ((InstanceOfExpression)filter).getBaseExpression() instanceof ContextItemExpression) { return ((InstanceOfExpression)filter).getRequiredItemType(); } return start.getItemType(th); } /** * Get the underlying expression * * @return the expression being filtered */ public Expression getBaseExpression() { return start; } /** * Get the filter expression * * @return the expression acting as the filter predicate */ public Expression getFilter() { return filter; } /** * Determine if the filter is positional * * @param th the Type Hierarchy (for cached access to type information) * @return true if the value of the filter depends on the position of the item against * which it is evaluated */ public boolean isPositional(TypeHierarchy th) { return isPositionalFilter(filter, th); } /** * Test if the filter always returns a singleton boolean * * @return true if the filter is a simple boolean expression */ public boolean isSimpleBooleanFilter() { return filterIsSingletonBoolean; } /** * Determine whether the filter is a simple independent numeric, that is, an expression * that satisfies the following conditions: (a) its value is numeric; * (b) the value does not depend on the context item or position; * (c) the cardinality is zero or one. * * @return true if the filter is a numeric value that does not depend on the context item or position */ public boolean isIndependentNumericFilter() { return filterIsIndependentNumeric; } /** * Simplify an expression * * @param visitor the expression visitor * @return the simplified expression * @throws XPathException if any failure occurs */ public Expression simplify(ExpressionVisitor visitor) throws XPathException { start = visitor.simplify(start); filter = visitor.simplify(filter); // ignore the filter if the base expression is an empty sequence if (Literal.isEmptySequence(start)) { return start; } // check whether the filter is a constant true() or false() if (filter instanceof Literal && !(((Literal)filter).getValue() instanceof NumericValue)) { try { if (filter.effectiveBooleanValue(visitor.getStaticContext().makeEarlyEvaluationContext())) { return start; } else { return new Literal(EmptySequence.getInstance()); } } catch (XPathException e) { e.maybeSetLocation(this); throw e; } } // check whether the filter is [last()] (note, position()=last() is handled elsewhere) if (filter instanceof Last) { filter = new IsLastExpression(true); adoptChildExpression(filter); } return this; } /** * Type-check the expression * * @param visitor the expression visitor * @param contextItemType the type of the context item for this expression * @return the expression after type-checking (potentially modified to add run-time * checks and/or conversions) */ public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { final TypeHierarchy th = visitor.getConfiguration().getTypeHierarchy(); Expression start2 = visitor.typeCheck(start, contextItemType); if (start2 != start) { start = start2; adoptChildExpression(start2); } start.setFiltered(true); Expression filter2 = visitor.typeCheck(filter, start.getItemType(th)); if (filter2 != filter) { filter = filter2; adoptChildExpression(filter2); } // The filter expression usually doesn't need to be sorted filter2 = ExpressionTool.unsortedIfHomogeneous(visitor.getConfiguration().getOptimizer(), filter); if (filter2 != filter) { filter = filter2; adoptChildExpression(filter2); } // detect head expressions (E[1]) and treat them specially if (Literal.isConstantOne(filter)) { FirstItemExpression fie = new FirstItemExpression(start); ExpressionTool.copyLocationInfo(this, fie); return fie; } // Handle other constant filter expressions // if (filter instanceof Literal) { // Value filterValue = ((Literal)filter).getValue(); // // if (filterValue instanceof NumericValue) { // // if (((NumericValue)filterValue).isWholeNumber() && // ((NumericValue)filterValue).compareTo(0) > 0) { // return visitor.getConfiguration().getVendorFunctionLibrary().makeSaxonFunction( // "item-at", visitor.getStaticContext(), new Expression[]{filter}); // //filter = new PositionRange(filter, null, PositionRange.EQ_MIN); // } else { // // filter is not a whole number, or is < 1: result is empty // return new Literal(EmptySequence.getInstance()); // } // // } else { // // Convert the filter value to its effective boolean value // try { // filter = Literal.makeLiteral( // BooleanValue.get(((Literal)filter).getValue().effectiveBooleanValue())); // } catch (XPathException e) { // e.maybeSetLocation(this); // throw e; // } // } // } // Detect other numeric positional predicates e.g. [position() > 2] // if (filter instanceof PositionRange) { // PositionRange range = (PositionRange)filter; // if (range.isFirstPositionOnly()) { // FirstItemExpression fie = new FirstItemExpression(start); // ExpressionTool.copyLocationInfo(this, fie); // return fie; // } // TailExpression tail = range.makeTailExpression(start); // if (tail != null) { // ExpressionTool.copyLocationInfo(this, tail); // return tail; // } // } // determine whether the filter might depend on position filterIsPositional = isPositionalFilter(filter, th); // determine whether the filter always evaluates to a single boolean filterIsSingletonBoolean = filter.getCardinality() == StaticProperty.EXACTLY_ONE && filter.getItemType(th).equals(BuiltInAtomicType.BOOLEAN); // determine whether the filter evaluates to a single number, where the number will be the same for // all values in the sequence filterIsIndependentNumeric = th.isSubType(filter.getItemType(th), BuiltInAtomicType.NUMERIC) && (filter.getDependencies() & (StaticProperty.DEPENDS_ON_CONTEXT_ITEM | StaticProperty.DEPENDS_ON_POSITION)) == 0 && !Cardinality.allowsMany(filter.getCardinality()); visitor.resetStaticProperties(); return this; } /** * Perform optimisation of an expression and its subexpressions. *

    *

    This method is called after all references to functions and variables have been resolved * to the declaration of the function or variable, and after all type checking has been done.

    * * @param visitor an expression visitor * @param contextItemType the static type of "." at the point where this expression is invoked. * The parameter is set to null if it is known statically that the context item will be undefined. * If the type of the context item is not known statically, the argument is set to * {@link net.sf.saxon.type.Type#ITEM_TYPE} * @return the original expression, rewritten if appropriate to optimize execution * @throws XPathException if an error is discovered during this phase * (typically a type error) */ public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { final StaticContext env = visitor.getStaticContext(); final Optimizer opt = visitor.getConfiguration().getOptimizer(); final boolean debug = visitor.getConfiguration().isOptimizerTracing(); final TypeHierarchy th = visitor.getConfiguration().getTypeHierarchy(); Expression start2 = visitor.optimize(start, contextItemType); if (start2 != start) { start = start2; adoptChildExpression(start2); } start.setFiltered(true); Expression originalFilter; try { originalFilter = filter.copy(); } catch (UnsupportedOperationException err) { originalFilter = null; } Expression filter2 = filter.optimize(visitor, start.getItemType(th)); if (filter2 != filter) { filter = filter2; adoptChildExpression(filter2); } // The filter expression usually doesn't need to be sorted filter2 = ExpressionTool.unsortedIfHomogeneous(opt, filter); if (filter2 != filter) { filter = filter2; adoptChildExpression(filter2); } // the filter expression may have been reduced to a constant boolean by previous optimizations if (filter instanceof Literal && ((Literal)filter).getValue() instanceof BooleanValue) { if (((BooleanValue)((Literal)filter).getValue()).getBooleanValue()) { if (debug) { opt.trace("Redundant filter removed", start); } return start; } else { if (debug) { opt.trace("Filter expression eliminated because predicate is always false", new Literal(EmptySequence.getInstance())); } return new Literal(EmptySequence.getInstance()); } } // determine whether the filter might depend on position filterIsPositional = isPositionalFilter(filter, th); filterIsSingletonBoolean = filter.getCardinality() == StaticProperty.EXACTLY_ONE && filter.getItemType(th).equals(BuiltInAtomicType.BOOLEAN); // determine whether the filter is indexable if (!filterIsPositional) { int isIndexable = opt.isIndexableFilter(filter); if (isIndexable == 0 && filter != originalFilter && originalFilter != null) { // perhaps the original filter was indexable; if so, revert to the original // this happens when [@a = 1] is rewritten as [some $x in @a satisfies $x eq 1] // TODO: this rollback mechanism is very unsatisfactory. Better: make the some expression indexable! int origIndexable = opt.isIndexableFilter(originalFilter); if (origIndexable != 0) { isIndexable = origIndexable; filter = originalFilter; adoptChildExpression(originalFilter); } } // If the filter is indexable consider creating a key, or an indexed filter expression // (This happens in Saxon-SA only) if (isIndexable != 0) { Expression f = opt.tryIndexedFilter(this, visitor, isIndexable > 0); if (f != this) { return f.typeCheck(visitor, contextItemType).optimize(visitor, contextItemType); } } } // if the filter is positional, try changing f[a and b] to f[a][b] to increase // the chances of finishing early. if (filterIsPositional && filter instanceof BooleanExpression && ((BooleanExpression)filter).operator == Token.AND) { BooleanExpression bf = (BooleanExpression)filter; if (isExplicitlyPositional(bf.operand0) && !isExplicitlyPositional(bf.operand1)) { Expression p0 = forceToBoolean(bf.operand0, env.getConfiguration()); Expression p1 = forceToBoolean(bf.operand1, env.getConfiguration()); FilterExpression f1 = new FilterExpression(start, p0); ExpressionTool.copyLocationInfo(this, f1); FilterExpression f2 = new FilterExpression(f1, p1); ExpressionTool.copyLocationInfo(this, f2); if (debug) { opt.trace("Composite filter replaced by nested filter expressions", f2); } return visitor.optimize(f2, contextItemType); } if (isExplicitlyPositional(bf.operand1) && !isExplicitlyPositional(bf.operand0)) { Expression p0 = forceToBoolean(bf.operand0, env.getConfiguration()); Expression p1 = forceToBoolean(bf.operand1, env.getConfiguration()); FilterExpression f1 = new FilterExpression(start, p1); ExpressionTool.copyLocationInfo(this, f1); FilterExpression f2 = new FilterExpression(f1, p0); ExpressionTool.copyLocationInfo(this, f2); if (debug) { opt.trace("Composite filter replaced by nested filter expressions", f2); } return visitor.optimize(f2, contextItemType); } } if (filter instanceof IsLastExpression && ((IsLastExpression)filter).getCondition()) { if (start instanceof Literal) { filter = Literal.makeLiteral(new Int64Value(((Literal)start).getValue().getLength())); } else { return new LastItemExpression(start); } } Expression subsequence = tryToRewritePositionalFilter(visitor); if (subsequence != null) { if (debug) { opt.trace("Rewrote Filter Expression as:", subsequence); } ExpressionTool.copyLocationInfo(this, subsequence); return subsequence.simplify(visitor) .typeCheck(visitor, contextItemType) .optimize(visitor, contextItemType); } // If any subexpressions within the filter are not dependent on the focus, // promote them: this causes them to be evaluated once, outside the filter // expression. Note: we do this even if the filter is numeric, because it ensures that // the subscript is pre-evaluated, allowing direct indexing into the sequence. PromotionOffer offer = new PromotionOffer(opt); offer.action = PromotionOffer.FOCUS_INDEPENDENT; offer.promoteDocumentDependent = (start.getSpecialProperties() & StaticProperty.CONTEXT_DOCUMENT_NODESET) != 0; offer.containingExpression = this; filter2 = doPromotion(filter, offer); if (filter2 != filter) { filter = filter2; adoptChildExpression(filter2); } if (offer.containingExpression instanceof LetExpression) { if (debug) { opt.trace("Subexpression extracted from filter because independent of context", offer.containingExpression); } offer.containingExpression = visitor.optimize(offer.containingExpression, contextItemType); } Expression result = offer.containingExpression; if (result instanceof FilterExpression) { Value value = ((FilterExpression)result).tryEarlyEvaluation(visitor); if (value != null) { return new Literal(value); } } return result; } private Value tryEarlyEvaluation(ExpressionVisitor visitor) throws XPathException { // Attempt early evaluation of a filter expression if the base sequence is constant and the // filter depends only on the context. (This can't be done if, for example, the predicate uses // local variables, even variables declared within the predicate) try { if (start instanceof Literal && (filter.getDependencies()&~StaticProperty.DEPENDS_ON_FOCUS) == 0) { XPathContext context = visitor.getStaticContext().makeEarlyEvaluationContext(); return (Value)SequenceExtent.makeSequenceExtent(iterate(context)); } } catch (Exception e) { // can happen for a variety of reasons, for example the filter references a global parameter, // references the doc() function, etc. return null; } return null; } /** * Add a representation of this expression to a PathMap. The PathMap captures a map of the nodes visited * by an expression in a source tree. * * @param pathMap the PathMap to which the expression should be added * @param pathMapNodeSet * @return the pathMapNode representing the focus established by this expression, in the case where this * expression is the first operand of a path expression or filter expression */ public PathMap.PathMapNodeSet addToPathMap(PathMap pathMap, PathMap.PathMapNodeSet pathMapNodeSet) { PathMap.PathMapNodeSet target = start.addToPathMap(pathMap, pathMapNodeSet); filter.addToPathMap(pathMap, target); return target; } /** * Construct an expression that obtains the effective boolean value of a given expression, * by wrapping it in a call of the boolean() function * * @param in the given expression * @param config the Saxon configuration * @return an expression that wraps the given expression in a call to the fn:boolean() function */ private static Expression forceToBoolean(Expression in, Configuration config) { final TypeHierarchy th = config.getTypeHierarchy(); if (in.getItemType(th).getPrimitiveType() == StandardNames.XS_BOOLEAN) { return in; } return SystemFunction.makeSystemFunction("boolean", new Expression[]{in}); } /** * Attempt to rewrite a filter expression whose predicate is a test of the form * [position() op expr] as a call on functions such as subsequence, remove, or saxon:itemAt * @param visitor the current expression visitor * @return the rewritten expression if a rewrite was possible, or null otherwise */ private Expression tryToRewritePositionalFilter(ExpressionVisitor visitor) throws XPathException { if (filter instanceof Literal) { Value val = ((Literal)filter).getValue(); if (val instanceof NumericValue) { if (((NumericValue)val).isWholeNumber()) { long lvalue = ((NumericValue)val).longValue(); if (lvalue <= 0) { return Literal.makeEmptySequence(); } else if (lvalue == 1) { return new FirstItemExpression(start); } else { return visitor.getConfiguration().getVendorFunctionLibrary().makeSaxonFunction( "item-at", visitor.getStaticContext(), new Expression[]{start, filter}); } } else { return Literal.makeEmptySequence(); } } else { return (val.effectiveBooleanValue() ? start : Literal.makeEmptySequence()); } } if (filter instanceof ComparisonExpression) { TypeHierarchy th = visitor.getConfiguration().getTypeHierarchy(); VendorFunctionLibrary lib = visitor.getConfiguration().getVendorFunctionLibrary(); StaticContext env = visitor.getStaticContext(); Expression[] operands = ((ComparisonExpression)filter).getOperands(); int operator = ((ComparisonExpression)filter).getSingletonOperator(); Expression comparand; if (operands[0] instanceof Position && th.isSubType(operands[1].getItemType(th), BuiltInAtomicType.NUMERIC)) { comparand = operands[1]; } else if (operands[1] instanceof Position && th.isSubType(operands[0].getItemType(th), BuiltInAtomicType.NUMERIC)) { comparand = operands[0]; operator = Token.inverse(operator); } else { return null; } if ((comparand.getDependencies() & StaticProperty.DEPENDS_ON_FOCUS) != 0) { return null; } int card = comparand.getCardinality(); if (Cardinality.allowsMany(card)) { return null; } // If the comparand might be an empty sequence, do the base rewrite and then wrap the // rewritten expression EXP in "let $n := comparand if exists($n) then EXP else () if (Cardinality.allowsZero(card)) { LetExpression let = new LetExpression(); let.setRequiredType(SequenceType.makeSequenceType(comparand.getItemType(th), card)); let.setVariableQName(new StructuredQName("pp", NamespaceConstant.SAXON, "pp" + let.hashCode())); let.setSequence(comparand); comparand = new LocalVariableReference(let); LocalVariableReference existsArg = new LocalVariableReference(let); Existence exists = (Existence)SystemFunction.makeSystemFunction("exists", new Expression[]{existsArg}); Expression rewrite = tryToRewritePositionalFilterSupport(start, comparand, operator, th, lib, env); if (rewrite == null) { return this; } Expression choice = Choose.makeConditional(exists, rewrite); let.setAction(choice); return let; } else { return tryToRewritePositionalFilterSupport(start, comparand, operator, th, lib, env); } } else if (filter instanceof IntegerRangeTest) { // rewrite SEQ[position() = N to M] // => let $n := N return subsequence(SEQ, $n, (M - ($n - 1)) // (precise form is optimized for the case where $n is a literal, especially N = 1) Expression val = ((IntegerRangeTest)filter).getValueExpression(); if (!(val instanceof Position)) { return null; } Expression min = ((IntegerRangeTest)filter).getMinValueExpression(); Expression max = ((IntegerRangeTest)filter).getMaxValueExpression(); LetExpression let = new LetExpression(); let.setRequiredType(SequenceType.SINGLE_INTEGER); let.setVariableQName(new StructuredQName("nn", NamespaceConstant.SAXON, "nn" + let.hashCode())); let.setSequence(min); min = new LocalVariableReference(let); LocalVariableReference min2 = new LocalVariableReference(let); Expression minMinusOne = new ArithmeticExpression( min2, Token.MINUS, new Literal(Int64Value.makeIntegerValue(1))); Expression length = new ArithmeticExpression(max, Token.MINUS, minMinusOne); Subsequence subs = (Subsequence)SystemFunction.makeSystemFunction( "subsequence", new Expression[]{start, min, length}); let.setAction(subs); return let; } else { return null; } } private static Expression tryToRewritePositionalFilterSupport( Expression start, Expression comparand, int operator, TypeHierarchy th, VendorFunctionLibrary lib, StaticContext env) throws XPathException { if (th.isSubType(comparand.getItemType(th), BuiltInAtomicType.INTEGER)) { switch (operator) { case Token.FEQ: { if (Literal.isConstantOne(comparand)) { return new FirstItemExpression(start); } else { return lib.makeSaxonFunction( "item-at", env, new Expression[] {start, comparand}); } } case Token.FLT: { Expression[] args = new Expression[3]; args[0] = start; args[1] = new Literal(Int64Value.makeIntegerValue(1)); if (Literal.isAtomic(comparand)) { long n = ((NumericValue)((Literal)comparand).getValue()).longValue(); args[2] = new Literal(Int64Value.makeIntegerValue(n - 1)); } else { args[2] = new ArithmeticExpression( comparand, Token.MINUS, new Literal(Int64Value.makeIntegerValue(1))); } return SystemFunction.makeSystemFunction("subsequence", args); } case Token.FLE: { Expression[] args = new Expression[3]; args[0] = start; args[1] = new Literal(Int64Value.makeIntegerValue(1)); args[2] = comparand; return SystemFunction.makeSystemFunction("subsequence", args); } case Token.FNE: { return SystemFunction.makeSystemFunction("remove", new Expression[]{start, comparand}); } case Token.FGT: { Expression[] args = new Expression[2]; args[0] = start; if (Literal.isAtomic(comparand)) { long n = ((NumericValue)((Literal)comparand).getValue()).longValue(); args[1] = new Literal(Int64Value.makeIntegerValue(n + 1)); } else { args[1] = new ArithmeticExpression( comparand, Token.PLUS, new Literal(Int64Value.makeIntegerValue(1))); } return SystemFunction.makeSystemFunction("subsequence", args); } case Token.FGE: { return SystemFunction.makeSystemFunction("subsequence", new Expression[]{start, comparand}); } default: throw new IllegalArgumentException("operator"); } } else { // the comparand is not known statically to be an integer switch (operator) { case Token.FEQ: { return lib.makeSaxonFunction( "item-at", env, new Expression[] {start, comparand}); } case Token.FLT: { // rewrite SEQ[position() lt V] as // let $N := V return subsequence(SEQ, 1, if (is-whole-number($N)) then $N-1 else floor($N))) LetExpression let = new LetExpression(); let.setRequiredType(SequenceType.makeSequenceType( comparand.getItemType(th), StaticProperty.ALLOWS_ONE)); let.setVariableQName(new StructuredQName("pp", NamespaceConstant.SAXON, "pp" + let.hashCode())); let.setSequence(comparand); LocalVariableReference isWholeArg = new LocalVariableReference(let); LocalVariableReference arithArg = new LocalVariableReference(let); LocalVariableReference floorArg = new LocalVariableReference(let); Expression isWhole = lib.makeSaxonFunction( "is-whole-number", env, new Expression[] {isWholeArg}); Expression minusOne = new ArithmeticExpression( arithArg, Token.MINUS, new Literal(Int64Value.makeIntegerValue(1))); Rounding floor = (Rounding)SystemFunction.makeSystemFunction( "floor", new Expression[] {floorArg}); Expression choice = Choose.makeConditional(isWhole, minusOne, floor); Subsequence subs = (Subsequence)SystemFunction.makeSystemFunction( "subsequence", new Expression[] {start, new Literal(Int64Value.makeIntegerValue(1)), choice}); let.setAction(subs); //decl.fixupReferences(let); return let; } case Token.FLE: { Rounding floor = (Rounding)SystemFunction.makeSystemFunction( "floor", new Expression[] {comparand}); return SystemFunction.makeSystemFunction( "subsequence", new Expression[] {start, new Literal(Int64Value.makeIntegerValue(1)), floor}); } case Token.FNE: { // rewrite SEQ[position() ne V] as // let $N := V return remove(SEQ, if (is-whole-number($N)) then xs:integer($N) else 0) LetExpression let = new LetExpression(); ExpressionTool.copyLocationInfo(start, let); let.setRequiredType(SequenceType.makeSequenceType( comparand.getItemType(th), StaticProperty.ALLOWS_ONE)); let.setVariableQName(new StructuredQName("pp", NamespaceConstant.SAXON, "pp" + let.hashCode())); let.setSequence(comparand); LocalVariableReference isWholeArg = new LocalVariableReference(let); LocalVariableReference castArg = new LocalVariableReference(let); Expression isWhole = lib.makeSaxonFunction( "is-whole-number", env, new Expression[] {isWholeArg}); ExpressionTool.copyLocationInfo(start, isWhole); Expression cast = new CastExpression(castArg, BuiltInAtomicType.INTEGER, false); ExpressionTool.copyLocationInfo(start, cast); Expression choice = Choose.makeConditional( isWhole, cast, new Literal(Int64Value.makeIntegerValue(0))); Remove rem = (Remove)SystemFunction.makeSystemFunction( "remove", new Expression[] {start, choice}); let.setAction(rem); return let; } case Token.FGT: { // rewrite SEQ[position() gt V] as // let $N := V return subsequence(SEQ, if (is-whole-number($N)) then $N+1 else ceiling($N))) LetExpression let = new LetExpression(); let.setRequiredType(SequenceType.makeSequenceType( comparand.getItemType(th), StaticProperty.ALLOWS_ONE)); let.setVariableQName(new StructuredQName("pp", NamespaceConstant.SAXON, "pp" + let.hashCode())); let.setSequence(comparand); LocalVariableReference isWholeArg = new LocalVariableReference(let); LocalVariableReference arithArg = new LocalVariableReference(let); LocalVariableReference ceilingArg = new LocalVariableReference(let); Expression isWhole = lib.makeSaxonFunction( "is-whole-number", env, new Expression[] {isWholeArg}); Expression plusOne = new ArithmeticExpression( arithArg, Token.PLUS, new Literal(Int64Value.makeIntegerValue(1))); Rounding ceiling = (Rounding)SystemFunction.makeSystemFunction( "ceiling", new Expression[] {ceilingArg}); Expression choice = Choose.makeConditional(isWhole, plusOne, ceiling); Subsequence subs = (Subsequence)SystemFunction.makeSystemFunction( "subsequence", new Expression[] {start, choice}); let.setAction(subs); return let; } case Token.FGE: { // rewrite SEQ[position() ge V] => subsequence(SEQ, ceiling(V)) Rounding ceiling = (Rounding)SystemFunction.makeSystemFunction( "ceiling", new Expression[] {comparand}); return SystemFunction.makeSystemFunction( "subsequence", new Expression[] {start, ceiling}); } default: throw new IllegalArgumentException("operator"); } } } /** * Promote this expression if possible * * @param offer details of the promotion that is possible * @return the promoted expression (or the original expression, unchanged) */ public Expression promote(PromotionOffer offer) throws XPathException { Expression exp = offer.accept(this); if (exp != null) { return exp; } else { if (offer.action == PromotionOffer.RANGE_INDEPENDENT && start instanceof FilterExpression) { // Try to handle the situation where we have (EXP[PRED1])[PRED2], and // EXP[PRED2] does not depend on the range variable, but PRED1 does TypeHierarchy th = offer.getOptimizer().getConfiguration().getTypeHierarchy(); FilterExpression newfe = promoteIndependentPredicates(offer.bindingList, offer.getOptimizer(), th); if (newfe != this) { return newfe.promote(offer); } } if (!(offer.action == PromotionOffer.UNORDERED && filterIsPositional)) { start = doPromotion(start, offer); } if (offer.action == PromotionOffer.REPLACE_CURRENT) { filter = doPromotion(filter, offer); } else if (offer.action == PromotionOffer.INLINE_VARIABLE_REFERENCES) { filter = doPromotion(filter, offer); } else { // Don't pass on other requests. We could pass them on, but only after augmenting // them to say we are interested in subexpressions that don't depend on either the // outer context or the inner context. } return this; } } /** * Rearrange a filter expression so that predicates that are independent of a given * set of range variables come first, allowing them to be promoted along with the base * expression * * @param bindings the given set of range variables * @param th the type hierarchy cache * @return the expression after promoting independent predicates */ private FilterExpression promoteIndependentPredicates(Binding[] bindings, Optimizer opt, TypeHierarchy th) { if (!ExpressionTool.dependsOnVariable(start, bindings)) { return this; } if (isPositional(th)) { return this; } if (start instanceof FilterExpression) { FilterExpression fe = (FilterExpression)start; if (fe.isPositional(th)) { return this; } if (!ExpressionTool.dependsOnVariable(fe.filter, bindings)) { return this; } if (!ExpressionTool.dependsOnVariable(filter, bindings)) { FilterExpression result = new FilterExpression( new FilterExpression(fe.start, filter).promoteIndependentPredicates(bindings, opt, th), fe.filter); opt.trace("Reordered filter predicates:", result); return result; } } return this; } /** * Determine whether an expression, when used as a filter, is potentially positional; * that is, where it either contains a call on position() or last(), or where it is capable of returning * a numeric result. * * @param exp the expression to be examined * @param th the type hierarchy cache * @return true if the expression depends on position() or last() explicitly or implicitly */ private static boolean isPositionalFilter(Expression exp, TypeHierarchy th) { ItemType type = exp.getItemType(th); if (type.equals(BuiltInAtomicType.BOOLEAN)) { // common case, get it out of the way quickly return isExplicitlyPositional(exp); } return (type.equals(BuiltInAtomicType.ANY_ATOMIC) || type instanceof AnyItemType || type.equals(BuiltInAtomicType.INTEGER) || type.equals(BuiltInAtomicType.NUMERIC) || th.isSubType(type, BuiltInAtomicType.NUMERIC) || isExplicitlyPositional(exp)); } /** * Determine whether an expression, when used as a filter, has an explicit dependency on position() or last() * * @param exp the expression being tested * @return true if the expression is explicitly positional, that is, if it contains an explicit call on * position() or last() */ private static boolean isExplicitlyPositional(Expression exp) { return (exp.getDependencies() & (StaticProperty.DEPENDS_ON_POSITION | StaticProperty.DEPENDS_ON_LAST)) != 0; } /** * Get the immediate subexpressions of this expression * * @return the subexpressions, as an array */ public Iterator iterateSubExpressions() { return new PairIterator(start, filter); } /** * Given an expression that is an immediate child of this expression, test whether * the evaluation of the parent expression causes the child expression to be * evaluated repeatedly * * @param child the immediate subexpression * @return true if the child expression is evaluated repeatedly */ public boolean hasLoopingSubexpression(Expression child) { return child == filter; } /** * Replace one subexpression by a replacement subexpression * * @param original the original subexpression * @param replacement the replacement subexpression * @return true if the original subexpression is found */ public boolean replaceSubExpression(Expression original, Expression replacement) { boolean found = false; if (start == original) { start = replacement; found = true; } if (filter == original) { filter = replacement; found = true; } return found; } /** * Get the static cardinality of this expression * * @return the cardinality. The method attempts to determine the case where the * filter predicate is guaranteed to select at most one item from the sequence being filtered */ public int computeCardinality() { if (filter instanceof Literal && ((Literal)filter).getValue() instanceof NumericValue) { if (((NumericValue)((Literal)filter).getValue()).compareTo(1) == 0 && !Cardinality.allowsZero(start.getCardinality())) { return StaticProperty.ALLOWS_ONE; } else { return StaticProperty.ALLOWS_ZERO_OR_ONE; } } if (filterIsIndependentNumeric) { return StaticProperty.ALLOWS_ZERO_OR_ONE; } if (filter instanceof IsLastExpression && ((IsLastExpression)filter).getCondition()) { return start.getCardinality() & ~StaticProperty.ALLOWS_MANY; } if (!Cardinality.allowsMany(start.getCardinality())) { return StaticProperty.ALLOWS_ZERO_OR_ONE; } return StaticProperty.ALLOWS_ZERO_OR_MORE; } /** * Get the static properties of this expression (other than its type). The result is * bit-significant. These properties are used for optimizations. In general, if * property bit is set, it is true, but if it is unset, the value is unknown. * * @return the static properties of the expression, as a bit-significant value */ public int computeSpecialProperties() { return start.getSpecialProperties(); } /** * Is this expression the same as another expression? * * @param other the expression to be compared with this one * @return true if the two expressions are statically equivalent */ public boolean equals(Object other) { if (other instanceof FilterExpression) { FilterExpression f = (FilterExpression)other; return (start.equals(f.start) && filter.equals(f.filter)); } return false; } /** * get HashCode for comparing two expressions * * @return the hash code */ public int hashCode() { return "FilterExpression".hashCode() + start.hashCode() + filter.hashCode(); } /** * Iterate over the results, returning them in the correct order * * @param context the dynamic context for the evaluation * @return an iterator over the expression results * @throws XPathException if any dynamic error occurs */ public SequenceIterator iterate(XPathContext context) throws XPathException { // Fast path where both operands are constants, or simple variable references Expression startExp = start; Value startValue = null; if (startExp instanceof Literal) { startValue = ((Literal)startExp).getValue(); } else if (startExp instanceof VariableReference) { startValue = Value.asValue(((VariableReference)startExp).evaluateVariable(context)); startExp = new Literal(startValue); } if (startValue instanceof EmptySequence) { return EmptyIterator.getInstance(); } ValueRepresentation filterValue = null; if (filter instanceof Literal) { filterValue = ((Literal)filter).getValue(); } else if (filter instanceof VariableReference) { filterValue = ((VariableReference)filter).evaluateVariable(context); } // Handle the case where the filter is a value. Because of earlier static rewriting, this covers // all cases where the filter expression is independent of the context, that is, where the // value of the filter expression is the same for all items in the sequence being filtered. if (filterValue != null) { if (filterValue instanceof Value) { filterValue = ((Value)filterValue).reduce(); if (filterValue instanceof NumericValue) { // Filter is a constant number if (((NumericValue)filterValue).isWholeNumber()) { int pos = (int)(((NumericValue)filterValue).longValue()); if (startValue != null) { // if sequence is a value, use direct indexing return SingletonIterator.makeIterator(startValue.itemAt(pos - 1)); } if (pos >= 1) { SequenceIterator base = startExp.iterate(context); return SubsequenceIterator.make(base, pos, pos); } else { // index is less than one, no items will be selected return EmptyIterator.getInstance(); } } else { // a non-integer value will never be equal to position() return EmptyIterator.getInstance(); } } // Filter is a value that we can treat as boolean boolean b; try { b = ((Value)filterValue).effectiveBooleanValue(); } catch (XPathException err) { err.maybeSetLocation(this); throw err; } if (b) { return start.iterate(context); } else { return EmptyIterator.getInstance(); } } else if (filterValue instanceof NodeInfo) { return start.iterate(context); } } // get an iterator over the base nodes SequenceIterator base = startExp.iterate(context); // quick exit for an empty sequence if (base instanceof EmptyIterator) { return base; } if (filterIsPositional && !filterIsSingletonBoolean) { return new FilterIterator(base, filter, context); } else { return new FilterIterator.NonNumeric(base, filter, context); } } /** * Determine which aspects of the context the expression depends on. The result is * a bitwise-or'ed value composed from constants such as XPathContext.VARIABLES and * XPathContext.CURRENT_NODE * * @return the dependencies */ public int computeDependencies() { // not all dependencies in the filter expression matter, because the context node, // position, and size are not dependent on the outer context. return (start.getDependencies() | (filter.getDependencies() & (StaticProperty.DEPENDS_ON_XSLT_CONTEXT | StaticProperty.DEPENDS_ON_LOCAL_VARIABLES | StaticProperty.DEPENDS_ON_USER_FUNCTIONS))); } /** * Copy an expression. This makes a deep copy. * * @return the copy of the original expression */ public Expression copy() { return new FilterExpression(start.copy(), filter.copy()); } /** * The toString() method for an expression attempts to give a representation of the expression * in an XPath-like form, but there is no guarantee that the syntax will actually be true XPath. * In the case of XSLT instructions, the toString() method gives an abstracted view of the syntax */ public String toString() { return "(" + start.toString() + "[" + filter.toString() + "])"; } /** * Diagnostic print of expression structure. The abstract expression tree * is written to the supplied output destination. * * @param out the ExpressionPresenter to be used */ public void explain(ExpressionPresenter out) { out.startElement("filterExpression"); start.explain(out); filter.explain(out); out.endElement(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/expr/ExpressionLocation.java0000644000175000017500000001505711033112257023060 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.event.LocationProvider; import net.sf.saxon.event.SaxonLocator; import net.sf.saxon.instruct.LocationMap; import org.xml.sax.Locator; import javax.xml.transform.SourceLocator; import java.io.Serializable; /** * Class to hold details of the location of an expression, of an error in a source file, etc. */ public class ExpressionLocation implements SaxonLocator, Serializable { private String systemId; private int lineNumber; private int columnNumber = -1; /** * Create an ExpressionLocation */ public ExpressionLocation() {} /** * Create an ExpressionLocation, taking the data from a supplied JAXP SourceLocator * @param loc the JAXP SourceLocator */ public ExpressionLocation(SourceLocator loc) { systemId = loc.getSystemId(); lineNumber = loc.getLineNumber(); columnNumber = loc.getColumnNumber(); } /** * Create an ExpressionLocation, taking the data from a supplied SAX Locator * @param loc the SAX Locator */ public static ExpressionLocation makeFromSax(Locator loc) { return new ExpressionLocation(loc.getSystemId(), loc.getLineNumber(), loc.getColumnNumber()); } /** * Create an ExpressionLocation, taking the data from a supplied locationId along with a * LocationProvider to interpret its meaning * @param provider the LocationProvider * @param locationId the locationId */ public ExpressionLocation(LocationProvider provider, long locationId) { systemId = provider.getSystemId(locationId); lineNumber = provider.getLineNumber(locationId); } /** * Create an ExpressionLocation corresponding to a given module, line number, and column number * @param systemId the module URI * @param lineNumber the line number * @param columnNumber the column number */ public ExpressionLocation(String systemId, int lineNumber, int columnNumber) { this.systemId = systemId; this.lineNumber = lineNumber; this.columnNumber = columnNumber; } /** * Get the system ID (the module URI) * @return the system ID */ public String getSystemId() { return systemId; } /** * Get the Public ID * @return always null in this implementation */ public String getPublicId() { return null; } /** * Get the line number * @return the line number */ public int getLineNumber() { return lineNumber; } /** * Get the column number * @return the column number */ public int getColumnNumber() { return columnNumber; } /** * Set the systemId (the module URI) * @param systemId the systemId */ public void setSystemId(String systemId) { this.systemId = systemId; } /** * Set the line number * @param lineNumber the line number within the module */ public void setLineNumber(int lineNumber) { this.lineNumber = lineNumber; } /** * Set the column number * @param columnNumber the column number */ public void setColumnNumber(int columnNumber) { this.columnNumber = columnNumber; } /** * Get the system Id corresponding to a given location Id * @param locationId the location Id * @return the system Id */ public String getSystemId(long locationId) { return getSystemId(); } /** * Get the line number corresponding to a given location Id * @param locationId the location Id * @return the line number */ public int getLineNumber(long locationId) { return getLineNumber(); } public int getColumnNumber(long locationId) { return getColumnNumber(); } /** * Construct an object holding location information for a validation error message * @param locationId The locationId as supplied with an event such as startElement or attribute * @param locationProvider The object that understands how to interpret the locationId * @return a SaxonLocator containing the location information */ public static SaxonLocator getSourceLocator(long locationId, LocationProvider locationProvider) { SaxonLocator locator; if (locationProvider instanceof LocationMap && locationId != 0) { // this is typically true when validating output documents ExpressionLocation loc = new ExpressionLocation(); loc.setLineNumber(locationProvider.getLineNumber(locationId)); loc.setSystemId(locationProvider.getSystemId(locationId)); locator = loc; } else if (locationProvider instanceof SaxonLocator) { // this is typically true when validating input documents locator = (SaxonLocator)locationProvider; } else { // return a dummy location object providing no information. This can happen for example // if a built-in template rule writes invalid output before the transformation properly begins. return new ExpressionLocation(); } return locator; } /** * Truncate a URI to its last component * @param uri the URI to be truncated * @return the last component of the supplied URI */ public static String truncateURI(String uri) { String file = uri; if (file == null) file = ""; while (true) { int i = file.indexOf('/'); if (i >= 0 && i < file.length() - 6) { file = file.substring(i + 1); } else { break; } } return file; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. //saxonb-9.1.0.8/bj/net/sf/saxon/expr/IdentityComparison.java0000644000175000017500000001611211033112257023045 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.om.Item; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.sort.GlobalOrderComparer; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.BuiltInAtomicType; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.TypeHierarchy; import net.sf.saxon.value.BooleanValue; import net.sf.saxon.value.SequenceType; /** * IdentityComparison: a boolean expression that compares two nodes * for equals, not-equals, greater-than or less-than based on identity and * document ordering */ public final class IdentityComparison extends BinaryExpression { private boolean generateIdEmulation = false; // this flag is set if an "X is Y" or "X isnot Y" comparison is being used // to emulate generate-id(X) = / != generate-id(Y). The handling of an empty // sequence in the two cases is different. /** * Create an identity comparison identifying the two operands and the operator * @param p1 the left-hand operand * @param op the operator, as a token returned by the Tokenizer (e.g. Token.LT) * @param p2 the right-hand operand */ public IdentityComparison(Expression p1, int op, Expression p2) { super(p1, op, p2); } /** * Set flag to indicate different empty-sequence behavior when emulating * comparison of two generate-id's * @param flag true if this function is being used to compare generate-id() output */ public void setGenerateIdEmulation(boolean flag) { generateIdEmulation = flag; } /** * Test the flag that indicates different empty-sequence behavior when emulating * comparison of two generate-id's * @return true if this function is being used to compare generate-id() output */ public boolean isGenerateIdEmulation() { return generateIdEmulation; } /** * Type-check the expression */ public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { operand0 = visitor.typeCheck(operand0, contextItemType); operand1 = visitor.typeCheck(operand1, contextItemType); if (!generateIdEmulation) { if (Literal.isEmptySequence(operand0) || Literal.isEmptySequence(operand1)) { return Literal.makeEmptySequence(); } } RoleLocator role0 = new RoleLocator(RoleLocator.BINARY_EXPR, Token.tokens[operator], 0); //role0.setSourceLocator(this); operand0 = TypeChecker.staticTypeCheck( operand0, SequenceType.OPTIONAL_NODE, false, role0, visitor); RoleLocator role1 = new RoleLocator(RoleLocator.BINARY_EXPR, Token.tokens[operator], 1); //role1.setSourceLocator(this); operand1 = TypeChecker.staticTypeCheck( operand1, SequenceType.OPTIONAL_NODE, false, role1, visitor); return this; } /** * Perform optimisation of an expression and its subexpressions. *

    *

    This method is called after all references to functions and variables have been resolved * to the declaration of the function or variable, and after all type checking has been done.

    * * @param visitor an expression visitor * @param contextItemType the static type of "." at the point where this expression is invoked. * The parameter is set to null if it is known statically that the context item will be undefined. * If the type of the context item is not known statically, the argument is set to * {@link net.sf.saxon.type.Type#ITEM_TYPE} * @return the original expression, rewritten if appropriate to optimize execution * @throws XPathException if an error is discovered during this phase * (typically a type error) */ public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { Expression r = super.optimize(visitor, contextItemType); if (r != this) { if (!generateIdEmulation) { if (Literal.isEmptySequence(operand0) || Literal.isEmptySequence(operand1)) { return Literal.makeEmptySequence(); } } } return r; } /** * Copy an expression. This makes a deep copy. * * @return the copy of the original expression */ public Expression copy() { return new IdentityComparison(operand0.copy(), operator, operand1.copy()); } /** * Evaluate the expression */ public Item evaluateItem(XPathContext context) throws XPathException { NodeInfo node1 = getNode(operand0, context); if (node1==null) { if (generateIdEmulation) { return BooleanValue.get(getNode(operand1, context)==null); } return null; } NodeInfo node2 = getNode(operand1, context); if (node2==null) { if (generateIdEmulation) { return BooleanValue.FALSE; } return null; } return BooleanValue.get(compareIdentity(node1, node2)); } public boolean effectiveBooleanValue(XPathContext context) throws XPathException { NodeInfo node1 = getNode(operand0, context); if (node1==null) { return generateIdEmulation && getNode(operand1, context) == null; } NodeInfo node2 = getNode(operand1, context); return node2 != null && compareIdentity(node1, node2); } private boolean compareIdentity(NodeInfo node1, NodeInfo node2) { switch (operator) { case Token.IS: return node1.isSameNodeInfo(node2); case Token.PRECEDES: return GlobalOrderComparer.getInstance().compare(node1, node2) < 0; case Token.FOLLOWS: return GlobalOrderComparer.getInstance().compare(node1, node2) > 0; default: throw new UnsupportedOperationException("Unknown node identity test"); } } private NodeInfo getNode(Expression exp, XPathContext c) throws XPathException { return (NodeInfo)exp.evaluateItem(c); } /** * Determine the data type of the expression * @return Type.BOOLEAN * @param th the type hierarchy cache */ public ItemType getItemType(TypeHierarchy th) { return BuiltInAtomicType.BOOLEAN; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/expr/StatefulMappingFunction.java0000644000175000017500000000242111033112257024030 0ustar eugeneeugenepackage net.sf.saxon.expr; /** * MappingFunction is an interface that must be satisfied by an object passed to a * MappingIterator. StatefulMappingFunction is a sub-interface representing a mapping * function that maintains state information, and which must therefore be cloned * when the mapping iterator is cloned. */ public interface StatefulMappingFunction extends MappingFunction { /** * Return a clone of this MappingFunction, with the state reset to its state at the beginning * of the underlying iteration * @return a clone of this MappingFunction */ public StatefulMappingFunction getAnother(); } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/expr/MultiIterator.java0000644000175000017500000000546511033112257022036 0ustar eugeneeugenepackage net.sf.saxon.expr; import java.util.Iterator; /** * An iterator that combines the results of a sequence of iterators */ public class MultiIterator implements Iterator { private Iterator[] array; private int current; /** * Create an iterator that concatenates a number of supplied iterators * @param array the iterators to be concatenated */ public MultiIterator(Iterator[] array) { this.array = array; current = 0; } /** * Returns true if the iteration has more elements. (In other * words, returns true if next would return an element * rather than throwing an exception.) * * @return true if the iterator has more elements. */ public boolean hasNext() { while (true) { if (current >= array.length) { return false; } if (array[current].hasNext()) { return true; } current++; } } /** * Returns the next element in the iteration. * * @return the next element in the iteration. * @exception java.util.NoSuchElementException iteration has no more elements. */ public Object next() { return array[current].next(); } /** * * Removes from the underlying collection the last element returned by the * iterator (optional operation). This method can be called only once per * call to next. The behavior of an iterator is unspecified if * the underlying collection is modified while the iteration is in * progress in any way other than by calling this method. * * @exception UnsupportedOperationException if the remove * operation is not supported by this Iterator. * @exception IllegalStateException if the next method has not * yet been called, or the remove method has already * been called after the last call to the next * method. */ public void remove() { throw new UnsupportedOperationException(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): Michael Kay // saxonb-9.1.0.8/bj/net/sf/saxon/expr/GeneralComparison10.java0000644000175000017500000003651111033112257022777 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.functions.NumberFn; import net.sf.saxon.om.Item; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.sort.AtomicComparer; import net.sf.saxon.sort.CodepointCollator; import net.sf.saxon.sort.GenericAtomicComparer; import net.sf.saxon.sort.StringCollator; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.BuiltInAtomicType; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.TypeHierarchy; import net.sf.saxon.value.AtomicValue; import net.sf.saxon.value.BooleanValue; import net.sf.saxon.value.DoubleValue; import net.sf.saxon.value.StringValue; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /** * GeneralComparison10: a boolean expression that compares two expressions * for equals, not-equals, greater-than or less-than. This implements the operators * =, !=, <, >, etc. This version of the class implements general comparisons * in XPath 1.0 backwards compatibility mode, as defined in the Oct 2004 revision * of the specifications. */ public class GeneralComparison10 extends BinaryExpression { protected int singletonOperator; protected AtomicComparer comparer; private boolean atomize0 = true; private boolean atomize1 = true; private boolean maybeBoolean0 = true; private boolean maybeBoolean1 = true; /** * Create a general comparison identifying the two operands and the operator * @param p0 the left-hand operand * @param op the operator, as a token returned by the Tokenizer (e.g. Token.LT) * @param p1 the right-hand operand */ public GeneralComparison10(Expression p0, int op, Expression p1) { super(p0, op, p1); singletonOperator = getSingletonOperator(op); } /** * Determine the static cardinality. Returns [1..1] */ public int computeCardinality() { return StaticProperty.EXACTLY_ONE; } /** * Type-check the expression * @return the checked expression */ public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { operand0 = visitor.typeCheck(operand0, contextItemType); operand1 = visitor.typeCheck(operand1, contextItemType); StaticContext env = visitor.getStaticContext(); StringCollator comp = env.getCollation(env.getDefaultCollationName()); if (comp==null) { comp = CodepointCollator.getInstance(); } XPathContext context = env.makeEarlyEvaluationContext(); comparer = new GenericAtomicComparer(comp, context); // evaluate the expression now if both arguments are constant if ((operand0 instanceof Literal) && (operand1 instanceof Literal)) { return Literal.makeLiteral((AtomicValue)evaluateItem(context)); } return this; } /** * Optimize the expression * @return the checked expression */ public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { Optimizer opt = visitor.getConfiguration().getOptimizer(); StaticContext env = visitor.getStaticContext(); operand0 = visitor.optimize(operand0, contextItemType); operand1 = visitor.optimize(operand1, contextItemType); // Neither operand needs to be sorted operand0 = ExpressionTool.unsorted(opt, operand0, false); operand1 = ExpressionTool.unsorted(opt, operand1, false); // evaluate the expression now if both arguments are constant if ((operand0 instanceof Literal) && (operand1 instanceof Literal)) { return Literal.makeLiteral( (AtomicValue)evaluateItem(env.makeEarlyEvaluationContext())); } final TypeHierarchy th = env.getConfiguration().getTypeHierarchy(); ItemType type0 = operand0.getItemType(th); ItemType type1 = operand1.getItemType(th); if (type0.isAtomicType()) { atomize0 = false; } if (type1.isAtomicType()) { atomize1 = false; } if (th.relationship(type0, BuiltInAtomicType.BOOLEAN) == TypeHierarchy.DISJOINT) { maybeBoolean0 = false; } if (th.relationship(type1, BuiltInAtomicType.BOOLEAN) == TypeHierarchy.DISJOINT) { maybeBoolean1 = false; } if (!maybeBoolean0 && !maybeBoolean1) { int n0 = th.relationship(type0, BuiltInAtomicType.NUMERIC); int n1 = th.relationship(type1, BuiltInAtomicType.NUMERIC); boolean maybeNumeric0 = (n0 != TypeHierarchy.DISJOINT); boolean maybeNumeric1 = (n1 != TypeHierarchy.DISJOINT); boolean numeric0 = (n0 == TypeHierarchy.SUBSUMED_BY || n0 == TypeHierarchy.SAME_TYPE); boolean numeric1 = (n1 == TypeHierarchy.SUBSUMED_BY || n1 == TypeHierarchy.SAME_TYPE); // Use the 2.0 path if we don't have to deal with the possibility of boolean values, // or the complications of converting values to numbers if (operator == Token.EQUALS || operator == Token.NE) { if ((!maybeNumeric0 && !maybeNumeric1) || (numeric0 && numeric1)) { BinaryExpression gc = opt.makeGeneralComparison(operand0, operator, operand1, false); ExpressionTool.copyLocationInfo(this, gc); return visitor.optimize(visitor.typeCheck(gc, contextItemType), contextItemType); } } else if (numeric0 && numeric1) { BinaryExpression gc = opt.makeGeneralComparison(operand0, operator, operand1, false); ExpressionTool.copyLocationInfo(this, gc); return visitor.optimize(visitor.typeCheck(gc, contextItemType), contextItemType); } } return this; } /** * Evaluate the expression in a given context * @param context the given context for evaluation * @return a BooleanValue representing the result of the numeric comparison of the two operands */ public Item evaluateItem(XPathContext context) throws XPathException { return BooleanValue.get(effectiveBooleanValue(context)); } /** * Evaluate the expression in a boolean context * @param context the given context for evaluation * @return a boolean representing the result of the numeric comparison of the two operands */ public boolean effectiveBooleanValue(XPathContext context) throws XPathException { // If the first operand is a singleton boolean, // compare it with the effective boolean value of the other operand SequenceIterator iter0 = null; if (maybeBoolean0) { iter0 = operand0.iterate(context); Item i01 = iter0.next(); Item i02 = (i01 == null ? null : iter0.next()); if (i01 instanceof BooleanValue && i02 == null) { boolean b = operand1.effectiveBooleanValue(context); return compare((BooleanValue)i01, singletonOperator, BooleanValue.get(b), comparer, context); } if (i01 == null && !maybeBoolean1) { return false; } } // If the second operand is a singleton boolean, // compare it with the effective boolean value of the other operand SequenceIterator iter1 = null; if (maybeBoolean1) { iter1 = operand1.iterate(context); Item i11 = iter1.next(); Item i12 = (i11 == null ? null : iter1.next()); if (i11 instanceof BooleanValue && i12 == null) { boolean b = operand0.effectiveBooleanValue(context); return compare(BooleanValue.get(b), singletonOperator, (BooleanValue)i11, comparer, context); } if (i11 == null && !maybeBoolean0) { return false; } } // Atomize both operands where necessary if (iter0 == null) { iter0 = operand0.iterate(context); } else { iter0 = iter0.getAnother(); } if (iter1 == null) { iter1 = operand1.iterate(context); } else { iter1 = iter1.getAnother(); } if (atomize0) { iter0 = Atomizer.getAtomizingIterator(iter0); } if (atomize1) { iter1 = Atomizer.getAtomizingIterator(iter1); } // If the operator is one of <, >, <=, >=, then convert both operands to sequences of xs:double // using the number() function if (operator == Token.LT || operator == Token.LE || operator == Token.GT || operator == Token.GE) { iter0 = new ItemMappingIterator(iter0, new NumberFn()); iter1 = new ItemMappingIterator(iter1, new NumberFn()); } // Compare all pairs of atomic values in the two atomized sequences List seq1 = null; while (true) { AtomicValue item0 = (AtomicValue)iter0.next(); if (item0 == null) { return false; } if (iter1 != null) { while (true) { AtomicValue item1 = (AtomicValue)iter1.next(); if (item1 == null) { iter1 = null; if (seq1 == null) { // second operand is empty return false; } break; } try { if (compare(item0, singletonOperator, item1, comparer, context)) { return true; } if (seq1 == null) { seq1 = new ArrayList(40); } seq1.add(item1); } catch (XPathException e) { // re-throw the exception with location information added e.maybeSetLocation(this); e.maybeSetContext(context); throw e; } } } else { //assert seq1 != null; Iterator listIter1 = seq1.iterator(); while (listIter1.hasNext()) { AtomicValue item1 = (AtomicValue)listIter1.next(); if (compare(item0, singletonOperator, item1, comparer, context)) { return true; } } } } } /** * Copy an expression. This makes a deep copy. * * @return the copy of the original expression */ public Expression copy() { GeneralComparison10 gc = new GeneralComparison10(operand0.copy(), operator, operand1.copy()); gc.comparer = comparer; gc.atomize0 = atomize0; gc.atomize1 = atomize1; gc.maybeBoolean0 = maybeBoolean0; gc.maybeBoolean1 = maybeBoolean1; return gc; } /** * Compare two atomic values * @param a0 the first value to be compared * @param operator the comparison operator * @param a1 the second value to be compared * @param comparer the comparer to be used (perhaps including a collation) * @param context the XPath dynamic context * @return the result of the comparison */ private static boolean compare(AtomicValue a0, int operator, AtomicValue a1, AtomicComparer comparer, XPathContext context) throws XPathException { comparer = comparer.provideContext(context); BuiltInAtomicType t0 = a0.getPrimitiveType(); BuiltInAtomicType t1 = a1.getPrimitiveType(); // If either operand is a number, convert both operands to xs:double using // the rules of the number() function, and compare them if (t0.isPrimitiveNumeric() || t1.isPrimitiveNumeric()) { DoubleValue v0 = NumberFn.convert(a0); DoubleValue v1 = NumberFn.convert(a1); return ValueComparison.compare(v0, operator, v1, comparer); } // If either operand is a string, or if both are untyped atomic, convert // both operands to strings and compare them if (t0.equals(BuiltInAtomicType.STRING) || t1.equals(BuiltInAtomicType.STRING) || (t0.equals(BuiltInAtomicType.UNTYPED_ATOMIC) && t1.equals(BuiltInAtomicType.UNTYPED_ATOMIC))) { StringValue s0 = (StringValue)a0.convert(BuiltInAtomicType.STRING, true, context).asAtomic(); StringValue s1 = (StringValue)a1.convert(BuiltInAtomicType.STRING, true, context).asAtomic(); return ValueComparison.compare(s0, operator, s1, comparer); } // If either operand is untyped atomic, // convert it to the type of the other operand, and compare if (t0.equals(BuiltInAtomicType.UNTYPED_ATOMIC)) { a0 = a0.convert(t1, true, context).asAtomic(); } if (t1.equals(BuiltInAtomicType.UNTYPED_ATOMIC)) { a1 = a1.convert(t0, true, context).asAtomic(); } return ValueComparison.compare(a0, operator, a1, comparer); } /** * Determine the data type of the expression * @return Type.BOOLEAN * @param th the type hierarchy cache */ public ItemType getItemType(TypeHierarchy th) { return BuiltInAtomicType.BOOLEAN; } /** * Return the singleton form of the comparison operator, e.g. FEQ for EQUALS, FGT for GT * @param op the general comparison operator, for example Token.EQUALS * @return the corresponding value comparison operator, for example Token.FEQ */ private static int getSingletonOperator(int op) { switch (op) { case Token.EQUALS: return Token.FEQ; case Token.GE: return Token.FGE; case Token.NE: return Token.FNE; case Token.LT: return Token.FLT; case Token.GT: return Token.FGT; case Token.LE: return Token.FLE; default: return op; } } protected String displayOperator() { return "many-to-many (1.0) " + super.displayOperator(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/expr/StringLiteral.java0000644000175000017500000000321711033112257022006 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.value.StringValue; /** * Subclass of Literal used specifically for string literals, as this is a common case */ public class StringLiteral extends Literal { /** * Create a StringLiteral that wraps a StringValue * @param value the StringValue */ public StringLiteral(StringValue value) { super(value); } /** * Create a StringLiteral that wraps any CharSequence (including, of course, a String) * @param value the CharSequence to be wrapped */ public StringLiteral(CharSequence value) { super(StringValue.makeStringValue(value)); } /** * Get the string represented by this StringLiteral * @return the underlying string */ public String getStringValue() { //noinspection RedundantCast return ((StringValue)getValue()).getStringValue(); } public Expression copy() { return new StringLiteral((StringValue)getValue()); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/expr/ContextItemExpression.java0000644000175000017500000001706211033112257023551 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.om.Item; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.om.SingletonIterator; import net.sf.saxon.trace.ExpressionPresenter; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.Type; import net.sf.saxon.type.TypeHierarchy; /** * This class represents the expression "(dot)", which always returns the context item. * This may be a AtomicValue or a Node. */ public class ContextItemExpression extends Expression { ItemType itemType = Type.ITEM_TYPE; /** * Create the expression */ public ContextItemExpression() {} /** * Create a clone copy of this expression * @return a copy of this expression */ public Expression copy() { ContextItemExpression cie2 = new ContextItemExpression(); cie2.itemType = itemType; return cie2; } protected String getErrorCodeForUndefinedContext() { return "XPDY0002"; } /** * Type-check the expression. */ public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { if (contextItemType == null) { XPathException err = new XPathException("The context item is undefined at this point"); err.setErrorCode(getErrorCodeForUndefinedContext()); err.setIsTypeError(true); err.setLocator(this); throw err; } itemType = contextItemType; return this; } /** * Perform optimisation of an expression and its subexpressions. *

    *

    This method is called after all references to functions and variables have been resolved * to the declaration of the function or variable, and after all type checking has been done.

    * * @param visitor an expression visitor * @param contextItemType the static type of "." at the point where this expression is invoked. * The parameter is set to null if it is known statically that the context item will be undefined. * If the type of the context item is not known statically, the argument is set to * {@link net.sf.saxon.type.Type#ITEM_TYPE} * @return the original expression, rewritten if appropriate to optimize execution * @throws XPathException if an error is discovered during this phase * (typically a type error) */ public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { // In XSLT, we don't catch this error at the typeCheck() phase because it's done one XPath expression // at a time. So we repeat the check here. return typeCheck(visitor, contextItemType); } /** * Determine the item type * @param th the type hierarchy cache */ public ItemType getItemType(TypeHierarchy th) { return itemType; } /** * Get the static cardinality */ public int computeCardinality() { return StaticProperty.EXACTLY_ONE; } /** * Determine the special properties of this expression * @return the value {@link StaticProperty#NON_CREATIVE} */ public int computeSpecialProperties() { int p = super.computeSpecialProperties(); return p | StaticProperty.NON_CREATIVE; } /** * Is this expression the same as another expression? */ public boolean equals(Object other) { return (other instanceof ContextItemExpression); } /** * get HashCode for comparing two expressions */ public int hashCode() { return "ContextItemExpression".hashCode(); } public int getIntrinsicDependencies() { return StaticProperty.DEPENDS_ON_CONTEXT_ITEM; } /** * Add a representation of this expression to a PathMap. The PathMap captures a map of the nodes visited * by an expression in a source tree. *

    *

    The default implementation of this method assumes that an expression does no navigation other than * the navigation done by evaluating its subexpressions, and that the subexpressions are evaluated in the * same context as the containing expression. The method must be overridden for any expression * where these assumptions do not hold. For example, implementations exist for AxisExpression, ParentExpression, * and RootExpression (because they perform navigation), and for the doc(), document(), and collection() * functions because they create a new navigation root. Implementations also exist for PathExpression and * FilterExpression because they have subexpressions that are evaluated in a different context from the * calling expression.

    * * @param pathMap the PathMap to which the expression should be added * @param pathMapNodeSet the PathMapNodeSet to which the paths embodied in this expression should be added * @return the pathMapNodeSet representing the points in the source document that are both reachable by this * expression, and that represent possible results of this expression. For an expression that does * navigation, it represents the end of the arc in the path map that describes the navigation route. For other * expressions, it is the same as the input pathMapNode. */ public PathMap.PathMapNodeSet addToPathMap(PathMap pathMap, PathMap.PathMapNodeSet pathMapNodeSet) { return pathMapNodeSet; } /** * Iterate over the value of the expression */ public SequenceIterator iterate(XPathContext context) throws XPathException { Item item = context.getContextItem(); if (item==null) { dynamicError("The context item is not set", getErrorCodeForUndefinedContext(), context); } return SingletonIterator.makeIterator(item); } /** * Evaluate the expression */ public Item evaluateItem(XPathContext context) throws XPathException { Item item = context.getContextItem(); if (item==null) { dynamicError("The context item is not set", getErrorCodeForUndefinedContext(), context); } return item; } /** * The toString() method for an expression attempts to give a representation of the expression * in an XPath-like form, but there is no guarantee that the syntax will actually be true XPath. * In the case of XSLT instructions, the toString() method gives an abstracted view of the syntax */ public String toString() { return "."; } /** * Diagnostic print of expression structure. The abstract expression tree * is written to the supplied output destination. */ public void explain(ExpressionPresenter destination) { destination.startElement("dot"); destination.endElement(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/expr/PairIterator.java0000644000175000017500000000545511033112257021636 0ustar eugeneeugenepackage net.sf.saxon.expr; import java.util.Iterator; import java.util.NoSuchElementException; /** * An iterator over a pair of objects (typically sub-expressions of an expression) */ public class PairIterator implements Iterator { private Object one; private Object two; private int pos = 0; /** * Create an iterator over two objects * @param one the first object to be returned * @param two the second object to be returned */ public PairIterator(Object one, Object two) { this.one = one; this.two = two; } /** * Returns true if the iteration has more elements. (In other * words, returns true if next would return an element * rather than throwing an exception.) * * @return true if the iterator has more elements. */ public boolean hasNext() { return pos<2; } /** * Returns the next element in the iteration. * * @return the next element in the iteration. * @exception NoSuchElementException iteration has no more elements. */ public Object next() { switch (pos++) { case 0: return one; case 1: return two; default: throw new NoSuchElementException(); } } /** * * Removes from the underlying collection the last element returned by the * iterator (optional operation). This method can be called only once per * call to next. The behavior of an iterator is unspecified if * the underlying collection is modified while the iteration is in * progress in any way other than by calling this method. * * @exception UnsupportedOperationException if the remove * operation is not supported by this Iterator. * @exception IllegalStateException if the next method has not * yet been called, or the remove method has already * been called after the last call to the next * method. */ public void remove() { throw new UnsupportedOperationException(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): Michael Kay // saxonb-9.1.0.8/bj/net/sf/saxon/expr/IntersectionEnumeration.java0000644000175000017500000001036311033112257024100 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.om.Item; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.sort.NodeOrderComparer; import net.sf.saxon.trans.XPathException; /** * An enumeration representing a nodeset that is an intersection of two other NodeSets. * This implements the XPath 2.0 operator "intersect". */ public class IntersectionEnumeration implements SequenceIterator { private SequenceIterator e1; private SequenceIterator e2; private NodeInfo nextNode1 = null; private NodeInfo nextNode2 = null; private NodeOrderComparer comparer; private NodeInfo current = null; private int position = 0; /** * Form an enumeration of the intersection of the nodes in two nodesets * @param p1 the first operand: must be in document order * @param p2 the second operand: must be in document order * @param comparer Comparer to be used for putting nodes in document order */ public IntersectionEnumeration(SequenceIterator p1, SequenceIterator p2, NodeOrderComparer comparer ) throws XPathException { e1 = p1; e2 = p2; this.comparer = comparer; // move to the first node in each input nodeset nextNode1 = next(e1); nextNode2 = next(e2); } /** * Get the next item from one of the input sequences, * checking that it is a node. * @param iter the iterator from which the next item is to be taken * @return the next value returned by that iterator */ private NodeInfo next(SequenceIterator iter) throws XPathException { return (NodeInfo)iter.next(); // rely on type-checking to prevent a ClassCastException } public Item next() throws XPathException { // main merge loop: iterate whichever sequence has the lower value, returning when a pair // is found that match. if (nextNode1 == null || nextNode2 == null) { current = null; position = -1; return null; } while (nextNode1 != null && nextNode2 != null) { int c = comparer.compare(nextNode1, nextNode2); if (c<0) { nextNode1 = next(e1); } else if (c>0) { nextNode2 = next(e2); } else { // keys are equal current = nextNode2; // which is the same as nextNode1 nextNode2 = next(e2); nextNode1 = next(e1); position++; return current; } } return null; } public Item current() { return current; } public int position() { return position; } public void close() { e1.close(); e2.close(); } public SequenceIterator getAnother() throws XPathException { return new IntersectionEnumeration(e1.getAnother(), e2.getAnother(), comparer); } /** * Get properties of this iterator, as a bit-significant integer. * * @return the properties of this iterator. This will be some combination of * properties such as {@link SequenceIterator#GROUNDED}, {@link SequenceIterator#LAST_POSITION_FINDER}, * and {@link SequenceIterator#LOOKAHEAD}. It is always * acceptable to return the value zero, indicating that there are no known special properties. * It is acceptable for the properties of the iterator to change depending on its state. */ public int getProperties() { return 0; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/expr/UserFunctionCall.java0000644000175000017500000005464711033112257022460 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.Configuration; import net.sf.saxon.event.SequenceReceiver; import net.sf.saxon.evpull.EmptyEventIterator; import net.sf.saxon.evpull.EventIterator; import net.sf.saxon.instruct.UserFunction; import net.sf.saxon.instruct.Executable; import net.sf.saxon.om.Item; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.om.StructuredQName; import net.sf.saxon.om.ValueRepresentation; import net.sf.saxon.trace.ExpressionPresenter; import net.sf.saxon.trace.Location; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.AnyItemType; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.TypeHierarchy; import net.sf.saxon.value.*; /** * This class represents a call to a user-defined function in the stylesheet or query. */ public class UserFunctionCall extends FunctionCall { private SequenceType staticType; private UserFunction function; private boolean tailCall = false; // indicates only that this is a tail call, not necessarily a recursive tail call private boolean confirmed = false; // A functionCall is confirmed if the function being called has been located. Generally in this // case the value of 'function' will be non-null; but in XSLT it is possible to look-ahead to confirm // a function binding before the relevant function is actually compiled. private int[] argumentEvaluationModes = null; /** * Create a function call to a user-written function in a query or stylesheet */ public UserFunctionCall() {} /** * Set the static type * @param type the static type */ public void setStaticType(SequenceType type) { staticType = type; } /** * Create the reference to the function to be called * @param compiledFunction the function being called */ public void setFunction(UserFunction compiledFunction) { function = compiledFunction; confirmed = true; } /** * Check the function call against the declared function signature * @param compiledFunction the function being called * @param visitor an expression visitor */ public void checkFunctionCall(UserFunction compiledFunction, ExpressionVisitor visitor) throws XPathException { Executable executable = visitor.getExecutable(); boolean isXSLT = executable != null && executable.getHostLanguage() == Configuration.XSLT; int n = compiledFunction.getNumberOfArguments(); for (int i=0; i 1) { m = ExpressionTool.MAKE_MEMO_CLOSURE; } argumentEvaluationModes[i] = m; } } } /** * Add a representation of this expression to a PathMap. The PathMap captures a map of the nodes visited * by an expression in a source tree. *

    *

    The default implementation of this method assumes that an expression does no navigation other than * the navigation done by evaluating its subexpressions, and that the subexpressions are evaluated in the * same context as the containing expression. The method must be overridden for any expression * where these assumptions do not hold. For example, implementations exist for AxisExpression, ParentExpression, * and RootExpression (because they perform navigation), and for the doc(), document(), and collection() * functions because they create a new navigation root. Implementations also exist for PathExpression and * FilterExpression because they have subexpressions that are evaluated in a different context from the * calling expression.

    * * @param pathMap the PathMap to which the expression should be added * @param pathMapNodeSet the PathMapNodeSet to which the paths embodied in this expression should be added * @return the pathMapNode representing the focus established by this expression, in the case where this * expression is the first operand of a path expression or filter expression. For an expression that does * navigation, it represents the end of the arc in the path map that describes the navigation route. For other * expressions, it is the same as the input pathMapNode. */ public PathMap.PathMapNodeSet addToPathMap(PathMap pathMap, PathMap.PathMapNodeSet pathMapNodeSet) { return addExternalFunctionCallToPathMap(pathMap, pathMapNodeSet); } /** * Mark tail-recursive calls on stylesheet functions. This marks the function call as tailRecursive if * if is a call to the containing function, and in this case it also returns "true" to the caller to indicate * that a tail call was found. */ public int markTailFunctionCalls(StructuredQName qName, int arity) { tailCall = true; return (getFunctionName().equals(qName) && arity == getNumberOfArguments() ? 2 : 1); } // TODO: attempt to establish whether the function is capable of creating new nodes. This // enables non-creative functions to be moved out of loops. The problem is how to achieve this // without looping in the case of recursive functions. A simple solution might be to go only // one level deep: if the body of a function is known (without analysing function calls) to be // non-creative, then all calls on that function can be marked as non-creative. Note also that // a function is creative if one of its arguments is creative and the result of the function // depends on the identity of that argument. public int getImplementationMethod() { if (Cardinality.allowsMany(getCardinality())) { return ITERATE_METHOD | PROCESS_METHOD; } else { return EVALUATE_METHOD; } } /** * Call the function, returning the value as an item. This method will be used * only when the cardinality is zero or one. If the function is tail recursive, * it returns an Object representing the arguments to the next (recursive) call */ public Item evaluateItem(XPathContext c) throws XPathException { ValueRepresentation val = callFunction(c); return Value.asItem(val); } /** * Call the function, returning an iterator over the results. (But if the function is * tail recursive, it returns an iterator over the arguments of the recursive call) */ public SequenceIterator iterate(XPathContext c) throws XPathException { ValueRepresentation result = callFunction(c); return Value.getIterator(result); } /** * Evaluate an updating expression, adding the results to a Pending Update List. * The default implementation of this method, which is used for non-updating expressions, * throws an UnsupportedOperationException * * @param context the XPath dynamic evaluation context * @param pul the pending update list to which the results should be written */ public void evaluatePendingUpdates(XPathContext context, PendingUpdateList pul) throws XPathException { ValueRepresentation[] actualArgs = evaluateArguments(context); XPathContextMajor c2 = context.newCleanContext(); c2.setOrigin(this); function.callUpdating(actualArgs, c2, pul); } /** * This is the method that actually does the function call * @param c the dynamic context * @return the result of the function * @throws XPathException if dynamic errors occur */ private ValueRepresentation callFunction(XPathContext c) throws XPathException { ValueRepresentation[] actualArgs = evaluateArguments(c); if (tailCall) { ((XPathContextMajor)c).requestTailCall(function, actualArgs); return EmptySequence.getInstance(); } XPathContextMajor c2 = c.newCleanContext(); c2.setOrigin(this); c2.setTemporaryOutputState(true); try { return function.call(actualArgs, c2); } catch (StackOverflowError err) { throw new XPathException("Too many nested function calls. May be due to infinite recursion.", this); } catch (NullPointerException err) { if (function == null) { throw new NullPointerException("Unbound function call " + function.getFunctionName().getDisplayName()); } else { throw err; } } } /** * Process the function call in push mode * @param context the XPath dynamic context * @throws XPathException */ public void process(XPathContext context) throws XPathException { ValueRepresentation[] actualArgs = evaluateArguments(context); if (tailCall) { ((XPathContextMajor)context).requestTailCall(function, actualArgs); } else { SequenceReceiver out = context.getReceiver(); XPathContextMajor c2 = context.newCleanContext(); c2.setReceiver(out); c2.setOrigin(this); function.process(actualArgs, c2); } } /** * Process the function call in pull mode * @param context the XPath dynamic context * @throws XPathException */ public EventIterator iterateEvents(XPathContext context) throws XPathException { ValueRepresentation[] actualArgs = evaluateArguments(context); if (tailCall) { ((XPathContextMajor)context).requestTailCall(function, actualArgs); return EmptyEventIterator.getInstance(); } else { SequenceReceiver out = context.getReceiver(); XPathContextMajor c2 = context.newCleanContext(); c2.setReceiver(out); c2.setOrigin(this); return function.iterateEvents(actualArgs, c2); } } private ValueRepresentation[] evaluateArguments(XPathContext c) throws XPathException { int numArgs = argument.length; ValueRepresentation[] actualArgs = new ValueRepresentation[numArgs]; if (argumentEvaluationModes == null) { // should have been done at compile time computeArgumentEvaluationModes(); } for (int i=0; i 1 && actualArgs[i] instanceof Closure && !(actualArgs[i] instanceof MemoClosure)) { actualArgs[i] = ((Closure)actualArgs[i]).reduce(); } } return actualArgs; } /** * Call the function dynamically. For this to be possible, the static arguments of the function call * must have been set up as SuppliedParameterReference objects. The actual arguments are placed on the * callee's stack, and the type conversion takes place "in situ". * @param suppliedArguments the values to be used for the arguments of the function * @param context the dynamic evaluation context * @return the result of evaluating the function */ public ValueRepresentation dynamicCall(ValueRepresentation[] suppliedArguments, XPathContext context) throws XPathException { ValueRepresentation[] convertedArgs = new ValueRepresentation[suppliedArguments.length]; XPathContextMajor c2 = context.newCleanContext(); c2.setOrigin(this); c2.setCaller(context); c2.openStackFrame(suppliedArguments.length); for (int i=0; iAn AxisExpression delivers nodes in axis order (not in document order). * To get nodes in document order, in the case of a reverse axis, the expression * should be wrapped in a call on reverse().

    */ public final class AxisExpression extends Expression { private byte axis; private NodeTest test; private ItemType itemType = null; private ItemType contextItemType = null; int computedCardinality = -1; private boolean doneWarnings = false; /** * Constructor * @param axis The axis to be used in this AxisExpression: relevant constants are defined * in class net.sf.saxon.om.Axis. * @param nodeTest The conditions to be satisfied by selected nodes. May be null, * indicating that any node on the axis is acceptable * @see net.sf.saxon.om.Axis */ public AxisExpression(byte axis, NodeTest nodeTest) { this.axis = axis; test = nodeTest; } /** * Simplify an expression * @return the simplified expression * @param visitor an expression visitor */ public Expression simplify(ExpressionVisitor visitor) { if (axis == Axis.PARENT && (test==null || test instanceof AnyNodeTest)) { ParentNodeExpression p = new ParentNodeExpression(); ExpressionTool.copyLocationInfo(this, p); return p; } return this; } /** * Type-check the expression */ public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { Configuration config = visitor.getConfiguration(); NamePool namePool = config.getNamePool(); StaticContext env = visitor.getStaticContext(); if (contextItemType == null) { XPathException err = new XPathException("Axis step " + toString(namePool) + " cannot be used here: the context item is undefined"); err.setIsTypeError(true); err.setErrorCode("XPDY0002"); err.setLocator(this); throw err; } if (contextItemType.isAtomicType()) { XPathException err = new XPathException("Axis step " + toString(namePool) + " cannot be used here: the context item is an atomic value"); err.setIsTypeError(true); err.setErrorCode("XPTY0020"); err.setLocator(this); throw err; } if (this.contextItemType == contextItemType && doneWarnings) { return this; } this.contextItemType = contextItemType; doneWarnings = true; if (contextItemType instanceof NodeTest) { int origin = contextItemType.getPrimitiveType(); if (origin != Type.NODE) { if (Axis.isAlwaysEmpty(axis, origin)) { env.issueWarning("The " + Axis.axisName[axis] + " axis starting at " + (origin==Type.ELEMENT || origin == Type.ATTRIBUTE ? "an " : "a ") + NodeKindTest.nodeKindName(origin) + " node will never select anything", this); return Literal.makeEmptySequence(); } } if (test != null) { int kind = test.getPrimitiveType(); if (kind != Type.NODE) { if (!Axis.containsNodeKind(axis, kind)) { env.issueWarning("The " + Axis.axisName[axis] + " axis will never select any " + NodeKindTest.nodeKindName(kind) + " nodes", this); return Literal.makeEmptySequence(); } } if (axis==Axis.SELF && kind!=Type.NODE && origin!=Type.NODE && kind!=origin) { env.issueWarning("The self axis will never select any " + NodeKindTest.nodeKindName(kind) + " nodes when starting at " + (origin==Type.ELEMENT || origin == Type.ATTRIBUTE ? "an " : "a ") + NodeKindTest.nodeKindName(origin) + " node", this); return Literal.makeEmptySequence(); } if (axis==Axis.SELF) { itemType = new CombinedNodeTest((NodeTest)contextItemType, Token.INTERSECT, test); } // If the content type of the context item is known, see whether the node test can select anything if (contextItemType instanceof DocumentNodeTest && axis == Axis.CHILD && kind == Type.ELEMENT) { NodeTest elementTest = ((DocumentNodeTest)contextItemType).getElementTest(); IntHashSet requiredNames = elementTest.getRequiredNodeNames(); if (requiredNames != null) { // check that the name appearing in the step is one of the names allowed by the nodetest IntHashSet selected = test.getRequiredNodeNames(); if (selected != null && selected.intersect(requiredNames).isEmpty()) { env.issueWarning("Starting at a document node, the step is selecting an element whose name " + "is not among the names of child elements permitted for this document node type", this); return Literal.makeEmptySequence(); } } itemType = elementTest; return this; } SchemaType contentType = ((NodeTest)contextItemType).getContentType(); if (contentType == AnyType.getInstance()) { // fast exit in non-schema-aware case return this; } int targetfp = test.getFingerprint(); if (contentType.isSimpleType()) { if ((axis == Axis.CHILD || axis==Axis.DESCENDANT || axis==Axis.DESCENDANT_OR_SELF) && (kind==Type.ELEMENT || kind==Type.ATTRIBUTE || kind==Type.DOCUMENT)) { env.issueWarning("The " + Axis.axisName[axis] + " axis will never select any " + NodeKindTest.nodeKindName(kind) + " nodes when starting at a node with simple type " + contentType.getDescription(), this); } else if (axis == Axis.CHILD && kind == Type.TEXT && (visitor.getParentExpression() instanceof Atomizer)) { env.issueWarning("Selecting the text nodes of an element with simple content may give the " + "wrong answer in the presence of comments or processing instructions. It is usually " + "better to omit the '/text()' step", this); } else if (axis == Axis.ATTRIBUTE) { Iterator extensions = config.getExtensionsOfType(contentType); boolean found = false; if (targetfp == -1) { while (extensions.hasNext()) { ComplexType extension = (ComplexType)extensions.next(); if (extension.allowsAttributes()) { found = true; break; } } } else { while (extensions.hasNext()) { ComplexType extension = (ComplexType)extensions.next(); try { if (extension.getAttributeUseType(targetfp) != null) { found = true; break; } } catch (SchemaException e) { // ignore the error } } } if (!found) { env.issueWarning("The " + Axis.axisName[axis] + " axis will never select " + (targetfp == -1 ? "any attribute nodes" : "an attribute node named " + env.getNamePool().getDisplayName(targetfp)) + " when starting at a node with simple type " + contentType.getDescription(), this); // Despite the warning, leave the expression unchanged. This is because // we don't necessarily know about all extended types at compile time: // in particular, we don't seal the XML Schema namespace to block extensions // of built-in types } } } else if (((ComplexType)contentType).isSimpleContent() && (axis==Axis.CHILD || axis==Axis.DESCENDANT || axis==Axis.DESCENDANT_OR_SELF) && (kind==Type.ELEMENT || kind==Type.DOCUMENT)) { // We don't need to consider extended types here, because a type with complex content // can never be defined as an extension of a type with simple content env.issueWarning("The " + Axis.axisName[axis] + " axis will never select any " + NodeKindTest.nodeKindName(kind) + " nodes when starting at a node with type " + contentType.getDescription() + ", as this type requires simple content", this); return new Literal(EmptySequence.getInstance()); } else if (((ComplexType)contentType).isEmptyContent() && (axis==Axis.CHILD || axis==Axis.DESCENDANT || axis==Axis.DESCENDANT_OR_SELF)) { for (Iterator iter=config.getExtensionsOfType(contentType); iter.hasNext();) { ComplexType extension = (ComplexType)iter.next(); if (!extension.isEmptyContent()) { return this; } } env.issueWarning("The " + Axis.axisName[axis] + " axis will never select any" + " nodes when starting at a node with type " + contentType.getDescription() + ", as this type requires empty content", this); return new Literal(EmptySequence.getInstance()); } else if (axis==Axis.ATTRIBUTE && targetfp != -1) { try { SchemaType schemaType = ((ComplexType)contentType).getAttributeUseType(targetfp); if (schemaType == null) { String n = env.getNamePool().getDisplayName(targetfp); env.issueWarning("The complex type " + contentType.getDescription() + " does not allow an attribute named " + n, this); return new Literal(EmptySequence.getInstance()); } else { itemType = new CombinedNodeTest( test, Token.INTERSECT, new ContentTypeTest(Type.ATTRIBUTE, schemaType, env.getConfiguration())); } } catch (SchemaException e) { // ignore the exception } } else if (axis==Axis.CHILD && kind==Type.ELEMENT) { try { int childElement = targetfp; if (targetfp == -1) { // select="child::*" IntHashSet children = new IntHashSet(); ((ComplexType)contentType).gatherAllPermittedChildren(children); if (children.isEmpty()) { env.issueWarning("The complex type " + contentType.getDescription() + " does not allow children", this); return new Literal(EmptySequence.getInstance()); } if (children.contains(-1)) { return this; } if (children.size() == 1) { IntIterator iter = children.iterator(); if (iter.hasNext()) { childElement = iter.next(); } } else { return this; } } SchemaType schemaType = ((ComplexType)contentType).getElementParticleType(childElement, true); if (schemaType == null) { String n = env.getNamePool().getDisplayName(childElement); env.issueWarning("The complex type " + contentType.getDescription() + " does not allow a child element named " + n, this); return new Literal(EmptySequence.getInstance()); } else { itemType = new CombinedNodeTest( test, Token.INTERSECT, new ContentTypeTest(Type.ELEMENT, schemaType, env.getConfiguration())); computedCardinality = ((ComplexType)contentType).getElementParticleCardinality(childElement, true); visitor.resetStaticProperties(); if (computedCardinality == StaticProperty.ALLOWS_ZERO) { // this shouldn't happen, because we've already checked for this a different way. // but it's worth being safe (there was a bug involving an incorrect inference here) String n = env.getNamePool().getDisplayName(childElement); env.issueWarning("The complex type " + contentType.getDescription() + " appears not to allow a child element named " + n, this); return new Literal(EmptySequence.getInstance()); } if (!Cardinality.allowsMany(computedCardinality)) { // if there can be at most one child of this name, create a FirstItemExpression // to stop the search after the first one is found return new FirstItemExpression(this); } } } catch (SchemaException e) { // ignore the exception } } else if (axis==Axis.DESCENDANT && kind==Type.ELEMENT && targetfp != -1) { // when searching for a specific element on the descendant axis, try to produce a more // specific path that avoids searching branches of the tree where the element cannot occur try { IntHashSet descendants = new IntHashSet(); ((ComplexType)contentType).gatherAllPermittedDescendants(descendants); if (descendants.contains(-1)) { return this; } if (descendants.contains(targetfp)) { IntHashSet children = new IntHashSet(); ((ComplexType)contentType).gatherAllPermittedChildren(children); IntHashSet usefulChildren = new IntHashSet(); boolean considerSelf = false; boolean considerDescendants = false; for (IntIterator child = children.iterator(); child.hasNext();) { int c = child.next(); if (c == targetfp) { usefulChildren.add(c); considerSelf = true; } SchemaType st = ((ComplexType)contentType).getElementParticleType(c, true); if (st == null) { throw new AssertionError("Can't find type for element " + c); } if (st instanceof ComplexType) { IntHashSet subDescendants = new IntHashSet(); ((ComplexType)st).gatherAllPermittedDescendants(subDescendants); if (subDescendants.contains(targetfp)) { usefulChildren.add(c); considerDescendants = true; } } } if (usefulChildren.size() < children.size()) { NodeTest childTest = makeUnionNodeTest(usefulChildren, visitor.getConfiguration().getNamePool()); AxisExpression first = new AxisExpression(Axis.CHILD, childTest); ExpressionTool.copyLocationInfo(this, first); byte nextAxis; if (considerSelf) { nextAxis = (considerDescendants ? Axis.DESCENDANT_OR_SELF : Axis.SELF); } else { nextAxis = Axis.DESCENDANT; } AxisExpression next = new AxisExpression(nextAxis, test); ExpressionTool.copyLocationInfo(this, next); PathExpression path = new PathExpression(first, next); ExpressionTool.copyLocationInfo(this, path); return path.typeCheck(visitor, contextItemType); } } else { String n = env.getNamePool().getDisplayName(targetfp); env.issueWarning("The complex type " + contentType.getDescription() + " does not allow a descendant element named " + n, this); } } catch (SchemaException e) { throw new AssertionError(e); } } } } return this; } /** * Make a union node test for a set of supplied element fingerprints * @param elements the set of integer element fingerprints to be tested for * @param pool the name pool * @return a NodeTest that returns true if the node is an element whose name is one of the names * in this set */ private NodeTest makeUnionNodeTest(IntHashSet elements, NamePool pool) { NodeTest test = null; for (IntIterator iter = elements.iterator(); iter.hasNext();) { int fp = iter.next(); NodeTest nextTest = new NameTest(Type.ELEMENT, fp, pool); if (test == null) { test = nextTest; } else { test = new CombinedNodeTest(test, Token.UNION, nextTest); } } if (test == null) { return EmptySequenceTest.getInstance(); } else { return test; } } /** * Get the static type of the context item for this AxisExpression. May be null if not known. * @return the statically-inferred type, or null if not known */ public ItemType getContextItemType() { return contextItemType; } /** * Perform optimisation of an expression and its subexpressions. *

    *

    This method is called after all references to functions and variables have been resolved * to the declaration of the function or variable, and after all type checking has been done.

    * * @param visitor an expression visitor * @param contextItemType the static type of "." at the point where this expression is invoked. * The parameter is set to null if it is known statically that the context item will be undefined. * If the type of the context item is not known statically, the argument is set to * {@link net.sf.saxon.type.Type#ITEM_TYPE} * @return the original expression, rewritten if appropriate to optimize execution */ public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) { return this; } /** * Is this expression the same as another expression? */ public boolean equals(Object other) { if (!(other instanceof AxisExpression)) { return false; } if (axis != ((AxisExpression)other).axis) { return false; } if (test==null) { return ((AxisExpression)other).test==null; } return test.toString().equals(((AxisExpression)other).test.toString()); } /** * get HashCode for comparing two expressions */ public int hashCode() { // generate an arbitrary hash code that depends on the axis and the node test int h = 9375162 + axis<<20; if (test != null) { h ^= test.getPrimitiveType()<<16; h ^= test.getFingerprint(); } return h; } /** * Determine which aspects of the context the expression depends on. The result is * a bitwise-or'ed value composed from constants such as XPathContext.VARIABLES and * XPathContext.CURRENT_NODE */ public int getIntrinsicDependencies() { return StaticProperty.DEPENDS_ON_CONTEXT_ITEM; } /** * Copy an expression. This makes a deep copy. * * @return the copy of the original expression */ public Expression copy() { AxisExpression a2 = new AxisExpression(axis, test); a2.itemType = itemType; a2.contextItemType = contextItemType; a2.computedCardinality = computedCardinality; return a2; } /** * Get the static properties of this expression (other than its type). The result is * bit-signficant. These properties are used for optimizations. In general, if * property bit is set, it is true, but if it is unset, the value is unknown. */ public int computeSpecialProperties() { return StaticProperty.CONTEXT_DOCUMENT_NODESET | StaticProperty.SINGLE_DOCUMENT_NODESET | StaticProperty.NON_CREATIVE | (Axis.isForwards[axis] ? StaticProperty.ORDERED_NODESET : StaticProperty.REVERSE_DOCUMENT_ORDER) | (Axis.isPeerAxis[axis] ? StaticProperty.PEER_NODESET : 0) | (Axis.isSubtreeAxis[axis] ? StaticProperty.SUBTREE_NODESET : 0) | ((axis==Axis.ATTRIBUTE || axis==Axis.NAMESPACE) ? StaticProperty.ATTRIBUTE_NS_NODESET : 0); } /** * Determine the data type of the items returned by this expression * @return Type.NODE or a subtype, based on the NodeTest in the axis step, plus * information about the content type if this is known from schema analysis * @param th the type hierarchy cache */ public final ItemType getItemType(TypeHierarchy th) { if (itemType != null) { return itemType; } int p = Axis.principalNodeType[axis]; switch (p) { case Type.ATTRIBUTE: case Type.NAMESPACE: return NodeKindTest.makeNodeKindTest(p); default: if (test==null) { return AnyNodeTest.getInstance(); } else { return test; //return NodeKindTest.makeNodeKindTest(test.getPrimitiveType()); } } } /** * Specify that the expression returns a singleton */ public final int computeCardinality() { if (computedCardinality != -1) { return computedCardinality; } if (axis == Axis.ATTRIBUTE && test instanceof NameTest) { return StaticProperty.ALLOWS_ZERO_OR_ONE; } else if (axis == Axis.SELF) { return StaticProperty.ALLOWS_ZERO_OR_ONE; } else { return StaticProperty.ALLOWS_ZERO_OR_MORE; } // the parent axis isn't handled by this class } /** * Get the axis * @return the axis number, for example {@link Axis#CHILD} */ public byte getAxis() { return axis; } /** * Get the NodeTest. Returns null if the AxisExpression can return any node. * @return the node test, or null if all nodes are returned */ public NodeTest getNodeTest() { return test; } /** * Add a representation of this expression to a PathMap. The PathMap captures a map of the nodes visited * by an expression in a source tree. * * @param pathMap the PathMap to which the expression should be added * @param pathMapNodeSet * @return the pathMapNode representing the focus established by this expression, in the case where this * expression is the first operand of a path expression or filter expression */ public PathMap.PathMapNodeSet addToPathMap(PathMap pathMap, PathMap.PathMapNodeSet pathMapNodeSet) { if (pathMapNodeSet == null) { ContextItemExpression cie = new ContextItemExpression(); cie.setContainer(getContainer()); pathMapNodeSet = new PathMap.PathMapNodeSet(pathMap.makeNewRoot(cie)); } PathMap.PathMapNodeSet target = pathMapNodeSet.createArc(this); // if (isStringValueUsed()) { // target.setAtomized(); // } return target; } /** * Evaluate the path-expression in a given context to return a NodeSet * @param context the evaluation context */ public SequenceIterator iterate(XPathContext context) throws XPathException { Item item = context.getContextItem(); try { if (test==null) { return ((NodeInfo)item).iterateAxis(axis); } else { return ((NodeInfo)item).iterateAxis(axis, test); } } catch (NullPointerException npe) { NamePool pool; try { pool = context.getConfiguration().getNamePool(); } catch (Exception err) { pool = null; } XPathException err = new XPathException("The context item for axis step " + (pool == null ? toString() : toString(pool)) + " is undefined"); err.setErrorCode("XPDY0002"); err.setXPathContext(context); err.setLocator(this); err.setIsTypeError(true); throw err; } catch (ClassCastException cce) { NamePool pool; try { pool = context.getConfiguration().getNamePool(); } catch (Exception err) { pool = null; } XPathException err = new XPathException("The context item for axis step " + (pool == null ? toString() : toString(pool)) + " is not a node"); err.setErrorCode("XPTY0020"); err.setXPathContext(context); err.setLocator(this); err.setIsTypeError(true); throw err; } catch (UnsupportedOperationException err) { // the namespace axis is not supported for all tree implementations dynamicError(err.getMessage(), "XPST0010", context); return null; } } /** * Iterate the axis from a given starting node, without regard to context * @param origin the starting node * @return the iterator over the axis */ public SequenceIterator iterate(Item origin) throws XPathException { try { if (test==null) { return ((NodeInfo)origin).iterateAxis(axis); } else { return ((NodeInfo)origin).iterateAxis(axis, test); } } catch (ClassCastException cce) { XPathException err = new XPathException("The context item for axis step " + toString() + " is not a node"); err.setErrorCode("XPTY0020"); err.setLocator(this); err.setIsTypeError(true); throw err; } } /** * Diagnostic print of expression structure. The abstract expression tree * is written to the supplied output destination. */ public void explain(ExpressionPresenter destination) { destination.startElement("axis"); destination.emitAttribute("name", Axis.axisName[axis]); destination.emitAttribute("nodeTest", (test==null ? "node()" : test.toString())); destination.endElement(); } /** * Represent the expression as a string for diagnostics */ public String toString() { return Axis.axisName[axis] + "::" + (test==null ? "node()" : test.toString()); } /** * Represent the expression as a string for diagnostics * @param pool the name pool, used for expanding names in the node test * @return a string representation of the expression */ public String toString(NamePool pool) { return Axis.axisName[axis] + "::" + (test==null ? "node()" : test.toString(pool)); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/expr/XPathContextMinor.java0000644000175000017500000005034411033112257022624 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.Configuration; import net.sf.saxon.Controller; import net.sf.saxon.event.*; import net.sf.saxon.instruct.LocalParam; import net.sf.saxon.instruct.ParameterSet; import net.sf.saxon.om.*; import net.sf.saxon.regex.RegexIterator; import net.sf.saxon.sort.CodepointCollator; import net.sf.saxon.sort.GroupIterator; import net.sf.saxon.sort.StringCollator; import net.sf.saxon.trace.Location; import net.sf.saxon.trace.InstructionInfo; import net.sf.saxon.trace.ContextStackIterator; import net.sf.saxon.trans.Mode; import net.sf.saxon.trans.Rule; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.SchemaType; import net.sf.saxon.value.DateTimeValue; import net.sf.saxon.value.Whitespace; import javax.xml.transform.Result; import java.util.Properties; import java.util.Iterator; /** * This class represents a minor change in the dynamic context in which an XPath expression is evaluated: * a "major context" object allows all aspects of the dynamic context to change, whereas * a "minor context" only allows changes to the focus and the destination for push output. */ public class XPathContextMinor implements XPathContext { Controller controller; SequenceIterator currentIterator; int last = -1; SequenceReceiver currentReceiver; boolean isTemporaryDestination = false; XPathContext caller = null; protected StackFrame stackFrame; Object origin = null; /** * Private Constructor */ protected XPathContextMinor() { } /** * Construct a new context as a copy of another. The new context is effectively added * to the top of a stack, and contains a pointer to the previous context */ public XPathContextMajor newContext() { return XPathContextMajor.newContext(this); } public XPathContextMinor newMinorContext() { XPathContextMinor c = new XPathContextMinor(); c.controller = controller; c.caller = this; c.currentIterator = currentIterator; c.currentReceiver = currentReceiver; c.last = last; c.isTemporaryDestination = isTemporaryDestination; c.stackFrame = stackFrame; return c; } /** * Set the calling XPathContext */ public void setCaller(XPathContext caller) { this.caller = caller; } /** * Construct a new context without copying (used for the context in a function call) */ public XPathContextMajor newCleanContext() { XPathContextMajor c = new XPathContextMajor(getController()); c.setCaller(this); return c; } /** * Get the local parameters for the current template call. * @return the supplied parameters */ public ParameterSet getLocalParameters() { return getCaller().getLocalParameters(); } /** * Get the tunnel parameters for the current template call. * @return the supplied tunnel parameters */ public ParameterSet getTunnelParameters() { return getCaller().getTunnelParameters(); } /** * Set the creating expression (for use in diagnostics). The origin is generally set to "this" by the * object that creates the new context. It's up to the debugger to determine whether this information * is useful. Where possible, the object will be an {@link Expression}, allowing information * about the calling instruction to be obtained. */ public void setOrigin(InstructionInfo expr) { origin = expr; } /** * Set the type of creating expression (for use in diagnostics). When a new context is created, either * this method or {@link XPathContext#setOrigin} should be called. * @param loc The originating location: the argument must be one of the integer constants in class * {@link net.sf.saxon.trace.Location} */ public void setOriginatingConstructType(int loc) { origin = new Integer(loc); } /** * Get the type of location from which this context was created. */ public int getOriginatingConstructType() { if (origin == null) { return -1; } if (origin instanceof Expression) { if (origin instanceof PathExpression) { return Location.PATH_EXPRESSION; } return ((Expression)origin).getConstructType(); } else if (origin instanceof Integer) { return ((Integer)origin).intValue(); } else if (origin instanceof InstructionInfo) { return ((InstructionInfo)origin).getConstructType(); } else { return -1; } } /** * Get information about the creating expression or other construct. */ public InstructionInfo getOrigin() { if (origin instanceof InstructionInfo) { return (InstructionInfo)origin; } else { return null; } } /** * Get the Controller. May return null when running outside XSLT or XQuery */ public final Controller getController() { return controller; } /** * Get the Configuration */ public final Configuration getConfiguration() { return controller.getConfiguration(); } /** * Get the Name Pool */ public final NamePool getNamePool() { return controller.getNamePool(); } /** * Get a NameChecker for checking names against the XML 1.0 or XML 1.1 specification as appropriate * @return the appropriate name checker */ public final NameChecker getNameChecker() { return controller.getConfiguration().getNameChecker(); } /** * Get the calling XPathContext (the next one down the stack). This will be null if unknown, or * if the bottom of the stack has been reached. */ public final XPathContext getCaller() { return caller; } /** * Set a new sequence iterator. */ public void setCurrentIterator(SequenceIterator iter) { currentIterator = iter; last = 0; } /** * Get the current iterator. * This encapsulates the context item, context position, and context size. * @return the current iterator, or null if there is no current iterator * (which means the context item, position, and size are undefined). */ public final SequenceIterator getCurrentIterator() { return currentIterator; } /** * Get the context position (the position of the context item) * @return the context position (starting at one) * @throws XPathException if the context position is undefined */ public final int getContextPosition() throws XPathException { if (currentIterator==null) { XPathException e = new XPathException("The context position is currently undefined"); e.setXPathContext(this); e.setErrorCode("FONC0001"); throw e; } return currentIterator.position(); } /** * Get the context item * @return the context item, or null if the context item is undefined */ public final Item getContextItem() { if (currentIterator==null) { return null; } return currentIterator.current(); } /** * Get the context size (the position of the last item in the current node list) * @return the context size * @throws XPathException if the context position is undefined */ public final int getLast() throws XPathException { if (last > 0) { return last; } if (currentIterator == null) { XPathException e = new XPathException("The context size is currently undefined"); e.setXPathContext(this); e.setErrorCode("FONC0001"); throw e; } if ((currentIterator.getProperties() & SequenceIterator.LAST_POSITION_FINDER) == 0) { SequenceIterator another = currentIterator.getAnother(); last = 0; while (another.next() != null) { last++; } return last; } else { last = ((LastPositionFinder)currentIterator).getLastPosition(); return last; } } /** * Determine whether the context position is the same as the context size * that is, whether position()=last() */ public final boolean isAtLast() throws XPathException { if ((currentIterator.getProperties() & SequenceIterator.LOOKAHEAD) != 0) { return !((LookaheadIterator)currentIterator).hasNext(); } return getContextPosition() == getLast(); } /** * Get a named collation * @throws XPathException if the collation is not recognized */ public final StringCollator getCollation(String name) throws XPathException { if (name.equals(NamespaceConstant.CODEPOINT_COLLATION_URI)) { return CodepointCollator.getInstance(); } StringCollator collation = null; if (controller != null) { collation = controller.getExecutable().getNamedCollation(name); if (collation == null) { Configuration config = controller.getConfiguration(); collation = config.getCollationURIResolver().resolve(name, null, config); //collation = CollationFactory.makeCollationFromURI(name, getController().getConfiguration()); } } if (collation==null) { XPathException e = new XPathException("Unknown collation " + name); e.setErrorCode("FOCH0002"); // Caller may have to change this e.setXPathContext(this); throw e; } return collation; } /** * Get the default collation */ public final StringCollator getDefaultCollation() { if (controller != null) { return controller.getExecutable().getDefaultCollation(); } else { return CodepointCollator.getInstance(); } } /** * Get a reference to the local stack frame for variables. Note that it's * the caller's job to make a local copy of this. This is used for creating * a Closure containing a retained copy of the variables for delayed evaluation. * @return array of variables. */ public StackFrame getStackFrame() { return stackFrame; } /** * Get the value of a local variable, identified by its slot number */ public ValueRepresentation evaluateLocalVariable(int slotnumber) { return stackFrame.slots[slotnumber]; } /** * Set the value of a local variable, identified by its slot number */ public void setLocalVariable(int slotnumber, ValueRepresentation value) { try { stackFrame.slots[slotnumber] = value; } catch (ArrayIndexOutOfBoundsException e) { throw new AssertionError("Internal error: invalid slot number for local variable " + (slotnumber == -999 ? "(No slot allocated)" : "(" + slotnumber + ")")); } } /** * Set a new output destination, supplying the output format details.
    * This affects all further output until resetOutputDestination() is called. Note that * it is the caller's responsibility to close the Writer after use. * * @exception XPathException if any dynamic error occurs; and * specifically, if an attempt is made to switch to a final output * destination while writing a temporary tree or sequence * @param props properties defining the output format * @param result Details of the new output destination * @param isFinal true if the destination is a final result tree * (either the principal output or a secondary result tree); false if * @param hostLanguage the host language, for example {@link Configuration#XSLT} */ public void changeOutputDestination(Properties props, Result result, boolean isFinal, int hostLanguage, int validation, SchemaType schemaType) throws XPathException { if (isFinal && isTemporaryDestination) { XPathException err = new XPathException("Cannot switch to a final result destination while writing a temporary tree"); err.setErrorCode("XTDE1480"); throw err; } if (isFinal) { validation |= Validation.VALIDATE_OUTPUT; } else { isTemporaryDestination = true; } PipelineConfiguration pipe = null; if (result instanceof Receiver) { pipe = ((Receiver)result).getPipelineConfiguration(); } if (pipe == null) { pipe = controller.makePipelineConfiguration(); pipe.setSerializing(isFinal); pipe.setHostLanguage(hostLanguage); } ComplexContentOutputter out = new ComplexContentOutputter(); out.setHostLanguage(hostLanguage); out.setPipelineConfiguration(pipe); if (props == null) { props = new Properties(); } SerializerFactory sf = getConfiguration().getSerializerFactory(); Receiver receiver = sf.getReceiver(result, pipe, props); // if this is the implicit XSLT result document, and if the executable is capable // of creating a secondary result document, then add a filter to check the first write boolean openNow = false; if ("yes".equals(props.getProperty(SaxonOutputKeys.IMPLICIT_RESULT_DOCUMENT))) { if (controller.getExecutable().createsSecondaryResult()) { receiver = new ImplicitResultChecker(receiver, controller); } else { openNow = true; } } // add a filter to remove duplicate namespaces NamespaceReducer ne = new NamespaceReducer(); ne.setUnderlyingReceiver(receiver); ne.setPipelineConfiguration(pipe); //out.setReceiver(ne); // add a validator to the pipeline if required receiver = controller.getConfiguration().getDocumentValidator( ne, receiver.getSystemId(), validation, Whitespace.NONE, schemaType, -1); out.setReceiver(receiver); currentReceiver = out; if (openNow) { out.open(); out.startDocument(0); } } /** * Set the output destination to write to a sequence.
    * This affects all further output until resetOutputDestination() is called. * * @param out The SequenceReceiver to be used */ public void setTemporaryReceiver(SequenceReceiver out) { isTemporaryDestination = true; currentReceiver = out; } /** * Change the Receiver to which output is written */ public void setReceiver(SequenceReceiver receiver) { currentReceiver = receiver; } /** * Get the Receiver to which output is currently being written. * * @return the current Receiver */ public final SequenceReceiver getReceiver() { return currentReceiver; } /** * Use local parameter. This is called when a local xsl:param element is processed. * If a parameter of the relevant name was supplied, it is bound to the xsl:param element. * Otherwise the method returns false, so the xsl:param default will be evaluated * @param qName The fingerprint of the parameter name * @param binding The XSLParam element to bind its value to * @param isTunnel True if a tunnel parameter is required, else false * @return true if a parameter of this name was supplied, false if not */ public boolean useLocalParameter(StructuredQName qName, LocalParam binding, boolean isTunnel) throws XPathException { return getCaller().useLocalParameter(qName, binding, isTunnel); } /** * Get the current mode. * @return the current mode */ public Mode getCurrentMode() { return getCaller().getCurrentMode(); } /** * Get the current template. This is used to support xsl:apply-imports * * @return the current template */ public Rule getCurrentTemplateRule() { return getCaller().getCurrentTemplateRule(); } /** * Get the current group iterator. This supports the current-group() and * current-grouping-key() functions in XSLT 2.0 * @return the current grouped collection */ public GroupIterator getCurrentGroupIterator() { return getCaller().getCurrentGroupIterator(); } /** * Get the current regex iterator. This supports the functionality of the regex-group() * function in XSLT 2.0. * @return the current regular expressions iterator */ public RegexIterator getCurrentRegexIterator() { return getCaller().getCurrentRegexIterator(); } /** * Get the current date and time for this query or transformation. * All calls during one transformation return the same answer. * * @return Get the current date and time. This will deliver the same value * for repeated calls within the same transformation */ public DateTimeValue getCurrentDateTime() { return controller.getCurrentDateTime(); } /** * Get the implicit timezone, as a positive or negative offset from UTC in minutes. * The range is -14hours to +14hours * @return the implicit timezone as an offset from UTC in minutes */ public final int getImplicitTimezone() { return controller.getImplicitTimezone(); } /** * Mark the context as being in (or not in) temporary output state * @param temp true to set temporary output state; false to unset it */ public void setTemporaryOutputState(boolean temp) { isTemporaryDestination = temp; } /** * Get the context stack. This method returns an iterator whose items are instances of * {@link net.sf.saxon.trace.ContextStackFrame}, starting with the top-most stackframe and * ending at the point the query or transformation was invoked by a calling application. * * @return an iterator over a copy of the run-time call stack */ public Iterator iterateStackFrames() { return new ContextStackIterator(this); } // TODO: eliminate this class. A new XPathContextMinor is created under two circumstances, // (a) when the focus changes (i.e., a new current iterator), and (b) when the current // receiver changes. We could handle these by maintaining a stack of iterators and a stack of // receivers in the XPathContextMajor object. Adding a new iterator or receiver to the stack would // generally be cheaper than creating the new XPathContextMinor object. The main difficulty (in the // case of iterators) is knowing when to pop the stack: currently we rely on the garbage collector. // We can only really do this when the iterator comes to its end, which is difficult to detect. // Perhaps we should try to do static allocation, so that fixed slots are allocated for different // minor-contexts within a Procedure, and a compiled expression that uses the focus knows which // slot to look in. // It's also worth noting that with path expressions such as a/b/c/d the context object is essentially // unused. It only gets used if there is a reference to the context such as ".", "position()", or "last()". // We could potentially mark steps in a path expression at compile time where there is no need to create // a context object. } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/expr/PathMap.java0000644000175000017500000007274311033112257020567 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.Configuration; import net.sf.saxon.functions.Doc; import net.sf.saxon.functions.Document; import net.sf.saxon.functions.SystemFunction; import net.sf.saxon.om.Axis; import net.sf.saxon.pattern.AnyNodeTest; import net.sf.saxon.pattern.NodeKindTest; import net.sf.saxon.query.StaticQueryContext; import net.sf.saxon.query.XQueryExpression; import net.sf.saxon.sxpath.XPathEvaluator; import net.sf.saxon.sxpath.XPathExpression; import net.sf.saxon.trans.XPathException; import java.io.File; import java.io.FileReader; import java.io.PrintStream; import java.net.URI; import java.net.URISyntaxException; import java.util.*; /** * A PathMap is a description of all the paths followed by an expression. * It is a set of trees. Each tree contains as its root an expression that selects * nodes without any dependency on the context. The arcs in the tree are axis steps. * So the expression doc('a.xml')/a[b=2]/c has a single root (the call on doc()), with * a single arc representing child::a, this leads to a node which has two further arcs * representing child::b and child::c. Because element b is atomized, there will also be * an arc for the step descendant::text() indicating the requirement to access the text * nodes of the element. * *

    The current implementation works only for XPath 2.0 expressions (for example, constructs * like xsl:for-each-group are not handled.)

    * *

    This class, together with the overloaded method * {@link Expression#addToPathMap(PathMap, net.sf.saxon.expr.PathMap.PathMapNodeSet)} can be * seen as an implementation of the static path analysis algorithm given in section 4 of * A. Marian and J. Simeon, * Projecting XML Documents, VLDB 2003.

    */ public class PathMap { private List pathMapRoots = new ArrayList(); // a list of PathMapRoot objects private HashMap pathsForVariables = new HashMap(); // a map from a variable Binding to a PathMapNodeSet /** * A node in the path map. A node holds a set of arcs, each representing a link to another * node in the path map. */ public static class PathMapNode { List arcs; // a list of PathMapArcs private boolean returnable; private boolean atomized; private boolean hasUnknownDependencies; /** * Create a node in the PathMap (initially with no arcs) */ private PathMapNode() { arcs = new ArrayList(); } /** * Create a new arc * @param step the AxisExpression representing this step * @return the newly-constructed target of the new arc */ public PathMapNode createArc(AxisExpression step) { for (int i=0; i=0; i--) { PathMapArc arc = (PathMapArc)root.arcs.get(i); byte axis = arc.getStep().getAxis(); switch (axis) { case Axis.ATTRIBUTE: case Axis.NAMESPACE: { AxisExpression newStep = new AxisExpression(Axis.DESCENDANT, NodeKindTest.ELEMENT); PathMapNode newTarget = new PathMapNode(); newTarget.arcs.add(arc); newRoot.createArc(newStep, newTarget); break; } default: { AxisExpression newStep = new AxisExpression( Axis.DESCENDANT_OR_SELF, arc.getStep().getNodeTest()); newRoot.createArc(newStep, arc.getTarget()); break; } } } for (int i=0; i=0; i--) { PathMapArc thisArc = (PathMapArc)node.arcs.get(i); AxisExpression axisStep = thisArc.getStep(); PathMapNode grandParent = (nodeStack.size() < 2 ? null : (PathMapNode)nodeStack.get(nodeStack.size()-2)); byte lastAxis = -1; if (grandParent != null) { for (Iterator iter = grandParent.arcs.iterator(); iter.hasNext(); ) { PathMapArc arc = ((PathMapArc)iter.next()); if (arc.getTarget() == node) { lastAxis = arc.getStep().getAxis(); } } } switch (axisStep.getAxis()) { case Axis.ANCESTOR_OR_SELF: case Axis.DESCENDANT_OR_SELF: if (axisStep.getNodeTest() == NodeKindTest.DOCUMENT) { // This is typically an absolute path expression appearing within a predicate node.arcs.remove(i); for (Iterator iter = thisArc.getTarget().arcs.iterator(); iter.hasNext(); ) { root.arcs.add(iter.next()); } break; } else { // fall through } case Axis.ANCESTOR: case Axis.FOLLOWING: case Axis.PRECEDING: { // replace the axis by a downwards axis from the root if (axisStep.getAxis() != Axis.DESCENDANT_OR_SELF) { AxisExpression newStep = new AxisExpression(Axis.DESCENDANT_OR_SELF, axisStep.getNodeTest()); newStep.setContainer(axisStep.getContainer()); root.createArc(newStep, thisArc.getTarget()); node.arcs.remove(i); } break; } case Axis.ATTRIBUTE: case Axis.CHILD: case Axis.DESCENDANT: case Axis.NAMESPACE: // no action break; case Axis.FOLLOWING_SIBLING: case Axis.PRECEDING_SIBLING: { if (grandParent != null) { AxisExpression newStep = new AxisExpression(lastAxis, axisStep.getNodeTest()); newStep.setContainer(axisStep.getContainer()); grandParent.createArc(newStep, thisArc.getTarget()); node.arcs.remove(i); break; } else { AxisExpression newStep = new AxisExpression(Axis.CHILD, axisStep.getNodeTest()); newStep.setContainer(axisStep.getContainer()); root.createArc(newStep, thisArc.getTarget()); node.arcs.remove(i); break; } } case Axis.PARENT: { if (lastAxis == Axis.CHILD || lastAxis == Axis.ATTRIBUTE || lastAxis == Axis.NAMESPACE) { // ignore the parent step - it leads to somewhere we have already been. // But it might become a returned node if (node.isReturnable()) { grandParent.setReturnable(true); } // any paths after the parent step need to be attached to the grandparent PathMapNode target = thisArc.getTarget(); for (int a=0; a1] * @param base An iteration of the items to be filtered * @param start The position of the first item to be included (base 1) * @return an iterator over the items in the sequence from the start item to the end of the sequence. * The returned iterator will not necessarily be an instance of this class. */ public static SequenceIterator make(SequenceIterator base, int start) throws XPathException { if (start == 1) { return base; } else if (base instanceof ArrayIterator) { return ((ArrayIterator)base).makeSliceIterator(start, Integer.MAX_VALUE); } else if (base instanceof GroundedIterator) { GroundedValue value = ((GroundedIterator)base).materialize(); if (value == EmptySequence.getInstance()) { return EmptyIterator.getInstance(); } else { return new ValueTailIterator(value, start-1); } } else { // discard the first n-1 items from the underlying iterator for (int i=0; i < start-1; i++) { Item b = base.next(); if (b == null) { return EmptyIterator.getInstance(); } } return new TailIterator(base, start); } } public Item next() throws XPathException { return base.next(); } public Item current() { return base.current(); } public int position() { int bp = base.position(); return (bp > 0 ? (base.position() - start + 1) : bp); } public boolean hasNext() { return ((LookaheadIterator)base).hasNext(); } public int getLastPosition() throws XPathException { int bl = ((LastPositionFinder)base).getLastPosition() - start + 1; return (bl > 0 ? bl : 0); } public void close() { base.close(); } public SequenceIterator getAnother() throws XPathException { return make(base.getAnother(), start); } /** * Get properties of this iterator, as a bit-significant integer. * * @return the properties of this iterator. This will be some combination of * properties such as {@link #GROUNDED}, {@link #LAST_POSITION_FINDER}, * and {@link #LOOKAHEAD}. It is always * acceptable to return the value zero, indicating that there are no known special properties. * It is acceptable for the properties of the iterator to change depending on its state. */ public int getProperties() { return base.getProperties() & (LAST_POSITION_FINDER | LOOKAHEAD); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/expr/AtomicMappingExpression.java0000644000175000017500000000673311033112257024041 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.trace.ExpressionPresenter; import net.sf.saxon.trace.Location; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ItemType; /** * An atomic mapping expression is a slash expression A/B where B has a static type that is an atomic type. * For example, * / name(). */ public final class AtomicMappingExpression extends SlashExpression implements ContextMappingFunction { /** * Constructor * @param start A node-set expression denoting the absolute or relative set of nodes from which the * navigation path should start. * @param step The step to be followed from each node in the start expression to yield a new * node-set */ public AtomicMappingExpression(Expression start, Expression step) { super(start, step); } /** * Determine whether this expression is capable (as far as static analysis is concerned) * of returning a mixture of nodes and atomic values. If so, this needs to be prevented * at run time * @return true if the static type allows both nodes and atomic values */ public boolean isHybrid() { return false; } /** * Type-check the expression */ public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) { // rely on the fact that the original slash expression has already been type-checked return this; } /** * Copy an expression. This makes a deep copy. * * @return the copy of the original expression */ public Expression copy() { return new AtomicMappingExpression(getStartExpression().copy(), getStepExpression().copy()); } /** * Iterate the path-expression in a given context * @param context the evaluation context */ public SequenceIterator iterate(final XPathContext context) throws XPathException { // This class delivers the result of the expression in unsorted order, // without removal of duplicates. SequenceIterator result = start.iterate(context); XPathContext context2 = context.newMinorContext(); context2.setCurrentIterator(result); context2.setOrigin(this); context2.setOriginatingConstructType(Location.PATH_EXPRESSION); return new ContextMappingIterator(this, context2); } /** * Diagnostic print of expression structure. The abstract expression tree * is written to the supplied output destination. */ public void explain(ExpressionPresenter destination) { destination.startElement("atomicMap"); getStartExpression().explain(destination); getStepExpression().explain(destination); destination.endElement(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/expr/TreatExpression.java0000644000175000017500000000303411033112257022357 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.value.SequenceType; /** * Treat Expression: implements "treat as data-type ( expression )". This is a factory class only. */ public abstract class TreatExpression { /** * This class is never instantiated */ private TreatExpression() { } /** * Make a treat expression * @return the expression */ public static Expression make(Expression sequence, SequenceType type) { RoleLocator role = new RoleLocator(RoleLocator.TYPE_OP, "treat as", 0); role.setErrorCode("XPDY0050"); Expression e = CardinalityChecker.makeCardinalityChecker(sequence, type.getCardinality(), role); ItemChecker checker = new ItemChecker(e, type.getPrimaryType(), role); return checker; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/expr/TailExpression.java0000644000175000017500000001241411033112257022173 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.om.*; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.TypeHierarchy; import net.sf.saxon.trace.ExpressionPresenter; import java.util.Iterator; /** * A TailExpression represents a FilterExpression of the form EXPR[position() > n] * Here n is usually 2, but we allow other values */ public class TailExpression extends Expression { Expression base; int start; // 1-based offset of first item from base expression // to be included /** * Construct a TailExpression, representing a filter expression of the form * $base[position() >= $start] * @param base the expression to be filtered * @param start the position (1-based) of the first item to be included */ public TailExpression(Expression base, int start) { this.base = base; this.start = start; adoptChildExpression(base); } public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { base = visitor.typeCheck(base, contextItemType); return this; } public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { base = visitor.optimize(base, contextItemType); return this; } public Expression promote(PromotionOffer offer) throws XPathException { Expression exp = offer.accept(this); if (exp != null) { return exp; } else { if (offer.action != PromotionOffer.UNORDERED) { base = doPromotion(base, offer); } return this; } } public int computeSpecialProperties() { return base.getSpecialProperties(); } /** * Copy an expression. This makes a deep copy. * * @return the copy of the original expression */ public Expression copy() { return new TailExpression(base.copy(), start); } public ItemType getItemType(TypeHierarchy th) { return base.getItemType(th); } public int computeCardinality() { return base.getCardinality() | StaticProperty.ALLOWS_ZERO; } public Iterator iterateSubExpressions() { return new MonoIterator(base); } /** * Replace one subexpression by a replacement subexpression * @param original the original subexpression * @param replacement the replacement subexpression * @return true if the original subexpression is found */ public boolean replaceSubExpression(Expression original, Expression replacement) { boolean found = false; if (base == original) { base = replacement; found = true; } return found; } /** * Get the base expression (of which this expression returns the tail part of the value) * @return the base expression */ public Expression getBaseExpression() { return base; } /** * Get the start offset * @return the one-based start offset (returns 2 if all but the first item is being selected) */ public int getStart() { return start; } /** * Compare two expressions to see if they are equal * @param other the other expression * @return true if the expressions are equivalent */ public boolean equals(Object other) { return other instanceof TailExpression && base.equals(((TailExpression)other).base) && start == ((TailExpression)other).start; } public int hashCode() { return base.hashCode(); } public SequenceIterator iterate(XPathContext context) throws XPathException { SequenceIterator baseIter = base.iterate(context); if ((baseIter.getProperties() & SequenceIterator.GROUNDED) != 0) { return new ValueTailIterator(((GroundedIterator)baseIter).materialize(), start - 1); } else { return TailIterator.make(baseIter, start); } } /** * Diagnostic print of expression structure. The abstract expression tree * is written to the supplied output destination. */ public void explain(ExpressionPresenter destination) { destination.startElement("tail"); destination.emitAttribute("start", start+""); base.explain(destination); destination.endElement(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. //saxonb-9.1.0.8/bj/net/sf/saxon/expr/ExpressionParser.java0000644000175000017500000030455111135365014022550 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.Configuration; import net.sf.saxon.trans.Err; import net.sf.saxon.event.LocationProvider; import net.sf.saxon.functions.CurrentGroup; import net.sf.saxon.functions.RegexGroup; import net.sf.saxon.functions.SystemFunction; import net.sf.saxon.instruct.*; import net.sf.saxon.om.*; import net.sf.saxon.pattern.*; import net.sf.saxon.trace.Location; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.*; import net.sf.saxon.value.*; import java.io.Serializable; import java.util.ArrayList; import java.util.List; import java.util.Stack; /** * Parser for XPath expressions and XSLT patterns. * * This code was originally inspired by James Clark's xt but has been totally rewritten (several times) * * @author Michael Kay */ public class ExpressionParser { protected Tokenizer t; protected StaticContext env; protected Stack rangeVariables = null; // The stack holds a list of range variables that are in scope. // Each entry on the stack is a VariableDeclaration object containing details // of the variable. protected NameChecker nameChecker; protected boolean scanOnly = false; // scanOnly is set to true while attributes in direct element constructors // are being processed. We need to parse enclosed expressions in the attribute // in order to find the end of the attribute value, but we don't yet know the // full namespace context at this stage. protected boolean compileWithTracing = false; protected int language = XPATH; // know which language we are parsing, for diagnostics protected static final int XPATH = 0; protected static final int XSLT_PATTERN = 1; protected static final int SEQUENCE_TYPE = 2; protected static final int XQUERY = 3; /** * Create an expression parser */ public ExpressionParser(){ } /** * Set whether trace hooks are to be included in the compiled code. To use tracing, it is necessary * both to compile the code with trace hooks included, and to supply a TraceListener at run-time * @param trueOrFalse true if trace code is to be compiled in, false otherwise */ public void setCompileWithTracing(boolean trueOrFalse) { compileWithTracing = trueOrFalse; } /** * Determine whether trace hooks are included in the compiled code. * @return true if trace hooks are included, false if not. */ public boolean isCompileWithTracing() { return compileWithTracing; } /** * Get the tokenizer (the lexical analyzer) * @return the tokenizer (the lexical analyzer) */ public Tokenizer getTokenizer() { return t; } /** * Read the next token, catching any exception thrown by the tokenizer */ protected void nextToken() throws XPathException { try { t.next(); } catch (XPathException err) { grumble(err.getMessage()); } } /** * Expect a given token; fail if the current token is different. Note that this method * does not read any tokens. * * @param token the expected token * @throws XPathException if the current token is not the expected * token */ protected void expect(int token) throws XPathException { if (t.currentToken != token) grumble("expected \"" + Token.tokens[token] + "\", found " + currentTokenDisplay()); } /** * Report a syntax error (a static error with error code XP0003) * @param message the error message * @throws XPathException always thrown: an exception containing the * supplied message */ protected void grumble(String message) throws XPathException { grumble(message, (language == XSLT_PATTERN ? "XTSE0340" : "XPST0003")); } /** * Report a static error * * @param message the error message * @param errorCode the error code * @throws XPathException always thrown: an exception containing the * supplied message */ protected void grumble(String message, String errorCode) throws XPathException { if (errorCode == null) { errorCode = "XPST0003"; } String s = t.recentText(); int line = t.getLineNumber(); int column = t.getColumnNumber(); String lineInfo = (line==1 ? "" : ("on line " + line + ' ')); String columnInfo = "at char " + column + ' '; String prefix = getLanguage() + " syntax error " + columnInfo + lineInfo + (message.startsWith("...") ? "near" : "in") + ' ' + Err.wrap(s) + ":\n "; XPathException err = new XPathException(prefix + message); err.setIsStaticError(true); err.setErrorCode(errorCode); throw err; } /** * Output a warning message * @param message the text of the message */ protected void warning(String message) throws XPathException { String s = t.recentText(); int line = t.getLineNumber(); String lineInfo = (line==1 ? "" : ("on line " + line + ' ')); String prefix = lineInfo + (message.startsWith("...") ? "near" : "in") + ' ' + Err.wrap(s) + ":\n "; env.issueWarning(prefix + message, null); } /** * Get the current language (XPath or XQuery) * @return a string representation of the language being parsed, for use in error messages */ protected String getLanguage() { switch (language) { case XPATH: return "XPath"; case XSLT_PATTERN: return "XSLT Pattern"; case SEQUENCE_TYPE: return "SequenceType"; case XQUERY: return "XQuery"; default: return "XPath"; } } /** * Display the current token in an error message * * @return the display representation of the token */ protected String currentTokenDisplay() { if (t.currentToken==Token.NAME) { return "name \"" + t.currentTokenValue + '\"'; } else if (t.currentToken==Token.UNKNOWN) { return "(unknown token)"; } else { return '\"' + Token.tokens[t.currentToken] + '\"'; } } /** * Parse a string representing an expression * * @throws XPathException if the expression contains a syntax error * @param expression the expression expressed as a String * @param start offset within the string where parsing is to start * @param terminator character to treat as terminating the expression * @param lineNumber location of the start of the expression, for diagnostics * @param env the static context for the expression * @return an Expression object representing the result of parsing */ public Expression parse(String expression, int start, int terminator, int lineNumber, StaticContext env) throws XPathException { // System.err.println("Parse expression: " + expression); this.env = env; nameChecker = env.getConfiguration().getNameChecker(); t = new Tokenizer(); try { t.tokenize(expression, start, -1, lineNumber); } catch (XPathException err) { grumble(err.getMessage()); } Expression exp = parseExpression(); if (t.currentToken != terminator) { if (t.currentToken == Token.EOF && terminator == Token.RCURLY) { grumble("Missing curly brace after expression in attribute value template", "XTSE0350"); } else { grumble("Unexpected token " + currentTokenDisplay() + " beyond end of expression"); } } return exp; } /** * Parse a string representing an XSLT pattern * * @throws XPathException if the pattern contains a syntax error * @param pattern the pattern expressed as a String * @param env the static context for the pattern * @return a Pattern object representing the result of parsing */ public Pattern parsePattern(String pattern, StaticContext env) throws XPathException { this.env = env; nameChecker = env.getConfiguration().getNameChecker(); language = XSLT_PATTERN; t = new Tokenizer(); try { t.tokenize(pattern, 0, -1, env.getLineNumber()); } catch (XPathException err) { grumble(err.getMessage()); } Pattern pat = parseUnionPattern(); if (t.currentToken != Token.EOF) { grumble("Unexpected token " + currentTokenDisplay() + " beyond end of pattern"); } return pat; } /** * Parse a string representing a sequence type * * @param input the string, which should conform to the XPath SequenceType * production * @param env the static context * @throws XPathException if any error is encountered * @return a SequenceType object representing the type */ public SequenceType parseSequenceType(String input, StaticContext env) throws XPathException { this.env = env; nameChecker = env.getConfiguration().getNameChecker(); language = SEQUENCE_TYPE; t = new Tokenizer(); try { t.tokenize(input, 0, -1, 1); } catch (XPathException err) { grumble(err.getMessage()); } SequenceType req = parseSequenceType(); if (t.currentToken != Token.EOF) { grumble("Unexpected token " + currentTokenDisplay() + " beyond end of SequenceType"); } return req; } ////////////////////////////////////////////////////////////////////////////////// // EXPRESSIONS // ////////////////////////////////////////////////////////////////////////////////// /** * Parse a top-level Expression: * ExprSingle ( ',' ExprSingle )* * * @throws XPathException if the expression contains a syntax error * @return the Expression object that results from parsing */ protected Expression parseExpression() throws XPathException { Expression exp = parseExprSingle(); ArrayList list = null; while (t.currentToken == Token.COMMA) { // An expression containing a comma often contains many, so we accumulate all the // subexpressions into a list before creating the Block expression which reduces it to an array if (list == null) { list = new ArrayList(10); list.add(exp); } nextToken(); Expression next = parseExprSingle(); setLocation(next); list.add(next); } if (list != null) { exp = Block.makeBlock(list); setLocation(exp); } return exp; } /** * Parse an ExprSingle * * @throws XPathException if any error is encountered * @return the resulting subexpression */ protected Expression parseExprSingle() throws XPathException { switch (t.currentToken) { case Token.FOR: case Token.LET: // XQuery only return parseForExpression(); case Token.SOME: case Token.EVERY: return parseQuantifiedExpression(); case Token.IF: return parseIfExpression(); case Token.TYPESWITCH: return parseTypeswitchExpression(); case Token.VALIDATE: case Token.VALIDATE_STRICT: case Token.VALIDATE_LAX: return parseValidateExpression(); case Token.PRAGMA: return parseExtensionExpression(); default: return parseOrExpression(); } } /** * Parse a Typeswitch Expression. * This construct is XQuery-only, so the XPath version of this * method throws an error unconditionally * @return the expression that results from the parsing */ protected Expression parseTypeswitchExpression() throws XPathException { grumble("typeswitch is not allowed in XPath"); return null; } /** * Parse a Validate Expression. * This construct is XQuery-only, so the XPath version of this * method throws an error unconditionally * @return the parsed expression; except that this version of the method always * throws an exception */ protected Expression parseValidateExpression() throws XPathException { grumble("validate{} expressions are not allowed in XPath"); return null; } /** * Parse an Extension Expression * This construct is XQuery-only, so the XPath version of this * method throws an error unconditionally * @return the parsed expression; except that this version of the method * always throws an exception */ protected Expression parseExtensionExpression() throws XPathException { grumble("extension expressions (#...#) are not allowed in XPath"); return null; } /** * Parse an OrExpression: * AndExpr ( 'or' AndExpr )* * * @throws XPathException if any error is encountered * @return the resulting subexpression */ private Expression parseOrExpression() throws XPathException { Expression exp = parseAndExpression(); while (t.currentToken == Token.OR) { nextToken(); exp = new BooleanExpression(exp, Token.OR, parseAndExpression()); setLocation(exp); } return exp; } /** * Parse an AndExpr: * EqualityExpr ( 'and' EqualityExpr )* * * @throws XPathException if any error is encountered * @return the resulting subexpression */ private Expression parseAndExpression() throws XPathException { Expression exp = parseComparisonExpression(); while (t.currentToken == Token.AND) { nextToken(); exp = new BooleanExpression(exp, Token.AND, parseComparisonExpression()); setLocation(exp); } return exp; } /** * Parse a FOR expression: * for $x in expr (',' $y in expr)* 'return' expr * * @throws XPathException if any error is encountered * @return the resulting subexpression */ protected Expression parseForExpression() throws XPathException { if (t.currentToken==Token.LET) { grumble("'let' is not supported in XPath"); } return parseMappingExpression(); } /** * Parse a quantified expression: * (some|every) $x in expr 'satisfies' expr * * @throws XPathException if any error is encountered * @return the resulting subexpression */ private Expression parseQuantifiedExpression() throws XPathException { return parseMappingExpression(); } /** * Parse a mapping expression. This is a common routine that handles * XPath 'for' expressions and quantified expressions. * *

    Syntax:
    * (for|some|every) $x in expr (',' $y in expr)* (return|satisfies) expr *

    * *

    On entry, the current token indicates whether a for, some, or every * expression is expected.

    * * @throws XPathException if any error is encountered * @return the resulting subexpression */ protected Expression parseMappingExpression() throws XPathException { int offset = t.currentTokenStartOffset; int operator = t.currentToken; List clauseList = new ArrayList(3); do { ForClause clause = new ForClause(); clause.offset = offset; clause.requiredType = SequenceType.SINGLE_ITEM; clauseList.add(clause); nextToken(); expect(Token.DOLLAR); nextToken(); expect(Token.NAME); String var = t.currentTokenValue; // declare the range variable Assignation v; if (operator == Token.FOR) { v = new ForExpression(); } else { v = new QuantifiedExpression(); ((QuantifiedExpression)v).setOperator(operator); } v.setRequiredType(SequenceType.SINGLE_ITEM); v.setVariableQName(makeStructuredQName(var, false)); clause.rangeVariable = v; nextToken(); if (t.currentToken == Token.AS && language == XQUERY) { nextToken(); SequenceType type = parseSequenceType(); clause.requiredType = type; if (type.getCardinality() != StaticProperty.EXACTLY_ONE) { warning("Occurrence indicator on singleton range variable has no effect"); type = SequenceType.makeSequenceType(type.getPrimaryType(), StaticProperty.EXACTLY_ONE); } v.setRequiredType(type); } // "at" clauses are not recognized in XPath clause.positionVariable = null; // process the "in" clause expect(Token.IN); nextToken(); clause.sequence = parseExprSingle(); declareRangeVariable(clause.rangeVariable); } while (t.currentToken==Token.COMMA); // process the "return/satisfies" expression (called the "action") if (operator==Token.FOR) { expect(Token.RETURN); } else { expect(Token.SATISFIES); } nextToken(); Expression action = parseExprSingle(); // work back through the list of range variables, fixing up all references // to the variables in the inner expression final TypeHierarchy th = env.getConfiguration().getTypeHierarchy(); for (int i = clauseList.size()-1; i>=0; i--) { ForClause fc = (ForClause)clauseList.get(i); Assignation exp = fc.rangeVariable; setLocation(exp, offset); exp.setSequence(fc.sequence); // Attempt to give the range variable a more precise type, base on analysis of the // "action" expression. This will often be approximate, because variables and function // calls in the action expression have not yet been resolved. We rely on the ability // of all expressions to return some kind of type information even if this is // imprecise. if (fc.requiredType == SequenceType.SINGLE_ITEM) { SequenceType type = SequenceType.makeSequenceType( fc.sequence.getItemType(th), StaticProperty.EXACTLY_ONE); fc.rangeVariable.setRequiredType(type); } else { fc.rangeVariable.setRequiredType(fc.requiredType); } exp.setAction(action); // for the next outermost "for" clause, the "action" is this ForExpression action = exp; } // undeclare all the range variables for (int i = clauseList.size()-1; i>=0; i--) { undeclareRangeVariable(); } //action = makeTracer(offset, action, Location.FOR_EXPRESSION, -1); return action; } /** * Parse an IF expression: * if '(' expr ')' 'then' expr 'else' expr * * @throws XPathException if any error is encountered * @return the resulting subexpression */ private Expression parseIfExpression() throws XPathException { // left paren already read int ifoffset = t.currentTokenStartOffset; nextToken(); Expression condition = parseExpression(); expect(Token.RPAR); nextToken(); int thenoffset = t.currentTokenStartOffset; expect(Token.THEN); nextToken(); Expression thenExp = makeTracer(thenoffset, parseExprSingle(), Location.THEN_EXPRESSION, null); int elseoffset = t.currentTokenStartOffset; expect(Token.ELSE); nextToken(); Expression elseExp = makeTracer(elseoffset, parseExprSingle(), Location.ELSE_EXPRESSION, null); Expression ifExp = Choose.makeConditional(condition, thenExp, elseExp); setLocation(ifExp, ifoffset); return makeTracer(ifoffset, ifExp, Location.IF_EXPRESSION, null); } /** * Parse an "instance of" expression * Expr ("instance" "of") SequenceType * * @throws XPathException if any error is encountered * @return the resulting subexpression */ private Expression parseInstanceOfExpression() throws XPathException { Expression exp = parseTreatExpression(); if (t.currentToken == Token.INSTANCE_OF) { nextToken(); exp = new InstanceOfExpression(exp, parseSequenceType()); setLocation(exp); } return exp; } /** * Parse a "treat as" expression * castable-expression ("treat" "as" SequenceType )? * * @throws XPathException if any error is encountered * @return the resulting subexpression */ private Expression parseTreatExpression() throws XPathException { Expression exp = parseCastableExpression(); if (t.currentToken == Token.TREAT_AS) { nextToken(); SequenceType target = parseSequenceType(); exp = TreatExpression.make(exp, target); setLocation(exp); } return exp; } /** * Parse a "castable as" expression * Expr "castable as" AtomicType "?"? * * @throws XPathException if any error is encountered * @return the resulting subexpression */ private Expression parseCastableExpression() throws XPathException { Expression exp = parseCastExpression(); if (t.currentToken == Token.CASTABLE_AS) { nextToken(); expect(Token.NAME); AtomicType at = getAtomicType(t.currentTokenValue); if (at.getFingerprint() == StandardNames.XS_ANY_ATOMIC_TYPE) { grumble("No value is castable to xs:anyAtomicType", "XPST0080"); } if (at.getFingerprint() == StandardNames.XS_NOTATION) { grumble("No value is castable to xs:NOTATION", "XPST0080"); } nextToken(); boolean allowEmpty = (t.currentToken == Token.QMARK); if (allowEmpty) { nextToken(); } if (at.isNamespaceSensitive()) { if (exp instanceof StringLiteral) { try { String source = ((StringLiteral)exp).getStringValue(); makeNameCode(source, false); exp = new Literal(BooleanValue.TRUE); } catch (Exception e) { exp = new Literal(BooleanValue.FALSE); } } else { exp = new CastableExpression(exp, at, allowEmpty); } } else { exp = new CastableExpression(exp, at, allowEmpty); } setLocation(exp); } return exp; } /** * Parse a "cast as" expression * castable-expression ("cast" "as" AtomicType "?"?) * * @throws XPathException if any error is encountered * @return the resulting subexpression */ private Expression parseCastExpression() throws XPathException { Expression exp = parseUnaryExpression(); if (t.currentToken == Token.CAST_AS) { nextToken(); expect(Token.NAME); AtomicType at = getAtomicType(t.currentTokenValue); if (at.getFingerprint() == StandardNames.XS_ANY_ATOMIC_TYPE) { grumble("Cannot cast to xs:anyAtomicType", "XPST0080"); } if (at.getFingerprint() == StandardNames.XS_NOTATION) { grumble("Cannot cast to xs:NOTATION", "XPST0080"); } nextToken(); boolean allowEmpty = (t.currentToken == Token.QMARK); if (allowEmpty) { nextToken(); } if (at.isNamespaceSensitive() && exp instanceof StringLiteral) { try { String source = ((StringLiteral)exp).getStringValue(); return new Literal(CastExpression.castStringToQName(source, at, env)); } catch (XPathException e) { grumble(e.getMessage(), e.getErrorCodeLocalPart()); } } else { exp = new CastExpression(exp, at, allowEmpty); exp = ExpressionVisitor.make(env).simplify(exp); } setLocation(exp); } return exp; } /** * Analyze a token whose expected value is the name of an atomic type, * and return the object representing the atomic type. * @param qname The lexical QName of the atomic type * @return The atomic type * @throws XPathException if the QName is invalid or if no atomic type of that * name exists as a built-in type or a type in an imported schema */ private AtomicType getAtomicType(String qname) throws XPathException { if (scanOnly) { return BuiltInAtomicType.STRING; } try { String[] parts = nameChecker.getQNameParts(qname); String uri; if (parts[0].length() == 0) { uri = env.getDefaultElementNamespace(); } else { try { uri = env.getURIForPrefix(parts[0]); } catch (XPathException err) { grumble(err.getMessage(), err.getErrorCodeLocalPart()); uri = ""; } } boolean builtInNamespace = uri.equals(NamespaceConstant.SCHEMA); // if (!builtInNamespace && NamespaceConstant.isXDTNamespace(uri)) { // uri = NamespaceConstant.XDT; // builtInNamespace = true; // } if (builtInNamespace) { ItemType t = Type.getBuiltInItemType(uri, parts[1]); if (t == null) { grumble("Unknown atomic type " + qname, "XPST0051"); } if (t instanceof BuiltInAtomicType) { if (!env.isAllowedBuiltInType((BuiltInAtomicType)t)) { grumble("The type " + qname + " is not recognized by a Basic XSLT Processor. ", "XPST0080"); } return (AtomicType)t; } else { grumble("The type " + qname + " is not atomic", "XPST0051"); } } else if (uri.equals(NamespaceConstant.JAVA_TYPE)) { Class theClass = null; try { String className = parts[1].replace('-', '$'); theClass = env.getConfiguration().getClass(className, false, null); } catch (XPathException err) { grumble("Unknown Java class " + parts[1], "XPST0051"); } return new ExternalObjectType(theClass, env.getConfiguration()); } else if (uri.equals(NamespaceConstant.DOT_NET_TYPE)) { return (AtomicType)Configuration.getPlatform().getExternalObjectType(env.getConfiguration(), uri, parts[1]); } else { if (env.isImportedSchema(uri)) { int fp = env.getNamePool().getFingerprint(uri, parts[1]); if (fp == -1) { grumble("Unknown type " + qname, "XPST0051"); } SchemaType st = env.getConfiguration().getSchemaType(fp); if (st == null) { grumble("Unknown atomic type " + qname, "XPST0051"); } else if (st.isAtomicType()) { return (AtomicType)st; } else if (st.isComplexType()) { grumble("Type (" + qname + ") is a complex type", "XPST0051"); return null; } else { grumble("Type (" + qname + ") is a list or union type", "XPST0051"); return null; } } else { if (uri.length() == 0) { grumble("There is no imported schema for the null namespace", "XPST0051"); } else { grumble("There is no imported schema for namespace " + uri, "XPST0051"); } return null; } } grumble("Unknown atomic type " + qname, "XPST0051"); } catch (QNameException err) { grumble(err.getMessage()); } return null; } /** * Parse a ComparisonExpr:
    * RangeExpr ( op RangeExpr )* * where op is one of =, <, >, !=, <=, >=, * eq, lt, gt, ne, le, ge, * is, isnot, <<, >> * * @throws XPathException if any error is encountered * @return the resulting subexpression */ private Expression parseComparisonExpression() throws XPathException { Expression exp = parseRangeExpression(); switch (t.currentToken) { case Token.IS: case Token.PRECEDES: case Token.FOLLOWS: int op = t.currentToken; nextToken(); exp = new IdentityComparison(exp, op, parseRangeExpression()); setLocation(exp); return exp; case Token.EQUALS: case Token.NE: case Token.LT: case Token.GT: case Token.LE: case Token.GE: op = t.currentToken; nextToken(); exp = env.getConfiguration().getOptimizer().makeGeneralComparison( exp, op, parseRangeExpression(), env.isInBackwardsCompatibleMode()); setLocation(exp); return exp; case Token.FEQ: case Token.FNE: case Token.FLT: case Token.FGT: case Token.FLE: case Token.FGE: op = t.currentToken; nextToken(); exp = new ValueComparison(exp, op, parseRangeExpression()); setLocation(exp); return exp; default: return exp; } } /** * Parse a RangeExpr:
    * AdditiveExpr ('to' AdditiveExpr )? * * @throws XPathException if any error is encountered * @return the resulting subexpression */ private Expression parseRangeExpression() throws XPathException { Expression exp = parseAdditiveExpression(); if (t.currentToken == Token.TO ) { nextToken(); exp = new RangeExpression(exp, Token.TO, parseAdditiveExpression()); setLocation(exp); } return exp; } /** * Parse the sequence type production. * The QName must be the name of a built-in schema-defined data type. * * @throws XPathException if any error is encountered * @return the resulting subexpression */ protected SequenceType parseSequenceType() throws XPathException { ItemType primaryType; if (t.currentToken == Token.NAME) { primaryType = getAtomicType(t.currentTokenValue); nextToken(); } else if (t.currentToken == Token.NODEKIND) { if (t.currentTokenValue.equals("item")) { nextToken(); expect(Token.RPAR); nextToken(); primaryType = AnyItemType.getInstance(); } else if (t.currentTokenValue.equals("empty-sequence")) { nextToken(); expect(Token.RPAR); nextToken(); return SequenceType.makeSequenceType(EmptySequenceTest.getInstance(), StaticProperty.EMPTY); // return before trying to read an occurrence indicator } else { primaryType = parseKindTest(); } } else { grumble("Expected type name in SequenceType, found " + Token.tokens[t.currentToken]); return null; } int occurrenceFlag; switch (t.currentToken) { case Token.STAR: case Token.MULT: // "*" will be tokenized different ways depending on what precedes it occurrenceFlag = StaticProperty.ALLOWS_ZERO_OR_MORE; // Make the tokenizer ignore the occurrence indicator when classifying the next token t.currentToken = Token.RPAR; nextToken(); break; case Token.PLUS: occurrenceFlag = StaticProperty.ALLOWS_ONE_OR_MORE; // Make the tokenizer ignore the occurrence indicator when classifying the next token t.currentToken = Token.RPAR; nextToken(); break; case Token.QMARK: occurrenceFlag = StaticProperty.ALLOWS_ZERO_OR_ONE; // Make the tokenizer ignore the occurrence indicator when classifying the next token t.currentToken = Token.RPAR; nextToken(); break; default: occurrenceFlag = StaticProperty.EXACTLY_ONE; } return SequenceType.makeSequenceType(primaryType, occurrenceFlag); } /** * Parse an AdditiveExpr: * MultiplicativeExpr ( (+|-) MultiplicativeExpr )* * * @throws XPathException if any error is encountered * @return the resulting subexpression */ private Expression parseAdditiveExpression() throws XPathException { Expression exp = parseMultiplicativeExpression(); while (t.currentToken == Token.PLUS || t.currentToken == Token.MINUS ) { int op = t.currentToken; nextToken(); exp = new ArithmeticExpression(exp, op, parseMultiplicativeExpression()); setLocation(exp); } return exp; } /** * Parse a MultiplicativeExpr:
    * UnionExpr ( (*|div|idiv|mod) UnionExpr )* * * @throws XPathException if any error is encountered * @return the resulting subexpression */ private Expression parseMultiplicativeExpression() throws XPathException { Expression exp = parseUnionExpression(); while (t.currentToken == Token.MULT || t.currentToken == Token.DIV || t.currentToken == Token.IDIV || t.currentToken == Token.MOD ) { int op = t.currentToken; nextToken(); exp = new ArithmeticExpression(exp, op, parseUnionExpression()); setLocation(exp); } return exp; } /** * Parse a UnaryExpr:
    * ('+'|'-')* ValueExpr * parsed as ('+'|'-')? UnaryExpr * * @throws XPathException if any error is encountered * @return the resulting subexpression */ private Expression parseUnaryExpression() throws XPathException { Expression exp; switch (t.currentToken) { case Token.MINUS: nextToken(); exp = new ArithmeticExpression(new Literal(Int64Value.ZERO), Token.NEGATE, parseUnaryExpression()); break; case Token.PLUS: nextToken(); // Unary plus: can't ignore it completely, it might be a type error, or it might // force conversion to a number which would affect operations such as "=". exp = new ArithmeticExpression(new Literal(Int64Value.ZERO), Token.PLUS, parseUnaryExpression()); break; case Token.VALIDATE: case Token.VALIDATE_STRICT: case Token.VALIDATE_LAX: exp = parseValidateExpression(); break; case Token.PRAGMA: exp = parseExtensionExpression(); break; default: exp = parsePathExpression(); } setLocation(exp); return exp; } /** * Parse a UnionExpr:
    * IntersectExceptExpr ( "|" | "union" IntersectExceptExpr )* * * @throws XPathException if any error is encountered * @return the resulting subexpression */ private Expression parseUnionExpression() throws XPathException { Expression exp = parseIntersectExpression(); while (t.currentToken == Token.UNION ) { nextToken(); exp = new VennExpression(exp, Token.UNION, parseIntersectExpression()); setLocation(exp); } return exp; } /** * Parse an IntersectExceptExpr:
    * PathExpr ( ( 'intersect' | 'except') PathExpr )* * * @throws XPathException if any error is encountered * @return the resulting subexpression */ private Expression parseIntersectExpression() throws XPathException { Expression exp = parseInstanceOfExpression(); while (t.currentToken == Token.INTERSECT || t.currentToken == Token.EXCEPT ) { int op = t.currentToken; nextToken(); exp = new VennExpression(exp, op, parseInstanceOfExpression()); setLocation(exp); } return exp; } /** * Test whether the current token is one that can start a RelativePathExpression * * @return the resulting subexpression */ private boolean atStartOfRelativePath() { switch(t.currentToken) { case Token.AXIS: case Token.AT: case Token.NAME: case Token.PREFIX: case Token.SUFFIX: case Token.STAR: case Token.NODEKIND: case Token.DOT: case Token.DOTDOT: case Token.FUNCTION: case Token.STRING_LITERAL: case Token.NUMBER: case Token.LPAR: return true; default: return false; } } /** * Parse a PathExpresssion. This includes "true" path expressions such as A/B/C, and also * constructs that may start a path expression such as a variable reference $name or a * parenthesed expression (A|B). Numeric and string literals also come under this heading. * * @throws XPathException if any error is encountered * @return the resulting subexpression */ private Expression parsePathExpression() throws XPathException { switch (t.currentToken) { case Token.SLASH: nextToken(); final RootExpression start = new RootExpression(); setLocation(start); if (atStartOfRelativePath()) { //final Expression path = new PathExpression(start, parseRelativePath(null)); final Expression path = parseRemainingPath(start); setLocation(path); return path; } else { return start; } case Token.SLSL: // The logic for absolute path expressions changed in 8.4 so that //A/B/C parses to // (((root()/descendant-or-self::node())/A)/B)/C rather than // (root()/descendant-or-self::node())/(((A)/B)/C) as previously. This is to allow // the subsequent //A optimization to kick in. nextToken(); final RootExpression start2 = new RootExpression(); setLocation(start2); final AxisExpression axisExp = new AxisExpression(Axis.DESCENDANT_OR_SELF, null); setLocation(axisExp); final Expression exp = parseRemainingPath(new SlashExpression(start2, axisExp)); setLocation(exp); return exp; default: return parseRelativePath(); } } /** * Parse a relative path (a sequence of steps). Called when the current token immediately * follows a separator (/ or //), or an implicit separator (XYZ is equivalent to ./XYZ) * @throws XPathException if any error is encountered * @return the resulting subexpression */ protected Expression parseRelativePath() throws XPathException { Expression exp = parseStepExpression(); while (t.currentToken == Token.SLASH || t.currentToken == Token.SLSL ) { int op = t.currentToken; nextToken(); Expression next = parseStepExpression(); if (op == Token.SLASH) { exp = new SlashExpression(exp, next); } else { // add implicit descendant-or-self::node() step AxisExpression ae = new AxisExpression(Axis.DESCENDANT_OR_SELF, null); setLocation(ae); SlashExpression se = new SlashExpression(ae, next); setLocation(se); exp = new SlashExpression(exp, se); } setLocation(exp); } return exp; } /** * Parse the remaining steps of an absolute path expression (one starting in "/" or "//"). Note that the * token immediately after the "/" or "//" has already been read, and in the case of "/", it has been confirmed * that we have a path expression starting with "/" rather than a standalone "/" expression. * @param start the initial implicit expression: root() in the case of "/", root()/descendant-or-self::node in * the case of "//" * @return the completed path expression * @throws XPathException */ protected Expression parseRemainingPath(Expression start) throws XPathException { Expression exp = start; int op = Token.SLASH; while (true) { Expression next = parseStepExpression(); if (op == Token.SLASH) { exp = new SlashExpression(exp, next); } else { // add implicit descendant-or-self::node() step exp = new SlashExpression(exp, new SlashExpression(new AxisExpression(Axis.DESCENDANT_OR_SELF, null), next)); } setLocation(exp); op = t.currentToken; if (op != Token.SLASH && op != Token.SLSL) { break; } nextToken(); } return exp; } /** * Parse a step (including an optional sequence of predicates) * * @throws XPathException if any error is encountered * @return the resulting subexpression */ protected Expression parseStepExpression() throws XPathException { Expression step = parseBasicStep(); // When the filter is applied to an Axis step, the nodes are considered in // axis order. In all other cases they are considered in document order boolean reverse = (step instanceof AxisExpression) && !Axis.isForwards[((AxisExpression)step).getAxis()]; // && ((AxisExpression)step).getAxis() != Axis.SELF; while (t.currentToken == Token.LSQB) { nextToken(); Expression predicate = parseExpression(); expect(Token.RSQB); nextToken(); step = new FilterExpression(step, predicate); setLocation(step); } if (reverse) { return SystemFunction.makeSystemFunction("reverse", new Expression[]{step}); } else { return step; } } /** * Parse a basic step expression (without the predicates) * * @throws XPathException if any error is encountered * @return the resulting subexpression */ private Expression parseBasicStep() throws XPathException { switch(t.currentToken) { case Token.DOLLAR: nextToken(); expect(Token.NAME); String var = t.currentTokenValue; nextToken(); if (scanOnly) { return new ContextItemExpression(); // don't do any semantic checks during a prescan } //int vtest = makeNameCode(var, false) & 0xfffff; StructuredQName vtest = makeStructuredQName(var, false); // See if it's a range variable or a variable in the context Binding b = findRangeVariable(vtest); VariableReference ref; if (b != null) { ref = new LocalVariableReference(b); } else { try { ref = env.bindVariable(vtest); } catch (XPathException err) { if ("XPST0008".equals(err.getErrorCodeLocalPart())) { // Improve the error message grumble("Variable $" + var + " has not been declared", "XPST0008"); ref = null; // humour the compiler } else { throw err; } } } setLocation(ref); return ref; case Token.LPAR: nextToken(); if (t.currentToken==Token.RPAR) { nextToken(); return new Literal(EmptySequence.getInstance()); } Expression seq = parseExpression(); expect(Token.RPAR); nextToken(); return seq; case Token.STRING_LITERAL: Literal literal = makeStringLiteral(t.currentTokenValue); nextToken(); return literal; case Token.NUMBER: NumericValue number = NumericValue.parseNumber(t.currentTokenValue); if (number.isNaN()) { grumble("Invalid numeric literal " + Err.wrap(t.currentTokenValue, Err.VALUE)); } nextToken(); Literal lit = new Literal(number); setLocation(lit); return lit; case Token.FUNCTION: return parseFunctionCall(); case Token.DOT: nextToken(); Expression cie = new ContextItemExpression(); setLocation(cie); return cie; case Token.DOTDOT: nextToken(); Expression pne = new ParentNodeExpression(); setLocation(pne); return pne; case Token.NAME: case Token.PREFIX: case Token.SUFFIX: case Token.STAR: case Token.NODEKIND: byte defaultAxis = Axis.CHILD; if (t.currentToken == Token.NODEKIND && (t.currentTokenValue.equals("attribute") || t.currentTokenValue.equals("schema-attribute"))) { defaultAxis = Axis.ATTRIBUTE; } AxisExpression ae = new AxisExpression(defaultAxis, parseNodeTest(Type.ELEMENT)); setLocation(ae); return ae; case Token.AT: nextToken(); switch(t.currentToken) { case Token.NAME: case Token.PREFIX: case Token.SUFFIX: case Token.STAR: case Token.NODEKIND: AxisExpression ae2 = new AxisExpression(Axis.ATTRIBUTE, parseNodeTest(Type.ATTRIBUTE)); setLocation(ae2); return ae2; default: grumble("@ must be followed by a NodeTest"); } break; case Token.AXIS: byte axis; try { axis = Axis.getAxisNumber(t.currentTokenValue); } catch (XPathException err) { grumble(err.getMessage()); axis = Axis.CHILD; // error recovery } if (axis == Axis.NAMESPACE && language == XQUERY) { grumble("The namespace axis is not available in XQuery"); } short principalNodeType = Axis.principalNodeType[axis]; nextToken(); switch (t.currentToken) { case Token.NAME: case Token.PREFIX: case Token.SUFFIX: case Token.STAR: case Token.NODEKIND: Expression ax = new AxisExpression(axis, parseNodeTest(principalNodeType)); setLocation(ax); return ax; default: grumble("Unexpected token " + currentTokenDisplay() + " after axis name"); } break; case Token.KEYWORD_CURLY: case Token.ELEMENT_QNAME: case Token.ATTRIBUTE_QNAME: case Token.PI_QNAME: case Token.TAG: return parseConstructor(); default: grumble("Unexpected token " + currentTokenDisplay() + " in path expression"); //break; } return null; } /** * Method to make a string literal from a token identified as a string * literal. This is trivial in XPath, but in XQuery the method is overridden * to identify pseudo-XML character and entity references. Note that the job of handling * doubled string delimiters is done by the tokenizer. * @param currentTokenValue the token as read (excluding quotation marks) * @return The string value of the string literal */ protected Literal makeStringLiteral(String currentTokenValue) throws XPathException { StringLiteral literal = new StringLiteral(currentTokenValue); setLocation(literal); return literal; } /** * Parse a node constructor. This is allowed only in XQuery, so the method throws * an error for XPath. * @return the expression that results from the parsing */ protected Expression parseConstructor() throws XPathException { grumble("Node constructor expressions are allowed only in XQuery, not in XPath"); return null; } /** * Parse a NodeTest. * One of QName, prefix:*, *:suffix, *, text(), node(), comment(), or * processing-instruction(literal?), or element(~,~), attribute(~,~), etc. * * @throws XPathException if any error is encountered * @param nodeType the node type being sought if one is specified * @return the resulting NodeTest object */ protected NodeTest parseNodeTest(short nodeType) throws XPathException { int tok = t.currentToken; String tokv = t.currentTokenValue; switch (tok) { case Token.NAME: nextToken(); return makeNameTest(nodeType, tokv, nodeType==Type.ELEMENT); case Token.PREFIX: nextToken(); return makeNamespaceTest(nodeType, tokv); case Token.SUFFIX: nextToken(); tokv = t.currentTokenValue; expect(Token.NAME); nextToken(); return makeLocalNameTest(nodeType, tokv); case Token.STAR: nextToken(); return NodeKindTest.makeNodeKindTest(nodeType); case Token.NODEKIND: return parseKindTest(); default: grumble("Unrecognized node test"); return null; } } /** * Parse a KindTest * @return the KindTest, expressed as a NodeTest object */ private NodeTest parseKindTest() throws XPathException { String typeName = t.currentTokenValue; boolean schemaDeclaration = (typeName.startsWith("schema-")); int primaryType = getSystemType(typeName); int nameCode = -1; int contentType; boolean empty = false; nextToken(); if (t.currentToken == Token.RPAR) { if (schemaDeclaration) { grumble("schema-element() and schema-attribute() require a name to be supplied"); return null; } empty = true; nextToken(); } switch (primaryType) { case Type.ITEM: grumble("item() is not allowed in a path expression"); return null; case Type.NODE: if (empty) { return AnyNodeTest.getInstance(); } else { grumble("No arguments are allowed in node()"); return null; } case Type.TEXT: if (empty) { return NodeKindTest.TEXT; } else { grumble("No arguments are allowed in text()"); return null; } case Type.COMMENT: if (empty) { return NodeKindTest.COMMENT; } else { grumble("No arguments are allowed in comment()"); return null; } case Type.NAMESPACE: grumble("No node test is defined for namespace nodes"); return null; case Type.DOCUMENT: if (empty) { return NodeKindTest.DOCUMENT; } else { int innerType; try { innerType = getSystemType(t.currentTokenValue); } catch (XPathException err) { innerType = Type.ITEM; } if (innerType != Type.ELEMENT) { grumble("Argument to document-node() must be an element type descriptor"); return null; } NodeTest inner = parseKindTest(); expect(Token.RPAR); nextToken(); return new DocumentNodeTest(inner); } case Type.PROCESSING_INSTRUCTION: if (empty) { return NodeKindTest.PROCESSING_INSTRUCTION; } else if (t.currentToken == Token.STRING_LITERAL) { try { String[] parts = nameChecker.getQNameParts(t.currentTokenValue); if (parts[0].length() == 0) { nameCode = makeNameCode(parts[1], false); } else { warning("No processing instruction name will ever contain a colon"); nameCode = env.getNamePool().allocate("prefix", "http://saxon.sf.net/ nonexistent namespace", "___invalid-name"); } } catch (QNameException e) { warning("No processing instruction will ever be named '" + t.currentTokenValue + "'. " + e.getMessage()); nameCode = env.getNamePool().allocate("prefix", "http://saxon.sf.net/ nonexistent namespace", "___invalid-name"); } } else if (t.currentToken == Token.NAME) { try { String[] parts = nameChecker.getQNameParts(t.currentTokenValue); if (parts[0].length() == 0) { nameCode = makeNameCode(parts[1], false); } else { grumble("Processing instruction name must not contain a colon"); } } catch (QNameException e) { grumble("Invalid processing instruction name. " + e.getMessage()); } } else { grumble("Processing instruction name must be a QName or a string literal"); } nextToken(); expect(Token.RPAR); nextToken(); return new NameTest(Type.PROCESSING_INSTRUCTION, nameCode, env.getNamePool()); case Type.ATTRIBUTE: // drop through case Type.ELEMENT: String nodeName = ""; if (empty) { return NodeKindTest.makeNodeKindTest(primaryType); } else if (t.currentToken == Token.STAR || t.currentToken == Token.MULT) { // allow for both representations of "*" to be safe if (schemaDeclaration) { grumble("schema-element() and schema-attribute() must specify an actual name, not '*'"); return null; } nameCode = -1; } else if (t.currentToken == Token.NAME) { nodeName = t.currentTokenValue; nameCode = makeNameCode(t.currentTokenValue, primaryType == Type.ELEMENT); // & 0xfffff; } else { grumble("Unexpected " + Token.tokens[t.currentToken] + " after '(' in SequenceType"); } String suri = null; if (nameCode != -1) { suri = env.getNamePool().getURI(nameCode); } nextToken(); if (t.currentToken == Token.RPAR) { nextToken(); if (nameCode == -1) { // element(*) or attribute(*) return NodeKindTest.makeNodeKindTest(primaryType); } else { NodeTest nameTest = null; SchemaType schemaType = null; boolean nillable = false; if (primaryType == Type.ATTRIBUTE) { // attribute(N) or schema-attribute(N) if (schemaDeclaration) { // schema-attribute(N) SchemaDeclaration attributeDecl = env.getConfiguration().getAttributeDeclaration(nameCode & 0xfffff); if (!env.isImportedSchema(suri)) { grumble("No schema has been imported for namespace '" + suri + '\'', "XPST0008"); } if (attributeDecl == null) { grumble("There is no declaration for attribute @" + nodeName + " in an imported schema", "XPST0008"); } else { schemaType = attributeDecl.getType(); nameTest = new NameTest(Type.ATTRIBUTE, nameCode, env.getNamePool()); } } else { nameTest = new NameTest(Type.ATTRIBUTE, nameCode, env.getNamePool()); return nameTest; } } else { // element(N) or schema-element(N) if (schemaDeclaration) { // schema-element(N) if (!env.isImportedSchema(suri)) { grumble("No schema has been imported for namespace '" + suri + '\'', "XPST0008"); } SchemaDeclaration elementDecl = env.getConfiguration().getElementDeclaration(nameCode & 0xfffff); if (elementDecl == null) { grumble("There is no declaration for element <" + nodeName + "> in an imported schema", "XPST0008"); } else { schemaType = elementDecl.getType(); nameTest = elementDecl.makeSchemaNodeTest(); nillable = elementDecl.isNillable(); } } else { nameTest = new NameTest(Type.ELEMENT, nameCode, env.getNamePool()); return nameTest; } } ContentTypeTest contentTest = null; if (schemaType != null) { contentTest = new ContentTypeTest(primaryType, schemaType, env.getConfiguration()); contentTest.setNillable(nillable); } if (contentTest == null) { return nameTest; } else { CombinedNodeTest combo = new CombinedNodeTest(nameTest, Token.INTERSECT, contentTest); combo.setGlobalComponentTest(schemaDeclaration); return combo; } } } else if (t.currentToken == Token.COMMA) { if (schemaDeclaration) { grumble("schema-element() and schema-attribute() must have one argument only"); return null; } nextToken(); NodeTest result; if (t.currentToken == Token.STAR) { grumble("'*' is no longer permitted as the second argument of element() and attribute()"); return null; } else if (t.currentToken == Token.NAME) { SchemaType schemaType; contentType = makeNameCode(t.currentTokenValue, true) & NamePool.FP_MASK; String uri = env.getNamePool().getURI(contentType); String lname = env.getNamePool().getLocalName(contentType); if (uri.equals(NamespaceConstant.SCHEMA)) { schemaType = env.getConfiguration().getSchemaType(contentType); } else { if (!env.isImportedSchema(uri)) { grumble("No schema has been imported for namespace '" + uri + '\'', "XPST0008"); } schemaType = env.getConfiguration().getSchemaType(contentType); } if (schemaType == null) { grumble("Unknown type name " + lname, "XPST0008"); } if (primaryType == Type.ATTRIBUTE && schemaType.isComplexType()) { warning("An attribute cannot have a complex type"); } ContentTypeTest typeTest = new ContentTypeTest(primaryType, schemaType, env.getConfiguration()); if (nameCode == -1) { // this represents element(*,T) or attribute(*,T) result = typeTest; if (primaryType == Type.ATTRIBUTE) { nextToken(); } else { // assert (primaryType == Type.ELEMENT); nextToken(); if (t.currentToken == Token.QMARK) { typeTest.setNillable(true); nextToken(); } } } else { if (primaryType == Type.ATTRIBUTE) { NodeTest nameTest = new NameTest(Type.ATTRIBUTE, nameCode, env.getNamePool()); result = new CombinedNodeTest(nameTest, Token.INTERSECT, typeTest); nextToken(); } else { // assert (primaryType == Type.ELEMENT); NodeTest nameTest = new NameTest(Type.ELEMENT, nameCode, env.getNamePool()); result = new CombinedNodeTest(nameTest, Token.INTERSECT, typeTest); nextToken(); if (t.currentToken == Token.QMARK) { typeTest.setNillable(true); nextToken(); } } } } else { grumble("Unexpected " + Token.tokens[t.currentToken] + " after ',' in SequenceType"); return null; } expect(Token.RPAR); nextToken(); return result; } else { grumble("Expected ')' or ',' in SequenceType"); } return null; default: // can't happen! grumble("Unknown node kind"); return null; } } /** * Get a system type - that is, one whose name is a keyword rather than a QName. This includes the node * kinds such as element and attribute, the generic types node() and item(), and the pseudo-type empty-sequence() * * @param name the name of the system type, for example "element" or "comment" * @return the integer constant denoting the type, for example {@link Type#ITEM} or {@link Type#ELEMENT} * @throws XPathException if the name is not recognized */ private int getSystemType(String name) throws XPathException { if ("item".equals(name)) return Type.ITEM; else if ("document-node".equals(name)) return Type.DOCUMENT; else if ("element".equals(name)) return Type.ELEMENT; else if ("schema-element".equals(name)) return Type.ELEMENT; else if ("attribute".equals(name)) return Type.ATTRIBUTE; else if ("schema-attribute".equals(name)) return Type.ATTRIBUTE; else if ("text".equals(name)) return Type.TEXT; else if ("comment".equals(name)) return Type.COMMENT; else if ("processing-instruction".equals(name)) return Type.PROCESSING_INSTRUCTION; else if ("namespace".equals(name)) return Type.NAMESPACE; else if ("node".equals(name)) return Type.NODE; else { grumble("Unknown type " + name); return -1; } } /** * Parse a function call. * function-name '(' ( Expression (',' Expression )* )? ')' * * @throws XPathException if any error is encountered * @return the resulting subexpression */ protected Expression parseFunctionCall() throws XPathException { String fname = t.currentTokenValue; int offset = t.currentTokenStartOffset; ArrayList args = new ArrayList(10); // the "(" has already been read by the Tokenizer: now parse the arguments nextToken(); if (t.currentToken!=Token.RPAR) { Expression arg = parseExprSingle(); args.add(arg); while(t.currentToken==Token.COMMA) { nextToken(); arg = parseExprSingle(); args.add(arg); } expect(Token.RPAR); } nextToken(); if (scanOnly) { return new StringLiteral(StringValue.EMPTY_STRING); } Expression[] arguments = new Expression[args.size()]; args.toArray(arguments); String[] parts; try { parts = nameChecker.getQNameParts(fname); } catch (QNameException e) { grumble("Function name is not a valid QName: " + fname + "()"); return null; } String uri; if (parts[0].length() == 0) { uri = env.getDefaultFunctionNamespace(); } else { try { uri = env.getURIForPrefix(parts[0]); } catch (XPathException err) { grumble(err.getMessage(), "XPST0081"); return null; } } StructuredQName functionName = new StructuredQName(parts[0], uri, parts[1]); if (uri.equals(NamespaceConstant.SCHEMA)) { ItemType t = Type.getBuiltInItemType(uri, parts[1]); if (t instanceof BuiltInAtomicType && !env.isAllowedBuiltInType((BuiltInAtomicType)t)) { grumble("The type " + fname + " is not recognized by a Basic XSLT Processor. ", "XPST0080"); return null; } } Expression fcall; try { fcall = env.getFunctionLibrary().bind(functionName, arguments, env); } catch (XPathException err) { if (err.getErrorCodeLocalPart() == null) { err.setErrorCode("XPST0017"); err.setIsStaticError(true); } grumble(err.getMessage(), err.getErrorCodeLocalPart()); return null; } if (fcall == null) { String msg = "Cannot find a matching " + arguments.length + "-argument function named " + functionName.getClarkName() + "()"; if (!env.getConfiguration().isAllowExternalFunctions()) { msg += ". Note: external function calls have been disabled"; } String similarNamespace = NamespaceConstant.findSimilarNamespace(functionName.getNamespaceURI()); if (similarNamespace != null) { msg += ". Perhaps the intended namespace was '" + similarNamespace + "'"; } if (env.isInBackwardsCompatibleMode()) { // treat this as a dynamic error to be reported only if the function call is executed XPathException err = new XPathException(msg); ErrorExpression exp = new ErrorExpression(err); setLocation(exp); return exp; } grumble(msg, "XPST0017"); return null; } // A QName or NOTATION constructor function must be evaluated now, while we know the namespace context if (fcall instanceof CastExpression && ((AtomicType)fcall.getItemType(env.getConfiguration().getTypeHierarchy())).isNamespaceSensitive() && arguments[0] instanceof StringLiteral) { try { AtomicValue av = CastExpression.castStringToQName(((StringLiteral)arguments[0]).getStringValue(), (AtomicType)fcall.getItemType(env.getConfiguration().getTypeHierarchy()), env); return new Literal(av); } catch (XPathException e) { grumble(e.getMessage(), e.getErrorCodeLocalPart()); return null; } } // There are special rules for certain functions appearing in a pattern if (language == XSLT_PATTERN) { if (fcall instanceof RegexGroup) { return new Literal(EmptySequence.getInstance()); } else if (fcall instanceof CurrentGroup) { String errorCode = "XTSE1060"; String function = ((CurrentGroup)fcall).getDisplayName(); if (function.equals("current-grouping-key")) { errorCode = "XTSE1070"; } grumble("The " + Err.wrap(function, Err.FUNCTION) + " function cannot be used in a pattern", errorCode); return null; } } setLocation(fcall, offset); for (int a=0; a=0; v--) { Binding b = (Binding)rangeVariables.elementAt(v); if (b.getVariableQName().equals(qName)) { return b; } } return null; // not an in-scope range variable } /** * Get the range variable stack. Used when parsing a nested subexpression * inside an attribute constructor * @return the stack used for locally-declared variables */ public Stack getRangeVariableStack() { return rangeVariables; } /** * Set the range variable stack. Used when parsing a nested subexpression * inside an attribute constructor. * @param stack the stack to be used for local variables declared within the expression */ public void setRangeVariableStack(Stack stack) { rangeVariables = stack; } ////////////////////////////////////////////////////////////////////////////////// // PATTERNS // ////////////////////////////////////////////////////////////////////////////////// /** * Parse a Union Pattern:
    * pathPattern ( | pathPattern )* * * @throws XPathException if any error is encountered * @return the pattern that results from parsing */ private Pattern parseUnionPattern() throws XPathException { Pattern exp1 = parsePathPattern(); while (t.currentToken == Token.UNION ) { if (t.currentTokenValue.equals("union")) { grumble("Union operator in a pattern must be written as '|'"); } nextToken(); Pattern exp2 = parsePathPattern(); exp1 = new UnionPattern(exp1, exp2); } return exp1; } /** * Parse a Location Path Pattern: * * @throws XPathException if any error is encountered * @return the pattern that results from parsing */ private Pattern parsePathPattern() throws XPathException { Pattern prev = null; int connector = -1; boolean rootonly = false; // special handling of stuff before the first component switch(t.currentToken) { case Token.SLASH: connector = t.currentToken; nextToken(); prev = new NodeTestPattern(NodeKindTest.makeNodeKindTest(Type.DOCUMENT)); rootonly = true; break; case Token.SLSL: // leading double slash can't be ignored // because it changes the default priority connector = t.currentToken; nextToken(); prev = new NodeTestPattern(NodeKindTest.makeNodeKindTest(Type.DOCUMENT)); rootonly = false; break; default: break; } while(true) { Pattern pat; switch(t.currentToken) { case Token.AXIS: if ("child".equals(t.currentTokenValue)) { nextToken(); pat = parsePatternStep(Type.ELEMENT); } else if ("attribute".equals(t.currentTokenValue)) { nextToken(); pat = parsePatternStep(Type.ATTRIBUTE); } else { grumble("Axis in pattern must be child or attribute"); return null; } break; case Token.STAR: case Token.NAME: case Token.PREFIX: case Token.SUFFIX: pat = parsePatternStep(Type.ELEMENT); break; case Token.NODEKIND: pat = parsePatternStep( (t.currentTokenValue.equals("attribute") || t.currentTokenValue.equals("schema-attribute")) ? Type.ATTRIBUTE : Type.ELEMENT); break; case Token.AT: nextToken(); pat = parsePatternStep(Type.ATTRIBUTE); break; case Token.FUNCTION: // must be id(literal) or key(literal,literal) if (prev!=null) { grumble("Function call may appear only at the start of a pattern"); return null; } if ("id".equals(t.currentTokenValue)) { nextToken(); Expression idValue; if (t.currentToken == Token.STRING_LITERAL) { idValue = new StringLiteral(t.currentTokenValue); } else if (t.currentToken == Token.DOLLAR) { nextToken(); expect(Token.NAME); StructuredQName varName = makeStructuredQName(t.currentTokenValue, false); idValue = env.bindVariable(varName); } else { grumble("id value in pattern must be either a literal or a variable reference"); return null; } pat = new IDPattern(idValue); nextToken(); expect(Token.RPAR); nextToken(); } else if ("key".equals(t.currentTokenValue)) { nextToken(); expect(Token.STRING_LITERAL); String keyname = t.currentTokenValue; nextToken(); expect(Token.COMMA); nextToken(); Expression idValue; if (t.currentToken == Token.STRING_LITERAL) { idValue = new StringLiteral(t.currentTokenValue); } else if (t.currentToken == Token.NUMBER) { NumericValue number = NumericValue.parseNumber(t.currentTokenValue); if (number.isNaN()) { grumble("Invalid numeric literal " + Err.wrap(t.currentTokenValue, Err.VALUE)); } idValue = new Literal(number); } else if (t.currentToken == Token.DOLLAR) { nextToken(); expect(Token.NAME); StructuredQName varName = makeStructuredQName(t.currentTokenValue, false); idValue = env.bindVariable(varName); } else { grumble("key value must be either a literal or a variable reference"); return null; } pat = new KeyPattern(makeStructuredQName(keyname, false), idValue); nextToken(); expect(Token.RPAR); nextToken(); } else { grumble("The only functions allowed in a pattern are id() and key()"); return null; } break; default: if (rootonly) { // the pattern was plain '/' return prev; } grumble("Unexpected token in pattern, found " + currentTokenDisplay()); return null; } if (prev != null) { if (connector==Token.SLASH) { ((LocationPathPattern)pat).parentPattern = prev; } else { // connector == SLSL ((LocationPathPattern)pat).ancestorPattern = prev; } } connector = t.currentToken; rootonly = false; if (connector == Token.SLASH || connector == Token.SLSL) { prev = pat; nextToken(); } else { return pat; } } } /** * Parse a pattern step (after any axis name or @) * * @throws XPathException if any error is encountered * @param principalNodeType is ELEMENT if we're on the child axis, ATTRIBUTE for * the attribute axis * @return the pattern that results from parsing */ private Pattern parsePatternStep(short principalNodeType) throws XPathException { LocationPathPattern step = new LocationPathPattern(); NodeTest test = parseNodeTest(principalNodeType); if (test instanceof AnyNodeTest) { // handle node() and @node() specially if (principalNodeType == Type.ELEMENT) { // this means we're on the CHILD axis test = AnyChildNodePattern.getInstance(); } else { // we're on the attribute axis test = NodeKindTest.makeNodeKindTest(principalNodeType); } } // Deal with nonsense patterns such as @comment() or child::attribute(). These // are legal, but will never match anything. int kind = test.getPrimitiveType(); if (principalNodeType == Type.ELEMENT && (kind == Type.ATTRIBUTE || kind == Type.NAMESPACE)) { test = EmptySequenceTest.getInstance(); } else if (principalNodeType == Type.ATTRIBUTE && (kind == Type.COMMENT || kind == Type.TEXT || kind == Type.PROCESSING_INSTRUCTION || kind == Type.ELEMENT || kind == Type.DOCUMENT)) { test = EmptySequenceTest.getInstance(); } step.nodeTest = test; parseFilters(step); return step; } /** * Test to see if there are filters for a Pattern, if so, parse them * * @param path the LocationPathPattern to which the filters are to be * added * @throws XPathException if any error is encountered */ private void parseFilters(LocationPathPattern path) throws XPathException { while (t.currentToken == Token.LSQB) { nextToken(); Expression qual = parseExpression(); expect(Token.RSQB); nextToken(); path.addFilter(qual); } } // Helper methods to access the static context /** * Make a NameCode, using the static context for namespace resolution * * @throws XPathException if the name is invalid, or the prefix * undeclared * @param qname The name as written, in the form "[prefix:]localname" * @param useDefault Defines the action when there is no prefix. If * true, use the default namespace URI for element names. If false, * use no namespace URI (as for attribute names). * @return the namecode, which can be used to identify this name in the * name pool */ public final int makeNameCode(String qname, boolean useDefault) throws XPathException { if (scanOnly) { return StandardNames.XML_SPACE; } try { String[] parts = nameChecker.getQNameParts(qname); String prefix = parts[0]; if (prefix.length() == 0) { if (useDefault) { String uri = env.getDefaultElementNamespace(); return env.getNamePool().allocate("", uri, qname); } else { return env.getNamePool().allocate("", "", qname); } } else { try { String uri = env.getURIForPrefix(prefix); return env.getNamePool().allocate(prefix, uri, parts[1]); } catch (XPathException err) { grumble(err.getMessage(), err.getErrorCodeLocalPart()); return -1; } } } catch (QNameException e) { grumble(e.getMessage()); return -1; } } /** * Make a NameCode, using the static context for namespace resolution. * This variant of the method does not call "grumble" to report any errors * to the ErrorListener, it only reports errors by throwing exceptions. This * allows the caller to control the message output. * * @throws XPathException if the name is invalid, or the prefix * undeclared * @param qname The name as written, in the form "[prefix:]localname" * @param useDefault Defines the action when there is no prefix. If * true, use the default namespace URI for element names. If false, * use no namespace URI (as for attribute names). * @return the namecode, which can be used to identify this name in the * name pool */ public final int makeNameCodeSilently(String qname, boolean useDefault) throws XPathException, QNameException { if (scanOnly) { return StandardNames.XML_SPACE; } String[] parts = nameChecker.getQNameParts(qname); String prefix = parts[0]; if (prefix.length() == 0) { if (useDefault) { String uri = env.getDefaultElementNamespace(); return env.getNamePool().allocate("", uri, qname); } else { return env.getNamePool().allocate("", "", qname); } } else { String uri = env.getURIForPrefix(prefix); return env.getNamePool().allocate(prefix, uri, parts[1]); } } /** * Make a Structured QName, using the static context for namespace resolution * * @throws XPathException if the name is invalid, or the prefix * undeclared * @param qname The name as written, in the form "[prefix:]localname" * @param useDefault Defines the action when there is no prefix. If * true, use the default namespace URI for element names. If false, * use no namespace URI (as for attribute names). * @return the namecode, which can be used to identify this name in the * name pool */ public final StructuredQName makeStructuredQName(String qname, boolean useDefault) throws XPathException { if (scanOnly) { return null; } try { String[] parts = nameChecker.getQNameParts(qname); String prefix = parts[0]; if (prefix.length() == 0) { if (useDefault) { String uri = env.getDefaultElementNamespace(); return new StructuredQName("", uri, qname); } else { return new StructuredQName("", "", qname); } } else { try { String uri = env.getURIForPrefix(prefix); return new StructuredQName(prefix, uri, parts[1]); } catch (XPathException err) { grumble(err.getMessage(), err.getErrorCodeLocalPart()); return null; } } } catch (QNameException e) { grumble(e.getMessage()); return null; } } /** * Make a NameTest, using the static context for namespace resolution * * @param nodeType the type of node required (identified by a constant in * class Type) * @param qname the lexical QName of the required node * @param useDefault true if the default namespace should be used when * the QName is unprefixed * @throws XPathException if the QName is invalid * @return a NameTest, representing a pattern that tests for a node of a * given node kind and a given name */ public NameTest makeNameTest(short nodeType, String qname, boolean useDefault) throws XPathException { int nameCode = makeNameCode(qname, useDefault); return new NameTest(nodeType, nameCode, env.getNamePool()); } /** * Make a NamespaceTest (name:*) * * @param nodeType integer code identifying the type of node required * @param prefix the namespace prefix * @throws XPathException if the namespace prefix is not declared * @return the NamespaceTest, a pattern that matches all nodes in this * namespace */ public NamespaceTest makeNamespaceTest(short nodeType, String prefix) throws XPathException { if (scanOnly) { // return an arbitrary namespace if we're only doing a syntax check return new NamespaceTest(env.getNamePool(), nodeType, NamespaceConstant.SAXON); } try { return new NamespaceTest(env.getNamePool(), nodeType, env.getURIForPrefix(prefix)); } catch (XPathException e) { // env.getURIForPrefix can return a dynamic error grumble(e.getMessage(), "XPST0081"); return null; } } /** * Make a LocalNameTest (*:name) * * @param nodeType the kind of node to be matched * @param localName the requred local name * @throws XPathException if the local name is invalid * @return a LocalNameTest, a pattern which matches all nodes of a given * local name, regardless of namespace */ public LocalNameTest makeLocalNameTest(short nodeType, String localName) throws XPathException { if (!nameChecker.isValidNCName(localName)) { grumble("Local name [" + localName + "] contains invalid characters"); } return new LocalNameTest(env.getNamePool(), nodeType, localName); } /** * Set location information on an expression. At present this consists of a simple * line number. Needed mainly for XQuery. * @param exp the expression whose location information is to be set */ protected void setLocation(Expression exp) { setLocation(exp, t.currentTokenStartOffset); } /** * Set location information on an expression. At present only the line number * is retained. Needed mainly for XQuery. This version of the method supplies an * explicit offset (character position within the expression or query), which the tokenizer * can convert to a line number and column number. * @param exp the expression whose location information is to be set * @param offset the character position within the expression (ignoring newlines) */ protected void setLocation(Expression exp, int offset) { // Although we could get the column position from the offset, we choose not to retain this, // and only use the line number int line = t.getLineNumber(offset); if (exp.getLocationId()==-1) { int loc = env.getLocationMap().allocateLocationId(env.getSystemId(), line); exp.setLocationId(loc); // add a temporary container to provide location information if (exp.getContainer() == null) { TemporaryContainer container = new TemporaryContainer(env.getLocationMap(), loc); exp.setContainer(container); } } } /** * If tracing, wrap an expression in a trace instruction * @param startOffset the position of the expression in the soruce * @param exp the expression to be wrapped * @param construct integer constant identifying the kind of construct * @param qName the name of the construct (if applicable) * @return the expression that does the tracing */ protected Expression makeTracer(int startOffset, Expression exp, int construct, StructuredQName qName) { if (isCompileWithTracing()) { TraceExpression trace = new TraceExpression(exp); long lc = t.getLineAndColumn(startOffset); trace.setLineNumber((int)(lc>>32)); trace.setColumnNumber((int)(lc&0x7fffffff)); trace.setSystemId(env.getSystemId()); trace.setNamespaceResolver(env.getNamespaceResolver()); trace.setConstructType(construct); trace.setObjectName(qName); //trace.setObjectNameCode(objectNameCode); return trace; } else { return exp; } } /** * Test whether the current token is a given keyword. * @param s The string to be compared with the current token * @return true if they are the same */ protected boolean isKeyword(String s) { return (t.currentToken == Token.NAME && t.currentTokenValue.equals(s)); } /** * Set that we are parsing in "scan only" * @param scanOnly true if parsing is to proceed in scan-only mode. In this mode * namespace bindings are not yet known, so no attempt is made to look up namespace * prefixes. */ public void setScanOnly(boolean scanOnly) { this.scanOnly = scanOnly; } public static class ForClause { public Assignation rangeVariable; public PositionVariable positionVariable; public Expression sequence; public SequenceType requiredType; public int offset; } protected static class TemporaryContainer implements Container, LocationProvider, Serializable { private LocationMap map; private int locationId; public TemporaryContainer(LocationMap map, int locationId) { this.map = map; this.locationId = locationId; } public Executable getExecutable() { return null; } public LocationProvider getLocationProvider() { return map; } public String getPublicId() { return null; } public String getSystemId() { return map.getSystemId(locationId); } public int getLineNumber() { return map.getLineNumber(locationId); } public int getColumnNumber() { return -1; } public String getSystemId(long locationId) { return getSystemId(); } public int getLineNumber(long locationId) { return getLineNumber(); } public int getColumnNumber(long locationId) { return getColumnNumber(); } /** * Get the host language (XSLT, XQuery, XPath) used to implement the code in this container * @return typically {@link net.sf.saxon.Configuration#XSLT} or {@link net.sf.saxon.Configuration#XQUERY} */ public int getHostLanguage() { return Configuration.XPATH; } /** * Replace one subexpression by a replacement subexpression * @param original the original subexpression * @param replacement the replacement subexpression * @return true if the original subexpression is found */ public boolean replaceSubExpression(Expression original, Expression replacement) { // overridden in subclasses throw new IllegalArgumentException("Invalid replacement"); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/expr/Optimizer.java0000644000175000017500000003140711063015754021216 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.Configuration; import net.sf.saxon.instruct.Choose; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.om.ValueRepresentation; import net.sf.saxon.sort.DocumentSorter; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.TypeHierarchy; import net.sf.saxon.value.Closure; import net.sf.saxon.value.MemoClosure; import net.sf.saxon.value.SequenceExtent; import net.sf.saxon.value.Value; import java.io.Serializable; import java.util.Iterator; /** * This class performs optimizations that vary between different versions of the Saxon product. * The optimizer is obtained from the Saxon Configuration. This class is the version used in Saxon-B, * which in most cases does no optimization at all: the methods are provided so that they can be * overridden in Saxon-SA. */ public class Optimizer implements Serializable { protected Configuration config; /** * Create an Optimizer. * @param config the Saxon configuration */ public Optimizer(Configuration config) { this.config = config; } /** * Get the Saxon configuration object * @return the configuration */ public Configuration getConfiguration() { return config; } /** * Create a GeneralComparison expression * @param p0 the first operand * @param op the operator * @param p1 the second operand * @param backwardsCompatible true if XPath 1.0 backwards compatibility is in force * @return the constructed expression */ public BinaryExpression makeGeneralComparison(Expression p0, int op, Expression p1, boolean backwardsCompatible) { if (backwardsCompatible) { return new GeneralComparison10(p0, op, p1); } else { return new GeneralComparison(p0, op, p1); } } /** * Attempt to optimize a copy operation. Return null if no optimization is possible. * @param select the expression that selects the items to be copied * @return null if no optimization is possible, or an expression that does an optimized * copy of these items otherwise */ public Expression optimizeCopy(Expression select) throws XPathException { final TypeHierarchy th = config.getTypeHierarchy(); if (select.getItemType(th).isAtomicType()) { return select; } return null; } /** * Make a Closure, given the expected reference count * @param expression the expression to be evaluated * @param ref the (nominal) number of times the value of the expression is required * @param context the XPath dynamic evaluation context * @return the constructed Closure */ public Value makeClosure(Expression expression, int ref, XPathContext context) throws XPathException { if (ref == 1) { return new Closure(); } else { return new MemoClosure(); } } /** * Make a SequenceExtent, given the expected reference count * @param expression the expression to be evaluated * @param ref the (nominal) number of times the value of the expression is required * @param context the XPath dynamic evaluation context * @return the constructed Closure */ public ValueRepresentation makeSequenceExtent(Expression expression, int ref, XPathContext context) throws XPathException { return SequenceExtent.makeSequenceExtent(expression.iterate(context)); } /** * Examine a path expression to see whether it can be replaced by a call on the key() function; * if so, generate an appropriate key definition and return the call on key(). If not, return null. * @param pathExp The path expression to be converted. * @param visitor The expression visitor * @return the optimized expression, or null if no optimization is possible */ public Expression convertPathExpressionToKey(PathExpression pathExp, ExpressionVisitor visitor) throws XPathException { return null; } /** * Try converting a filter expression to a call on the key function. Return the supplied * expression unchanged if not possible * @param f the filter expression to be converted * @param visitor the expression visitor, which must be currently visiting the filter expression f * @param indexFirstOperand true if the first operand of the filter comparison is to be indexed; * false if it is the second operand * @return the optimized expression, or the unchanged expression f if no optimization is possible */ public Expression tryIndexedFilter(FilterExpression f, ExpressionVisitor visitor, boolean indexFirstOperand) { return f; } /** * Convert a path expression such as a/b/c[predicate] into a filter expression * of the form (a/b/c)[predicate]. This is possible whenever the predicate is non-positional. * The conversion is useful in the case where the path expression appears inside a loop, * where the predicate depends on the loop variable but a/b/c does not. * @param pathExp the path expression to be converted * @param th the type hierarchy cache * @return the resulting filterexpression if conversion is possible, or null if not */ public FilterExpression convertToFilterExpression(PathExpression pathExp, TypeHierarchy th) throws XPathException { return null; } /** * Test whether a filter predicate is indexable. * @param filter the predicate expression * @return 0 if not indexable; +1 if the predicate is in the form expression=value; -1 if it is in * the form value=expression */ public int isIndexableFilter(Expression filter) { return 0; } /** * Create an indexed value * @param iter the iterator that delivers the sequence of values to be indexed * @return the indexed value * @throws UnsupportedOperationException: this method should not be called in Saxon-B */ public ValueRepresentation makeIndexedValue(SequenceIterator iter) throws XPathException { throw new UnsupportedOperationException("Indexing requires Saxon-SA"); } /** * Determine whether it is possible to rearrange an expression so that all references to a given * variable are replaced by a reference to ".". This is true of there are no references to the variable * within a filter predicate or on the rhs of a "/" operator. * @param exp the expression in question * @param binding an array of bindings defining range variables; the method tests that there are no * references to any of these variables within a predicate or on the rhs of "/" * @return true if the variable reference can be replaced */ public boolean isVariableReplaceableByDot(Expression exp, Binding[] binding) { if (exp instanceof FilterExpression) { Expression start = ((FilterExpression)exp).getBaseExpression(); Expression filter = ((FilterExpression)exp).getFilter(); return isVariableReplaceableByDot(start, binding) && !ExpressionTool.dependsOnVariable(filter, binding); } else if (exp instanceof PathExpression) { Expression start = ((PathExpression)exp).getFirstStep(); Expression rest = ((PathExpression)exp).getRemainingSteps(); return isVariableReplaceableByDot(start, binding) && !ExpressionTool.dependsOnVariable(rest, binding); } else if (exp instanceof SlashExpression) { // TODO: it is probably safe to use this branch for PathExpression as well Expression start = ((SlashExpression)exp).getStartExpression(); Expression rest = ((SlashExpression)exp).getStepExpression(); return isVariableReplaceableByDot(start, binding) && !ExpressionTool.dependsOnVariable(rest, binding); } else { Iterator iter = exp.iterateSubExpressions(); while (iter.hasNext()) { Expression sub = (Expression)iter.next(); if (!isVariableReplaceableByDot(sub, binding)) { return false; } } return true; } } /** * Make a conditional document sorter. This optimization is attempted * when a DocumentSorter is wrapped around a path expression * @param sorter the document sorter * @param path the path expression * @return the original sorter unchanged when no optimization is possible, which is always the * case in Saxon-B */ public Expression makeConditionalDocumentSorter(DocumentSorter sorter, PathExpression path) { return sorter; } /** * Replace a function call by the body of the function, assuming all conditions for inlining * the function are satisfied * @param functionCall the functionCall expression * @param visitor the expression visitor * @param contextItemType the context item type * @return either the original expression unchanged, or an expression that consists of the inlined * function body, with all function parameters bound as required. In Saxon-B, function inlining is * not supported, so the original functionCall is always returned unchanged */ public Expression tryInlineFunctionCall( UserFunctionCall functionCall, ExpressionVisitor visitor, ItemType contextItemType) { return functionCall; } /** * Identify expressions within a function or template body that can be promoted to be * evaluated as global variables. * @param body the body of the template or function * @param visitor the expression visitor * @return the expression after subexpressions have been promoted to global variables */ public Expression promoteExpressionsToGlobal(Expression body, ExpressionVisitor visitor) throws XPathException { return body; } /** * Try to convert a Choose expression into a switch * @param choose the Choose expression * @param env the static context * @return the result of optimizing this (the original expression if no optimization was possible) */ public Expression trySwitch(Choose choose, StaticContext env) { return choose; } /** * Extract subexpressions from the body of a function that can be evaluated * as global variables * @param body the body of the function * @return a reference to the new global variable if a variable has been created, or null if not */ public Expression extractGlobalVariables(Expression body, ExpressionVisitor visitor) throws XPathException { return null; } /** * Trace optimization actions * @param message the message to be displayed * @param exp the expression after being rewritten */ public void trace(String message, Expression exp) { if (getConfiguration().isOptimizerTracing()) { System.err.println("OPT ======================================"); System.err.println("OPT : At line " + exp.getLineNumber() + " of " + exp.getSystemId()); System.err.println("OPT : " + message); System.err.println("OPT ====== Expression after rewrite ======"); exp.explain(System.err); System.err.println("\nOPT ======================================"); } } /** * Trace optimization actions * @param message the message to be displayed */ public void trace(String message) { if (getConfiguration().isOptimizerTracing()) { System.err.println("OPT ======================================"); System.err.println("OPT : " + message); System.err.println("OPT ======================================"); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/expr/ContextMappingFunction.java0000644000175000017500000000337311033112257023674 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.trans.XPathException; /** * ContextMappingFunction is an interface that must be satisfied by an object passed to a * ContextMappingIterator. It represents an object which, given an Item, can return a * SequenceIterator that delivers a sequence of zero or more Items. *

    * This is a specialization of the more general MappingFunction class: it differs in that * each item being processed becomes the context item while it is being processed. */ public interface ContextMappingFunction { /** * Map one item to a sequence. * @param context The processing context. The item to be mapped is the context item identified * from this context: the values of position() and last() also relate to the set of items being mapped * @return a SequenceIterator over the sequence of items that the supplied input * item maps to */ public SequenceIterator map(XPathContext context) throws XPathException; } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/expr/VariableDeclaration.java0000644000175000017500000000357011033112257023120 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.om.StructuredQName; /** * Generic interface representing a variable declaration in the static context of an XPath expression. * The declaration may be internal or external to the XPath expression itself. An external * VariableDeclaration is identified (perhaps created) by the bindVariable() method in the StaticContext. */ public interface VariableDeclaration { /** * Method called by a BindingReference to register the variable reference for * subsequent fixup. * This method is called by the XPath parser when * each reference to the variable is encountered. At some time after parsing and before execution of the * expression, the VariableDeclaration is responsible for calling the two methods setStaticType() * and fixup() on each BindingReference that has been registered with it.
    * @param ref the variable reference */ public void registerReference(BindingReference ref); /** * Get the name of the variable as a structured QName * @return the variable name */ public StructuredQName getVariableQName(); } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/expr/TypeChecker.java0000644000175000017500000007251211133615332021440 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.Configuration; import net.sf.saxon.functions.NumberFn; import net.sf.saxon.functions.StringFn; import net.sf.saxon.functions.SystemFunction; import net.sf.saxon.om.Item; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.om.StandardNames; import net.sf.saxon.om.ValueRepresentation; import net.sf.saxon.pattern.EmptySequenceTest; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.*; import net.sf.saxon.value.Cardinality; import net.sf.saxon.value.SequenceExtent; import net.sf.saxon.value.SequenceType; import net.sf.saxon.value.Value; /** * This class provides Saxon's type checking capability. It contains a static method, * staticTypeCheck, which is called at compile time to perform type checking of * an expression. This class is never instantiated. */ public final class TypeChecker { // Class is not instantiated private TypeChecker() {} /** * Check an expression against a required type, modifying it if necessary. * *

    This method takes the supplied expression and checks to see whether it is * known statically to conform to the specified type. There are three possible * outcomes. If the static type of the expression is a subtype of the required * type, the method returns the expression unchanged. If the static type of * the expression is incompatible with the required type (for example, if the * supplied type is integer and the required type is string) the method throws * an exception (this results in a compile-time type error being reported). If * the static type is a supertype of the required type, then a new expression * is constructed that evaluates the original expression and checks the dynamic * type of the result; this new expression is returned as the result of the * method.

    * *

    The rules applied are those for function calling in XPath, that is, the rules * that the argument of a function call must obey in relation to the signature of * the function. Some contexts require slightly different rules (for example, * operands of polymorphic operators such as "+"). In such cases this method cannot * be used.

    * *

    Note that this method does not do recursive type-checking of the * sub-expressions.

    * * @param supplied The expression to be type-checked * @param req The required type for the context in which the expression is used * @param backwardsCompatible * True if XPath 1.0 backwards compatibility mode is applicable * @param role Information about the role of the subexpression within the * containing expression, used to provide useful error messages * @param visitor An expression visitor * @return The original expression if it is type-safe, or the expression * wrapped in a run-time type checking expression if not. * @throws XPathException if the supplied type is statically inconsistent with the * required type (that is, if they have no common subtype) */ public static Expression staticTypeCheck(Expression supplied, SequenceType req, boolean backwardsCompatible, RoleLocator role, ExpressionVisitor visitor) throws XPathException { // System.err.println("Static Type Check on expression (requiredType = " + req + "):"); supplied.display(10); if (supplied.implementsStaticTypeCheck()) { return supplied.staticTypeCheck(req, backwardsCompatible, role, visitor); } Expression exp = supplied; final StaticContext env = visitor.getStaticContext(); final TypeHierarchy th = visitor.getConfiguration().getTypeHierarchy(); ItemType reqItemType = req.getPrimaryType(); int reqCard = req.getCardinality(); boolean allowsMany = Cardinality.allowsMany(reqCard); ItemType suppliedItemType = null; // item type of the supplied expression: null means not yet calculated int suppliedCard = -1; // cardinality of the supplied expression: -1 means not yet calculated boolean cardOK = (reqCard == StaticProperty.ALLOWS_ZERO_OR_MORE); // Unless the required cardinality is zero-or-more (no constraints). // check the static cardinality of the supplied expression if (!cardOK) { suppliedCard = exp.getCardinality(); cardOK = Cardinality.subsumes(reqCard, suppliedCard); // May later find that cardinality is not OK after all, if atomization takes place } boolean itemTypeOK = reqItemType instanceof AnyItemType; // Unless the required item type and content type are ITEM (no constraints) // check the static item type against the supplied expression. // NOTE: we don't currently do any static inference regarding the content type if (!itemTypeOK) { suppliedItemType = exp.getItemType(th); if (suppliedItemType instanceof EmptySequenceTest) { // supplied type is empty-sequence(): this can violate a cardinality constraint but not an item type constraint itemTypeOK = true; } else { if (reqItemType == null || suppliedItemType == null) { throw new NullPointerException(); } int relation = th.relationship(reqItemType, suppliedItemType); itemTypeOK = relation == TypeHierarchy.SAME_TYPE || relation == TypeHierarchy.SUBSUMES; } } // Handle the special rules for 1.0 compatibility mode if (backwardsCompatible && !allowsMany) { // rule 1 if (Cardinality.allowsMany(suppliedCard)) { Expression cexp = new FirstItemExpression(exp); cexp.adoptChildExpression(exp); exp = cexp; suppliedCard = StaticProperty.ALLOWS_ZERO_OR_ONE; cardOK = Cardinality.subsumes(reqCard, suppliedCard); } if (!itemTypeOK) { // rule 2 if (reqItemType.equals(BuiltInAtomicType.STRING)) { StringFn fn = (StringFn) SystemFunction.makeSystemFunction("string", new Expression[]{exp}); try { exp = visitor.typeCheck(visitor.simplify(fn), AnyItemType.getInstance()); } catch (XPathException err) { err.maybeSetLocation(exp); throw err.makeStatic(); } suppliedItemType = BuiltInAtomicType.STRING; suppliedCard = StaticProperty.EXACTLY_ONE; cardOK = Cardinality.subsumes(reqCard, suppliedCard); itemTypeOK = true; } // rule 3 if (reqItemType.equals(BuiltInAtomicType.NUMERIC) || reqItemType.equals(BuiltInAtomicType.DOUBLE)) { NumberFn fn = (NumberFn)SystemFunction.makeSystemFunction("number", new Expression[]{exp}); try { exp = visitor.typeCheck(visitor.simplify(fn), AnyItemType.getInstance()); } catch (XPathException err) { err.maybeSetLocation(exp); throw err.makeStatic(); } suppliedItemType = BuiltInAtomicType.DOUBLE; suppliedCard = StaticProperty.EXACTLY_ONE; cardOK = Cardinality.subsumes(reqCard, suppliedCard); itemTypeOK = true; } } } if (!itemTypeOK) { // Now apply the conversions needed in 2.0 mode if (reqItemType.isAtomicType()) { // rule 1: Atomize if (!(suppliedItemType.isAtomicType()) && !(suppliedCard == StaticProperty.EMPTY)) { Expression cexp = new Atomizer(exp, env.getConfiguration()).simplify(visitor); ExpressionTool.copyLocationInfo(exp, cexp); exp = cexp; suppliedItemType = exp.getItemType(th); suppliedCard = exp.getCardinality(); cardOK = Cardinality.subsumes(reqCard, suppliedCard); } // rule 2: convert untypedAtomic to the required type // 2a: all supplied values are untyped atomic. Convert if necessary, and we're finished. if ((suppliedItemType.equals(BuiltInAtomicType.UNTYPED_ATOMIC)) && !(reqItemType.equals(BuiltInAtomicType.UNTYPED_ATOMIC) || reqItemType.equals(BuiltInAtomicType.ANY_ATOMIC))) { Expression cexp = new UntypedAtomicConverter(exp, (AtomicType)reqItemType, true); ExpressionTool.copyLocationInfo(exp, cexp); try { if (exp instanceof Literal) { exp = Literal.makeLiteral( new SequenceExtent(cexp.iterate(env.makeEarlyEvaluationContext())).simplify()); } else { exp = cexp; } } catch (XPathException err) { err.maybeSetLocation(exp); err.setErrorCode(role.getErrorCode()); throw err.makeStatic(); } itemTypeOK = true; suppliedItemType = reqItemType; } // 2b: some supplied values are untyped atomic. Convert these to the required type; but // there may be other values in the sequence that won't convert and still need to be checked if ((suppliedItemType.equals(BuiltInAtomicType.ANY_ATOMIC)) && !(reqItemType.equals(BuiltInAtomicType.UNTYPED_ATOMIC) || reqItemType.equals(BuiltInAtomicType.ANY_ATOMIC)) && (exp.getSpecialProperties()&StaticProperty.NOT_UNTYPED) ==0 ) { Expression cexp = new UntypedAtomicConverter(exp, (AtomicType)reqItemType, false); ExpressionTool.copyLocationInfo(exp, cexp); try { if (exp instanceof Literal) { exp = Literal.makeLiteral( new SequenceExtent(cexp.iterate(env.makeEarlyEvaluationContext())).simplify()); } else { exp = cexp; } suppliedItemType = exp.getItemType(th); } catch (XPathException err) { err.maybeSetLocation(exp); throw err.makeStatic(); } } // Rule 3a: numeric promotion decimal -> float -> double int rt = ((AtomicType)reqItemType).getFingerprint(); if ((rt == StandardNames.XS_DOUBLE && th.relationship(suppliedItemType, BuiltInAtomicType.NUMERIC) != TypeHierarchy.DISJOINT) || (rt == StandardNames.XS_FLOAT && th.relationship(suppliedItemType, BuiltInAtomicType.NUMERIC) != TypeHierarchy.DISJOINT) && !th.isSubType(suppliedItemType, BuiltInAtomicType.DOUBLE)) { Expression cexp = new NumericPromoter(exp, (BuiltInAtomicType)reqItemType.getPrimitiveItemType()); ExpressionTool.copyLocationInfo(exp, cexp); exp = cexp; try { exp = visitor.typeCheck(visitor.simplify(exp), AnyItemType.getInstance()); } catch (XPathException err) { err.maybeSetLocation(exp); throw err.makeStatic(); } suppliedItemType = (rt == StandardNames.XS_DOUBLE ? BuiltInAtomicType.DOUBLE : BuiltInAtomicType.FLOAT); suppliedCard = -1; } // Rule 3b: promotion from anyURI -> string if (rt == StandardNames.XS_STRING && th.isSubType(suppliedItemType, BuiltInAtomicType.ANY_URI)) { suppliedItemType = BuiltInAtomicType.STRING; itemTypeOK = true; // we don't generate code to do a run-time type conversion; rather, we rely on // operators and functions that accept a string to also accept an xs:anyURI. This // is straightforward, because anyURIValue is a subclass of StringValue } } } // If both the cardinality and item type are statically OK, return now. if (itemTypeOK && cardOK) { return exp; } // If we haven't evaluated the cardinality of the supplied expression, do it now if (suppliedCard == -1) { suppliedCard = exp.getCardinality(); if (!cardOK) { cardOK = Cardinality.subsumes(reqCard, suppliedCard); } } // If an empty sequence was explicitly supplied, and empty sequence is allowed, // then the item type doesn't matter if (cardOK && suppliedCard==StaticProperty.EMPTY) { return exp; } // If the supplied value is () and () isn't allowed, fail now if (suppliedCard==StaticProperty.EMPTY && ((reqCard & StaticProperty.ALLOWS_ZERO) == 0) ) { XPathException err = new XPathException("An empty sequence is not allowed as the " + role.getMessage(), supplied); err.setErrorCode(role.getErrorCode()); err.setIsTypeError(true); err.setLocator(exp); throw err; } // Try a static type check. We only throw it out if the call cannot possibly succeed. int relation = (itemTypeOK ? TypeHierarchy.SUBSUMED_BY : th.relationship(suppliedItemType, reqItemType)); if (relation == TypeHierarchy.DISJOINT) { // The item types may be disjoint, but if both the supplied and required types permit // an empty sequence, we can't raise a static error. Raise a warning instead. if (Cardinality.allowsZero(suppliedCard) && Cardinality.allowsZero(reqCard)) { if (suppliedCard != StaticProperty.EMPTY) { String msg = "Required item type of " + role.getMessage() + " is " + reqItemType.toString(env.getNamePool()) + "; supplied value has item type " + suppliedItemType.toString(env.getNamePool()) + ". The expression can succeed only if the supplied value is an empty sequence."; env.issueWarning(msg, supplied); } } else { XPathException err = new XPathException("Required item type of " + role.getMessage() + " is " + reqItemType.toString(env.getNamePool()) + "; supplied value has item type " + suppliedItemType.toString(env.getNamePool()), supplied); err.setErrorCode(role.getErrorCode()); err.setIsTypeError(true); err.setLocator(supplied); throw err; } } // Unless the type is guaranteed to match, add a dynamic type check, // unless the value is already known in which case we might as well report // the error now. if (!(relation == TypeHierarchy.SAME_TYPE || relation == TypeHierarchy.SUBSUMED_BY)) { if (exp instanceof Literal) { XPathException err = new XPathException("Required item type of " + role.getMessage() + " is " + reqItemType.toString(env.getNamePool()) + "; supplied value has item type " + suppliedItemType.toString(env.getNamePool()), supplied); err.setErrorCode(role.getErrorCode()); err.setIsTypeError(true); err.setLocator(supplied); throw err; } Expression cexp = new ItemChecker(exp, reqItemType, role); ExpressionTool.copyLocationInfo(exp, cexp); exp = cexp; } if (!cardOK) { if (exp instanceof Literal) { XPathException err = new XPathException("Required cardinality of " + role.getMessage() + " is " + Cardinality.toString(reqCard) + "; supplied value has cardinality " + Cardinality.toString(suppliedCard), supplied); err.setIsTypeError(true); err.setErrorCode(role.getErrorCode()); err.setLocator(supplied); throw err; } else { Expression cexp = CardinalityChecker.makeCardinalityChecker(exp, reqCard, role); ExpressionTool.copyLocationInfo(exp, cexp); exp = cexp; } } return exp; } /** * Check an expression against a required type, modifying it if necessary. This * is a variant of the method {@link #staticTypeCheck} used for expressions that * declare variables in XQuery. In these contexts, conversions such as numeric * type promotion and atomization are not allowed. * * @param supplied The expression to be type-checked * @param req The required type for the context in which the expression is used * @param role Information about the role of the subexpression within the * containing expression, used to provide useful error messages * @param env The static context containing the types being checked. At present * this is used only to locate a NamePool * @return The original expression if it is type-safe, or the expression * wrapped in a run-time type checking expression if not. * @throws XPathException if the supplied type is statically inconsistent with the * required type (that is, if they have no common subtype) */ public static Expression strictTypeCheck(Expression supplied, SequenceType req, RoleLocator role, StaticContext env) throws XPathException { // System.err.println("Strict Type Check on expression (requiredType = " + req + "):"); supplied.display(10); Expression exp = supplied; final TypeHierarchy th = env.getConfiguration().getTypeHierarchy(); ItemType reqItemType = req.getPrimaryType(); int reqCard = req.getCardinality(); ItemType suppliedItemType = null; // item type of the supplied expression: null means not yet calculated int suppliedCard = -1; // cardinality of the supplied expression: -1 means not yet calculated boolean cardOK = (reqCard == StaticProperty.ALLOWS_ZERO_OR_MORE); // Unless the required cardinality is zero-or-more (no constraints). // check the static cardinality of the supplied expression if (!cardOK) { suppliedCard = exp.getCardinality(); cardOK = Cardinality.subsumes(reqCard, suppliedCard); } boolean itemTypeOK = req.getPrimaryType() instanceof AnyItemType; // Unless the required item type and content type are ITEM (no constraints) // check the static item type against the supplied expression. // NOTE: we don't currently do any static inference regarding the content type if (!itemTypeOK) { suppliedItemType = exp.getItemType(th); int relation = th.relationship(reqItemType, suppliedItemType); itemTypeOK = relation == TypeHierarchy.SAME_TYPE || relation == TypeHierarchy.SUBSUMES; } // If both the cardinality and item type are statically OK, return now. if (itemTypeOK && cardOK) { return exp; } // If we haven't evaluated the cardinality of the supplied expression, do it now if (suppliedCard == -1) { if (suppliedItemType instanceof EmptySequenceTest) { suppliedCard = StaticProperty.EMPTY; } else { suppliedCard = exp.getCardinality(); } if (!cardOK) { cardOK = Cardinality.subsumes(reqCard, suppliedCard); } } // If an empty sequence was explicitly supplied, and empty sequence is allowed, // then the item type doesn't matter if (cardOK && suppliedCard==StaticProperty.EMPTY) { return exp; } // If we haven't evaluated the item type of the supplied expression, do it now if (suppliedItemType == null) { suppliedItemType = exp.getItemType(th); } if (suppliedCard==StaticProperty.EMPTY && ((reqCard & StaticProperty.ALLOWS_ZERO) == 0) ) { XPathException err = new XPathException("An empty sequence is not allowed as the " + role.getMessage(), supplied); err.setErrorCode(role.getErrorCode()); err.setIsTypeError(true); err.setLocator(exp); throw err; } // Try a static type check. We only throw it out if the call cannot possibly succeed. int relation = th.relationship(suppliedItemType, reqItemType); if (relation == TypeHierarchy.DISJOINT) { // The item types may be disjoint, but if both the supplied and required types permit // an empty sequence, we can't raise a static error. Raise a warning instead. if (Cardinality.allowsZero(suppliedCard) && Cardinality.allowsZero(reqCard)) { if (suppliedCard != StaticProperty.EMPTY) { String msg = "Required item type of " + role.getMessage() + " is " + reqItemType.toString(env.getNamePool()) + "; supplied value has item type " + suppliedItemType.toString(env.getNamePool()) + ". The expression can succeed only if the supplied value is an empty sequence."; env.issueWarning(msg, supplied); } } else { XPathException err = new XPathException("Required item type of " + role.getMessage() + " is " + reqItemType.toString(env.getNamePool()) + "; supplied value has item type " + suppliedItemType.toString(env.getNamePool()), supplied); err.setErrorCode(role.getErrorCode()); err.setIsTypeError(true); err.setLocator(exp); throw err; } } // Unless the type is guaranteed to match, add a dynamic type check, // unless the value is already known in which case we might as well report // the error now. if (!(relation == TypeHierarchy.SAME_TYPE || relation == TypeHierarchy.SUBSUMED_BY)) { Expression cexp = new ItemChecker(exp, reqItemType, role); cexp.adoptChildExpression(exp); exp = cexp; } if (!cardOK) { if (exp instanceof Literal) { XPathException err = new XPathException("Required cardinality of " + role.getMessage() + " is " + Cardinality.toString(reqCard) + "; supplied value has cardinality " + Cardinality.toString(suppliedCard), supplied); err.setIsTypeError(true); err.setErrorCode(role.getErrorCode()); throw err; } else { Expression cexp = CardinalityChecker.makeCardinalityChecker(exp, reqCard, role); cexp.adoptChildExpression(exp); exp = cexp; } } return exp; } /** * Test whether a given value conforms to a given type * @param val the value * @param requiredType the required type * @param context XPath dynamic context * @return an XPathException describing the error condition if the value doesn't conform; * or null if it does. * @throws XPathException if a failure occurs reading the value */ public static XPathException testConformance( ValueRepresentation val, SequenceType requiredType, XPathContext context) throws XPathException { ItemType reqItemType = requiredType.getPrimaryType(); final Configuration config = context.getConfiguration(); final TypeHierarchy th = config.getTypeHierarchy(); SequenceIterator iter = Value.asIterator(val); int count = 0; while (true) { Item item = iter.next(); if (item == null) { break; } count++; if (!reqItemType.matchesItem(item, false, config)) { XPathException err = new XPathException("Required type is " + reqItemType + "; supplied value has type " + Value.asValue(val).getItemType(th)); err.setIsTypeError(true); err.setErrorCode("XPTY0004"); return err; } } int reqCardinality = requiredType.getCardinality(); if (count == 0 && !Cardinality.allowsZero(reqCardinality)) { XPathException err = new XPathException( "Required type does not allow empty sequence, but supplied value is empty"); err.setIsTypeError(true); err.setErrorCode("XPTY0004"); return err; } if (count > 1 && !Cardinality.allowsMany(reqCardinality)) { XPathException err = new XPathException( "Required type requires a singleton sequence; supplied value contains " + count + " items"); err.setIsTypeError(true); err.setErrorCode("XPTY0004"); return err; } if (count > 0 && reqCardinality == StaticProperty.EMPTY) { XPathException err = new XPathException( "Required type requires an empty sequence, but supplied value is non-empty"); err.setIsTypeError(true); err.setErrorCode("XPTY0004"); return err; } return null; } /** * Test whether a given expression is capable of returning a value that has an effective boolean * value. * @param exp the given expression * @param th the type hierarchy cache * @return null if the expression is OK (optimistically), an exception object if not */ public static XPathException ebvError(Expression exp, TypeHierarchy th) { if (Cardinality.allowsZero(exp.getCardinality())) { return null; } ItemType t = exp.getItemType(th); if (th.relationship(t, Type.NODE_TYPE) == TypeHierarchy.DISJOINT && th.relationship(t, BuiltInAtomicType.BOOLEAN) == TypeHierarchy.DISJOINT && th.relationship(t, BuiltInAtomicType.STRING) == TypeHierarchy.DISJOINT && th.relationship(t, BuiltInAtomicType.ANY_URI) == TypeHierarchy.DISJOINT && th.relationship(t, BuiltInAtomicType.UNTYPED_ATOMIC) == TypeHierarchy.DISJOINT && th.relationship(t, BuiltInAtomicType.NUMERIC) == TypeHierarchy.DISJOINT && !(t instanceof ExternalObjectType)) { XPathException err = new XPathException( "Effective boolean value is defined only for sequences containing " + "booleans, strings, numbers, URIs, or nodes"); err.setErrorCode("FORG0006"); err.setIsTypeError(true); return err; } return null; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/expr/IsLastExpression.java0000644000175000017500000000671211033112257022505 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.trace.ExpressionPresenter; import net.sf.saxon.om.Item; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.BuiltInAtomicType; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.TypeHierarchy; import net.sf.saxon.value.BooleanValue; /** * A position() eq last() expression, generated by the optimizer. */ public final class IsLastExpression extends Expression { private boolean condition; /** * Construct a condition that tests position() eq last() (if condition * is true) or position() ne last() (if condition is false). * @param condition true if we are testing "equals", false for "not equals". */ public IsLastExpression(boolean condition){ this.condition = condition; } /** * Get the condition we are testing for * @return true if we are testing "equals", false for "not equals". */ public boolean getCondition() { return condition; } public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) { return this; } public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) { return this; } /** * Determine the special properties of this expression * @return {@link StaticProperty#NON_CREATIVE}. */ public int computeSpecialProperties() { int p = super.computeSpecialProperties(); return p | StaticProperty.NON_CREATIVE; } public Item evaluateItem(XPathContext c) throws XPathException { return BooleanValue.get(condition==c.isAtLast()); } /** * Determine the data type of the expression * @return Type.BOOLEAN * @param th the type hierarchy cache */ public ItemType getItemType(TypeHierarchy th) { return BuiltInAtomicType.BOOLEAN; } /** * Determine the static cardinality */ public int computeCardinality() { return StaticProperty.EXACTLY_ONE; } /** * Get the dependencies of this expression on the context */ public int getIntrinsicDependencies() { return StaticProperty.DEPENDS_ON_POSITION | StaticProperty.DEPENDS_ON_LAST; } /** * Copy an expression. This makes a deep copy. * @return the copy of the original expression */ public Expression copy() { return new IsLastExpression(condition); } /** * Diagnostic print of expression structure. The abstract expression tree * is written to the supplied output destination. */ public void explain(ExpressionPresenter destination) { destination.startElement("isLast"); destination.emitAttribute("condition", (condition ? "true" : "false")); destination.endElement(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/expr/MonoIterator.java0000644000175000017500000000522011033112257021641 0ustar eugeneeugenepackage net.sf.saxon.expr; import java.util.Iterator; import java.util.NoSuchElementException; /** * An iterator over a single object (typically a sub-expression of an expression) */ public class MonoIterator implements Iterator { private Object thing; // the single object in the collection private boolean gone; // true if the single object has already been returned /** * Create an iterator of the single object supplied * @param thing the object to be iterated over */ public MonoIterator(Object thing) { gone = false; this.thing = thing; } /** * Returns true if the iteration has more elements. (In other * words, returns true if next would return an element * rather than throwing an exception.) * * @return true if the iterator has more elements. */ public boolean hasNext() { return !gone; } /** * Returns the next element in the iteration. * * @return the next element in the iteration. * @exception NoSuchElementException iteration has no more elements. */ public Object next() { if (gone) { throw new NoSuchElementException(); } else { gone = true; return thing; } } /** * * Removes from the underlying collection the last element returned by the * iterator (optional operation). This method can be called only once per * call to next. The behavior of an iterator is unspecified if * the underlying collection is modified while the iteration is in * progress in any way other than by calling this method. * * @exception UnsupportedOperationException if the remove * operation is not supported by this Iterator (which is the * case for this iterator). */ public void remove() { throw new UnsupportedOperationException(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): Michael Kay // saxonb-9.1.0.8/bj/net/sf/saxon/expr/ReversibleIterator.java0000644000175000017500000000260211033112257023034 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.om.SequenceIterator; /** * A ReversibleIterator is an interface implemented by any SequenceIterator that is * able to deliver items in reverse order (or to supply another iterator that can * do so). */ public interface ReversibleIterator extends SequenceIterator { /** * Get a new SequenceIterator that returns the same items in reverse order. * If this SequenceIterator is an AxisIterator, then the returned SequenceIterator * must also be an AxisIterator. * @return an iterator over the items in reverse order */ public SequenceIterator getReverseIterator(); } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/expr/EarlyEvaluationContext.java0000644000175000017500000003363011033112257023676 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.Configuration; import net.sf.saxon.Controller; import net.sf.saxon.trace.InstructionInfo; import net.sf.saxon.value.DateTimeValue; import net.sf.saxon.event.SequenceReceiver; import net.sf.saxon.instruct.LocalParam; import net.sf.saxon.instruct.ParameterSet; import net.sf.saxon.om.*; import net.sf.saxon.regex.RegexIterator; import net.sf.saxon.sort.GroupIterator; import net.sf.saxon.sort.StringCollator; import net.sf.saxon.trans.Mode; import net.sf.saxon.trans.Rule; import net.sf.saxon.trans.XPathException; import net.sf.saxon.trans.NoDynamicContextException; import net.sf.saxon.type.SchemaType; import javax.xml.transform.Result; import java.io.Serializable; import java.util.Properties; import java.util.Iterator; import java.util.Collections; /** * This class is an implementation of XPathContext used when evaluating constant sub-expressions at * compile time. */ public class EarlyEvaluationContext implements XPathContext, Serializable { private CollationMap collationMap; private Configuration config; /** * Create an early evaluation context, used for evaluating constant expressions at compile time * @param config the Saxon configuration * @param map the available collations */ public EarlyEvaluationContext(Configuration config, CollationMap map) { this.config = config; collationMap = map; } /** * Set a new output destination, supplying the output format details.
    * Note that it is the caller's responsibility to close the Writer after use. * * @param props properties defining the output format * @param result Details of the new output destination * @param isFinal true if the destination is a final result tree * (either the principal output or a secondary result tree); false if * it is a temporary tree, xsl:attribute, etc. * @param hostLanguage the host language (XSLT, XQuery, XPath) * @throws net.sf.saxon.trans.XPathException * if any dynamic error occurs; and * specifically, if an attempt is made to switch to a final output * destination while writing a temporary tree or sequence */ public void changeOutputDestination(Properties props, Result result, boolean isFinal, int hostLanguage, int validation, SchemaType schemaType) throws XPathException { notAllowed(); } /** * Get the value of a local variable, identified by its slot number */ public ValueRepresentation evaluateLocalVariable(int slotnumber) { notAllowed(); return null; } /** * Get the calling XPathContext (the next one down the stack). This will be null if unknown, or * if the bottom of the stack has been reached. */ public XPathContext getCaller() { return null; } /** * Get a named collation */ public StringCollator getCollation(String name) throws XPathException { return collationMap.getNamedCollation(name); } /** * Get the Configuration */ public Configuration getConfiguration() { return config; } /** * Get the context item * * @return the context item, or null if the context item is undefined */ public Item getContextItem() { return null; } /** * Get the context position (the position of the context item) * * @return the context position (starting at one) * @throws XPathException * if the context position is undefined */ public int getContextPosition() throws XPathException { XPathException err = new XPathException("The context position is undefined"); err.setErrorCode("FONC0001"); throw err; } /** * Get the Controller. May return null when running outside XSLT or XQuery */ public Controller getController() { return null; } /** * Get the current group iterator. This supports the current-group() and * current-grouping-key() functions in XSLT 2.0 * * @return the current grouped collection */ public GroupIterator getCurrentGroupIterator() { notAllowed(); return null; } /** * Get the current iterator. * This encapsulates the context item, context position, and context size. * * @return the current iterator, or null if there is no current iterator * (which means the context item, position, and size are undefined). */ public SequenceIterator getCurrentIterator() { return null; } /** * Get the current mode. * * @return the current mode */ public Mode getCurrentMode() { notAllowed(); return null; } /** * Get the current regex iterator. This supports the functionality of the regex-group() * function in XSLT 2.0. * * @return the current regular expressions iterator */ public RegexIterator getCurrentRegexIterator() { return null; } /** * Get the current template. This is used to support xsl:apply-imports * * @return the current template */ public Rule getCurrentTemplateRule() { return null; } /** * Get the default collation */ public StringCollator getDefaultCollation() { return collationMap.getDefaultCollation(); } /** * Get the context size (the position of the last item in the current node list) * * @return the context size * @throws net.sf.saxon.trans.XPathException * if the context position is undefined */ public int getLast() throws XPathException { XPathException err = new XPathException("The context item is undefined"); err.setErrorCode("XPDY0002"); throw err; } /** * Get the local (non-tunnel) parameters that were passed to the current function or template * * @return a ParameterSet containing the local parameters */ public ParameterSet getLocalParameters() { notAllowed(); return null; } /** * Get the Name Pool */ public NamePool getNamePool() { return config.getNamePool(); } /** * Get information about the creating expression or other construct. */ public InstructionInfo getOrigin() { return null; } /** * Get the type of location from which this context was created. */ public int getOriginatingConstructType() { return -1; } /** * Get the Receiver to which output is currently being written. * * @return the current Receiver */ public SequenceReceiver getReceiver() { notAllowed(); return null; } /** * Get a reference to the local stack frame for variables. Note that it's * the caller's job to make a local copy of this. This is used for creating * a Closure containing a retained copy of the variables for delayed evaluation. * * @return array of variables. */ public StackFrame getStackFrame() { notAllowed(); return null; } /** * Get the tunnel parameters that were passed to the current function or template. This includes all * active tunnel parameters whether the current template uses them or not. * * @return a ParameterSet containing the tunnel parameters */ public ParameterSet getTunnelParameters() { notAllowed(); return null; } /** * Determine whether the context position is the same as the context size * that is, whether position()=last() */ public boolean isAtLast() throws XPathException { XPathException err = new XPathException("The context item is undefined"); err.setErrorCode("XPDY0002"); throw err; } /** * Construct a new context without copying (used for the context in a function call) */ public XPathContextMajor newCleanContext() { notAllowed(); return null; } /** * Construct a new context as a copy of another. The new context is effectively added * to the top of a stack, and contains a pointer to the previous context */ public XPathContextMajor newContext() { Controller controller = new Controller(config); return controller.newXPathContext(); // notAllowed(); // return null; } /** * Construct a new minor context. A minor context can only hold new values of the focus * (currentIterator) and current output destination. */ public XPathContextMinor newMinorContext() { return newContext().newMinorContext(); // notAllowed(); // return null; } /** * Set the calling XPathContext */ public void setCaller(XPathContext caller) { // no-op } /** * Set a new sequence iterator. */ public void setCurrentIterator(SequenceIterator iter) { notAllowed(); } /** * Set the value of a local variable, identified by its slot number */ public void setLocalVariable(int slotnumber, ValueRepresentation value) { notAllowed(); } /** * Set the creating expression (for use in diagnostics). The origin is generally set to "this" by the * object that creates the new context. It's up to the debugger to determine whether this information * is useful. Where possible, the object will be an {@link Expression}, allowing information * about the calling instruction to be obtained. */ public void setOrigin(InstructionInfo expr) { // no-op } /** * Set the type of creating expression (for use in diagnostics). When a new context is created, either * this method or {@link XPathContext#setOrigin} should be called. * * @param loc The originating location: the argument must be one of the integer constants in class * {@link net.sf.saxon.trace.Location} */ public void setOriginatingConstructType(int loc) { // no-op } /** * Change the Receiver to which output is written */ public void setReceiver(SequenceReceiver receiver) { notAllowed(); } /** * Set the receiver to which output is to be written, marking it as a temporary (non-final) * output destination. * * @param out The SequenceOutputter to be used */ public void setTemporaryReceiver(SequenceReceiver out) { notAllowed(); } /** * Use local parameter. This is called when a local xsl:param element is processed. * If a parameter of the relevant name was supplied, it is bound to the xsl:param element. * Otherwise the method returns false, so the xsl:param default will be evaluated * * @param qName The fingerprint of the parameter name * @param binding The XSLParam element to bind its value to * @param isTunnel True if a tunnel parameter is required, else false * @return true if a parameter of this name was supplied, false if not */ public boolean useLocalParameter(StructuredQName qName, LocalParam binding, boolean isTunnel) throws XPathException { return false; } /** * Get the current date and time. This implementation always throws a * NoDynamicContextException. * @return the current date and time. All calls within a single query or transformation * will return the same value */ public DateTimeValue getCurrentDateTime() throws NoDynamicContextException { throw new NoDynamicContextException("current-dateTime"); } /** * Get the implicit timezone, as a positive or negative offset from UTC in minutes. * The range is -14hours to +14hours. This implementation always throws a * NoDynamicContextException. * @return the implicit timezone, as an offset from UTC in minutes */ public int getImplicitTimezone() throws NoDynamicContextException{ throw new NoDynamicContextException("implicit-timezone"); } /** * Get the context stack. This method returns an iterator whose items are instances of * {@link net.sf.saxon.trace.ContextStackFrame}, starting with the top-most stackframe and * ending at the point the query or transformation was invoked by a calling application. * * @return an iterator over a copy of the run-time call stack */ public Iterator iterateStackFrames() { return Collections.EMPTY_LIST.iterator(); } /** * Throw an error for operations that aren't supported when doing early evaluation of constant * subexpressions */ private void notAllowed() { throw new UnsupportedOperationException("Internal error: early evaluation of subexpression with no context"); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/expr/CompareToIntegerConstant.java0000644000175000017500000003562611033112257024155 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.trace.ExpressionPresenter; import net.sf.saxon.om.Item; import net.sf.saxon.sort.AtomicComparer; import net.sf.saxon.sort.DoubleSortComparer; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.BuiltInAtomicType; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.TypeHierarchy; import net.sf.saxon.value.BooleanValue; import net.sf.saxon.value.Int64Value; import net.sf.saxon.value.NumericValue; import java.util.Iterator; /** * This class implements a comparison of a numeric value to an integer constant using one of the operators * eq, ne, lt, gt, le, ge. The semantics are identical to ValueComparison, but this is a fast path for an * important common case. */ public class CompareToIntegerConstant extends Expression implements ComparisonExpression { private Expression operand; private long comparand; private int operator; /** * Create the expression * @param operand the operand to be compared with an integer constant * @param operator the comparison operator, * one of {@link Token#FEQ}, {@link Token#FNE}, {@link Token#FGE}, * {@link Token#FGT}, {@link Token#FLE}, {@link Token#FLT} * @param comparand the integer constant */ public CompareToIntegerConstant(Expression operand, int operator, long comparand) { this.operand = operand; this.operator = operator; this.comparand = comparand; adoptChildExpression(operand); } /** * Get the expression on the lhs of the comparison * @return the left hand operand */ public Expression getOperand() { return operand; } /** * Get the integer value on the rhs of the expression * @return the integer constant */ public long getComparand() { return comparand; } /** * Get the comparison operator * @return one of {@link Token#FEQ}, {@link Token#FNE}, {@link Token#FGE}, * {@link Token#FGT}, {@link Token#FLE}, {@link Token#FLT} */ public int getComparisonOperator() { return operator; } /** * An implementation of Expression must provide at least one of the methods evaluateItem(), iterate(), or process(). * This method indicates which of these methods is provided directly. The other methods will always be available * indirectly, using an implementation that relies on one of the other methods. * @return the value {@link #EVALUATE_METHOD} */ public int getImplementationMethod() { return EVALUATE_METHOD; } /** * Simplify an expression. This performs any static optimization (by rewriting the expression * as a different expression). The default implementation does nothing. * @param visitor the expression visitor * @return the simplified expression * @throws XPathException * if an error is discovered during expression * rewriting */ public Expression simplify(ExpressionVisitor visitor) throws XPathException { operand = visitor.simplify(operand); return this; } /** * Offer promotion for this subexpression. The offer will be accepted if the subexpression * is not dependent on the factors (e.g. the context item) identified in the PromotionOffer. * By default the offer is not accepted - this is appropriate in the case of simple expressions * such as constant values and variable references where promotion would give no performance * advantage. This method is always called at compile time. * * @param offer details of the offer, for example the offer to move * expressions that don't depend on the context to an outer level in * the containing expression * @return if the offer is not accepted, return this expression unchanged. * Otherwise return the result of rewriting the expression to promote * this subexpression * @throws net.sf.saxon.trans.XPathException * if any error is detected */ public Expression promote(PromotionOffer offer) throws XPathException { Expression exp = offer.accept(this); if (exp != null) { return exp; } else { operand = doPromotion(operand, offer); return this; } } public int computeSpecialProperties() { return StaticProperty.NON_CREATIVE; } /** * Compute the dependencies of an expression, as the union of the * dependencies of its subexpressions. (This is overridden for path expressions * and filter expressions, where the dependencies of a subexpression are not all * propogated). This method should be called only once, to compute the dependencies; * after that, getDependencies should be used. * * @return the depencies, as a bit-mask */ public int computeDependencies() { return operand.getDependencies(); } /** * Copy an expression. This makes a deep copy. * * @return the copy of the original expression */ public Expression copy() { return new CompareToIntegerConstant(operand.copy(), operator, comparand); } /** * Get the immediate sub-expressions of this expression. Default implementation * returns a zero-length array, appropriate for an expression that has no * sub-expressions. * * @return an iterator containing the sub-expressions of this expression */ public Iterator iterateSubExpressions() { return new MonoIterator(operand); } /** * Replace one subexpression by a replacement subexpression * * @param original the original subexpression * @param replacement the replacement subexpression * @return true if the original subexpression is found */ public boolean replaceSubExpression(Expression original, Expression replacement) { if (original == operand) { operand = replacement; return true; } return false; } /** * Evaluate an expression as a single item. This always returns either a single Item or * null (denoting the empty sequence). No conversion is done. This method should not be * used unless the static type of the expression is a subtype of "item" or "item?": that is, * it should not be called if the expression may return a sequence. There is no guarantee that * this condition will be detected. * * @param context The context in which the expression is to be evaluated * @return the node or atomic value that results from evaluating the * expression; or null to indicate that the result is an empty * sequence * @throws net.sf.saxon.trans.XPathException * if any dynamic error occurs evaluating the * expression */ public Item evaluateItem(XPathContext context) throws XPathException { return BooleanValue.get(effectiveBooleanValue(context)); } /** * Get the effective boolean value of the expression. This returns false if the value * is the empty sequence, a zero-length string, a number equal to zero, or the boolean * false. Otherwise it returns true. * * @param context The context in which the expression is to be evaluated * @return the effective boolean value * @throws net.sf.saxon.trans.XPathException * if any dynamic error occurs evaluating the * expression */ public boolean effectiveBooleanValue(XPathContext context) throws XPathException { NumericValue n = (NumericValue)operand.evaluateItem(context); if (n.isNaN()) { return (operator == Token.FNE); } int c = n.compareTo(comparand); switch (operator) { case Token.FEQ: return c == 0; case Token.FNE: return c != 0; case Token.FGT: return c > 0; case Token.FLT: return c < 0; case Token.FGE: return c >= 0; case Token.FLE: return c <= 0; default: throw new UnsupportedOperationException("Unknown operator " + operator); } } protected int computeCardinality() { return StaticProperty.EXACTLY_ONE; } /** * Perform type checking of an expression and its subexpressions. This is the second phase of * static optimization. *

    *

    This checks statically that the operands of the expression have * the correct type; if necessary it generates code to do run-time type checking or type * conversion. A static type error is reported only if execution cannot possibly succeed, that * is, if a run-time type error is inevitable. The call may return a modified form of the expression.

    *

    *

    This method is called after all references to functions and variables have been resolved * to the declaration of the function or variable. However, the types of such functions and * variables may not be accurately known if they have not been explicitly declared.

    *

    *

    If the implementation returns a value other than "this", then it is required to ensure that * the parent pointer and location information in the returned expression have been set up correctly. * It should not rely on the caller to do this, although for historical reasons many callers do so.

    * * @param visitor the expession visitor * @param contextItemType the static type of "." at the point where this expression is invoked. * The parameter is set to null if it is known statically that the context item will be undefined. * If the type of the context item is not known statically, the argument is set to * {@link net.sf.saxon.type.Type#ITEM_TYPE} * @return the original expression, rewritten to perform necessary run-time type checks, * and to perform other type-related optimizations * @throws XPathException if an error is discovered during this phase * (typically a type error) */ public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { operand = visitor.typeCheck(operand, contextItemType); return this; } /** * Perform optimisation of an expression and its subexpressions. This is the third and final * phase of static optimization. *

    *

    This method is called after all references to functions and variables have been resolved * to the declaration of the function or variable, and after all type checking has been done.

    * * @param visitor the expression visitor * @param contextItemType the static type of "." at the point where this expression is invoked. * The parameter is set to null if it is known statically that the context item will be undefined. * If the type of the context item is not known statically, the argument is set to * {@link net.sf.saxon.type.Type#ITEM_TYPE} * @return the original expression, rewritten if appropriate to optimize execution * @throws XPathException if an error is discovered during this phase * (typically a type error) */ public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { operand = visitor.optimize(operand, contextItemType); return this; } /** * Determine the data type of the expression, if possible. All expression return * sequences, in general; this method determines the type of the items within the * sequence, assuming that (a) this is known in advance, and (b) it is the same for * all items in the sequence. *

    *

    This method should always return a result, though it may be the best approximation * that is available at the time.

    * * @param th the type hierarchy cache * @return a value such as Type.STRING, Type.BOOLEAN, Type.NUMBER, * Type.NODE, or Type.ITEM (meaning not known at compile time) */ public ItemType getItemType(TypeHierarchy th) { return BuiltInAtomicType.BOOLEAN; } /** * Diagnostic print of expression structure. The abstract expression tree * is written to the supplied output destination. */ public void explain(ExpressionPresenter destination) { destination.startElement("compareToInteger"); destination.emitAttribute("op", Token.tokens[operator]); destination.emitAttribute("value", comparand+""); operand.explain(destination); destination.endElement(); } /** * Get the AtomicComparer used to compare atomic values. This encapsulates any collation that is used */ public AtomicComparer getAtomicComparer() { return DoubleSortComparer.getInstance(); // Note: this treats NaN=NaN as true, but it doesn't matter, because the rhs will never be NaN. } /** * Get the primitive (singleton) operator used: one of Token.FEQ, Token.FNE, Token.FLT, Token.FGT, * Token.FLE, Token.FGE */ public int getSingletonOperator() { return operator; } /** * Get the two operands of the comparison * @return the two operands */ public Expression[] getOperands() { return new Expression[] {operand, Literal.makeLiteral(Int64Value.makeIntegerValue(comparand))}; } /** * Determine whether untyped atomic values should be converted to the type of the other operand * * @return true if untyped values should be converted to the type of the other operand, false if they * should be converted to strings. */ public boolean convertsUntypedToOther() { return true; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/expr/SuppliedParameterReference.java0000644000175000017500000000773511033112257024501 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.trace.ExpressionPresenter; import net.sf.saxon.om.Item; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.om.ValueRepresentation; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.AnyItemType; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.TypeHierarchy; import net.sf.saxon.value.Value; /** * Supplied parameter reference: this is an internal expression used to refer to * the value of the n'th parameter supplied on a template call (apply-templates). * It is used within a type-checking expression designed to check the consistency * of the supplied value with the required type. This type checking is all done * at run-time, because the binding of apply-templates to actual template rules * is entirely dynamic. */ public class SuppliedParameterReference extends Expression { int slotNumber; /** * Constructor * @param slot identifies this parameter */ public SuppliedParameterReference(int slot) { slotNumber = slot; } public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { return this; } public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { return this; } /** * Determine the data type of the expression, if possible. * @return Type.ITEM, because we don't know the type of the supplied value * in advance. * @param th the type hierarchy cache */ public ItemType getItemType(TypeHierarchy th) { return AnyItemType.getInstance(); } /** * Get the static cardinality * @return ZERO_OR_MORE, because we don't know the type of the supplied value * in advance. */ public int computeCardinality() { return StaticProperty.ALLOWS_ZERO_OR_MORE; } /** * Copy an expression. This makes a deep copy. * * @return the copy of the original expression */ public Expression copy() { return new SuppliedParameterReference(slotNumber); } /** * Test if this expression is the same as another expression. * (Note, we only compare expressions that * have the same static and dynamic context). */ public boolean equals(Object other) { return this==other; } /** * Get the value of this expression in a given context. * @param c the XPathContext which contains the relevant variable bindings * @return the value of the variable, if it is defined * @throws XPathException if the variable is undefined */ public SequenceIterator iterate(XPathContext c) throws XPathException { return Value.getIterator(c.evaluateLocalVariable(slotNumber)); } public Item evaluateItem(XPathContext c) throws XPathException { ValueRepresentation actual = c.evaluateLocalVariable(slotNumber); return Value.asItem(actual); } /** * Diagnostic print of expression structure. The abstract expression tree * is written to the supplied output destination. */ public void explain(ExpressionPresenter destination) { destination.startElement("suppliedParameter"); destination.emitAttribute("slot", slotNumber+""); destination.endElement(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/expr/UnionEnumeration.java0000644000175000017500000001113211033112257022515 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.om.Item; import net.sf.saxon.om.LookaheadIterator; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.sort.NodeOrderComparer; import net.sf.saxon.trans.XPathException; /** * An enumeration representing a nodeset that is a union of two other NodeSets. */ public class UnionEnumeration implements SequenceIterator, LookaheadIterator { private SequenceIterator e1; private SequenceIterator e2; private NodeInfo nextNode1 = null; private NodeInfo nextNode2 = null; private NodeOrderComparer comparer; private NodeInfo current = null; private int position = 0; /** * Create the iterator. The two input iterators must return nodes in document * order for this to work. * @param p1 iterator over the first operand sequence (in document order) * @param p2 iterator over the second operand sequence * @param comparer used to test whether nodes are in document order. Different versions * are used for intra-document and cross-document operations */ public UnionEnumeration(SequenceIterator p1, SequenceIterator p2, NodeOrderComparer comparer) throws XPathException { this.e1 = p1; this.e2 = p2; this.comparer = comparer; nextNode1 = next(e1); nextNode2 = next(e2); } /** * Get the next item from one of the input sequences, * checking that it is a node. * @param iter the sequence from which a node is to be read * @return the node that was read */ private NodeInfo next(SequenceIterator iter) throws XPathException { return (NodeInfo)iter.next(); // we rely on the type-checking mechanism to prevent a ClassCastException here } public boolean hasNext() { return nextNode1!=null || nextNode2!=null; } public Item next() throws XPathException { // main merge loop: take a value from whichever set has the lower value position++; if (nextNode1 != null && nextNode2 != null) { int c = comparer.compare(nextNode1, nextNode2); if (c<0) { current = nextNode1; nextNode1 = next(e1); return current; } else if (c>0) { current = nextNode2; nextNode2 = next(e2); return current; } else { current = nextNode2; nextNode2 = next(e2); nextNode1 = next(e1); return current; } } // collect the remaining nodes from whichever set has a residue if (nextNode1!=null) { current = nextNode1; nextNode1 = next(e1); return current; } if (nextNode2!=null) { current = nextNode2; nextNode2 = next(e2); return current; } current = null; position = -1; return null; } public Item current() { return current; } public int position() { return position; } public void close() { e1.close(); e2.close(); } public SequenceIterator getAnother() throws XPathException { return new UnionEnumeration(e1.getAnother(), e2.getAnother(), comparer); } /** * Get properties of this iterator, as a bit-significant integer. * * @return the properties of this iterator. This will be some combination of * properties such as {@link #GROUNDED}, {@link #LAST_POSITION_FINDER}, * and {@link #LOOKAHEAD}. It is always * acceptable to return the value zero, indicating that there are no known special properties. * It is acceptable for the properties of the iterator to change depending on its state. */ public int getProperties() { return LOOKAHEAD; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/expr/JPConverter.java0000644000175000017500000006755011033112257021436 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.om.*; import net.sf.saxon.pattern.AnyNodeTest; import net.sf.saxon.trans.SaxonErrorCode; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.AnyItemType; import net.sf.saxon.type.BuiltInAtomicType; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.ExternalObjectType; import net.sf.saxon.value.*; import net.sf.saxon.Configuration; import javax.xml.transform.Source; import java.io.Serializable; import java.math.BigDecimal; import java.math.BigInteger; import java.net.URI; import java.net.URL; import java.util.*; /** * This class together with its embedded subclasses handles conversion from Java values to XPath values. * * The general principle is to allocate a specific JPConverter at compile time wherever possible. If there * is insufficient type information to make this feasible, a general-purpose JPConverter is allocated, which * in turn allocates a more specific converter at run-time to do the actual work. */ public abstract class JPConverter implements Serializable { private static HashMap map = new HashMap(); static { map.put(SequenceIterator.class, new FromSequenceIterator()); map.put(ValueRepresentation.class, FromValueRepresentation.INSTANCE); map.put(String.class, FromString.INSTANCE); map.put(Boolean.class, FromBoolean.INSTANCE); map.put(boolean.class, FromBoolean.INSTANCE); map.put(Double.class, FromDouble.INSTANCE); map.put(double.class, FromDouble.INSTANCE); map.put(Float.class, FromFloat.INSTANCE); map.put(float.class, FromFloat.INSTANCE); map.put(BigDecimal.class, FromBigDecimal.INSTANCE); map.put(BigInteger.class, FromBigInteger.INSTANCE); map.put(Long.class, FromLong.INSTANCE); map.put(long.class, FromLong.INSTANCE); map.put(Integer.class, FromInt.INSTANCE); map.put(int.class, FromInt.INSTANCE); map.put(Short.class, FromShort.INSTANCE); map.put(short.class, FromShort.INSTANCE); map.put(Byte.class, FromByte.INSTANCE); map.put(byte.class, FromByte.INSTANCE); map.put(Character.class, FromCharacter.INSTANCE); map.put(char.class, FromCharacter.INSTANCE); //map.put(QName.class, new FromQName()); map.put(URI.class, FromURI.INSTANCE); map.put(URL.class, FromURI.INSTANCE); map.put(Date.class, FromDate.INSTANCE); //map.put(Source.class, FromSource.INSTANCE); map.put(long[].class, FromLongArray.INSTANCE); map.put(int[].class, FromIntArray.INSTANCE); map.put(short[].class, FromShortArray.INSTANCE); map.put(byte[].class, FromByteArray.INSTANCE); map.put(char[].class, FromCharArray.INSTANCE); map.put(double[].class, FromDoubleArray.INSTANCE); map.put(float[].class, FromFloatArray.INSTANCE); map.put(boolean[].class, FromBooleanArray.INSTANCE); map.put(Collection.class, FromCollection.INSTANCE); //map.put(Object.class, FromExternalObject.INSTANCE); } public static JPConverter allocate(Class javaClass, Configuration config) { JPConverter c = (JPConverter)map.get(javaClass); if (c != null) { return c; } if (javaClass.getName().equals("javax.xml.namespace.QName")) { return FromQName.INSTANCE; } if (NodeInfo.class.isAssignableFrom(javaClass)) { return new FromValueRepresentation(AnyNodeTest.getInstance(), StaticProperty.ALLOWS_ZERO_OR_ONE); } if (Source.class.isAssignableFrom(javaClass)) { return FromSource.INSTANCE; } for (Iterator iter = map.keySet().iterator(); iter.hasNext();) { Class k = (Class)iter.next(); if (k.isAssignableFrom(javaClass)) { return (JPConverter)map.get(k); } } List externalObjectModels = config.getExternalObjectModels(); for (int m=0; m= start. */ public RangeIterator(long start, long end) { this.start = start; currentValue = start - 1; limit = end; } public boolean hasNext() { return currentValue < limit; } public Item next() { if (++currentValue > limit) { return null; } return Int64Value.makeIntegerValue(currentValue); } public Item current() { if (currentValue > limit) { return null; } else { return Int64Value.makeIntegerValue(currentValue); } } public int position() { if (currentValue > limit) { return -1; } else { return (int)(currentValue - start + 1); } } public void close() { } public int getLastPosition() { return (int)((limit - start) + 1); } public SequenceIterator getAnother() throws XPathException { return new RangeIterator(start, limit); } /** * Get properties of this iterator, as a bit-significant integer. * * @return the properties of this iterator. This will be some combination of * properties such as {@link net.sf.saxon.om.SequenceIterator#GROUNDED}, {@link net.sf.saxon.om.SequenceIterator#LAST_POSITION_FINDER}, * and {@link net.sf.saxon.om.SequenceIterator#LOOKAHEAD}. It is always * acceptable to return the value zero, indicating that there are no known special properties. * It is acceptable for the properties of the iterator to change depending on its state. */ public int getProperties() { return LOOKAHEAD | LAST_POSITION_FINDER | GROUNDED; } public SequenceIterator getReverseIterator() { return new ReverseRangeIterator(limit, start); } /** * Return a Value containing all the items in the sequence returned by this * SequenceIterator. This should be an "in-memory" value, not a Closure. * * @return the corresponding Value */ public GroundedValue materialize() throws XPathException { return new IntegerRange(start, limit); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/expr/ErrorExpression.java0000644000175000017500000001010011033112257022361 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.om.Item; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.trace.ExpressionPresenter; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.AnyItemType; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.TypeHierarchy; /** * Error expression: this expression is generated when the supplied expression cannot be * parsed, and the containing element enables forwards-compatible processing. It defers * the generation of an error message until an attempt is made to evaluate the expression */ public class ErrorExpression extends Expression { private XPathException exception; // the error found when parsing this expression /** * Constructor * @param exception the error found when parsing this expression */ public ErrorExpression(XPathException exception) { this.exception = exception; exception.setLocator(this); // to remove any links to the compile-time stylesheet objects }; /** * Get the wrapped exception */ public XPathException getException() { return exception; } /** * Type-check the expression. */ public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { return this; } public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { return this; } /** * Evaluate the expression. This always throws the exception registered when the expression * was first parsed. */ public Item evaluateItem(XPathContext context) throws XPathException { // copy the exception for thread-safety, because we want to add context information XPathException err = new XPathException(exception.getMessage()); err.setLocator(this); err.setErrorCode(exception.getErrorCodeNamespace(), exception.getErrorCodeLocalPart()); err.setXPathContext(context); throw err; } /** * Iterate over the expression. This always throws the exception registered when the expression * was first parsed. */ public SequenceIterator iterate(XPathContext context) throws XPathException { evaluateItem(context); return null; // to fool the compiler } /** * Determine the data type of the expression, if possible * @return Type.ITEM (meaning not known in advance) * @param th the type hierarchy cache */ public ItemType getItemType(TypeHierarchy th) { return AnyItemType.getInstance(); } /** * Determine the static cardinality */ public int computeCardinality() { return StaticProperty.ALLOWS_ZERO_OR_MORE; // we return a liberal value, so that we never get a type error reported // statically } /** * Copy an expression. This makes a deep copy. * * @return the copy of the original expression */ public Expression copy() { return new ErrorExpression(exception); } /** * Diagnostic print of expression structure. The abstract expression tree * is written to the supplied output destination. */ public void explain(ExpressionPresenter destination) { destination.startElement("error"); destination.emitAttribute("message", exception.getMessage()); destination.endElement(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/expr/EvaluableItem.java0000644000175000017500000000217011033112257021737 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.om.Item; import net.sf.saxon.trans.XPathException; /** * This interface is a simple subset of the Expression interface, that provides a single method to * evaluate the result of an expression as a single item */ public interface EvaluableItem { /** * Return an item * @param context the dynamic evaluation context * @return the item */ public Item evaluateItem(XPathContext context) throws XPathException; } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/expr/SequenceIterable.java0000644000175000017500000000243711033112257022446 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.trans.XPathException; import java.io.Serializable; /** * This interface is a simple subset of the Expression interface, that provides a single method to * evaluate the result of an expression as a sequence */ public interface SequenceIterable extends Serializable { /** * Return an iterator over the results of evaluating an expression * @param context the dynamic evaluation context * @return an iterator over the items delivered by the expression */ public SequenceIterator iterate(XPathContext context) throws XPathException; } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/expr/LazyExpression.java0000644000175000017500000001316111033112257022221 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.om.Item; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ItemType; /** * A LazyExpression is an expression that forces lazy evaluation: it must not be evaluated eagerly, * because a failure must not be reported unless the value is actually referenced. This is used * for an expression that has been moved out of a loop. If the loop iterates zero times, the expression * will not be evaluated, and in particular, it will not cause a dynamic error. * *

    Note that the LazyExpression class does not itself implement any kind of delayed evaluation: * calling its evaluateItem() and iterate() methods produces an immediate result. Instead, the existence * of a LazyExpression on the expression tree acts as a signal to other classes that evaluation should * be delayed, typically by holding the result of the iterate() method in a Closure object.

    */ public class LazyExpression extends UnaryExpression { /** * Create a LazyExpression * @param operand the expression to be evaluated lazily */ public LazyExpression(Expression operand) { super(operand); } /** * Create a LazyExpression (factory method) * @param operand the expression to be evaluated lazily * @return the LazyExpression */ public static Expression makeLazyExpression(Expression operand) { if (operand instanceof LazyExpression || operand instanceof Literal) { return operand; } else { return new LazyExpression(operand); } } /** * The typeCheck method suppresses compile-time evaluation * @param visitor an expression visitor * @param contextItemType the static type of the context item * @return the expression after typechecking * @throws XPathException */ public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { operand = visitor.typeCheck(operand, contextItemType); return this; } /** * Perform optimisation of an expression and its subexpressions. This method * suppresses compile-time evaluation */ public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { operand = visitor.optimize(operand, contextItemType); return this; } /** * Evaluate an expression as a single item. This always returns either a single Item or * null (denoting the empty sequence). No conversion is done. This method should not be * used unless the static type of the expression is a subtype of "item" or "item?": that is, * it should not be called if the expression may return a sequence. There is no guarantee that * this condition will be detected. * * @param context The context in which the expression is to be evaluated * @return the node or atomic value that results from evaluating the * expression; or null to indicate that the result is an empty * sequence * @throws net.sf.saxon.trans.XPathException * if any dynamic error occurs evaluating the * expression */ public Item evaluateItem(XPathContext context) throws XPathException { return operand.evaluateItem(context); } /** * Return an Iterator to iterate over the values of a sequence. The value of every * expression can be regarded as a sequence, so this method is supported for all * expressions. This default implementation handles iteration for expressions that * return singleton values: for non-singleton expressions, the subclass must * provide its own implementation. * * @param context supplies the context for evaluation * @return a SequenceIterator that can be used to iterate over the result * of the expression * @throws net.sf.saxon.trans.XPathException * if any dynamic error occurs evaluating the * expression */ public SequenceIterator iterate(XPathContext context) throws XPathException { return operand.iterate(context); } /** * Process the instruction, without returning any tail calls * * @param context The dynamic context, giving access to the current node, * the current variables, etc. */ public void process(XPathContext context) throws XPathException { operand.process(context); } /** * Copy an expression. This makes a deep copy. * * @return the copy of the original expression */ public Expression copy() { return new LazyExpression(getBaseExpression().copy()); } protected String displayExpressionName() { return "lazy"; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/expr/ValueTailIterator.java0000644000175000017500000000613411033112257022624 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.om.*; import net.sf.saxon.trans.XPathException; /** * ValueTailIterator iterates over a base sequence starting at an element other than the first. * It is used in the case where the base sequence is "grounded", that is, it exists in memory and * supports efficient direct addressing. */ public class ValueTailIterator implements SequenceIterator, GroundedIterator, LookaheadIterator { private GroundedValue baseValue; private int start; // zero-based private int pos = 0; /** * Construct a ValueTailIterator * @param base The items to be filtered * @param start The position of the first item to be included (zero-based) * @throws XPathException */ public ValueTailIterator(GroundedValue base, int start) throws XPathException { baseValue = base; this.start = start; pos = 0; } public Item next() throws XPathException { return baseValue.itemAt(start + pos++); } public Item current() { return baseValue.itemAt(start + pos - 1); } public int position() { return pos; } public boolean hasNext() { return baseValue.itemAt(start + pos) != null; } public void close() { } public SequenceIterator getAnother() throws XPathException { return new ValueTailIterator(baseValue, start); } /** * Return a Value containing all the items in the sequence returned by this * SequenceIterator. This should be an "in-memory" value, not a Closure. * * @return the corresponding Value */ public GroundedValue materialize() throws XPathException { if (start == 0) { return baseValue; } else { return baseValue.subsequence(start, Integer.MAX_VALUE); } } /** * Get properties of this iterator, as a bit-significant integer. * * @return the properties of this iterator. This will be some combination of * properties such as {@link #GROUNDED}, {@link #LAST_POSITION_FINDER}, * and {@link #LOOKAHEAD}. It is always * acceptable to return the value zero, indicating that there are no known special properties. * It is acceptable for the properties of the iterator to change depending on its state. */ public int getProperties() { return GROUNDED | LOOKAHEAD; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/expr/BindingReference.java0000644000175000017500000000313611033112257022414 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.value.SequenceType; import net.sf.saxon.value.Value; /** * BindingReference is a interface used to mark references to a variable declaration. The main * implementation is VariableReference, which represents a reference to a variable in an XPath * expression, but it is also used to represent a reference to a variable in a saxon:assign instruction. */ public interface BindingReference { /** * Fix up the static type of this variable reference; optionally, supply a constant value for * the variable. Also supplies other static properties of the expression to which the variable * is bound, for example whether it is an ordered node-set. */ public void setStaticType(SequenceType type, Value constantValue, int properties); /** * Fix up this binding reference to a binding */ public void fixup(Binding binding); } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/expr/Tokenizer.java0000644000175000017500000011365611033112257021206 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.Whitespace; import java.util.ArrayList; import java.util.List; /** * Tokenizer for expressions and inputs. * * This code was originally derived from James Clark's xt, though it has been greatly modified since. * See copyright notice at end of file. */ //@SuppressWarnings({"StringEquality"}) public final class Tokenizer { private int state = DEFAULT_STATE; // we may need to make this a stack at some time /** * Initial default state of the Tokenizer */ public static final int DEFAULT_STATE = 0; /** * State in which a name is NOT to be merged with what comes next, for example "(" */ public static final int BARE_NAME_STATE = 1; /** * State in which the next thing to be read is a SequenceType */ public static final int SEQUENCE_TYPE_STATE = 2; /** * State in which the next thing to be read is an operator */ public static final int OPERATOR_STATE = 3; /** * The starting line number (for XPath in XSLT, the line number in the stylesheet) */ public int startLineNumber; /** * The number identifying the most recently read token */ public int currentToken = Token.EOF; /** * The string value of the most recently read token */ public String currentTokenValue = null; /** * The position in the input expression where the current token starts */ public int currentTokenStartOffset = 0; /** * The number of the next token to be returned */ private int nextToken = Token.EOF; /** * The string value of the next token to be returned */ private String nextTokenValue = null; /** * The position in the expression of the start of the next token */ private int nextTokenStartOffset = 0; /** * The string being parsed */ public String input; /** * The current position within the input string */ public int inputOffset = 0; /** * The length of the input string */ private int inputLength; /** * The line number (within the expression) of the current token */ private int lineNumber = 1; /** * The line number (within the expression) of the next token */ private int nextLineNumber = 1; /** * List containing the positions (offsets in the input string) at which newline characters * occur */ private List newlineOffsets = null; /** * The token number of the token that preceded the current token */ private int precedingToken = Token.UNKNOWN; /** * Get the current tokenizer state * @return the current state */ public int getState() { return state; } /** * Set the tokenizer into a special state * @param state the new state */ public void setState(int state) { this.state = state; if (state==DEFAULT_STATE) { // force the followsOperator() test to return true precedingToken = Token.UNKNOWN; currentToken = Token.UNKNOWN; } else if (state==OPERATOR_STATE) { precedingToken = Token.RPAR; currentToken = Token.RPAR; } } // // Lexical analyser for expressions, queries, and XSLT patterns // /** * Prepare a string for tokenization. * The actual tokens are obtained by calls on next() * * @param input the string to be tokenized * @param start start point within the string * @param end end point within the string (last character not read): * -1 means end of string * @param lineNumber the linenumber in the source where the expression appears * @throws XPathException if a lexical error occurs, e.g. unmatched * string quotes */ public void tokenize(String input, int start, int end, int lineNumber) throws XPathException { nextToken = Token.EOF; nextTokenValue = null; nextTokenStartOffset = 0; inputOffset = start; this.input = input; startLineNumber = lineNumber; this.lineNumber = lineNumber; nextLineNumber = lineNumber; if (end==-1) { inputLength = input.length(); } else { inputLength = end; } // The tokenizer actually reads one token ahead. The raw lexical analysis performed by // the lookAhead() method does not (in general) distinguish names used as QNames from names // used for operators, axes, and functions. The next() routine further refines names into the // correct category, by looking at the following token. In addition, it combines compound tokens // such as "instance of" and "cast as". lookAhead(); next(); } //diagnostic version of next(): change real version to realnext() // //public void next() throws XPathException { // realnext(); // System.err.println("Token: " + currentToken + "[" + tokens[currentToken] + "]"); //} /** * Get the next token from the input expression. The type of token is returned in the * currentToken variable, the string value of the token in currentTokenValue. * * @throws XPathException if a lexical error is detected */ public void next() throws XPathException { precedingToken = currentToken; currentToken = nextToken; currentTokenValue = nextTokenValue; if (currentTokenValue==null) { currentTokenValue=""; } currentTokenStartOffset = nextTokenStartOffset; lineNumber = nextLineNumber; // disambiguate the current token based on the tokenizer state switch (currentToken) { case Token.NAME: int optype = getBinaryOp(currentTokenValue); if (optype!=Token.UNKNOWN && !followsOperator(precedingToken)) { currentToken = optype; } break; case Token.LT: if (followsOperator(precedingToken)) { currentToken = Token.TAG; } break; case Token.STAR: if (!followsOperator(precedingToken)) { currentToken = Token.MULT; } break; } if (currentToken == Token.TAG || currentToken == Token.RCURLY) { // No lookahead after encountering "<" at the start of an XML-like tag. // After an RCURLY, the parser must do an explicit lookahead() to continue // tokenizing; otherwise it can continue with direct character reading return; } int oldPrecedingToken = precedingToken; lookAhead(); if (currentToken == Token.NAME) { if (state == BARE_NAME_STATE) { return; } switch (nextToken) { case Token.LPAR: int op = getBinaryOp(currentTokenValue); // the test on followsOperator() is to cater for an operator being used as a function name, // e.g. is(): see XQTS test K-FunctionProlog-66 if (op == Token.UNKNOWN || followsOperator(oldPrecedingToken)) { currentToken = getFunctionType(currentTokenValue); lookAhead(); // swallow the "(" } else { currentToken = op; } break; case Token.LCURLY: if (!(state == SEQUENCE_TYPE_STATE)) { currentToken = Token.KEYWORD_CURLY; lookAhead(); // swallow the "{" } break; case Token.COLONCOLON: lookAhead(); currentToken = Token.AXIS; break; case Token.COLONSTAR: lookAhead(); currentToken = Token.PREFIX; break; case Token.DOLLAR: if (currentTokenValue=="for") { currentToken = Token.FOR; } else if (currentTokenValue=="some") { currentToken = Token.SOME; } else if (currentTokenValue=="every") { currentToken = Token.EVERY; } else if (currentTokenValue=="let") { currentToken = Token.LET; } else if (currentTokenValue=="copy") { currentToken = Token.COPY; } break; case Token.NAME: int candidate = -1; if (currentTokenValue.equals("element")) { candidate = Token.ELEMENT_QNAME; } else if (currentTokenValue.equals("attribute")) { candidate = Token.ATTRIBUTE_QNAME; } else if (currentTokenValue.equals("processing-instruction")) { candidate = Token.PI_QNAME; } if (candidate != -1) { // <'element' QName '{'> constructor // <'attribute' QName '{'> constructor // <'processing-instruction' QName '{'> constructor String qname = nextTokenValue; String saveTokenValue = currentTokenValue; int savePosition = inputOffset; lookAhead(); if (nextToken == Token.LCURLY) { currentToken = candidate; currentTokenValue = qname; lookAhead(); return; } else { // backtrack (we don't have 2-token lookahead; this is the // only case where it's needed. So we backtrack instead.) currentToken = Token.NAME; currentTokenValue = saveTokenValue; inputOffset = savePosition; nextToken = Token.NAME; nextTokenValue = qname; } } String composite = currentTokenValue + ' ' + nextTokenValue; Integer val = (Integer)Token.doubleKeywords.get(composite); if (val==null) { break; } else { currentToken = val.intValue(); currentTokenValue = composite; // some tokens are actually triples // if (currentToken == Token.AS_FIRST || currentToken == Token.AS_LAST) { // lookAhead(); // if (nextToken != Token.NAME || !nextTokenValue.equals("into")) { // throw new XPathException("After '" + composite + "', expected 'into'"); // } // nextToken = currentToken; // to reestablish after-operator state // } else if (currentToken == Token.REPLACE_VALUE) { // this one's a quadruplet - "replace value of node" lookAhead(); if (nextToken != Token.NAME || !nextTokenValue.equals("of")) { throw new XPathException("After '" + composite + "', expected 'of'"); } lookAhead(); if (nextToken != Token.NAME || !nextTokenValue.equals("node")) { throw new XPathException("After 'replace value of', expected 'node'"); } nextToken = currentToken; // to reestablish after-operator state } lookAhead(); return; } default: // no action needed } } } /** * Force the current token to be treated as an operator if possible */ public void treatCurrentAsOperator() { switch (currentToken) { case Token.NAME: int optype = getBinaryOp(currentTokenValue); if (optype!=Token.UNKNOWN) { currentToken = optype; } break; case Token.STAR: currentToken = Token.MULT; break; } } /** * Look ahead by one token. This method does the real tokenization work. * The method is normally called internally, but the XQuery parser also * calls it to resume normal tokenization after dealing with pseudo-XML * syntax. * @throws XPathException if a lexical error occurs */ public void lookAhead() throws XPathException { precedingToken = nextToken; nextTokenValue = null; nextTokenStartOffset = inputOffset; for (;;) { if (inputOffset >= inputLength) { nextToken = Token.EOF; return; } char c = input.charAt(inputOffset++); switch (c) { case '/': if (inputOffset < inputLength && input.charAt(inputOffset) == '/') { inputOffset++; nextToken = Token.SLSL; return; } nextToken = Token.SLASH; return; case ':': if (inputOffset < inputLength) { if (input.charAt(inputOffset) == ':') { inputOffset++; nextToken = Token.COLONCOLON; return; } else if (input.charAt(inputOffset) == '=') { nextToken = Token.ASSIGN; inputOffset++; return; } } throw new XPathException("Unexpected colon at start of token"); case '@': nextToken = Token.AT; return; case '?': nextToken = Token.QMARK; return; case '[': nextToken = Token.LSQB; return; case ']': nextToken = Token.RSQB; return; case '{': nextToken = Token.LCURLY; return; case '}': nextToken = Token.RCURLY; return; case ';': nextToken = Token.SEMICOLON; state = DEFAULT_STATE; return; case '(': if (inputOffset < inputLength && input.charAt(inputOffset) == '#') { inputOffset++; int pragmaStart = inputOffset; int nestingDepth = 1; while (nestingDepth > 0 && inputOffset < (inputLength-1)) { if (input.charAt(inputOffset) == '\n') { incrementLineNumber(); } else if (input.charAt(inputOffset) == '#' && input.charAt(inputOffset+1) == ')') { nestingDepth--; inputOffset++; } else if (input.charAt(inputOffset) == '(' && input.charAt(inputOffset+1) == '#') { nestingDepth++; inputOffset++; } inputOffset++; } if (nestingDepth > 0) { throw new XPathException("Unclosed XQuery pragma"); } nextToken = Token.PRAGMA; nextTokenValue = input.substring(pragmaStart, inputOffset-2 ); return; } if (inputOffset < inputLength && input.charAt(inputOffset) == ':') { // XPath comment syntax is (: .... :) // Comments may be nested, and may now be empty inputOffset++; int nestingDepth = 1; while (nestingDepth > 0 && inputOffset < (inputLength-1)) { if (input.charAt(inputOffset) == '\n') { incrementLineNumber(); } else if (input.charAt(inputOffset) == ':' && input.charAt(inputOffset+1) == ')') { nestingDepth--; inputOffset++; } else if (input.charAt(inputOffset) == '(' && input.charAt(inputOffset+1) == ':') { nestingDepth++; inputOffset++; } inputOffset++; } if (nestingDepth > 0) { throw new XPathException("Unclosed XPath comment"); } lookAhead(); } else { nextToken = Token.LPAR; } return; case ')': nextToken = Token.RPAR; return; case '+': nextToken = Token.PLUS; return; case '-': nextToken = Token.MINUS; // not detected if part of a name return; case '=': nextToken = Token.EQUALS; return; case '!': if (inputOffset < inputLength && input.charAt(inputOffset) == '=') { inputOffset++; nextToken = Token.NE; return; } throw new XPathException("'!' without '='"); case '*': // disambiguation of MULT and STAR is now done later if (inputOffset < inputLength && input.charAt(inputOffset) == ':') { inputOffset++; nextToken = Token.SUFFIX; // we leave the parser to get the following name as a separate // token, but first check there's no intervening white space or comments if (inputOffset < inputLength) { char ahead = input.charAt(inputOffset); if (" \r\t\n(".indexOf(ahead) >= 0) { throw new XPathException("Whitespace and comments are not allowed after '*:'"); } } return; } nextToken = Token.STAR; return; case ',': nextToken = Token.COMMA; return; case '$': nextToken = Token.DOLLAR; return; case '|': nextToken = Token.UNION; return; case '<': if (inputOffset < inputLength && input.charAt(inputOffset) == '=') { inputOffset++; nextToken = Token.LE; return; } if (inputOffset < inputLength && input.charAt(inputOffset) == '<') { inputOffset++; nextToken = Token.PRECEDES; return; } nextToken = Token.LT; return; case '>': if (inputOffset < inputLength && input.charAt(inputOffset) == '=') { inputOffset++; nextToken = Token.GE; return; } if (inputOffset < inputLength && input.charAt(inputOffset) == '>') { inputOffset++; nextToken = Token.FOLLOWS; return; } nextToken = Token.GT; return; case '.': if (inputOffset < inputLength && input.charAt(inputOffset) == '.') { inputOffset++; nextToken = Token.DOTDOT; return; } if (inputOffset == inputLength || input.charAt(inputOffset) < '0' || input.charAt(inputOffset) > '9') { nextToken = Token.DOT; return; } // otherwise drop through: we have a number starting with a decimal point case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': // The logic here can return some tokens that are not legitimate numbers, // for example "23e" or "1.0e+". However, this will only happen if the XPath // expression as a whole is syntactically incorrect. // These errors will be caught by the numeric constructor. boolean allowE = true; boolean allowSign = false; boolean allowDot = true; boolean endOfNum = false; numloop: while (!endOfNum) { switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': allowSign = false; break; case '.': if (allowDot) { allowDot = false; allowSign = false; } else { inputOffset--; break numloop; } break; case 'E': case 'e': if (allowE) { allowSign = true; allowE = false; } else { inputOffset--; break numloop; } break; case '+': case '-': if (allowSign) { allowSign = false; } else { inputOffset--; break numloop; } break; default: if (('a' <= c && c <= 'z') || c>127) { // this prevents the famous "10div 3" throw new XPathException("Separator needed after numeric literal"); } inputOffset--; break numloop; } if (inputOffset >= inputLength) break; c = input.charAt(inputOffset++); } nextTokenValue = input.substring(nextTokenStartOffset, inputOffset); nextToken = Token.NUMBER; return; case '"': case '\'': nextTokenValue = ""; while (true) { inputOffset = input.indexOf(c, inputOffset); if (inputOffset < 0) { inputOffset = nextTokenStartOffset + 1; throw new XPathException("Unmatched quote in expression"); } nextTokenValue += input.substring(nextTokenStartOffset + 1, inputOffset++); // look for doubled delimiters if (inputOffset < inputLength && input.charAt(inputOffset) == c) { nextTokenValue += c; nextTokenStartOffset = inputOffset; inputOffset++; } else { break; } } // maintain line number if there are newlines in the string if (nextTokenValue.indexOf('\n') >= 0) { for (int i = 0; i inputLength) { inputOffset = inputLength; } if (inputOffset < 34) { return input.substring(0, inputOffset); } else { return Whitespace.collapseWhitespace( "..." + input.substring(inputOffset-30, inputOffset)).toString(); } } /** * Get the line number of the current token * @return the line number */ public int getLineNumber() { return lineNumber; } /** * Get the column number of the current token * @return the column number */ public int getColumnNumber() { return (int)(getLineAndColumn(currentTokenStartOffset)&0x7fffffff); } /** * Get the line and column number corresponding to a given offset in the input expression, * as a long value with the line number in the top half * and the column number in the lower half * @param offset the byte offset in the expression * @return the line and column number, packed together */ public long getLineAndColumn(int offset) { if (newlineOffsets==null) { return ((long)startLineNumber) << 32 | (long)offset; } for (int line=newlineOffsets.size()-1; line>=0; line--) { int nloffset = ((Integer)newlineOffsets.get(line)).intValue(); if (offset > nloffset) { return ((long)(line+startLineNumber+1)<<32) | ((long)(offset - nloffset)); } } return ((long)startLineNumber) << 32 | (long)(offset+1); } /** * Return the line number corresponding to a given offset in the expression * @param offset the byte offset in the expression * @return the line number */ public int getLineNumber(int offset) { return (int)((getLineAndColumn(offset))>>32); } /** * Return the column number corresponding to a given offset in the expression * @param offset the byte offset in the expression * @return the column number */ public int getColumnNumber(int offset) { return (int)((getLineAndColumn(offset))&0x7fffffff); } } /* The following copyright notice is copied from the licence for xt, from which the original version of this module was derived: -------------------------------------------------------------------------------- Copyright (c) 1998, 1999 James Clark Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL JAMES CLARK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Except as contained in this notice, the name of James Clark shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from James Clark. --------------------------------------------------------------------------- */ // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file, other than the parts developed by James Clark as part of xt. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. //saxonb-9.1.0.8/bj/net/sf/saxon/expr/FirstItemExpression.java0000644000175000017500000001031611033112257023207 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.om.Item; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ItemType; /** * A FirstItemExpression returns the first item in the sequence returned by a given * base expression */ public final class FirstItemExpression extends UnaryExpression { /** * Constructor * @param base A sequence expression denoting sequence whose first item is to be returned */ public FirstItemExpression(Expression base) { super(base); computeStaticProperties(); } /** * Perform optimisation of an expression and its subexpressions. *

    *

    This method is called after all references to functions and variables have been resolved * to the declaration of the function or variable, and after all type checking has been done.

    * * @param visitor an expresion visitor * @param contextItemType the static type of "." at the point where this expression is invoked. * The parameter is set to null if it is known statically that the context item will be undefined. * If the type of the context item is not known statically, the argument is set to * {@link net.sf.saxon.type.Type#ITEM_TYPE} * @return the original expression, rewritten if appropriate to optimize execution * @throws XPathException if an error is discovered during this phase * (typically a type error) */ public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { operand = visitor.optimize(operand, contextItemType); // don't remove this expression just because the operand is known to be a singleton. // It might be that this expression was added to give early exit from evaluating the underlying expression // if (!Cardinality.allowsMany(operand.getCardinality())) { // ComputedExpression.setParentExpression(operand, getParentExpression()); // return operand; // } if (operand instanceof FirstItemExpression) { return operand; } return super.optimize(visitor, contextItemType); } /** * Promote this expression if possible */ public Expression promote(PromotionOffer offer) throws XPathException { Expression exp = offer.accept(this); if (exp != null) { return exp; } else { if (offer.action != PromotionOffer.UNORDERED) { // we can't push the UNORDERED property down to the operand, because order is significant operand = doPromotion(operand, offer); } return this; } } /** * Get the static cardinality */ public int computeCardinality() { return operand.getCardinality() & ~StaticProperty.ALLOWS_MANY; } /** * Copy an expression. This makes a deep copy. * * @return the copy of the original expression */ public Expression copy() { return new FirstItemExpression(getBaseExpression().copy()); } /** * Evaluate the expression */ public Item evaluateItem(XPathContext context) throws XPathException { SequenceIterator iter = operand.iterate(context); Item result = iter.next(); iter.close(); return result; } public String displayExpressionName() { return "firstItem"; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/expr/CurrentItemExpression.java0000644000175000017500000000237211033112257023545 0ustar eugeneeugenepackage net.sf.saxon.expr; /** * The expression is generated when compiling the current() function in XSLT. It differs from * the ContextItemExpression "." only in the error code that is returned when there is no context item. */ public class CurrentItemExpression extends ContextItemExpression { /** * Get the error code for use when there is no context item * @return the string "XTDE1360" */ protected String getErrorCodeForUndefinedContext() { return "XTDE1360"; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/expr/PositionVariable.java0000644000175000017500000000637211033112257022502 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.om.StructuredQName; import net.sf.saxon.om.ValueRepresentation; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.SequenceType; /** * Represents the defining occurrence of the position variable in a for expression * within an expression, for example the $p in "for $x at $p in ...". */ public class PositionVariable implements Binding { private StructuredQName variableName; private int slotNumber = -999; /** * Create a RangeVariable */ public PositionVariable(){} /** * Get the name of the variable, as a namepool name code * @return the nameCode */ public StructuredQName getVariableQName() { return variableName; } /** * Get the required type (declared type) of the variable * @return the required type */ public SequenceType getRequiredType() { return SequenceType.SINGLE_INTEGER; } /** * Set the name of the variable * @param variableName the name of the variable */ public void setVariableQName(StructuredQName variableName) { this.variableName = variableName; } /** * Set the slot number for the range variable * @param nr the slot number to be used */ public void setSlotNumber(int nr) { slotNumber = nr; } /** * If this is a local variable held on the local stack frame, return the corresponding slot number. * In other cases, return -1. */ public int getLocalSlotNumber() { return slotNumber; } /** * Get the value of the range variable */ public ValueRepresentation evaluateVariable(XPathContext context) throws XPathException { return context.evaluateLocalVariable(slotNumber); } /** * Test whether it is permitted to assign to the variable using the saxon:assign * extension element. This will only be for an XSLT global variable where the extra * attribute saxon:assignable="yes" is present. * * @return true if the binding is assignable */ public boolean isAssignable() { return false; } /** * Indicate whether the binding is local or global. A global binding is one that has a fixed * value for the life of a query or transformation; any other binding is local. * * @return true if the binding is global */ public boolean isGlobal() { return false; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. //saxonb-9.1.0.8/bj/net/sf/saxon/expr/LastPositionFinder.java0000644000175000017500000000304711033112257023004 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.trans.XPathException; /** * A LastPositionFinder is an interface implemented by any SequenceIterator that is * able to return the position of the last item in the sequence. */ public interface LastPositionFinder extends SequenceIterator { /** * Get the last position (that is, the number of items in the sequence). This method is * non-destructive: it does not change the state of the iterator. * The result is undefined if the next() method of the iterator has already returned null. * This method must not be called unless the result of getProperties() on the iterator * includes the bit setting {@link #LAST_POSITION_FINDER} */ public int getLastPosition() throws XPathException; } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/expr/Expression.java0000644000175000017500000013407711033112257021373 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.Configuration; import net.sf.saxon.event.LocationProvider; import net.sf.saxon.event.SequenceReceiver; import net.sf.saxon.evpull.EmptyEventIterator; import net.sf.saxon.evpull.EventIterator; import net.sf.saxon.evpull.EventIteratorOverSequence; import net.sf.saxon.evpull.SingletonEventIterator; import net.sf.saxon.instruct.Executable; import net.sf.saxon.instruct.LocationMap; import net.sf.saxon.om.*; import net.sf.saxon.sort.IntHashSet; import net.sf.saxon.sort.IntIterator; import net.sf.saxon.trace.ExpressionPresenter; import net.sf.saxon.trace.InstructionInfo; import net.sf.saxon.trace.Location; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.AtomicType; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.SchemaType; import net.sf.saxon.type.TypeHierarchy; import net.sf.saxon.value.Cardinality; import net.sf.saxon.value.SequenceType; import net.sf.saxon.value.StringValue; import javax.xml.transform.SourceLocator; import java.io.OutputStream; import java.io.PrintStream; import java.io.Serializable; import java.util.Arrays; import java.util.Collections; import java.util.Iterator; /** * Interface supported by an XPath expression. This includes both compile-time * and run-time methods. */ public abstract class Expression implements SequenceIterable, EvaluableItem, Serializable, SourceLocator, InstructionInfo { public static final int EVALUATE_METHOD = 1; public static final int ITERATE_METHOD = 2; public static final int PROCESS_METHOD = 4; protected int staticProperties = -1; protected int locationId = -1; private Container container; private int[] slotsUsed; // private void writeObject(ObjectOutputStream oos) throws IOException { // System.err.println("Expression " + this.getClass()); // oos.defaultWriteObject(); // } /** * An implementation of Expression must provide at least one of the methods evaluateItem(), iterate(), or process(). * This method indicates which of these methods is provided directly. The other methods will always be available * indirectly, using an implementation that relies on one of the other methods. * @return the implementation method, for example {@link #ITERATE_METHOD} or {@link #EVALUATE_METHOD} or * {@link #PROCESS_METHOD} */ public int getImplementationMethod() { if (Cardinality.allowsMany(getCardinality())) { return ITERATE_METHOD; } else { return EVALUATE_METHOD; } } /** * Determine whether this expression implements its own method for static type checking * @return true if this expression has a non-trivial implementation of the staticTypeCheck() * method */ public boolean implementsStaticTypeCheck() { return false; } /** * Simplify an expression. This performs any static optimization (by rewriting the expression * as a different expression). The default implementation does nothing. * * @exception net.sf.saxon.trans.XPathException if an error is discovered during expression * rewriting * @return the simplified expression * @param visitor an expression visitor */ public Expression simplify(ExpressionVisitor visitor) throws XPathException { return this; } /** * Perform type checking of an expression and its subexpressions. This is the second phase of * static optimization. * *

    This checks statically that the operands of the expression have * the correct type; if necessary it generates code to do run-time type checking or type * conversion. A static type error is reported only if execution cannot possibly succeed, that * is, if a run-time type error is inevitable. The call may return a modified form of the expression.

    * *

    This method is called after all references to functions and variables have been resolved * to the declaration of the function or variable. However, the types of such functions and * variables may not be accurately known if they have not been explicitly declared.

    * *

    If the implementation returns a value other than "this", then it is required to ensure that * the parent pointer and location information in the returned expression have been set up correctly. * It should not rely on the caller to do this, although for historical reasons many callers do so.

    * * @param visitor an expression visitor * @param contextItemType the static type of "." at the point where this expression is invoked. * The parameter is set to null if it is known statically that the context item will be undefined. * If the type of the context item is not known statically, the argument is set to * {@link net.sf.saxon.type.Type#ITEM_TYPE} * @throws XPathException if an error is discovered during this phase * (typically a type error) * @return the original expression, rewritten to perform necessary run-time type checks, * and to perform other type-related optimizations */ public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { return this; } /** * Static type checking of some expressions is delegated to the expression itself, by calling * this method. The default implementation of the method throws UnsupportedOperationException. * If there is a non-default implementation, then implementsStaticTypeCheck() will return true * @param req the required type * @param backwardsCompatible true if backwards compatibility mode applies * @param role the role of the expression in relation to the required type * @param visitor an expression visitor * @return the expression after type checking (perhaps augmented with dynamic type checking code) * @throws XPathException if failures occur, for example if the static type of one branch of the conditional * is incompatible with the required type */ public Expression staticTypeCheck(SequenceType req, boolean backwardsCompatible, RoleLocator role, ExpressionVisitor visitor) throws XPathException { throw new UnsupportedOperationException("staticTypeCheck"); } /** * Perform optimisation of an expression and its subexpressions. This is the third and final * phase of static optimization. * *

    This method is called after all references to functions and variables have been resolved * to the declaration of the function or variable, and after all type checking has been done.

    * @param visitor an expression visitor * @param contextItemType the static type of "." at the point where this expression is invoked. * The parameter is set to null if it is known statically that the context item will be undefined. * If the type of the context item is not known statically, the argument is set to * {@link net.sf.saxon.type.Type#ITEM_TYPE} * @throws XPathException if an error is discovered during this phase * (typically a type error) * @return the original expression, rewritten if appropriate to optimize execution */ public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { return this; } /** * Offer promotion for this subexpression. The offer will be accepted if the subexpression * is not dependent on the factors (e.g. the context item) identified in the PromotionOffer. * By default the offer is not accepted - this is appropriate in the case of simple expressions * such as constant values and variable references where promotion would give no performance * advantage. This method is always called at compile time. * * @param offer details of the offer, for example the offer to move * expressions that don't depend on the context to an outer level in * the containing expression * @exception net.sf.saxon.trans.XPathException if any error is detected * @return if the offer is not accepted, return this expression unchanged. * Otherwise return the result of rewriting the expression to promote * this subexpression */ public Expression promote(PromotionOffer offer) throws XPathException { // The following temporary code checks that this method is implemented for all expressions // that have subexpressions // if (iterateSubExpressions().hasNext()) { // throw new UnsupportedOperationException("promote is not implemented for " + getClass()); // } return this; } /** * Get the static properties of this expression (other than its type). The result is * bit-signficant. These properties are used for optimizations. In general, if * property bit is set, it is true, but if it is unset, the value is unknown. * * @return a set of flags indicating static properties of this expression */ public final int getSpecialProperties() { if (staticProperties == -1) { computeStaticProperties(); } return staticProperties & StaticProperty.SPECIAL_PROPERTY_MASK; } /** * Determine the static cardinality of the expression. This establishes how many items * there will be in the result of the expression, at compile time (i.e., without * actually evaluating the result. * * @return one of the values Cardinality.ONE_OR_MORE, * Cardinality.ZERO_OR_MORE, Cardinality.EXACTLY_ONE, * Cardinality.ZERO_OR_ONE, Cardinality.EMPTY. This default * implementation returns ZERO_OR_MORE (which effectively gives no * information). */ public int getCardinality() { if (staticProperties == -1) { computeStaticProperties(); } return staticProperties & StaticProperty.CARDINALITY_MASK; } /** * Determine the data type of the expression, if possible. All expression return * sequences, in general; this method determines the type of the items within the * sequence, assuming that (a) this is known in advance, and (b) it is the same for * all items in the sequence. * *

    This method should always return a result, though it may be the best approximation * that is available at the time.

    * * @return a value such as Type.STRING, Type.BOOLEAN, Type.NUMBER, * Type.NODE, or Type.ITEM (meaning not known at compile time) * @param th the type hierarchy cache */ public abstract ItemType getItemType(TypeHierarchy th); /** * Determine which aspects of the context the expression depends on. The result is * a bitwise-or'ed value composed from constants such as XPathContext.VARIABLES and * XPathContext.CURRENT_NODE. The default implementation combines the intrinsic * dependencies of this expression with the dependencies of the subexpressions, * computed recursively. This is overridden for expressions such as FilterExpression * where a subexpression's dependencies are not necessarily inherited by the parent * expression. * * @return a set of bit-significant flags identifying the dependencies of * the expression */ public int getDependencies() { // Implemented as a memo function: we only compute the dependencies // for each expression once if (staticProperties == -1) { computeStaticProperties(); } return staticProperties & StaticProperty.DEPENDENCY_MASK; } /** * Get the immediate sub-expressions of this expression. Default implementation * returns a zero-length array, appropriate for an expression that has no * sub-expressions. * @return an iterator containing the sub-expressions of this expression */ public Iterator iterateSubExpressions() { return Collections.EMPTY_LIST.iterator(); } /** * Given an expression that is an immediate child of this expression, test whether * the evaluation of the parent expression causes the child expression to be * evaluated repeatedly * @param child the immediate subexpression * @return true if the child expression is evaluated repeatedly */ public boolean hasLoopingSubexpression(Expression child) { return false; } /** * Within the subtree rooted at this node, find the expression that is the parent of a given leaf node. * @param leaf the expression whose parent is required * @return the parent of the expression. If leaf is not found in the tree, return null */ public Expression findParentOf(Expression leaf) { for (Iterator children = iterateSubExpressions(); children.hasNext();) { Expression child = (Expression)children.next(); if (child == leaf) { return this; } else { Expression target = child.findParentOf(leaf); if (target != null) { return target; } } } return null; } /** * Mark an expression as being "flattened". This is a collective term that includes extracting the * string value or typed value, or operations such as simple value construction that concatenate text * nodes before atomizing. The implication of all of these is that although the expression might * return nodes, the identity of the nodes has no significance. This is called during type checking * of the parent expression. * @param flattened set to true if the result of the expression is atomized or otherwise turned into * an atomic value */ public void setFlattened(boolean flattened) { // no action in general } /** * Mark an expression as filtered: that is, it appears as the base expression in a filter expression. * This notification currently has no effect except when the expression is a variable reference. * @param filtered if true, marks this expression as the base of a filter expression */ public void setFiltered(boolean filtered) { // default: do nothing } /** * Evaluate an expression as a single item. This always returns either a single Item or * null (denoting the empty sequence). No conversion is done. This method should not be * used unless the static type of the expression is a subtype of "item" or "item?": that is, * it should not be called if the expression may return a sequence. There is no guarantee that * this condition will be detected. * * @param context The context in which the expression is to be evaluated * @exception net.sf.saxon.trans.XPathException if any dynamic error occurs evaluating the * expression * @return the node or atomic value that results from evaluating the * expression; or null to indicate that the result is an empty * sequence */ public Item evaluateItem(XPathContext context) throws XPathException { return iterate(context).next(); } /** * Return an Iterator to iterate over the values of a sequence. The value of every * expression can be regarded as a sequence, so this method is supported for all * expressions. This default implementation handles iteration for expressions that * return singleton values: for non-singleton expressions, the subclass must * provide its own implementation. * * @exception net.sf.saxon.trans.XPathException if any dynamic error occurs evaluating the * expression * @param context supplies the context for evaluation * @return a SequenceIterator that can be used to iterate over the result * of the expression */ public SequenceIterator iterate(XPathContext context) throws XPathException { Item value = evaluateItem(context); return SingletonIterator.makeIterator(value); } /** * Deliver the result of the expression as a sequence of events. * *

    The events (of class {@link net.sf.saxon.evpull.PullEvent}) are either complete * items, or one of startElement, endElement, startDocument, or endDocument, known * as semi-nodes. The stream of events may also include a nested EventIterator. * If a start-end pair exists in the sequence, then the events between * this pair represent the content of the document or element. The content sequence will * have been processed to the extent that any attribute and namespace nodes in the * content sequence will have been merged into the startElement event. Namespace fixup * will have been performed: that is, unique prefixes will have been allocated to element * and attribute nodes, and all namespaces will be declared by means of a namespace node * in the startElement event or in an outer startElement forming part of the sequence. * However, duplicate namespaces may appear in the sequence.

    *

    The content of an element or document may include adjacent or zero-length text nodes, * atomic values, and nodes represented as nodes rather than broken down into events.

    * @param context The dynamic evaluation context * @return the result of the expression as an iterator over a sequence of PullEvent objects * @throws XPathException if a dynamic error occurs during expression evaluation */ public EventIterator iterateEvents(XPathContext context) throws XPathException { int m = getImplementationMethod(); if ((m & EVALUATE_METHOD) != 0) { Item item = evaluateItem(context); if (item == null) { return EmptyEventIterator.getInstance(); } else { return new SingletonEventIterator(item); } } else { return new EventIteratorOverSequence(iterate(context)); } } /** * Get the effective boolean value of the expression. This returns false if the value * is the empty sequence, a zero-length string, a number equal to zero, or the boolean * false. Otherwise it returns true. * * @param context The context in which the expression is to be evaluated * @exception net.sf.saxon.trans.XPathException if any dynamic error occurs evaluating the * expression * @return the effective boolean value */ public boolean effectiveBooleanValue(XPathContext context) throws XPathException { return ExpressionTool.effectiveBooleanValue(iterate(context)); } /** * Evaluate an expression as a String. This function must only be called in contexts * where it is known that the expression will return a single string (or where an empty sequence * is to be treated as a zero-length string). Implementations should not attempt to convert * the result to a string, other than converting () to "". This method is used mainly to * evaluate expressions produced by compiling an attribute value template. * * @exception net.sf.saxon.trans.XPathException if any dynamic error occurs evaluating the * expression * @exception ClassCastException if the result type of the * expression is not xs:string? * @param context The context in which the expression is to be evaluated * @return the value of the expression, evaluated in the current context. * The expression must return a string or (); if the value of the * expression is (), this method returns "". */ public CharSequence evaluateAsString(XPathContext context) throws XPathException { Item o = evaluateItem(context); // if (o instanceof AtomicValue && !((AtomicValue)o).hasBuiltInType()) { // o = ((AtomicValue) o).getPrimitiveValue(); // } StringValue value = (StringValue) o; // the ClassCastException is deliberate if (value == null) return ""; return value.getStringValue(); } /** * Process the instruction, without returning any tail calls * @param context The dynamic context, giving access to the current node, * the current variables, etc. */ public void process(XPathContext context) throws XPathException { int m = getImplementationMethod(); if ((m & EVALUATE_METHOD) != 0) { Item item = evaluateItem(context); if (item != null) { context.getReceiver().append(item, locationId, NodeInfo.ALL_NAMESPACES); } } else if ((m & ITERATE_METHOD) != 0) { SequenceIterator iter = iterate(context); SequenceReceiver out = context.getReceiver(); try { while (true) { Item it = iter.next(); if (it == null) { break; } out.append(it, locationId, NodeInfo.ALL_NAMESPACES); } } catch (XPathException e) { e.maybeSetLocation(this); e.maybeSetContext(context); throw e; } } else { throw new AssertionError("process() is not implemented in the subclass " + getClass()); } } /** * Evaluate an updating expression, adding the results to a Pending Update List. * The default implementation of this method, which is used for non-updating expressions, * throws an UnsupportedOperationException * @param context the XPath dynamic evaluation context * @param pul the pending update list to which the results should be written */ public void evaluatePendingUpdates(XPathContext context, PendingUpdateList pul) throws XPathException { throw new UnsupportedOperationException("Expression " + getClass() + " is not an updating expression"); } /** * The toString() method for an expression attempts to give a representation of the expression * in an XPath-like form, but there is no guarantee that the syntax will actually be true XPath. * In the case of XSLT instructions, the toString() method gives an abstracted view of the syntax */ public String toString() { // fallback implementation FastStringBuffer buff = new FastStringBuffer(120); String className = getClass().getName(); while (true) { int dot = className.indexOf('.'); if (dot >= 0) { className = className.substring(dot+1); } else { break; } } buff.append(className); Iterator iter = iterateSubExpressions(); boolean first = true; while (iter.hasNext()) { buff.append(first ? "(" : ", "); buff.append(iter.next().toString()); first = false; } buff.append(")"); return buff.toString(); } /** * Diagnostic print of expression structure. The abstract expression tree * is written to the supplied output destination. * @param level this argument is ignored * @param out the expression presenter used to display the structure * @param config the Saxon configuration * @deprecated since 9.0 - use the explain method */ public void display(int level, PrintStream out, Configuration config) { try { ExpressionPresenter ep = new ExpressionPresenter(config, ExpressionPresenter.defaultDestination(config, out)); explain(ep); } catch (XPathException err) { // ignore the exception } } /** * Diagnostic print of expression structure. The abstract expression tree * is written to the supplied output destination. * @param out the expression presenter used to display the structure */ public abstract void explain(ExpressionPresenter out); /** * Diagnostic print of expression structure. The abstract expression tree * is written to the supplied outputstream. * @param out the expression presenter used to display the structure */ public final void explain(OutputStream out) { ExpressionPresenter ep = new ExpressionPresenter(getExecutable().getConfiguration(), out); explain(ep); ep.close(); } /** * Check that any elements and attributes constructed or returned by this expression are acceptable * in the content model of a given complex type. It's always OK to say yes, since the check will be * repeated at run-time. The process of checking element and attribute constructors against the content * model of a complex type also registers the type of content expected of those constructors, so the * static validation can continue recursively. * @param parentType the "given complex type": the method is checking that the nodes returned by this * expression are acceptable members of the content model of this type * @param env the static context * @param whole if true, we want to check that the value of this expression satisfies the content model * as a whole; if false we want to check that the value of the expression is acceptable as one part * of the content * @throws XPathException if the value delivered by this expression cannot be part of the content model * of the given type */ public void checkPermittedContents(SchemaType parentType, StaticContext env, boolean whole) throws XPathException { // } /** * Mark an expression as being in a given Container. This link is used primarily for diagnostics: * the container links to the location map held in the executable. * *

    This affects the expression and all its subexpressions. Any subexpressions that are not in the * same container are marked with the new container, and this proceeds recursively. However, any * subexpression that is already in the correct container is not modified.

    * * @param container The container of this expression. */ public void setContainer(Container container) { this.container = container; if (container != null) { Iterator children = iterateSubExpressions(); while (children.hasNext()) { Expression child = (Expression)children.next(); // child can be null while expressions are under construction if (child != null && child.getContainer() != container) { child.setContainer(container); } } } } /** * Get the container in which this expression is located. This will usually be a top-level construct * such as a function or global variable, and XSLT template, or an XQueryExpression. In the case of * free-standing XPath expressions it will be the StaticContext object * @return the expression's container */ public Container getContainer() { return container; } /** * Set up a parent-child relationship between this expression and a given child expression. *

    * Note: many calls on this method are now redundant, but are kept in place for "belt-and-braces" * reasons. The rule is that an implementation of simplify(), typeCheck(), or optimize() that returns * a value other than "this" is required to set the location information and parent pointer in the new * child expression. However, in the past this was often left to the caller, which did it by calling * this method, either unconditionally on return from one of these methods, or after testing that the * returned object was not the same as the original. * @param child the child expression */ public void adoptChildExpression(Expression child) { if (child == null) { return; } if (container == null) { container = child.container; } else { child.setContainer(container); } if (locationId == -1) { ExpressionTool.copyLocationInfo(child, this); } else if (child.locationId == -1) { ExpressionTool.copyLocationInfo(this, child); } resetLocalStaticProperties(); } /** * Set the location ID on an expression. * @param id the location id */ public void setLocationId(int id) { locationId = id; } /** * Get the location ID of the expression * @return a location identifier, which can be turned into real * location information by reference to a location provider */ public final int getLocationId() { return locationId; } /** * Get the line number of the expression */ public int getLineNumber() { if (locationId == -1) { return -1; } return locationId & 0xfffff; } /** * Get the column number of the expression */ public int getColumnNumber() { return -1; } /** * Get the systemId of the module containing the expression */ public String getSystemId() { if (locationId == -1) { return null; } Executable exec = getExecutable(); if (exec == null) { return null; } LocationMap map = exec.getLocationMap(); if (map == null) { return null; } return map.getSystemId(locationId); } /** * Get the publicId of the module containing the expression (to satisfy the SourceLocator interface) */ public final String getPublicId() { return null; } /** * Get the executable containing this expression * @return the containing Executable */ public Executable getExecutable() { return getContainer().getExecutable(); } /** * Get the LocationProvider allowing location identifiers to be resolved. * @return the LocationProvider used to turn the location id into real location information */ public LocationProvider getLocationProvider() { Executable exec = getExecutable(); if (exec != null) { return exec.getLocationMap(); } else { return null; } } /** * Promote a subexpression if possible, and if the expression was changed, carry out housekeeping * to reset the static properties and correct the parent pointers in the tree * @param subexpression the subexpression that is a candidate for promotion * @param offer details of the promotion being considered * @return the result of the promotion. This will be the current expression if no promotion * actions have taken place */ public final Expression doPromotion(Expression subexpression, PromotionOffer offer) throws XPathException { Expression e = subexpression.promote(offer); if (e != subexpression) { adoptChildExpression(e); } else if (offer.accepted) { resetLocalStaticProperties(); } return e; } /** * Compute the static properties. This should only be done once for each * expression. */ public final void computeStaticProperties() { staticProperties = computeDependencies() | computeCardinality() | computeSpecialProperties(); } /** * Reset the static properties of the expression to -1, so that they have to be recomputed * next time they are used. */ protected void resetLocalStaticProperties() { staticProperties = -1; } /** * Compute the static cardinality of this expression * @return the computed cardinality, as one of the values {@link StaticProperty#ALLOWS_ZERO_OR_ONE}, * {@link StaticProperty#EXACTLY_ONE}, {@link StaticProperty#ALLOWS_ONE_OR_MORE}, * {@link StaticProperty#ALLOWS_ZERO_OR_MORE} */ protected abstract int computeCardinality(); /** * Compute the special properties of this expression. These properties are denoted by a bit-significant * integer, possible values are in class {@link StaticProperty}. The "special" properties are properties * other than cardinality and dependencies, and most of them relate to properties of node sequences, for * example whether the nodes are in document order. * @return the special properties, as a bit-significant integer */ protected int computeSpecialProperties() { return 0; } /** * Compute the dependencies of an expression, as the union of the * dependencies of its subexpressions. (This is overridden for path expressions * and filter expressions, where the dependencies of a subexpression are not all * propogated). This method should be called only once, to compute the dependencies; * after that, getDependencies should be used. * @return the depencies, as a bit-mask */ public int computeDependencies() { int dependencies = getIntrinsicDependencies(); for (Iterator children = iterateSubExpressions(); children.hasNext();) { dependencies |= ((Expression)children.next()).getDependencies(); } return dependencies; } /** * Determine the intrinsic dependencies of an expression, that is, those which are not derived * from the dependencies of its subexpressions. For example, position() has an intrinsic dependency * on the context position, while (position()+1) does not. The default implementation * of the method returns 0, indicating "no dependencies". * * @return a set of bit-significant flags identifying the "intrinsic" * dependencies. The flags are documented in class net.sf.saxon.value.StaticProperty */ public int getIntrinsicDependencies() { return 0; } /** * Check to ensure that this expression does not contain any inappropriate updating subexpressions. * This check is overridden for those expressions that permit updating subexpressions. * @throws XPathException if the expression has a non-permitted updating subexpression */ public void checkForUpdatingSubexpressions() throws XPathException { for (Iterator iter = iterateSubExpressions(); iter.hasNext();) { Expression sub = (Expression)iter.next(); sub.checkForUpdatingSubexpressions(); if (sub.isUpdatingExpression()) { XPathException err = new XPathException( "Updating expression appears in a context where it is not permitted", "XUST0001"); err.setLocator(sub); throw err; } } } /** * Determine whether this is an updating expression as defined in the XQuery update specification * @return true if this is an updating expression */ public boolean isUpdatingExpression() { for (Iterator iter = iterateSubExpressions(); iter.hasNext();) { if (((Expression)iter.next()).isUpdatingExpression()) { return true; } } return false; } /** * Copy an expression. This makes a deep copy. * @return the copy of the original expression */ public abstract Expression copy(); /** * Replace one subexpression by a replacement subexpression * @param original the original subexpression * @param replacement the replacement subexpression * @return true if the original subexpression is found */ public boolean replaceSubExpression(Expression original, Expression replacement) { // overridden in subclasses throw new IllegalArgumentException("Invalid replacement"); } /** * Suppress validation on contained element constructors, on the grounds that the parent element * is already performing validation. The default implementation does nothing. * @param validationMode the kind of validation being performed on the parent expression */ public void suppressValidation(int validationMode) { // do nothing } /** * Mark tail-recursive calls on stylesheet functions. For most expressions, this does nothing. * @param qName the name of the function * @param arity the arity (number of parameters) of the function * * @return 0 if no tail call was found; 1 if a tail call on a different function was found; * 2 if a tail recursive call was found and if this call accounts for the whole of the value. */ public int markTailFunctionCalls(StructuredQName qName, int arity) { return 0; } /** * Get the local variables (identified by their slot numbers) on which this expression depends. * Should only be called if the caller has established that there is a dependency on local variables. * @return an array of integers giving the slot numbers of the local variables referenced in this * expression. */ public synchronized int[] getSlotsUsed() { // synchronized because it's calculated lazily at run-time the first time it's needed if (slotsUsed != null) { return slotsUsed; } IntHashSet slots = new IntHashSet(10); gatherSlotsUsed(this, slots); slotsUsed = new int[slots.size()]; int i=0; IntIterator iter = slots.iterator(); while (iter.hasNext()) { slotsUsed[i++] = iter.next(); } Arrays.sort(slotsUsed); return slotsUsed; } private static void gatherSlotsUsed(Expression exp, IntHashSet slots) { if (exp instanceof VariableReference) { Binding binding = ((VariableReference)exp).getBinding(); if (binding == null) { throw new NullPointerException("Unbound variable at line " + exp.getLineNumber()); } if (!binding.isGlobal()) { int slot = binding.getLocalSlotNumber(); if (slot != -1) { if (!slots.contains(slot)) { slots.add(slot); } } } } else { Iterator iter = exp.iterateSubExpressions(); while (iter.hasNext()) { Expression sub = (Expression)iter.next(); gatherSlotsUsed(sub, slots); } } } /** * Method used in subclasses to signal a dynamic error * @param message the error message * @param code the error code * @param context the XPath dynamic context */ protected void dynamicError(String message, String code, XPathContext context) throws XPathException { XPathException err = new XPathException(message, this); err.setXPathContext(context); err.setErrorCode(code); throw err; } /** * Method used in subclasses to signal a runtime type error * @param message the error message * @param errorCode the error code * @param context the XPath dynamic context */ protected void typeError(String message, String errorCode, XPathContext context) throws XPathException { XPathException e = new XPathException(message, this); e.setIsTypeError(true); e.setErrorCode(errorCode); e.setXPathContext(context); throw e; } /** * Get InstructionInfo for this expression */ // public InstructionInfo getInstructionInfo() { // InstructionDetails details = new InstructionDetails(); // details.setConstructType(getConstructType()); // details.setProperty("expression", this); // details.setSystemId(getSystemId()); // details.setLineAndColumn(getLineNumber()); // details.setColumnNumber(getColumnNumber()); // if (this instanceof Assignation) { // details.setObjectName(((Assignation)this).getVariableQName()); // } // return details; // } /** * Get the type of this expression for use in tracing and diagnostics * @return the type of expression, as enumerated in class {@link net.sf.saxon.trace.Location} */ public int getConstructType() { return Location.XPATH_EXPRESSION; } public StructuredQName getObjectName() { return null; } public Object getProperty(String name) { if (name.equals("expression")) { return this; } else { return null; } } /** * Get the line number within the document or module containing a particular location * * @param locationId identifier of the location in question (as passed down the Receiver pipeline) * @return the line number within the document or module. */ public int getLineNumber(long locationId) { return getLineNumber(); } public int getColumnNumber(long locationId) { return getColumnNumber(); } /** * Get the URI of the document or module containing a particular location * * @param locationId identifier of the location in question (as passed down the Receiver pipeline) * @return the URI of the document or module. */ public String getSystemId(long locationId) { return getSystemId(); } /** * Get an iterator over all the properties available. The values returned by the iterator * will be of type String, and each string can be supplied as input to the getProperty() * method to retrieve the value of the property. The iterator may return properties whose * value is null. */ public Iterator getProperties() { return new MonoIterator("expression"); } /** * Get the host language (XSLT, XQuery, XPath) used to implement the code in this container * @return typically {@link net.sf.saxon.Configuration#XSLT} or {@link net.sf.saxon.Configuration#XQUERY} */ public int getHostLanguage() { return getContainer().getHostLanguage(); } /** * Add a representation of this expression to a PathMap. The PathMap captures a map of the nodes visited * by an expression in a source tree. * *

    The default implementation of this method assumes that an expression does no navigation other than * the navigation done by evaluating its subexpressions, and that the subexpressions are evaluated in the * same context as the containing expression. The method must be overridden for any expression * where these assumptions do not hold. For example, implementations exist for AxisExpression, ParentExpression, * and RootExpression (because they perform navigation), and for the doc(), document(), and collection() * functions because they create a new navigation root. Implementations also exist for PathExpression and * FilterExpression because they have subexpressions that are evaluated in a different context from the * calling expression.

    * * @param pathMap the PathMap to which the expression should be added * @param pathMapNodeSet the PathMapNodeSet to which the paths embodied in this expression should be added * @return the pathMapNodeSet representing the points in the source document that are both reachable by this * expression, and that represent possible results of this expression. For an expression that does * navigation, it represents the end of the arc in the path map that describes the navigation route. For other * expressions, it is the same as the input pathMapNode. */ public PathMap.PathMapNodeSet addToPathMap(PathMap pathMap, PathMap.PathMapNodeSet pathMapNodeSet) { boolean dependsOnFocus = (getDependencies() & StaticProperty.DEPENDS_ON_FOCUS) != 0; TypeHierarchy th = getExecutable().getConfiguration().getTypeHierarchy(); PathMap.PathMapNodeSet attachmentPoint; if (pathMapNodeSet == null) { if (dependsOnFocus) { ContextItemExpression cie = new ContextItemExpression(); cie.setContainer(getContainer()); pathMapNodeSet = new PathMap.PathMapNodeSet(pathMap.makeNewRoot(cie)); } attachmentPoint = pathMapNodeSet; } else { attachmentPoint = (dependsOnFocus ? pathMapNodeSet : null); } PathMap.PathMapNodeSet result = new PathMap.PathMapNodeSet(); for (Iterator iter = iterateSubExpressions(); iter.hasNext(); ) { Expression child = (Expression)iter.next(); result.addNodeSet(child.addToPathMap(pathMap, attachmentPoint)); } if (getItemType(th) instanceof AtomicType) { // if expression returns an atomic value then any nodes accessed don't contribute to the result return null; } else { return result; } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. //saxonb-9.1.0.8/bj/net/sf/saxon/expr/PJConverter.java0000644000175000017500000012023011073070365021426 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.Configuration; import net.sf.saxon.om.*; import net.sf.saxon.pattern.NodeTest; import net.sf.saxon.pattern.EmptySequenceTest; import net.sf.saxon.trans.SaxonErrorCode; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.BuiltInAtomicType; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.TypeHierarchy; import net.sf.saxon.type.ExternalObjectType; import net.sf.saxon.value.*; import java.io.Serializable; import java.lang.reflect.Array; import java.math.BigDecimal; import java.math.BigInteger; import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; /** * This class together with its embedded subclasses handles conversion from XPath values * to Java values */ public abstract class PJConverter implements Serializable { private static HashMap jpmap = new HashMap(); static { jpmap.put(boolean.class, SequenceType.SINGLE_BOOLEAN); jpmap.put(Boolean.class, SequenceType.OPTIONAL_BOOLEAN); jpmap.put(String.class, SequenceType.OPTIONAL_STRING); jpmap.put(CharSequence.class, SequenceType.OPTIONAL_STRING); // Mappings for long and int are chosen to avoid static type errors when // a Java method expecting long or int is called with an integer literal jpmap.put(long.class, SequenceType.SINGLE_INTEGER); jpmap.put(Long.class, SequenceType.OPTIONAL_INTEGER); jpmap.put(int.class, SequenceType.SINGLE_INTEGER); jpmap.put(Integer.class, SequenceType.OPTIONAL_INTEGER); jpmap.put(short.class, SequenceType.SINGLE_SHORT); jpmap.put(Short.class, SequenceType.OPTIONAL_SHORT); jpmap.put(byte.class, SequenceType.SINGLE_BYTE); jpmap.put(Byte.class, SequenceType.OPTIONAL_BYTE); jpmap.put(float.class, SequenceType.SINGLE_FLOAT); jpmap.put(Float.class, SequenceType.OPTIONAL_FLOAT); jpmap.put(double.class, SequenceType.SINGLE_DOUBLE); jpmap.put(Double.class, SequenceType.OPTIONAL_DOUBLE); jpmap.put(URI.class, SequenceType.OPTIONAL_ANY_URI); jpmap.put(URL.class, SequenceType.OPTIONAL_ANY_URI); jpmap.put(BigInteger.class, SequenceType.OPTIONAL_INTEGER); jpmap.put(BigDecimal.class, SequenceType.OPTIONAL_DECIMAL); } /** * Get the nearest XPath equivalent to a Java class. A function call will * be type-checked against an XPath function signature in which the Java classes * are replaced by their nearest equivalent XPath types * @param javaClass a Java class * @return the nearest equivalent XPath SequenceType */ public static SequenceType getEquivalentItemType(Class javaClass) { return (SequenceType)jpmap.get(javaClass); } /** * Convert an XPath value to a Java value of a specified class * @param value the supplied XPath value * @param targetClass the class of the required Java value * @param context the XPath dynamic context * @return the corresponding Java value, which is guaranteed to be an instance of the * target class (except that an empty sequence is converted to null) * @throws XPathException if the conversion is not possible or fails */ public abstract Object convert(ValueRepresentation value, Class targetClass, XPathContext context) throws XPathException; /** * Generate Java code to implement the type conversion * @param var the name of a variable whose value will be the XPath ValueRepresentation * to be converted * @param targetClass the required class of the Java value *@param compiler provides supporting services by callback @return the text of a Java expression whose result will be a Java object/value of the * required type */ public String compile(String var, Class targetClass, CodeGeneratorService compiler) { throw new UnsupportedOperationException( "Cannot generate Java code to support argument conversion for " + getClass()); } /** * Factory method to instantiate a converter from a given XPath type to a given Java class * @param config the Saxon Configuration * @param itemType the item type of the XPath value to be converted * @param cardinality the cardinality of the XPath value to be converted * @param targetClass the Java class required for the conversion result * @return a suitable converter */ public static PJConverter allocate(Configuration config, ItemType itemType, int cardinality, Class targetClass) throws XPathException { TypeHierarchy th = config.getTypeHierarchy(); if (targetClass == SequenceIterator.class) { return ToSequenceIterator.INSTANCE; } if (targetClass == ValueRepresentation.class || targetClass == Item.class) { return Identity.INSTANCE; } if (targetClass == Value.class | targetClass == SequenceExtent.class) { return ToSequenceExtent.INSTANCE; } if (!itemType.isAtomicType()) { List externalObjectModels = config.getExternalObjectModels(); for (int m=0; m * Note that it is the caller's responsibility to close the Writer after use. * * @exception XPathException if any dynamic error occurs; and * specifically, if an attempt is made to switch to a final output * destination while writing a temporary tree or sequence * @param props properties defining the output format * @param result Details of the new output destination * @param isFinal true if the destination is a final result tree * (either the principal output or a secondary result tree); false if not * @param hostLanguage typically XSLT or XQuery * @param validation validation mode: strict, lax, preserve, or strip * @param schemaType type against which the output must be validated */ public void changeOutputDestination(Properties props, Result result, boolean isFinal, int hostLanguage, int validation, SchemaType schemaType) throws XPathException; /** * Set the SequenceReceiver to which output is to be written, marking it as a temporary (non-final) * output destination. * @param out The SequenceReceiver to be used */ public void setTemporaryReceiver(SequenceReceiver out); /** * Change the SequenceReceiver to which output is written * @param receiver the SequenceReceiver to be used */ public void setReceiver(SequenceReceiver receiver); /** * Get the Receiver to which output is currently being written. * @return the current SequenceReceiver */ public SequenceReceiver getReceiver(); /** * Get the current mode. * @return the current mode */ public Mode getCurrentMode(); /** * Get the current template rule. This is used to support xsl:apply-imports and xsl:next-match * @return the current template rule */ public Rule getCurrentTemplateRule(); /** * Get the current group iterator. This supports the current-group() and * current-grouping-key() functions in XSLT 2.0 * @return the current grouped collection */ public GroupIterator getCurrentGroupIterator(); /** * Get the current regex iterator. This supports the functionality of the regex-group() * function in XSLT 2.0. * @return the current regular expressions iterator */ public RegexIterator getCurrentRegexIterator(); /** * Get the current date and time * @return the current date and time. All calls within a single query or transformation * will return the same value */ public DateTimeValue getCurrentDateTime() throws NoDynamicContextException; /** * Get the implicit timezone * @return the implicit timezone. This will be the timezone of the current date and time, and * all calls within a single query or transformation will return the same value. The result is * expressed as an offset from UTC in minutes. */ public int getImplicitTimezone() throws NoDynamicContextException; /** * Get the context stack. This method returns an iterator whose items are instances of * {@link net.sf.saxon.trace.ContextStackFrame}, starting with the top-most stackframe and * ending at the point the query or transformation was invoked by a calling application. * @return an iterator over a copy of the run-time call stack */ public Iterator iterateStackFrames(); } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/expr/TailCallLoop.java0000644000175000017500000001445011033112257021543 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.instruct.UserFunction; import net.sf.saxon.om.Item; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.om.ValueRepresentation; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.TypeHierarchy; import net.sf.saxon.value.SequenceExtent; import net.sf.saxon.value.Value; /** * A TailCallLoop wraps the body of a function that contains tail-recursive function calls. On completion * of the "real" body of the function it tests whether the function has executed a tail call, and if so, * iterates to evaluate the tail call. */ public final class TailCallLoop extends UnaryExpression { UserFunction containingFunction; /** * Constructor - create a TailCallLoop * @param function the function in which this tail call loop appears */ public TailCallLoop(UserFunction function) { super(function.getBody()); containingFunction = function; } /** * Get the containing function * @return the containing function */ public UserFunction getContainingFunction() { return containingFunction; } /** * Type-check the expression */ public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { operand = visitor.typeCheck(operand, contextItemType); return this; } /** * An implementation of Expression must provide at least one of the methods evaluateItem(), iterate(), or process(). * This method indicates which of these methods is provided. This implementation provides both iterate() and * process() methods natively. */ public int getImplementationMethod() { return operand.getImplementationMethod(); } /** * Copy an expression. This makes a deep copy. * * @return the copy of the original expression */ public Expression copy() { throw new UnsupportedOperationException("copy"); } /** * Iterate over the sequence of values */ public SequenceIterator iterate(XPathContext context) throws XPathException { final XPathContextMajor cm = (XPathContextMajor)context; while (true) { SequenceIterator iter = operand.iterate(cm); ValueRepresentation extent = SequenceExtent.makeSequenceExtent(iter); UserFunction fn = cm.getTailCallFunction(); if (fn == null) { return Value.asIterator(extent); } if (fn != containingFunction) { return Value.asIterator(tailCallDifferentFunction(fn, cm)); } // otherwise, loop round to execute the tail call } } /** * Evaluate as an Item. */ public Item evaluateItem(XPathContext context) throws XPathException { final XPathContextMajor cm = (XPathContextMajor)context; while (true) { Item item = operand.evaluateItem(context); UserFunction fn = cm.getTailCallFunction(); if (fn == null) { return item; } if (fn != containingFunction) { return Value.asItem(tailCallDifferentFunction(fn, cm)); } // otherwise, loop round to execute the tail call } } /** * Process the function body * @param context The dynamic context, giving access to the current node, * the current variables, etc. */ public void process(XPathContext context) throws XPathException { final XPathContextMajor cm = (XPathContextMajor)context; while (true) { operand.process(context); UserFunction fn = cm.getTailCallFunction(); if (fn == null) { return; } if (fn != containingFunction) { Value.asValue(tailCallDifferentFunction(fn, cm)).process(cm); return; } // otherwise, loop round to execute the tail call } } /** * Make a tail call on a different function. This reuses the context object and the stack frame array * where possible, but it does consume some Java stack space. It's still worth it, because we don't use * as much stack as we would if we didn't return down to the TailCallLoop level. * @param fn the function to be called * @param cm the dynamic context * @return the result of calling the other function * @throws XPathException if the called function fails */ private ValueRepresentation tailCallDifferentFunction(UserFunction fn, XPathContextMajor cm) throws XPathException { cm.resetStackFrameMap(fn.getStackFrameMap(), fn.getNumberOfArguments()); try { return ExpressionTool.evaluate(fn.getBody(), fn.getEvaluationMode(), cm, 1); } catch (XPathException err) { err.maybeSetLocation(this); err.maybeSetContext(cm); throw err; } } /** * Determine the data type of the items returned by the expression * @param th The type hierarchy cache */ public ItemType getItemType(TypeHierarchy th) { return operand.getItemType(th); } /** * Give a string representation of the expression name for use in diagnostics * @return the expression name, as a string */ protected String displayExpressionName() { return "tailCallLoop"; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/expr/IterateInstr.java0000644000175000017500000003255311033112257021645 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.instruct.Block; import net.sf.saxon.instruct.Instruction; import net.sf.saxon.instruct.TailCall; import net.sf.saxon.instruct.UserFunction; import net.sf.saxon.om.Item; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.trace.ExpressionPresenter; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.SchemaType; import net.sf.saxon.type.Type; import net.sf.saxon.type.TypeHierarchy; import net.sf.saxon.value.EmptySequence; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /** * A TailCallLoop wraps the body of a function that contains tail-recursive function calls. On completion * of the "real" body of the function it tests whether the function has executed a tail call, and if so, * iterates to evaluate the tail call. */ public final class IterateInstr extends Instruction { private Expression select; private Expression action; private Expression finallyExp; /** * Create a saxon:iterate instruction * @param select the select expression * @param action the body of the saxon:iterate loop * @param finallyExp the expression to be evaluated before final completion, may be null */ public IterateInstr(Expression select, Expression action, Expression finallyExp) { this.select = select; this.action = action; this.finallyExp = (finallyExp == null ? new Literal(EmptySequence.getInstance()) : finallyExp); adoptChildExpression(select); adoptChildExpression(action); adoptChildExpression(finallyExp); } /** * Get the action expression (the content of the for-each) * @return the body of the for-each loop */ public Expression getActionExpression() { return action; } /** * Simplify an expression. This performs any static optimization (by rewriting the expression * as a different expression). * * @exception XPathException if an error is discovered during expression * rewriting * @return the simplified expression * @param visitor the expression visitor */ public Expression simplify(ExpressionVisitor visitor) throws XPathException { select = visitor.simplify(select); action = visitor.simplify(action); finallyExp = visitor.simplify(finallyExp); return this; } /** * Type-check the expression */ public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { final TypeHierarchy th = visitor.getConfiguration().getTypeHierarchy(); select = visitor.typeCheck(select, contextItemType); adoptChildExpression(select); action = visitor.typeCheck(action, select.getItemType(th)); adoptChildExpression(action); finallyExp = visitor.typeCheck(finallyExp, null); adoptChildExpression(finallyExp); if (Literal.isEmptySequence(select)) { return select; } if (Literal.isEmptySequence(action)) { return action; } return this; } public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { final TypeHierarchy th = visitor.getConfiguration().getTypeHierarchy(); select = visitor.optimize(select, contextItemType); adoptChildExpression(select); action = action.optimize(visitor, select.getItemType(th)); adoptChildExpression(action); finallyExp = finallyExp.optimize(visitor, select.getItemType(th)); adoptChildExpression(finallyExp); if (Literal.isEmptySequence(select)) { return select; } if (Literal.isEmptySequence(action)) { return action; } return this; } /** * Determine the data type of the items returned by this expression * @return the data type * @param th the type hierarchy cache */ public final ItemType getItemType(TypeHierarchy th) { if (Literal.isEmptySequence(finallyExp)) { return action.getItemType(th); } else { return Type.getCommonSuperType(action.getItemType(th), finallyExp.getItemType(th), th); } } /** * Determine whether this instruction creates new nodes. * This implementation returns true if the "action" creates new nodes. * (Nodes created by the condition can't contribute to the result). */ public final boolean createsNewNodes() { return (action.getSpecialProperties() & finallyExp.getSpecialProperties() & StaticProperty.NON_CREATIVE) == 0; } /** * Add a representation of this expression to a PathMap. The PathMap captures a map of the nodes visited * by an expression in a source tree. *

    *

    The default implementation of this method assumes that an expression does no navigation other than * the navigation done by evaluating its subexpressions, and that the subexpressions are evaluated in the * same context as the containing expression. The method must be overridden for any expression * where these assumptions do not hold. For example, implementations exist for AxisExpression, ParentExpression, * and RootExpression (because they perform navigation), and for the doc(), document(), and collection() * functions because they create a new navigation root. Implementations also exist for PathExpression and * FilterExpression because they have subexpressions that are evaluated in a different context from the * calling expression.

    * * @param pathMap the PathMap to which the expression should be added * @param pathMapNodeSet the set of nodes in the path map that are affected * @return the pathMapNode representing the focus established by this expression, in the case where this * expression is the first operand of a path expression or filter expression. For an expression that does * navigation, it represents the end of the arc in the path map that describes the navigation route. For other * expressions, it is the same as the input pathMapNode. */ public PathMap.PathMapNodeSet addToPathMap(PathMap pathMap, PathMap.PathMapNodeSet pathMapNodeSet) { PathMap.PathMapNodeSet target = select.addToPathMap(pathMap, pathMapNodeSet); return action.addToPathMap(pathMap, target); } /** * Compute the dependencies of an expression, as the union of the * dependencies of its subexpressions. (This is overridden for path expressions * and filter expressions, where the dependencies of a subexpression are not all * propogated). This method should be called only once, to compute the dependencies; * after that, getDependencies should be used. * * @return the depencies, as a bit-mask */ public int computeDependencies() { // Some of the dependencies aren't relevant. Note that the sort keys are absorbed into the select // expression. int dependencies = 0; dependencies |= select.getDependencies(); dependencies |= (action.getDependencies() & ~StaticProperty.DEPENDS_ON_FOCUS); dependencies |= (finallyExp.getDependencies() & ~StaticProperty.DEPENDS_ON_FOCUS); return dependencies; } /** * Handle promotion offers, that is, non-local tree rewrites. * @param offer The type of rewrite being offered * @throws XPathException */ protected void promoteInst(PromotionOffer offer) throws XPathException { select = doPromotion(select, offer); action = doPromotion(action, offer); finallyExp = doPromotion(finallyExp, offer); } /** * Get all the XPath expressions associated with this instruction * (in XSLT terms, the expression present on attributes of the instruction, * as distinct from the child instructions in a sequence construction) */ public Iterator iterateSubExpressions() { List sub = new ArrayList(8); sub.add(select); sub.add(action); sub.add(finallyExp); return sub.iterator(); } /** * Given an expression that is an immediate child of this expression, test whether * the evaluation of the parent expression causes the child expression to be * evaluated repeatedly * @param child the immediate subexpression * @return true if the child expression is evaluated repeatedly */ public boolean hasLoopingSubexpression(Expression child) { return child == action; } /** * Replace one subexpression by a replacement subexpression * @param original the original subexpression * @param replacement the replacement subexpression * @return true if the original subexpression is found */ public boolean replaceSubExpression(Expression original, Expression replacement) { boolean found = false; if (select == original) { select = replacement; found = true; } if (action == original) { action = replacement; found = true; } if (finallyExp == original) { finallyExp = replacement; found = true; } return found; } /** * An implementation of Expression must provide at least one of the methods evaluateItem(), iterate(), or process(). * This method indicates which of these methods is provided. This implementation provides both iterate() and * process() methods natively. */ public int getImplementationMethod() { return PROCESS_METHOD; } /** * Check that any elements and attributes constructed or returned by this expression are acceptable * in the content model of a given complex type. It's always OK to say yes, since the check will be * repeated at run-time. The process of checking element and attribute constructors against the content * model of a complex type also registers the type of content expected of those constructors, so the * static validation can continue recursively. */ public void checkPermittedContents(SchemaType parentType, StaticContext env, boolean whole) throws XPathException { action.checkPermittedContents(parentType, env, false); } /** * Copy an expression. This makes a deep copy. * * @return the copy of the original expression */ public Expression copy() { throw new UnsupportedOperationException("copy"); } public TailCall processLeavingTail(XPathContext context) throws XPathException { SequenceIterator iter = select.iterate(context); XPathContextMajor c2 = context.newContext(); c2.setOrigin(this); c2.setCurrentIterator(iter); c2.setCurrentTemplateRule(null); // TODO: add tracing as in xsl:for-each while (true) { Item item = iter.next(); if (item == null) { if (action instanceof Block) { c2.setCurrentIterator(null); ((Block)action).processLocalParams(c2); } finallyExp.process(context); break; } action.process(c2); UserFunction fn = c2.getTailCallFunction(); if (fn == null) { // no saxon:continue or saxon:break was encountered; just loop around } else if (fn.getFunctionName().equals(BreakInstr.SAXON_BREAK)) { // indicates a saxon:break instruction was encountered: break the loop iter.close(); return null; } else { // a saxon:continue instruction was encountered. // It will have reset the parameters to the loop; we just need to loop round } } return null; } /** * Diagnostic print of expression structure. The abstract expression tree * is written to the supplied output destination. */ public void explain(ExpressionPresenter out) { out.startElement("saxonIterate"); select.explain(out); out.startSubsidiaryElement("return"); action.explain(out); out.endSubsidiaryElement(); if (!Literal.isEmptySequence(finallyExp)) { out.startSubsidiaryElement("saxonFinally"); finallyExp.explain(out); out.endSubsidiaryElement(); } out.endElement(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/expr/LastItemExpression.java0000644000175000017500000001043411033112257023024 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.om.Item; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ItemType; /** * A LastItemExpression returns the last item in the sequence returned by a given * base expression. The evaluation strategy is to read the input sequence with a one-item lookahead. */ public final class LastItemExpression extends UnaryExpression { /** * Constructor * @param base A sequence expression denoting sequence whose first item is to be returned */ public LastItemExpression(Expression base) { super(base); computeStaticProperties(); } /** * Perform optimisation of an expression and its subexpressions. *

    *

    This method is called after all references to functions and variables have been resolved * to the declaration of the function or variable, and after all type checking has been done.

    * * @param visitor an expresion visitor * @param contextItemType the static type of "." at the point where this expression is invoked. * The parameter is set to null if it is known statically that the context item will be undefined. * If the type of the context item is not known statically, the argument is set to * {@link net.sf.saxon.type.Type#ITEM_TYPE} * @return the original expression, rewritten if appropriate to optimize execution * @throws net.sf.saxon.trans.XPathException if an error is discovered during this phase * (typically a type error) */ public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { operand = visitor.optimize(operand, contextItemType); if (operand instanceof LastItemExpression || operand instanceof FirstItemExpression) { return operand; } return super.optimize(visitor, contextItemType); } /** * Promote this expression if possible */ public Expression promote(PromotionOffer offer) throws XPathException { Expression exp = offer.accept(this); if (exp != null) { return exp; } else { if (offer.action != PromotionOffer.UNORDERED) { // we can't push the UNORDERED property down to the operand, because order is significant operand = doPromotion(operand, offer); } return this; } } /** * Get the static cardinality */ public int computeCardinality() { return operand.getCardinality() & ~StaticProperty.ALLOWS_MANY; } /** * Copy an expression. This makes a deep copy. * * @return the copy of the original expression */ public Expression copy() { return new LastItemExpression(getBaseExpression().copy()); } /** * Evaluate the expression */ public Item evaluateItem(XPathContext context) throws XPathException { SequenceIterator forwards = operand.iterate(context); if (forwards instanceof ReversibleIterator) { return ((ReversibleIterator)forwards).getReverseIterator().next(); } else { Item current = null; while (true) { Item item = forwards.next(); if (item == null) { return current; } current = item; } } } public String displayExpressionName() { return "lastItem"; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/expr/Binding.java0000644000175000017500000000473611033112257020604 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.om.ValueRepresentation; import net.sf.saxon.om.StructuredQName; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.SequenceType; /** * Binding is a interface used to represent the run-time properties and methods * associated with a variable: specifically, a method to get the value * of the variable. */ public interface Binding { /** * Get the declared type of the variable * @return the declared type */ public SequenceType getRequiredType(); /** * Evaluate the variable * @param context the XPath dynamic evaluation context * @return the result of evaluating the variable */ public ValueRepresentation evaluateVariable(XPathContext context) throws XPathException; /** * Indicate whether the binding is local or global. A global binding is one that has a fixed * value for the life of a query or transformation; any other binding is local. * @return true if the binding is global */ public boolean isGlobal(); /** * Test whether it is permitted to assign to the variable using the saxon:assign * extension element. This will only be for an XSLT global variable where the extra * attribute saxon:assignable="yes" is present. * @return true if the binding is assignable */ public boolean isAssignable(); /** * If this is a local variable held on the local stack frame, return the corresponding slot number. * In other cases, return -1. * @return the slot number on the local stack frame */ public int getLocalSlotNumber(); /** * Get the name of the variable * @return the name of the variable, as a structured QName */ public StructuredQName getVariableQName(); } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/expr/package.html0000644000175000017500000000663511033112257020650 0ustar eugeneeugene Package overview for net.sf.saxon.expr

    This package provides classes associated with XPath expression handling. Generally, these classes are not intended to be used directly by user-written applications; the API for XPath evaluation is now provided by classes in the package net.sf.saxon.xpath

    The principal classes are:

    Expression:
    This represents an XPath Expression. There is a static method Expression.make() which is used to construct an Expression from a String (it is a factory method rather than a constructor, because it typically returns some subclass of Expression according to the syntax supplied). Subclasses of Expression represent different kinds of expression such as StringExpression and BooleanExpression. What they all have in common is an evaluate() method, which evaluates the expression in a given context to yield a Value, and an iterate() method, which treats the result of the expression as a sequence, and iterates over the items in the sequence.

    ExpressionParser:
    This class does the work of parsing both Expressions and Patterns. Applications should not call it directly. It uses the class Tokenizer for lexical analysis.

    StaticContext:
    This interface defines the information available at the time an expression is being parsed. This includes the names of variables, the bindings of namespace prefixes, the functions that are available, the names of collating sequences, and so on. When an XPath expression appears in a stylesheet, the class net.sf.saxon.style.ExpressionContext provides the StaticContext. For a free-standing XPath expression, the class net.sf.saxon.xpath.StandaloneContext is available, though a user-written class that implements StaticContext can also be used.

    XPathContext:
    This class defines the context information available at run-time, for example the context node, position, and size. (It actually does this by wrapping a SequenceIterator that represents the current sequence.) When expressions are used during an XSLT transformation, the XPathContext also provides access to the Controller, which contains all the context information about XSLT processing (for example the current template, the current group, and so on).

    Most of the classes in this package represent individual syntactic constructs found in XPath or XQuery expressions: for example ValueComparison, UserFunctionCall, and RootExpression. The objects that instantiate these classes form the nodes on the Abstract Syntax Tree constructed by the compiler and modified by the optimizer; at run-time their methods are used to drive a pipelined evaluation of the expression.

    The distinction between the compiled form of XSLT instructions and the compiled form of XPath expressions has become blurred. Generally, the compiled form of instructions is in the package net.sf.saxon.instruct (this includes expressions in XQuery that are equivalent to XSLT instructions, for example element constructors). However, some constructs such as conditional expressions now exist in both languages and may generate the same run-time constructs.


    Michael H. Kay
    Saxonica Limited
    9 February 2005

    saxonb-9.1.0.8/bj/net/sf/saxon/expr/CardinalityCheckingIterator.java0000644000175000017500000001232011044033432024626 0ustar eugeneeugenepackage net.sf.saxon.expr; import net.sf.saxon.om.Item; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.Cardinality; import javax.xml.transform.SourceLocator; /** * CardinalityCheckingIterator returns the items in an underlying sequence * unchanged, but checks that the number of items conforms to the required * cardinality. Because cardinality checks are required to take place even * if the consumer of the sequence does not require all the items, we read * the first two items at initialization time. This is sufficient to perform * the checks; after that we can simply return the items from the base sequence. */ public final class CardinalityCheckingIterator implements SequenceIterator { private SequenceIterator base; private int requiredCardinality; private RoleLocator role; private SourceLocator locator; private Item first = null; private Item second = null; private Item current = null; private int position = 0; /** * Construct an CardinalityCheckingIterator that will return the same items as the base sequence, * checking how many there are * * @param base the base iterator * @param requiredCardinality the required Cardinality */ public CardinalityCheckingIterator(SequenceIterator base, int requiredCardinality, RoleLocator role, SourceLocator locator) throws XPathException { this.base = base; this.requiredCardinality = requiredCardinality; this.role = role; first = base.next(); if (first==null) { if (!Cardinality.allowsZero(requiredCardinality)) { typeError("An empty sequence is not allowed as the " + role.getMessage(), role.getErrorCode()); } } else { if (requiredCardinality == StaticProperty.EMPTY) { typeError("The only value allowed for the " + role.getMessage() + " is an empty sequence", role.getErrorCode()); } second = base.next(); if (second!=null && !Cardinality.allowsMany(requiredCardinality)) { typeError( "A sequence of more than one item is not allowed as the " + role.getMessage() + CardinalityChecker.depictSequenceStart(base.getAnother(), 2), role.getErrorCode()); } } } public Item next() throws XPathException { if (position < 2) { if (position == 0) { current = first; position = (first==null ? -1 : 1); return current; } else if (position == 1) { current = second; position = (second==null ? -1 : 2); return current; } else { // position == -1 return null; } } current = base.next(); if (current == null) { position = -1; } else { position++; } return current; } public Item current() { return current; } public int position() { return position; } public void close() { base.close(); } public SequenceIterator getAnother() throws XPathException { return new CardinalityCheckingIterator(base.getAnother(), requiredCardinality, role, locator); } /** * Get properties of this iterator, as a bit-significant integer. * * @return the properties of this iterator. This will be some combination of * properties such as {@link net.sf.saxon.om.SequenceIterator#GROUNDED}, * {@link net.sf.saxon.om.SequenceIterator#LAST_POSITION_FINDER}, * and {@link net.sf.saxon.om.SequenceIterator#LOOKAHEAD}. It is always * acceptable to return the value zero, indicating that there are no known special properties. * It is acceptable for the properties of the iterator to change depending on its state. */ public int getProperties() { return 0; } private void typeError(String message, String errorCode) throws XPathException { XPathException e = new XPathException(message, locator); e.setIsTypeError(true); e.setErrorCode(errorCode); throw e; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/event/0000755000175000017500000000000012216261747016535 5ustar eugeneeugenesaxonb-9.1.0.8/bj/net/sf/saxon/event/ProxyReceiver.java0000644000175000017500000002200311033112257022166 0ustar eugeneeugenepackage net.sf.saxon.event; import net.sf.saxon.Configuration; import net.sf.saxon.om.NamePool; import net.sf.saxon.om.Item; import net.sf.saxon.trans.XPathException; /** * A ProxyReceiver is an Receiver that filters data before passing it to another * underlying Receiver. */ public abstract class ProxyReceiver extends SequenceReceiver { protected Receiver nextReceiver; public void setSystemId(String systemId) { //noinspection StringEquality if (systemId != this.systemId) { // use of == rather than equals() is deliberate, since this is only an optimization this.systemId = systemId; if (nextReceiver != null) { nextReceiver.setSystemId(systemId); } } } /** * Set the underlying receiver. This call is mandatory before using the Receiver. * @param receiver the underlying receiver, the one that is to receive events after processing * by this filter. */ public void setUnderlyingReceiver(Receiver receiver) { if (receiver != nextReceiver) { nextReceiver = receiver; if (pipelineConfiguration != null) { nextReceiver.setPipelineConfiguration(pipelineConfiguration); } } } /** * Get the underlying Receiver (that is, the next one in the pipeline) */ public Receiver getUnderlyingReceiver() { return nextReceiver; } public void setPipelineConfiguration(PipelineConfiguration pipe) { if (pipelineConfiguration != pipe) { pipelineConfiguration = pipe; if (nextReceiver != null) { nextReceiver.setPipelineConfiguration(pipe); } } } public Configuration getConfiguration() { return pipelineConfiguration.getConfiguration(); } /** * Get the namepool for this configuration */ public NamePool getNamePool() { return pipelineConfiguration.getConfiguration().getNamePool(); } /** * Start of event stream */ public void open() throws XPathException { if (nextReceiver == null) { throw new IllegalStateException("ProxyReceiver.open(): no underlying receiver provided"); } nextReceiver.open(); } /** * End of output */ public void close() throws XPathException { // TODO: this isn't safe. It's wrong to assume that because we've finished writing to this // receiver, then we've also finished writing to other receivers in the pipe. nextReceiver.close(); } /** * Start of a document node. */ public void startDocument(int properties) throws XPathException { nextReceiver.startDocument(properties); } /** * Notify the end of a document node */ public void endDocument() throws XPathException { nextReceiver.endDocument(); } /** * Notify the start of an element * * @param nameCode integer code identifying the name of the element within the name pool. * @param typeCode integer code identifying the element's type within the name pool. * @param properties properties of the element node */ public void startElement(int nameCode, int typeCode, int locationId, int properties) throws XPathException { nextReceiver.startElement(nameCode, typeCode, locationId, properties); } /** * Notify a namespace. Namespaces are notified after the startElement event, and before * any children for the element. The namespaces that are reported are only required * to include those that are different from the parent element; however, duplicates may be reported. * A namespace must not conflict with any namespaces already used for element or attribute names. * * @param namespaceCode an integer: the top half is a prefix code, the bottom half a URI code. * These may be translated into an actual prefix and URI using the name pool. A prefix code of * zero represents the empty prefix (that is, the default namespace). A URI code of zero represents * a URI of "", that is, a namespace undeclaration. * @throws IllegalStateException: attempt to output a namespace when there is no open element * start tag */ public void namespace(int namespaceCode, int properties) throws XPathException { nextReceiver.namespace(namespaceCode, properties); } /** * Notify an attribute. Attributes are notified after the startElement event, and before any * children. Namespaces and attributes may be intermingled. * * @param nameCode The name of the attribute, as held in the name pool * @param typeCode The type of the attribute, as held in the name pool * @param properties Bit significant value. The following bits are defined: *
    DISABLE_ESCAPING
    Disable escaping for this attribute
    *
    NO_SPECIAL_CHARACTERS
    Attribute value contains no special characters
    * @throws IllegalStateException: attempt to output an attribute when there is no open element * start tag */ public void attribute(int nameCode, int typeCode, CharSequence value, int locationId, int properties) throws XPathException { nextReceiver.attribute(nameCode, typeCode, value, locationId, properties); } /** * Notify the start of the content, that is, the completion of all attributes and namespaces. * Note that the initial receiver of output from XSLT instructions will not receive this event, * it has to detect it itself. Note that this event is reported for every element even if it has * no attributes, no namespaces, and no content. */ public void startContent() throws XPathException { nextReceiver.startContent(); } /** * End of element */ public void endElement() throws XPathException { nextReceiver.endElement(); } /** * Character data */ public void characters(CharSequence chars, int locationId, int properties) throws XPathException { nextReceiver.characters(chars, locationId, properties); } /** * Processing Instruction */ public void processingInstruction(String target, CharSequence data, int locationId, int properties) throws XPathException { nextReceiver.processingInstruction(target, data, locationId, properties); } /** * Output a comment */ public void comment(CharSequence chars, int locationId, int properties) throws XPathException { nextReceiver.comment(chars, locationId, properties); } /** * Set the URI for an unparsed entity in the document. */ public void setUnparsedEntity(String name, String uri, String publicId) throws XPathException { nextReceiver.setUnparsedEntity(name, uri, publicId); } /** * Append an arbitrary item (node or atomic value) to the output * * @param item the item to be appended * @param locationId the location of the calling instruction, for diagnostics * @param copyNamespaces if the item is an element node, this indicates whether its namespaces * need to be copied. Values are {@link net.sf.saxon.om.NodeInfo#ALL_NAMESPACES}, * {@link net.sf.saxon.om.NodeInfo#LOCAL_NAMESPACES}, {@link net.sf.saxon.om.NodeInfo#NO_NAMESPACES} */ public void append(Item item, int locationId, int copyNamespaces) throws XPathException { if (nextReceiver instanceof SequenceReceiver) { ((SequenceReceiver)nextReceiver).append(item, locationId, copyNamespaces); } else { throw new UnsupportedOperationException("append() method is not supported in this class"); } } /** * Get the Document Locator */ public LocationProvider getDocumentLocator() { return pipelineConfiguration.getLocationProvider(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/event/TracingFilter.java0000644000175000017500000002136011033112257022122 0ustar eugeneeugenepackage net.sf.saxon.event; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.Whitespace; import net.sf.saxon.om.FastStringBuffer; import net.sf.saxon.om.Item; /** * A filter that can be inserted into a Receiver pipeline to trace the events that pass through */ public class TracingFilter extends ProxyReceiver { private static int nextid = 0; private int id; private String indent = ""; /** * Create a TracingFilter and allocate a unique Id. */ public TracingFilter() { id = nextid++; } /** * Create a TracingFilter and allocate a unique Id. * @param r the base receiver to which the events will be sent */ public TracingFilter(Receiver r) { id = nextid++; setUnderlyingReceiver(r); } /** * Append an arbitrary item (node or atomic value) to the output * * @param item the item to be appended * @param locationId the location of the calling instruction, for diagnostics * @param copyNamespaces if the item is an element node, this indicates whether its namespaces * need to be copied. Values are {@link net.sf.saxon.om.NodeInfo#ALL_NAMESPACES}, * {@link net.sf.saxon.om.NodeInfo#LOCAL_NAMESPACES}, {@link net.sf.saxon.om.NodeInfo#NO_NAMESPACES} */ public void append(Item item, int locationId, int copyNamespaces) throws XPathException { System.err.println("RCVR " + id + indent + " APPEND " + item.getClass().getName()); if (nextReceiver instanceof SequenceReceiver) { ((SequenceReceiver)nextReceiver).append(item, locationId, copyNamespaces); } else { super.append(item, locationId, copyNamespaces); } } /** * Notify an attribute. Attributes are notified after the startElement event, and before any * children. Namespaces and attributes may be intermingled. * * @param nameCode The name of the attribute, as held in the name pool * @param typeCode The type of the attribute, as held in the name pool * @param properties Bit significant value. The following bits are defined: *
    DISABLE_ESCAPING
    Disable escaping for this attribute
    *
    NO_SPECIAL_CHARACTERS
    Attribute value contains no special characters
    * @throws IllegalStateException: attempt to output an attribute when there is no open element * start tag */ public void attribute(int nameCode, int typeCode, CharSequence value, int locationId, int properties) throws XPathException { System.err.println("RCVR " + id + indent + " ATTRIBUTE " + getNamePool().getDisplayName(nameCode)); nextReceiver.attribute(nameCode, typeCode, value, locationId, properties); } /** * Character data */ public void characters(CharSequence chars, int locationId, int properties) throws XPathException { System.err.println("RCVR " + id + indent + " CHARACTERS " + (Whitespace.isWhite(chars) ? "(whitespace)" : "")); FastStringBuffer sb = new FastStringBuffer(chars.length() * 3); for (int i=0; iafter the startElement event, and before * any children for the element. The namespaces that are reported are only required * to include those that are different from the parent element; however, duplicates may be reported. * A namespace must not conflict with any namespaces already used for element or attribute names. * * @param namespaceCode an integer: the top half is a prefix code, the bottom half a URI code. * These may be translated into an actual prefix and URI using the name pool. A prefix code of * zero represents the empty prefix (that is, the default namespace). A URI code of zero represents * a URI of "", that is, a namespace undeclaration. * @throws IllegalStateException: attempt to output a namespace when there is no open element * start tag */ public void namespace(int namespaceCode, int properties) throws XPathException { System.err.println("RCVR " + id + indent + " NAMESPACE " + getNamePool().getPrefixFromNamespaceCode(namespaceCode) + "=" + getNamePool().getURIFromNamespaceCode(namespaceCode)); nextReceiver.namespace(namespaceCode, properties); } /** * Start of event stream */ public void open() throws XPathException { System.err.println("RCVR " + id + indent + " OPEN"); if (nextReceiver == null) { nextReceiver = new Sink(); } nextReceiver.open(); } /** * Processing Instruction */ public void processingInstruction(String target, CharSequence data, int locationId, int properties) throws XPathException { System.err.println("RCVR " + id + indent + " PROCESSING INSTRUCTION"); nextReceiver.processingInstruction(target, data, locationId, properties); } /** * Notify the start of the content, that is, the completion of all attributes and namespaces. * Note that the initial receiver of output from XSLT instructions will not receive this event, * it has to detect it itself. Note that this event is reported for every element even if it has * no attributes, no namespaces, and no content. */ public void startContent() throws XPathException { System.err.println("RCVR " + id + indent + " START CONTENT"); nextReceiver.startContent(); } /** * Start of a document node. */ public void startDocument(int properties) throws XPathException { System.err.println("RCVR " + id + indent + " START DOCUMENT"); nextReceiver.startDocument(properties); } /** * Notify the start of an element * * @param nameCode integer code identifying the name of the element within the name pool. * @param typeCode integer code identifying the element's type within the name pool. * @param properties properties of the element node */ public void startElement(int nameCode, int typeCode, int locationId, int properties) throws XPathException { System.err.println("RCVR " + id + indent + " START ELEMENT " + getNamePool().getDisplayName(nameCode)); // System.err.println("RCVR " + id + indent + // " (Loc: sysId=" + // getPipelineConfiguration().getLocationProvider().getSystemId(locationId) + // " line=" + // getPipelineConfiguration().getLocationProvider().getLineNumber(locationId) + ")"); indent = indent + " "; nextReceiver.startElement(nameCode, typeCode, locationId, properties); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/event/PipelineConfiguration.java0000644000175000017500000002211711033112257023663 0ustar eugeneeugenepackage net.sf.saxon.event; import net.sf.saxon.Configuration; import net.sf.saxon.Controller; import net.sf.saxon.type.SchemaURIResolver; import javax.xml.transform.ErrorListener; import javax.xml.transform.URIResolver; /** * A PipelineConfiguration sets options that apply to all the operations in a pipeline. * Unlike the global Configuration, these options are always local to a process. */ public class PipelineConfiguration { private Configuration config; private LocationProvider locationProvider; private ErrorListener errorListener; private URIResolver uriResolver; private SchemaURIResolver schemaURIResolver; private Controller controller; private boolean isSerializing; private boolean expandAttributeDefaults = true; private boolean useXsiSchemaLocation = true; private boolean recoverFromValidationErrors = false; private int hostLanguage = Configuration.XSLT; /** * Create a PipelineConfiguration. Note: the normal way to create * a PipelineConfiguration is via the factory methods in the Controller and * Configuration classes * @see Configuration#makePipelineConfiguration * @see Controller#makePipelineConfiguration */ public PipelineConfiguration() { } /** * Create a PipelineConfiguration as a copy of an existing * PipelineConfiguration * @param p the existing PipelineConfiguration */ public PipelineConfiguration(PipelineConfiguration p) { config = p.config; locationProvider = p.locationProvider; errorListener = p.errorListener; uriResolver = p.uriResolver; schemaURIResolver = p.schemaURIResolver; controller = p.controller; isSerializing = p.isSerializing; useXsiSchemaLocation = p.useXsiSchemaLocation; hostLanguage = p.hostLanguage; recoverFromValidationErrors = p.recoverFromValidationErrors; } /** * Get the Saxon Configuration object * @return the Saxon Configuration */ public Configuration getConfiguration() { return config; } /** * Set the Saxon Configuration object * @param config the Saxon Configuration */ public void setConfiguration(Configuration config) { this.config = config; } /** * Get the LocationProvider for interpreting location ids passed down this pipeline * @return the appropriate LocationProvider */ public LocationProvider getLocationProvider() { return locationProvider; } /** * Set the LocationProvider for interpreting location ids passed down this pipeline * @param locationProvider the LocationProvider */ public void setLocationProvider(LocationProvider locationProvider) { this.locationProvider = locationProvider; } /** * Get the ErrorListener used for reporting errors in processing this pipeline * @return the ErrorListener */ public ErrorListener getErrorListener() { return errorListener; } /** * Set the ErrorListener used for reporting errors in processing this pipeline * @param errorListener the ErrorListener */ public void setErrorListener(ErrorListener errorListener) { this.errorListener = errorListener; } /** * Get the URIResolver used for processing URIs encountered on this pipeline * @return the URIResolver */ public URIResolver getURIResolver() { return uriResolver; } /** * Set the URIResolver used for processing URIs encountered on this pipeline * @param uriResolver the URIResolver */ public void setURIResolver(URIResolver uriResolver) { this.uriResolver = uriResolver; } /** * Get the user-defined SchemaURIResolver for resolving URIs used in "import schema" * declarations; returns null if none has been explicitly set. * @return the SchemaURIResolver */ public SchemaURIResolver getSchemaURIResolver() { return schemaURIResolver; } /** * Say whether xsi:schemaLocation and xsi:noNamespaceSchemaLocation attributes * should be recognized while validating an instance document * @param recognize true if these attributes should be recognized */ public void setUseXsiSchemaLocation(boolean recognize) { useXsiSchemaLocation = recognize; } /** * Ask whether xsi:schemaLocation and xsi:noNamespaceSchemaLocation attributes * should be recognized while validating an instance document * @return true if these attributes should be recognized */ public boolean isUseXsiSchemaLocation() { return useXsiSchemaLocation; } /** * Say whether validation errors encountered on this pipeline should be treated as fatal * or as recoverable. * @param recover set to true if validation errors are to be treated as recoverable. If this option is set to true, * such errors will be reported to the ErrorListener using the error() method, and validation will continue. * If it is set to false (the default), errors will be reported using the fatalError() method, and validation will * be abandoned. */ public void setRecoverFromValidationErrors(boolean recover) { recoverFromValidationErrors = recover; } /** * Ask if this pipeline recovers from validation errors * @return true if validation errors on this pipeline are treated as recoverable; false if they are treated * as fatal */ public boolean isRecoverFromValidationErrors() { return recoverFromValidationErrors; } /** * Set a user-defined SchemaURIResolver for resolving URIs used in "import schema" * declarations. * @param resolver the SchemaURIResolver */ public void setSchemaURIResolver(SchemaURIResolver resolver) { schemaURIResolver = resolver; } /** * Get the controller associated with this pipelineConfiguration * @return the controller if it is known; otherwise null. */ public Controller getController() { return controller; } /** * Set the Controller associated with this pipelineConfiguration * @param controller the Controller */ public void setController(Controller controller) { this.controller = controller; } /** * Get the host language in use * @return for example {@link Configuration#XSLT} or {@link Configuration#XQUERY} */ public int getHostLanguage() { return hostLanguage; } /** * Set the host language in use * @param language for example {@link Configuration#XSLT} or {@link Configuration#XQUERY} */ public void setHostLanguage(int language) { hostLanguage = language; } /** * Ask whether this pipeline is a serializing pipeline * @return true if this pipeline is producing serialized output */ public boolean isSerializing() { return isSerializing; } /** * Set whether this pipeline is a serializing pipeline * @param isSerializing true if this pipeline is producing serialized output */ public void setSerializing(boolean isSerializing) { this.isSerializing = isSerializing; } /** * Set whether attribute defaults defined in a schema or DTD are to be expanded or not * (by default, fixed and default attribute values are expanded, that is, they are inserted * into the document during validation as if they were present in the instance being validated) * @param expand true if defaults are to be expanded, false if not */ public void setExpandAttributeDefaults(boolean expand) { expandAttributeDefaults = expand; } /** * Ask whether attribute defaults defined in a schema or DTD are to be expanded or not * (by default, fixed and default attribute values are expanded, that is, they are inserted * into the document during validation as if they were present in the instance being validated) * @return true if defaults are to be expanded, false if not */ public boolean isExpandAttributeDefaults() { return expandAttributeDefaults; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/event/ReceiverOptions.java0000644000175000017500000000746611033112257022520 0ustar eugeneeugenepackage net.sf.saxon.event; /** * ReceiverOptions defines a set of constants, which can be used in * calls to methods on the Receiver interface. The values are * bit-significant. * * @author Michael H. Kay */ public class ReceiverOptions { /** * Flag to disable output escaping */ public static final int DISABLE_ESCAPING = 1; /** * Flag to disable use of character maps */ public static final int DISABLE_CHARACTER_MAPS = 2; /** * Flag indicating that the value contains no special characters * that need to be escaped */ public static final int NO_SPECIAL_CHARS = 4; /** * Flag indicating that an attribute value was added by the schema processor * because a default value was specified */ public static final int DEFAULTED_ATTRIBUTE = 8; /** * Flag used with character content that has been validated against a nillable element * declaration. Needed because of a peculiar rule for validating xs:key values */ public static final int NILLED_ELEMENT = 16; /** * Flag indicating that duplicate values should be rejected */ public static final int REJECT_DUPLICATES = 32; /** * Flag indicating that the namespace (of an element or attribute name) * has already been declared; it does not need to be generated by the namespace * fixup process. */ public static final int NAMESPACE_OK = 64; /** * Flag passed on startElement indicating that the element does not inherit * the namespaces of its ancestors. */ public static final int DISINHERIT_NAMESPACES = 128; /** * Flag used when an attribute value or text node contains null characters * before and after strings generated by character mapping; these strings * are to be output without escaping */ public static final int USE_NULL_MARKERS = 256; /** * Flag used with character content that has been validated against a nillable element * declaration. Needed because of a peculiar rule for validating xs:key values */ public static final int NILLABLE_ELEMENT = 512; /** * Flag used with the characters() event to indicate that the event represents an entire * text node, that is, the text node has not been fragmented over several characters() events */ public static final int WHOLE_TEXT_NODE = 1024; /** * Flag indicating an element or attribute that has the is-id property */ public static final int IS_ID = 2048; /** * Flag indicating an element or attribute that has the is-idref property */ public static final int IS_IDREF = 4096; /** * Flag indicating that the ID/IDREF properties have been set if applicable: if this bit is set, * then the absence of the IS_ID bit means the node is not an ID, and similarly for IS_IDREF */ public static final int ID_IDREF_CHECKED = 8192; /** * Flag set on startDocument() in relation to an xsl:message call with terminate="yes" */ public static final int TERMINATE = 16384; } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file,C. // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/event/MetaTagAdjuster.java0000644000175000017500000002074311253671035022425 0ustar eugeneeugenepackage net.sf.saxon.event; import net.sf.saxon.om.AttributeCollectionImpl; import net.sf.saxon.om.NamePool; import net.sf.saxon.om.NamespaceConstant; import net.sf.saxon.om.StandardNames; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.Whitespace; import javax.xml.transform.OutputKeys; import java.util.Properties; /** * The MetaTagAdjuster adds a meta element to the content of the head element, indicating * the required content type and encoding; it also removes any existing meta element * containing this information */ public class MetaTagAdjuster extends ProxyReceiver { boolean seekingHead = true; int droppingMetaTags = -1; boolean inMetaTag = false; boolean foundHead = false; String headPrefix = null; int metaCode; short requiredURICode = 0; AttributeCollectionImpl attributes; String encoding; String mediaType; int level = 0; boolean isXHTML = false; /** * Create a new MetaTagAdjuster */ public MetaTagAdjuster() { } /** * Set output properties */ public void setOutputProperties(Properties details) { encoding = details.getProperty(OutputKeys.ENCODING); if (encoding == null) { encoding = "UTF-8"; } mediaType = details.getProperty(OutputKeys.MEDIA_TYPE); if (mediaType == null) { mediaType = "text/html"; } } /** * Indicate whether we're handling HTML or XHTML */ public void setIsXHTML(boolean xhtml) { isXHTML = xhtml; if (xhtml) { requiredURICode = getNamePool().getCodeForURI(NamespaceConstant.XHTML); } else { requiredURICode = 0; } } /** * Compare a name: case-blindly in the case of HTML, case-sensitive for XHTML */ private boolean comparesEqual(String name1, String name2) { if (isXHTML) { return name1.equals(name2); } else { return name1.equalsIgnoreCase(name2); } } /** * Notify the start of an element * * @param nameCode integer code identifying the name of the element within the name pool. * @param typeCode integer code identifying the element's type within the name pool. * @param properties properties of the element node */ public void startElement(int nameCode, int typeCode, int locationId, int properties) throws XPathException { if (droppingMetaTags == level) { metaCode = nameCode; int uriCode = getNamePool().getURICode(nameCode); String localName = getNamePool().getLocalName(nameCode); if (uriCode == requiredURICode && comparesEqual(localName, "meta")) { inMetaTag = true; attributes.clear(); return; } } level++; nextReceiver.startElement(nameCode, typeCode, locationId, properties); if (seekingHead) { NamePool namePool = getNamePool(); int uriCode = namePool.getURICode(nameCode); String localName = namePool.getLocalName(nameCode); if (uriCode == requiredURICode && comparesEqual(localName, "head")) { foundHead = true; headPrefix = namePool.getPrefix(nameCode); } } } /** * Notify an attribute. Attributes are notified after the startElement event, and before any * children. Namespaces and attributes may be intermingled. * * @param nameCode The name of the attribute, as held in the name pool * @param typeCode The type of the attribute, as held in the name pool * @param properties Bit significant value. The following bits are defined: *
    DISABLE_ESCAPING
    Disable escaping for this attribute
    *
    NO_SPECIAL_CHARACTERS
    Attribute value contains no special characters
    * @throws IllegalStateException: attempt to output an attribute when there is no open element * start tag */ public void attribute(int nameCode, int typeCode, CharSequence value, int locationId, int properties) throws XPathException { if (inMetaTag) { attributes.addAttribute(nameCode, typeCode, value.toString(), locationId, properties); } else { nextReceiver.attribute(nameCode, typeCode, value, locationId, properties); } } /** * Notify the start of the content, that is, the completion of all attributes and namespaces. * Note that the initial receiver of output from XSLT instructions will not receive this event, * it has to detect it itself. Note that this event is reported for every element even if it has * no attributes, no namespaces, and no content. */ public void startContent() throws XPathException { if (foundHead) { foundHead = false; NamePool namePool = getNamePool(); nextReceiver.startContent(); int metaCode = namePool.allocate(headPrefix, requiredURICode, "meta"); nextReceiver.startElement(metaCode, StandardNames.XS_UNTYPED, 0, 0); int httpEquivCode = namePool.allocate("", "", "http-equiv"); nextReceiver.attribute(httpEquivCode, StandardNames.XS_UNTYPED_ATOMIC, "Content-Type", 0, 0); int contentCode = namePool.allocate("", "", "content"); nextReceiver.attribute(contentCode, StandardNames.XS_UNTYPED_ATOMIC, mediaType + "; charset=" + encoding, 0, 0); nextReceiver.startContent(); droppingMetaTags = level; seekingHead = false; attributes = new AttributeCollectionImpl(getConfiguration()); nextReceiver.endElement(); } if (!inMetaTag) { nextReceiver.startContent(); } } /** * End of element */ public void endElement() throws XPathException { if (inMetaTag) { inMetaTag = false; // if there was an http-equiv="ContentType" attribute, discard the meta element entirely boolean found = false; for (int i=0; i * A LocationProvider that represents locations in the source document from which the events * are derived (as distinct from locations in a query or stylesheet of the instructions causing the * events) will also implement the marker interface {@link net.sf.saxon.event.SourceLocationProvider} */ public interface LocationProvider { /** * Get the URI of the document or module containing a particular location * @param locationId identifier of the location in question (as passed down the Receiver pipeline) * @return the URI of the document or module. */ public String getSystemId(long locationId); /** * Get the line number within the document or module containing a particular location * @param locationId identifier of the location in question (as passed down the Receiver pipeline) * @return the line number within the document or module. */ public int getLineNumber(long locationId); /** * Get the column number within the document or module containing a particular location * @param locationId identifier of the location in question (as passed down the Receiver pipeline) * @return the column number within the document or module, or -1 if this is not available */ public int getColumnNumber(long locationId); } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/event/XMLEmitter.java0000644000175000017500000010326311155531766021401 0ustar eugeneeugenepackage net.sf.saxon.event; import net.sf.saxon.charcode.UnicodeCharacterSet; import net.sf.saxon.charcode.UTF16; import net.sf.saxon.om.FastStringBuffer; import net.sf.saxon.sort.IntHashMap; import net.sf.saxon.tinytree.CharSlice; import net.sf.saxon.tinytree.CompressedWhitespace; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.Whitespace; import javax.xml.transform.OutputKeys; import java.util.Properties; import java.util.Stack; /** * XMLEmitter is an Emitter that generates XML output * to a specified destination. */ public class XMLEmitter extends Emitter { // NOTE: we experimented with XMLUTF8Emitter which combines XML escaping and UTF8 encoding // into a single loop. Scrapped it because we couldn't measure any benefits - but there // ought to be, in theory. Perhaps we weren't buffering the writes carefully enough. protected boolean empty = true; protected boolean openStartTag = false; protected boolean declarationIsWritten = false; protected int elementCode; protected boolean preferHex = false; protected boolean undeclareNamespaces = false; //private boolean warningIssued = false; // The element stack holds the display names (lexical QNames) of elements that // have been started but not finished. It is used to obtain the element name // for the end tag. protected Stack elementStack = new Stack(); // Getting a display name for a namecode can be expensive because it involves string // concatenation, and more importantly, checking of the name against the encoding. So // we keep a local cache of names we have seen before. private IntHashMap nameLookup = new IntHashMap(100); // For other names we use a hashtable. It private boolean indenting = false; private int indentSpaces = 3; private String indentChars = "\n "; private int totalAttributeLength = 0; private boolean requireWellFormed = false; static boolean[] specialInText; // lookup table for special characters in text static boolean[] specialInAtt; // lookup table for special characters in attributes // create look-up table for ASCII characters that need special treatment static { specialInText = new boolean[128]; for (int i=0; i<=31; i++) specialInText[i] = true; // allowed in XML 1.1 as character references for (int i=32; i<=127; i++) specialInText[i] = false; // note, 0 is used to switch escaping on and off for mapped characters specialInText['\n'] = false; specialInText['\t'] = false; specialInText['\r'] = true; specialInText['<'] = true; specialInText['>'] = true; specialInText['&'] = true; specialInAtt = new boolean[128]; for (int i=0; i<=31; i++) specialInAtt[i] = true; // allowed in XML 1.1 as character references for (int i=32; i<=127; i++) specialInAtt[i] = false; specialInAtt[(char)0] = true; // used to switch escaping on and off for mapped characters specialInAtt['\r'] = true; specialInAtt['\n'] = true; specialInAtt['\t'] = true; specialInAtt['<'] = true; specialInAtt['>'] = true; specialInAtt['&'] = true; specialInAtt['\"'] = true; } /** * Start of the event stream. Nothing is done at this stage: the opening of the output * file is deferred until some content is written to it. */ public void open() throws XPathException {} /** * Start of a document node. Nothing is done at this stage: the opening of the output * file is deferred until some content is written to it. */ public void startDocument(int properties) throws XPathException {} /** * Notify the end of a document node */ public void endDocument() throws XPathException { if (!elementStack.isEmpty()) { throw new IllegalStateException("Attempt to end document in serializer when elements are unclosed"); } } /** * Do the real work of starting the document. This happens when the first * content is written. * @throws XPathException */ protected void openDocument () throws XPathException { if (writer==null) { makeWriter(); } if (characterSet==null) { characterSet = UnicodeCharacterSet.getInstance(); } if (outputProperties==null) { outputProperties = new Properties(); } String rep = outputProperties.getProperty(SaxonOutputKeys.CHARACTER_REPRESENTATION); rep = Whitespace.trim(rep); if (rep != null) { preferHex = (rep.equalsIgnoreCase("hex")); } rep = outputProperties.getProperty(SaxonOutputKeys.UNDECLARE_PREFIXES); if (rep!=null) { undeclareNamespaces = (rep.equalsIgnoreCase("yes")); } writeDeclaration(); } /** * Output the XML declaration */ public void writeDeclaration() throws XPathException { if (declarationIsWritten) return; declarationIsWritten = true; try { indenting = "yes".equals(outputProperties.getProperty(OutputKeys.INDENT)); String s = outputProperties.getProperty(SaxonOutputKeys.INDENT_SPACES); if (s!=null) { try { indentSpaces = Integer.parseInt(Whitespace.trim(s)); } catch (NumberFormatException err) { indentSpaces = 3; } } String byteOrderMark = outputProperties.getProperty(SaxonOutputKeys.BYTE_ORDER_MARK); String encoding = outputProperties.getProperty(OutputKeys.ENCODING); if (encoding==null || encoding.equalsIgnoreCase("utf8")) { encoding = "UTF-8"; } if ("yes".equals(byteOrderMark) && ( "UTF-8".equalsIgnoreCase(encoding) || "UTF-16LE".equalsIgnoreCase(encoding) || "UTF-16BE".equalsIgnoreCase(encoding))) { writer.write('\uFEFF'); } String omitXMLDeclaration = outputProperties.getProperty(OutputKeys.OMIT_XML_DECLARATION); if (omitXMLDeclaration==null) { omitXMLDeclaration = "no"; } String version = outputProperties.getProperty(OutputKeys.VERSION); if (version==null) { version = getConfiguration().getNameChecker().getXMLVersion(); } else { if (!version.equals("1.0") && !version.equals("1.1")) { XPathException err = new XPathException("XML version must be 1.0 or 1.1"); err.setErrorCode("SESU0006"); throw err; } if (!version.equals("1.0") && omitXMLDeclaration.equals("yes") && outputProperties.getProperty(OutputKeys.DOCTYPE_SYSTEM) != null) { XPathException err = new XPathException("Values of 'version', 'omit-xml-declaration', and 'doctype-system' conflict"); err.setErrorCode("SEPM0009"); throw err; } } if (version.equals("1.0") && undeclareNamespaces) { XPathException err = new XPathException("Cannot undeclare namespaces with XML version 1.0"); err.setErrorCode("SEPM0010"); throw err; } String standalone = outputProperties.getProperty(OutputKeys.STANDALONE); if ("omit".equals(standalone)) { standalone = null; } if (standalone != null) { requireWellFormed = true; if (omitXMLDeclaration.equals("yes")) { XPathException err = new XPathException("Values of 'standalone' and 'omit-xml-declaration' conflict"); err.setErrorCode("SEPM0009"); throw err; } } if (omitXMLDeclaration.equals("no")) { writer.write(""); // don't write a newline character: it's wrong if the output is an // external general parsed entity } } catch (java.io.IOException err) { throw new XPathException(err); } } /** * Output the document type declaration * @param type The element name * @param systemId The DOCTYP system identifier * @param publicId The DOCTYPE public identifier */ protected void writeDocType(String type, String systemId, String publicId) throws XPathException { try { if (declarationIsWritten && !indenting) { // don't add a newline if indenting, because the indenter will already have done so writer.write("\n"); } writer.write("\n"); } else if (systemId==null && publicId!=null) { // handles the HTML case writer.write(" PUBLIC \"" + publicId + "\">\n"); } else { writer.write(" PUBLIC \"" + publicId + "\" \"" + systemId + "\">\n"); } } catch (java.io.IOException err) { throw new XPathException(err); } } /** * End of the document. */ public void close() throws XPathException { // if nothing has been written, we should still create the file and write an XML declaration if (empty) { openDocument(); } try { if (writer != null) { writer.flush(); } } catch (java.io.IOException err) { throw new XPathException(err); } } /** * Start of an element. Output the start tag, escaping special characters. */ public void startElement (int nameCode, int typeCode, int locationId, int properties) throws XPathException { if (empty) { openDocument(); } else if (requireWellFormed && elementStack.isEmpty()) { XPathException err = new XPathException("When 'standalone' or 'doctype-system' is specified, the document must be well-formed; " + "but this document contains more than one top-level element"); err.setErrorCode("SEPM0004"); throw err; } String displayName; // See if we've seen this name before displayName = getCachedName(nameCode); // Otherwise, look it up in the namepool and check that it's encodable if (displayName == null) { displayName = namePool.getDisplayName(nameCode); if (!allCharactersEncodable) { int badchar = testCharacters(displayName); if (badchar!=0) { XPathException err = new XPathException("Element name contains a character (decimal + " + badchar + ") not available in the selected encoding"); err.setErrorCode("SERE0008"); throw err; } } putCachedName(nameCode, displayName); } elementStack.push(displayName); elementCode = nameCode; try { if (empty) { String systemId = outputProperties.getProperty(OutputKeys.DOCTYPE_SYSTEM); String publicId = outputProperties.getProperty(OutputKeys.DOCTYPE_PUBLIC); if (systemId!=null) { requireWellFormed = true; writeDocType(displayName, systemId, publicId); } empty = false; } if (openStartTag) { closeStartTag(); } writer.write('<'); writer.write(displayName); openStartTag = true; totalAttributeLength = 0; } catch (java.io.IOException err) { throw new XPathException(err); } } public void namespace(int namespaceCode, int properties) throws XPathException { try { String nsprefix = namePool.getPrefixFromNamespaceCode(namespaceCode); String nsuri = namePool.getURIFromNamespaceCode(namespaceCode); int len = nsuri.length() + nsprefix.length() + 8; String sep = " "; if (indenting && (totalAttributeLength + len) > 80 && totalAttributeLength != 0) { sep = getAttributeIndentString(); } totalAttributeLength += len; if (nsprefix.length() == 0) { writer.write(sep); writeAttribute(elementCode, "xmlns", nsuri, 0); } else if (nsprefix.equals("xml")) { //return; } else { int badchar = testCharacters(nsprefix); if (badchar!=0) { XPathException err = new XPathException("Namespace prefix contains a character (decimal + " + badchar + ") not available in the selected encoding"); err.setErrorCode("SERE0008"); throw err; } if (undeclareNamespaces || nsuri.length() != 0) { writer.write(sep); writeAttribute(elementCode, "xmlns:" + nsprefix, nsuri, 0); } } } catch (java.io.IOException err) { throw new XPathException(err); } } public void attribute(int nameCode, int typeCode, CharSequence value, int locationId, int properties) throws XPathException { String displayName; // See if we've seen this name before displayName = getCachedName(nameCode); // Otherwise, look it up in the namepool and check that it's encodable if (displayName == null) { displayName = namePool.getDisplayName(nameCode); if (!allCharactersEncodable) { int badchar = testCharacters(displayName); if (badchar!=0) { XPathException err = new XPathException("Attribute name contains a character (decimal + " + badchar + ") not available in the selected encoding"); err.setErrorCode("SERE0008"); throw err; } } putCachedName(nameCode, displayName); } final int len = displayName.length() + value.length() + 4; String sep = " "; if (indenting && (totalAttributeLength + len) > 80 && totalAttributeLength != 0) { sep = getAttributeIndentString(); } totalAttributeLength += len; try { writer.write(sep); writeAttribute( elementCode, displayName, value, properties ); } catch (java.io.IOException err) { throw new XPathException(err); } } private String getAttributeIndentString() { int indent = (elementStack.size()-1) * indentSpaces + ((String)elementStack.peek()).length() + 3; while (indent >= indentChars.length()) { indentChars += " "; } return indentChars.substring(0, indent); } public void startContent() throws XPathException { // don't add ">" to the start tag until we know whether the element has content } /** * Mark the end of the start tag * @throws XPathException if an IO exception occurs */ public void closeStartTag() throws XPathException { try { if (openStartTag) { writer.write('>'); openStartTag = false; } } catch (java.io.IOException err) { throw new XPathException(err); } } /** * Close an empty element tag. (This is overridden in XHTMLEmitter). * @param displayName the name of the empty element * @param nameCode the fingerprint of the name of the empty element * @return the string used to close an empty element tag. */ protected String emptyElementTagCloser(String displayName, int nameCode) { return "/>"; } /** * Write attribute name=value pair. * @param elCode The element name is not used in this version of the * method, but is used in the HTML subclass. * @param attname The attribute name, which has already been validated to ensure * it can be written in this encoding * @param value The value of the attribute * @param properties Any special properties of the attribute */ protected void writeAttribute(int elCode, String attname, CharSequence value, int properties) throws XPathException { try { String val = value.toString(); writer.write(attname); if ((properties & ReceiverOptions.NO_SPECIAL_CHARS) != 0) { writer.write('='); writer.write('"'); writer.write(val); writer.write('"'); } else if ((properties & ReceiverOptions.USE_NULL_MARKERS) != 0) { // null (0) characters will be used before and after any section of // the value generated from a character map writer.write('='); char delimiter = (val.indexOf('"') >= 0 && val.indexOf('\'') < 0 ? '\'' : '"'); writer.write(delimiter); writeEscape(value, true); writer.write(delimiter); } else { writer.write("=\""); writeEscape(value, true); writer.write('\"'); } } catch (java.io.IOException err) { throw new XPathException(err); } } /** * Test that all characters in a name (for example) are supported in the target encoding. * @param chars the characters to be tested * @return zero if all the characters are available, or the value of the * first offending character if not */ protected int testCharacters(CharSequence chars) throws XPathException { for (int i=0; i 127) { if (UTF16.isHighSurrogate(c)) { int cc = UTF16.combinePair(c, chars.charAt(++i)); if (!characterSet.inCharset(cc)) { return cc; } } else if (!characterSet.inCharset(c)) { return c; } } } return 0; } /** * End of an element. */ public void endElement () throws XPathException { String displayName = (String)elementStack.pop(); try { if (openStartTag) { writer.write(emptyElementTagCloser(displayName, elementCode)); openStartTag = false; } else { writer.write("'); } } catch (java.io.IOException err) { throw new XPathException(err); } } /** * Character data. */ public void characters (CharSequence chars, int locationId, int properties) throws XPathException { if (empty) { openDocument(); if (!Whitespace.isWhite(chars)) { if (requireWellFormed || outputProperties.getProperty(OutputKeys.DOCTYPE_SYSTEM)!=null) { XPathException err = new XPathException("When 'standalone' or 'doctype-system' is specified, the document must be well-formed; " + "but this document contains a top-level text node"); err.setErrorCode("SEPM0004"); throw err; } } } if (requireWellFormed && elementStack.isEmpty() && !Whitespace.isWhite(chars)) { XPathException err = new XPathException("When 'standalone' or 'doctype-system' is specified, the document must be well-formed; " + "but this document contains a top-level text node"); err.setErrorCode("SEPM0004"); throw err; } try { if (openStartTag) { closeStartTag(); } if ((properties & ReceiverOptions.NO_SPECIAL_CHARS) != 0) { writeCharSequence(chars); } else if ((properties & ReceiverOptions.DISABLE_ESCAPING) == 0) { writeEscape(chars, false); } else { // disable-output-escaping="yes" if (testCharacters(chars) == 0) { if ((properties & ReceiverOptions.USE_NULL_MARKERS) == 0) { // null (0) characters will be used before and after any section of // the value generated from a character map writeCharSequence(chars); } else { // Need to strip out any null markers. See test output-html109 final int len = chars.length(); for (int i=0; i 127 && UTF16.isHighSurrogate(c)) { char[] pair = new char[2]; pair[0] = c; pair[1] = chars.charAt(++i); int cc = UTF16.combinePair(c, pair[1]); if (!characterSet.inCharset(cc)) { writeEscape(new CharSlice(pair), false); } else { writeCharSequence(new CharSlice(pair)); } } else { char[] ca = {c}; if (!characterSet.inCharset(c)) { writeEscape(new CharSlice(ca), false); } else { writeCharSequence(new CharSlice(ca)); } } } } } } } catch (java.io.IOException err) { throw new XPathException(err); } } /** * Write a CharSequence (without any escaping of special characters): various implementations * @param s the character sequence to be written */ public void writeCharSequence(CharSequence s) throws java.io.IOException { if (s instanceof String) { writer.write((String)s); } else if (s instanceof CharSlice) { ((CharSlice)s).write(writer); } else if (s instanceof FastStringBuffer) { ((FastStringBuffer)s).write(writer); } else if (s instanceof CompressedWhitespace) { ((CompressedWhitespace)s).write(writer); } else { writer.write(s.toString()); } } /** * Handle a processing instruction. */ public void processingInstruction (String target, CharSequence data, int locationId, int properties) throws XPathException { if (empty) { openDocument(); } int x = testCharacters(target); if (x != 0) { XPathException err = new XPathException("Character in processing instruction name cannot be represented " + "in the selected encoding (code " + x + ')'); err.setErrorCode("SERE0008"); throw err; } x = testCharacters(data); if (x != 0) { XPathException err = new XPathException("Character in processing instruction data cannot be represented " + "in the selected encoding (code " + x + ')'); err.setErrorCode("SERE0008"); throw err; } try { if (openStartTag) { closeStartTag(); } writer.write("0 ? ' ' + data.toString() : "") + "?>"); } catch (java.io.IOException err) { throw new XPathException(err); } } /** * Write contents of array to current writer, after escaping special characters. * This method converts the XML special characters (such as < and &) into their * predefined entities. * @param chars The character sequence containing the string * @param inAttribute Set to true if the text is in an attribute value */ protected void writeEscape(final CharSequence chars, final boolean inAttribute) throws java.io.IOException, XPathException { int segstart = 0; boolean disabled = false; final boolean[] specialChars = (inAttribute ? specialInAtt : specialInText); if (chars instanceof CompressedWhitespace) { ((CompressedWhitespace)chars).writeEscape(specialChars, writer); return; } final int clength = chars.length(); while (segstart < clength) { int i = segstart; // find a maximal sequence of "ordinary" characters while (i < clength) { final char c = chars.charAt(i); if (c < 127) { if (specialChars[c]) { break; } else { i++; } } else if (c < 160) { break; } else if (c == 0x2028) { break; } else if (UTF16.isHighSurrogate(c)) { break; } else if (!characterSet.inCharset(c)) { break; } else { i++; } } // if this was the whole string write it out and exit if (i >= clength) { if (segstart == 0) { writeCharSequence(chars); } else { writeCharSequence(chars.subSequence(segstart, i)); } return; } // otherwise write out this sequence if (i > segstart) { writeCharSequence(chars.subSequence(segstart, i)); } // examine the special character that interrupted the scan final char c = chars.charAt(i); if (c==0) { // used to switch escaping on and off disabled = !disabled; } else if (disabled) { if (c > 127) { if (UTF16.isHighSurrogate(c)) { int cc = UTF16.combinePair(c, chars.charAt(i+1)); if (!characterSet.inCharset(cc)) { XPathException de = new XPathException("Character x" + Integer.toHexString(cc) + " is not available in the chosen encoding"); de.setErrorCode("SERE0008"); throw de; } } else if (!characterSet.inCharset(c)) { XPathException de = new XPathException("Character " + c + " (x" + Integer.toHexString((int)c) + ") is not available in the chosen encoding"); de.setErrorCode("SERE0008"); throw de; } } writer.write(c); } else if (c>=127 && c<160) { // XML 1.1 requires these characters to be written as character references outputCharacterReference(c); } else if (c>=160) { if (c==0x2028) { outputCharacterReference(c); } else if (UTF16.isHighSurrogate(c)) { char d = chars.charAt(++i); int charval = UTF16.combinePair(c, d); if (characterSet.inCharset(charval)) { writer.write(c); writer.write(d); } else { outputCharacterReference(charval); } } else { // process characters not available in the current encoding outputCharacterReference(c); } } else { // process special ASCII characters if (c=='<') { writer.write("<"); } else if (c=='>') { writer.write(">"); } else if (c=='&') { writer.write("&"); } else if (c=='\"') { writer.write("""); } else if (c=='\n') { writer.write(" "); } else if (c=='\r') { writer.write(" "); } else if (c=='\t') { writer.write(" "); } else { // C0 control characters outputCharacterReference(c); } } segstart = ++i; } } /** * Output a decimal or hexadecimal character reference */ private char[] charref = new char[10]; protected void outputCharacterReference(int charval) throws java.io.IOException { if (preferHex) { int o = 0; charref[o++]='&'; charref[o++]='#'; charref[o++]='x'; String code = Integer.toHexString(charval); int len = code.length(); for (int k=0; k"); } catch (java.io.IOException err) { throw new XPathException(err); } } /** * Get a name from the local name cache * @param nameCode the integer name code * @return a lexical QName if the name is in the cache; otherwise, null */ protected String getCachedName(int nameCode) { return (String)nameLookup.get(nameCode); } /** * Add a name to the local name cache * @param nameCode the integer name code * @param displayName the corresponding lexical QName */ protected void putCachedName(int nameCode, String displayName) { nameLookup.put(nameCode, displayName); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/event/TransformerReceiver.java0000644000175000017500000000777311033112257023370 0ustar eugeneeugenepackage net.sf.saxon.event; import net.sf.saxon.Controller; import net.sf.saxon.om.DocumentInfo; import net.sf.saxon.trans.XPathException; import javax.xml.transform.Result; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerException; /** * TransformerReceiver is similar in concept to the JAXP TransformerHandler, * except that it implements Saxon's Receiver interface rather than the standard * SAX2 interface. This means that it allows nodes with type annotations to be * passed down a pipeline from one transformation to another. */ public class TransformerReceiver extends ProxyReceiver { Controller controller; Builder builder; Result result; /** * Create a TransformerHandlerImpl and initialise variables. */ public TransformerReceiver(Controller controller) { this.controller = controller; } /** * Start of event stream */ public void open() throws XPathException { builder = controller.makeBuilder(); setPipelineConfiguration(builder.getPipelineConfiguration()); builder.setSystemId(systemId); Receiver stripper = controller.makeStripper(builder); if (controller.getExecutable().stripsInputTypeAnnotations()) { stripper = controller.getConfiguration().getAnnotationStripper(stripper); } setUnderlyingReceiver(stripper); nextReceiver.open(); } /** * Get the Transformer used for this transformation */ public Transformer getTransformer() { return controller; } /** * Set the SystemId of the document */ public void setSystemId(String systemId) { super.setSystemId(systemId); controller.setBaseOutputURI(systemId); } /** * Notify the start of an element * @param nameCode integer code identifying the name of the element within the name pool. * @param typeCode integer code identifying the element's type within the name pool. * @param properties bit-significant properties of the element node. */ public void startElement(int nameCode, int typeCode, int locationId, int properties) throws XPathException { nextReceiver.startElement(nameCode, typeCode, locationId, properties); } /** * Set the output destination of the transformation */ public void setResult(Result result) { if (result==null) { throw new IllegalArgumentException("Result must not be null"); } this.result = result; } /** * Get the output destination of the transformation */ public Result getResult() { return result; } /** * Override the behaviour of endDocument() in ProxyReceiver, so that it fires off * the transformation of the constructed document */ public void close() throws XPathException { nextReceiver.close(); DocumentInfo doc = (DocumentInfo)builder.getCurrentRoot(); builder.reset(); if (doc==null) { throw new XPathException("No source document has been built"); } //doc.getNamePool().allocateDocumentNumber(doc); try { controller.transformDocument(doc, result); } catch (TransformerException e) { throw XPathException.makeXPathException(e); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): None // saxonb-9.1.0.8/bj/net/sf/saxon/event/TypeCheckingFilter.java0000644000175000017500000002724411033112257023117 0ustar eugeneeugenepackage net.sf.saxon.event; import net.sf.saxon.expr.ExpressionLocation; import net.sf.saxon.expr.RoleLocator; import net.sf.saxon.expr.Token; import net.sf.saxon.om.Item; import net.sf.saxon.om.NamePool; import net.sf.saxon.pattern.CombinedNodeTest; import net.sf.saxon.pattern.ContentTypeTest; import net.sf.saxon.pattern.NameTest; import net.sf.saxon.pattern.NodeKindTest; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.Type; import net.sf.saxon.value.Cardinality; import net.sf.saxon.value.Value; import java.util.HashSet; /** * A filter on the push pipeline that performs type checking, both of the item type and the * cardinality. *

    * Note that the TypeCheckingFilter cannot currently check document node tests of the form * document-node(element(X,Y)), so it is not invoked in such cases. This isn't a big problem, because most * instructions that return document nodes materialize them anyway. */ public class TypeCheckingFilter extends ProxyReceiver { private ItemType itemType; private int cardinality; private RoleLocator role; private int count = 0; private int level = 0; private HashSet checkedElements = new HashSet(10); // used to avoid repeated checking when a template creates large numbers of elements of the same type public void setRequiredType(ItemType type, int cardinality, RoleLocator role) { itemType = type; this.cardinality = cardinality; this.role = role; } /** * Notify an attribute. Attributes are notified after the startElement event, and before any * children. Namespaces and attributes may be intermingled. * * @param nameCode The name of the attribute, as held in the name pool * @param typeCode The type of the attribute, as held in the name pool * @param properties Bit significant value. The following bits are defined: *

    DISABLE_ESCAPING
    Disable escaping for this attribute
    *
    NO_SPECIAL_CHARACTERS
    Attribute value contains no special characters
    * @throws IllegalStateException: attempt to output an attribute when there is no open element * start tag */ public void attribute(int nameCode, int typeCode, CharSequence value, int locationId, int properties) throws XPathException { if (level == 0) { if (++count == 2) { checkAllowsMany(locationId); } ItemType type = new CombinedNodeTest( new NameTest(Type.ATTRIBUTE, nameCode, getNamePool()), Token.INTERSECT, new ContentTypeTest(Type.ATTRIBUTE, getConfiguration().getSchemaType(typeCode), getConfiguration())); checkItemType(type, locationId); } nextReceiver.attribute(nameCode, typeCode, value, locationId, properties); } /** * Character data */ public void characters(CharSequence chars, int locationId, int properties) throws XPathException { if (level == 0) { if (++count == 2) { checkAllowsMany(locationId); } ItemType type = NodeKindTest.TEXT; checkItemType(type, locationId); } nextReceiver.characters(chars, locationId, properties); } /** * Output a comment */ public void comment(CharSequence chars, int locationId, int properties) throws XPathException { if (level == 0) { if (++count == 2) { checkAllowsMany(locationId); } ItemType type = NodeKindTest.COMMENT; checkItemType(type, locationId); } nextReceiver.comment(chars, locationId, properties); //To change body of overridden methods use File | Settings | File Templates. } /** * Notify a namespace. Namespaces are notified after the startElement event, and before * any children for the element. The namespaces that are reported are only required * to include those that are different from the parent element; however, duplicates may be reported. * A namespace must not conflict with any namespaces already used for element or attribute names. * * @param namespaceCode an integer: the top half is a prefix code, the bottom half a URI code. * These may be translated into an actual prefix and URI using the name pool. A prefix code of * zero represents the empty prefix (that is, the default namespace). A URI code of zero represents * a URI of "", that is, a namespace undeclaration. * @throws IllegalStateException: attempt to output a namespace when there is no open element * start tag */ public void namespace(int namespaceCode, int properties) throws XPathException { if (level == 0) { if (++count == 2) { checkAllowsMany(0); } ItemType type = NodeKindTest.NAMESPACE; checkItemType(type, 0); } nextReceiver.namespace(namespaceCode, properties); //To change body of overridden methods use File | Settings | File Templates. } /** * Processing Instruction */ public void processingInstruction(String target, CharSequence data, int locationId, int properties) throws XPathException { if (level == 0) { if (++count == 2) { checkAllowsMany(locationId); } ItemType type = NodeKindTest.PROCESSING_INSTRUCTION; checkItemType(type, locationId); } nextReceiver.processingInstruction(target, data, locationId, properties); } /** * Start of a document node. */ public void startDocument(int properties) throws XPathException { if (level == 0) { if (++count == 2) { checkAllowsMany(0); } ItemType type = NodeKindTest.DOCUMENT; checkItemType(type, 0); } level++; nextReceiver.startDocument(properties); } /** * Notify the start of an element * * @param nameCode integer code identifying the name of the element within the name pool. * @param typeCode integer code identifying the element's type within the name pool. * @param properties properties of the element node */ public void startElement(int nameCode, int typeCode, int locationId, int properties) throws XPathException { if (level == 0) { if (++count == 1) { // don't bother with any caching on the first item, it will often be the only one ItemType type = new CombinedNodeTest( new NameTest(Type.ELEMENT, nameCode, getNamePool()), Token.INTERSECT, new ContentTypeTest(Type.ELEMENT, getConfiguration().getSchemaType(typeCode), getConfiguration())); checkItemType(type, locationId); } else { if (count == 2) { checkAllowsMany(locationId); } Long key = new Long(((long)(nameCode&NamePool.FP_MASK))<<32 | (long)(typeCode&NamePool.FP_MASK)); if (!checkedElements.contains(key)) { ItemType type = new CombinedNodeTest( new NameTest(Type.ELEMENT, nameCode, getNamePool()), Token.INTERSECT, new ContentTypeTest(Type.ELEMENT, getConfiguration().getSchemaType(typeCode), getConfiguration())); checkItemType(type, locationId); checkedElements.add(key); } } } level++; nextReceiver.startElement(nameCode, typeCode, locationId, properties); } /** * Notify the end of a document node */ public void endDocument() throws XPathException { level--; nextReceiver.endDocument(); } /** * End of element */ public void endElement() throws XPathException { level--; nextReceiver.endElement(); } /** * End of event stream */ public void close() throws XPathException { if (count == 0 && !Cardinality.allowsZero(cardinality)) { XPathException err = new XPathException("An empty sequence is not allowed as the " + role.getMessage()); String errorCode = role.getErrorCode(); err.setErrorCode(errorCode); if (!"XPDY0050".equals(errorCode)) { err.setIsTypeError(true); } throw err; } // don't pass on the close event } /** * Output an item (atomic value or node) to the sequence */ public void append(Item item, int locationId, int copyNamespaces) throws XPathException { if (level == 0) { if (++count == 2) { checkAllowsMany(locationId); } checkItemType(Value.asValue(item).getItemType(getConfiguration().getTypeHierarchy()), locationId); } if (nextReceiver instanceof SequenceReceiver) { ((SequenceReceiver)nextReceiver).append(item, locationId, copyNamespaces); } else { super.append(item, locationId, copyNamespaces); } } private void checkItemType(ItemType type, long locationId) throws XPathException { if (!getConfiguration().getTypeHierarchy().isSubType(type, itemType)) { String message = role.composeErrorMessage(itemType, type, getNamePool()); String errorCode = role.getErrorCode(); XPathException err = new XPathException(message); err.setErrorCode(errorCode); if (!"XPDY0050".equals(errorCode)) { err.setIsTypeError(true); } err.setLocator(ExpressionLocation.getSourceLocator(locationId, getPipelineConfiguration().getLocationProvider())); throw err; } } private void checkAllowsMany(long locationId) throws XPathException { if (!Cardinality.allowsMany(cardinality)) { XPathException err = new XPathException("A sequence of more than one item is not allowed as the " + role.getMessage()); String errorCode = role.getErrorCode(); err.setErrorCode(errorCode); if (!"XPDY0050".equals(errorCode)) { err.setIsTypeError(true); } err.setLocator(ExpressionLocation.getSourceLocator(locationId, getPipelineConfiguration().getLocationProvider())); throw err; } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/event/IDFilter.java0000644000175000017500000001346311033112257021034 0ustar eugeneeugenepackage net.sf.saxon.event; import net.sf.saxon.om.NamePool; import net.sf.saxon.om.StandardNames; import net.sf.saxon.sort.IntHashSet; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.AtomicType; import net.sf.saxon.type.BuiltInAtomicType; import net.sf.saxon.type.SchemaType; /** * IDFilter is a ProxyReceiver that extracts the subtree of a document rooted at the * element with a given ID value. Namespace declarations outside this subtree are * treated as if they were present on the identified element. */ public class IDFilter extends StartTagBuffer { private String requiredId; private int activeDepth = 0; private boolean matched = false; private IntHashSet nonIDs; public IDFilter (String id) { // System.err.println("IDFilter, looking for " + id); this.requiredId = id; } /** * startElement */ public void startElement(int nameCode, int typeCode, int locationId, int properties) throws XPathException { matched = false; if (activeDepth>0) { activeDepth++; } super.startElement(nameCode, typeCode, locationId, properties); // this remembers the details } /** * Notify an attribute. Attributes are notified after the startElement event, and before any * children. Namespaces and attributes may be intermingled. * * @param nameCode The name of the attribute, as held in the name pool * @param typeCode The type of the attribute, as held in the name pool * @param properties Bit significant value. The following bits are defined: *
    DISABLE_ESCAPING
    Disable escaping for this attribute
    *
    NO_SPECIAL_CHARACTERS
    Attribute value contains no special characters
    * @throws IllegalStateException: attempt to output an attribute when there is no open element * start tag */ public void attribute(int nameCode, int typeCode, CharSequence value, int locationId, int properties) throws XPathException { super.attribute(nameCode, typeCode, value, locationId, properties); if ((nameCode & NamePool.FP_MASK) == StandardNames.XML_ID || isIDCode(typeCode)) { if (value.toString().equals(requiredId)) { matched = true; } } } /** * startContent: Test if a matching ID attribute was found; if so, start outputting. */ public void startContent() throws XPathException { if (activeDepth>0) { super.startContent(); } else if (matched) { activeDepth = 1; super.startContent(); } } protected void declareNamespacesForStartElement() throws XPathException { if (activeDepth == 1) { declareAllNamespaces(); } else { super.declareNamespacesForStartElement(); } } /** * endElement: */ public void endElement() throws XPathException { if (activeDepth > 0) { nextReceiver.endElement(); activeDepth--; } else { undeclareNamespacesForElement(); } } /** * Character data */ public void characters(CharSequence chars, int locationId, int properties) throws XPathException { if (activeDepth > 0) { super.characters(chars, locationId, properties); } } /** * Processing Instruction */ public void processingInstruction(String target, CharSequence data, int locationId, int properties) throws XPathException { if (activeDepth > 0) { super.processingInstruction(target, data, locationId, properties); } } /** * Output a comment */ public void comment(CharSequence chars, int locationId, int properties) throws XPathException { if (activeDepth > 0) { super.comment(chars, locationId, properties); } } /** * Test whether a type annotation code represents the type xs:ID or one of its subtypes */ private boolean isIDCode(int typeCode) { if ((typeCode & NamePool.FP_MASK) == StandardNames.XS_ID) { return true; } else if (typeCode < 1024) { // No other built-in type is an ID return false; } else { if (nonIDs == null) { nonIDs = new IntHashSet(20); } if (nonIDs.contains(typeCode)) { return false; } SchemaType type = getConfiguration().getSchemaType(typeCode); if (type.isAtomicType()) { if (getConfiguration().getTypeHierarchy().isSubType((AtomicType)type, BuiltInAtomicType.ID)) { return true; } else { nonIDs.add(typeCode); return false; } } else { return false; } } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/event/Sender.java0000644000175000017500000005661011253652267020631 0ustar eugeneeugenepackage net.sf.saxon.event; import net.sf.saxon.AugmentedSource; import net.sf.saxon.Configuration; import net.sf.saxon.StandardErrorHandler; import net.sf.saxon.Controller; import net.sf.saxon.evpull.PullEventSource; import net.sf.saxon.evpull.EventIterator; import net.sf.saxon.evpull.EventIteratorToReceiver; import net.sf.saxon.om.*; import net.sf.saxon.pull.PullProvider; import net.sf.saxon.pull.PullPushCopier; import net.sf.saxon.pull.PullSource; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.Type; import net.sf.saxon.type.SchemaType; import net.sf.saxon.value.Whitespace; import org.xml.sax.*; import javax.xml.transform.Source; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.sax.SAXSource; import javax.xml.transform.stream.StreamSource; import java.util.List; /** * Sender is a helper class that sends events to a Receiver from any kind of Source object */ public class Sender { PipelineConfiguration pipe; /** * Create a Sender * @param pipe the pipeline configuration */ public Sender (PipelineConfiguration pipe) { this.pipe = pipe; } /** * Send the contents of a Source to a Receiver. * @param source the source to be copied * @param receiver the destination to which it is to be copied */ public void send(Source source, Receiver receiver) throws XPathException { send(source, receiver, false); } /** * Send the contents of a Source to a Receiver. * @param source the source to be copied. Note that if the Source contains an InputStream * or Reader then it will be left open, unless it is an AugmentedSource with the pleaseCloseAfterUse * flag set. On the other hand, if it contains a URI that needs to be dereferenced to obtain * an InputStream, then the InputStream will be closed after use. * @param receiver the destination to which it is to be copied * @param isFinal set to true when the document is being processed purely for the * sake of validation, in which case multiple validation errors in the source can be * reported. */ public void send(Source source, Receiver receiver, boolean isFinal) throws XPathException { Configuration config = pipe.getConfiguration(); receiver.setPipelineConfiguration(pipe); receiver.setSystemId(source.getSystemId()); Receiver next = receiver; ParseOptions options = new ParseOptions(); options.setXIncludeAware(config.isXIncludeAware()); int schemaValidation = config.getSchemaValidationMode(); if (isFinal) { // this ensures that the Validate command produces multiple error messages schemaValidation |= Validation.VALIDATE_OUTPUT; } options.setSchemaValidationMode(schemaValidation); options.setDTDValidationMode(config.isValidation() ? Validation.STRICT : Validation.STRIP); options.setXIncludeAware(config.isXIncludeAware()); int stripSpace = Whitespace.UNSPECIFIED; // boolean xInclude = config.isXIncludeAware(); // boolean xqj = false; // boolean closeAfterUse = false; // int schemaValidation = config.getSchemaValidationMode(); // int topLevelNameCode = -1; // int dtdValidation = config.isValidation() ? Validation.STRICT : Validation.STRIP; XMLReader parser = null; SchemaType topLevelType = null; if (source instanceof AugmentedSource) { AugmentedSource as = (AugmentedSource)source; options.setPleaseCloseAfterUse(as.isPleaseCloseAfterUse()); stripSpace = as.getStripSpace(); if (as.isXIncludeAwareSet()) { options.setXIncludeAware(as.isXIncludeAware()); } options.setSourceIsXQJ(as.sourceIsXQJ()); int localValidate = ((AugmentedSource)source).getSchemaValidation(); if (localValidate != Validation.DEFAULT) { schemaValidation = localValidate; if (isFinal) { // this ensures that the Validate command produces multiple error messages schemaValidation |= Validation.VALIDATE_OUTPUT; } options.setSchemaValidationMode(schemaValidation); } topLevelType = ((AugmentedSource)source).getTopLevelType(); StructuredQName topLevelName = ((AugmentedSource)source).getTopLevelElement(); if (topLevelName != null) { options.setTopLevelElement(topLevelName); } int localDTDValidate = ((AugmentedSource)source).getDTDValidation(); if (localDTDValidate != Validation.DEFAULT) { options.setDTDValidationMode(localDTDValidate); } parser = ((AugmentedSource)source).getXMLReader(); List filters = ((AugmentedSource)source).getFilters(); if (filters != null) { for (int i=filters.size()-1; i>=0; i--) { ProxyReceiver filter = (ProxyReceiver)filters.get(i); filter.setPipelineConfiguration(pipe); filter.setSystemId(source.getSystemId()); filter.setUnderlyingReceiver(next); next = filter; } } source = ((AugmentedSource)source).getContainedSource(); } if (stripSpace == Whitespace.UNSPECIFIED) { stripSpace = config.getStripsWhiteSpace(); } options.setStripSpace(stripSpace); if (stripSpace == Whitespace.ALL) { Stripper s = new AllElementStripper(); s.setStripAll(); s.setPipelineConfiguration(pipe); s.setUnderlyingReceiver(receiver); next = s; } else if (stripSpace == Whitespace.XSLT) { Controller controller = pipe.getController(); if (controller != null) { next = controller.makeStripper(next); } } if (source instanceof NodeInfo) { NodeInfo ns = (NodeInfo)source; String baseURI = ns.getBaseURI(); int val = schemaValidation & Validation.VALIDATION_MODE_MASK; if (val != Validation.PRESERVE) { StructuredQName topLevelName = options.getTopLevelElement(); int topLevelNameCode = -1; if (topLevelName != null) { topLevelNameCode = config.getNamePool().allocate( topLevelName.getPrefix(), topLevelName.getNamespaceURI(), topLevelName.getLocalName()); } next = config.getDocumentValidator( next, baseURI, val, stripSpace, topLevelType, topLevelNameCode); } int kind = ns.getNodeKind(); if (kind != Type.DOCUMENT && kind != Type.ELEMENT) { throw new IllegalArgumentException("Sender can only handle document or element nodes"); } next.setSystemId(baseURI); sendDocumentInfo(ns, next); return; } else if (source instanceof PullSource) { sendPullSource((PullSource)source, next, options); return; } else if (source instanceof PullEventSource) { sendPullEventSource((PullEventSource)source, next, options); return; } else if (source instanceof EventSource) { ((EventSource)source).send(next); return; } else if (source instanceof SAXSource) { sendSAXSource((SAXSource)source, next, options); return; } else if (source instanceof StreamSource) { StreamSource ss = (StreamSource)source; // Following code allows the .NET platform to use a Pull parser boolean dtdValidation = options.getDTDValidationMode() == Validation.STRICT; Source ps = Configuration.getPlatform().getParserSource( pipe, ss, schemaValidation, dtdValidation, stripSpace); if (ps == ss) { String url = source.getSystemId(); InputSource is = new InputSource(url); is.setCharacterStream(ss.getReader()); is.setByteStream(ss.getInputStream()); boolean reuseParser = false; if (parser == null) { parser = config.getSourceParser(); reuseParser = true; } SAXSource sax = new SAXSource(parser, is); sax.setSystemId(source.getSystemId()); sendSAXSource(sax, next, options); if (reuseParser) { config.reuseSourceParser(parser); } } else { // the Platform substituted a different kind of source // On .NET with a default URIResolver we can expect an AugnmentedSource wrapping a PullSource send(ps, next, isFinal); } return; } else { next = makeValidator(next, source.getSystemId(), options); // See if there is a registered SourceResolver than can handle it Source newSource = config.getSourceResolver().resolveSource(source, config); if (newSource instanceof StreamSource || newSource instanceof SAXSource || newSource instanceof NodeInfo || newSource instanceof PullSource || newSource instanceof AugmentedSource || newSource instanceof EventSource) { send(newSource, next, isFinal); } // See if there is a registered external object model that knows about this kind of source List externalObjectModels = config.getExternalObjectModels(); for (int m=0; m 0) { throw new XPathException("The XML parser reported one or more errors"); } if (reuseParser) { config.reuseSourceParser(parser); } } private Receiver makeValidator(Receiver receiver, String systemId, ParseOptions options) { Configuration config = pipe.getConfiguration(); int schemaValidation = options.getSchemaValidationMode(); if ((schemaValidation & Validation.VALIDATION_MODE_MASK) != Validation.PRESERVE) { // Add a document validator to the pipeline int stripSpace = options.getStripSpace(); SchemaType topLevelType = options.getTopLevelType(); StructuredQName topLevelElement = options.getTopLevelElement(); int topLevelElementCode = -1; if (topLevelElement != null) { topLevelElementCode = config.getNamePool().allocate( topLevelElement.getPrefix(), topLevelElement.getNamespaceURI(), topLevelElement.getLocalName()); } receiver = config.getDocumentValidator( receiver, systemId, schemaValidation, stripSpace, topLevelType, topLevelElementCode); } return receiver; } private void sendPullSource(PullSource source, Receiver receiver, ParseOptions options) throws XPathException { boolean xInclude = options.isXIncludeAware(); if (xInclude) { throw new XPathException("XInclude processing is not supported with a pull parser"); } receiver = makeValidator(receiver, source.getSystemId(), options); PullProvider provider = source.getPullProvider(); if (provider instanceof LocationProvider) { pipe.setLocationProvider((LocationProvider)provider); } provider.setPipelineConfiguration(pipe); receiver.setPipelineConfiguration(pipe); PullPushCopier copier = new PullPushCopier(provider, receiver); try { copier.copy(); } finally { if (options.isPleaseCloseAfterUse()) { provider.close(); } } } private void sendPullEventSource(PullEventSource source, Receiver receiver, ParseOptions options) throws XPathException { boolean xInclude = options.isXIncludeAware(); if (xInclude) { throw new XPathException("XInclude processing is not supported with a pull parser"); } receiver = makeValidator(receiver, source.getSystemId(), options); receiver.open(); EventIterator provider = source.getEventIterator(); if (provider instanceof LocationProvider) { pipe.setLocationProvider((LocationProvider)provider); } receiver.setPipelineConfiguration(pipe); SequenceReceiver out = receiver instanceof SequenceReceiver ? ((SequenceReceiver)receiver) : new TreeReceiver(receiver); EventIteratorToReceiver.copy(provider, out); receiver.close(); } /** * Configure a SAX parser to ensure it has the correct namesapce properties set * @param parser the parser to be configured */ public static void configureParser(XMLReader parser) throws XPathException { try { parser.setFeature("http://xml.org/sax/features/namespaces", true); } catch (SAXNotSupportedException err) { // SAX2 parsers MUST support this feature! throw new XPathException( "The SAX2 parser " + parser.getClass().getName() + " does not recognize the 'namespaces' feature"); } catch (SAXNotRecognizedException err) { throw new XPathException( "The SAX2 parser " + parser.getClass().getName() + " does not support setting the 'namespaces' feature to true"); } try { parser.setFeature("http://xml.org/sax/features/namespace-prefixes", false); } catch (SAXNotSupportedException err) { // SAX2 parsers MUST support this feature! throw new XPathException( "The SAX2 parser "+ parser.getClass().getName() + " does not recognize the 'namespace-prefixes' feature"); } catch (SAXNotRecognizedException err) { throw new XPathException( "The SAX2 parser " + parser.getClass().getName() + " does not support setting the 'namespace-prefixes' feature to false"); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/event/StandardOutputResolver.java0000644000175000017500000001471411033112257024075 0ustar eugeneeugenepackage net.sf.saxon.event; import net.sf.saxon.OutputURIResolver; import net.sf.saxon.trans.XPathException; import javax.xml.transform.Result; import javax.xml.transform.stream.StreamResult; import java.io.File; import java.io.IOException; import java.io.OutputStream; import java.net.*; /** * This class defines the default OutputURIResolver. This is a counterpart to the JAXP * URIResolver, but is used to map the URI of a secondary result document to a Result object * which acts as the destination for the new document. * @author Michael H. Kay */ public class StandardOutputResolver implements OutputURIResolver { private static StandardOutputResolver theInstance = new StandardOutputResolver(); /** * Get a singular instance * @return the singleton instance of the class */ public static StandardOutputResolver getInstance() { return theInstance; } /** * Resolve an output URI * @param href The relative URI of the output document. This corresponds to the * href attribute of the xsl:result-document instruction. * @param base The base URI that should be used. This is the base output URI, * normally the URI of the principal output file. * @return a Result object representing the destination for the XML document */ public Result resolve(String href, String base) throws XPathException { // System.err.println("Output URI Resolver (href='" + href + "', base='" + base + "')"); try { URI absoluteURI; if (href.length() == 0) { if (base==null) { throw new XPathException("The system identifier of the principal output file is unknown"); } absoluteURI= new URI(base); } else { absoluteURI= new URI(href); } if (!absoluteURI.isAbsolute()) { if (base==null) { throw new XPathException("The system identifier of the principal output file is unknown"); } URI baseURI = new URI(base); absoluteURI = baseURI.resolve(href); } if ("file".equals(absoluteURI.getScheme())) { return makeOutputFile(absoluteURI); } else { // See if the Java VM can conjure up a writable URL connection for us. // This is optimistic: I have yet to discover a URL scheme that it can handle "out of the box". // But it can apparently be achieved using custom-written protocol handlers. URLConnection connection = absoluteURI.toURL().openConnection(); connection.setDoInput(false); connection.setDoOutput(true); connection.connect(); OutputStream stream = connection.getOutputStream(); StreamResult result = new StreamResult(stream); result.setSystemId(absoluteURI.toASCIIString()); return result; } } catch (URISyntaxException err) { throw new XPathException("Invalid syntax for base URI", err); } catch (IllegalArgumentException err2) { throw new XPathException("Invalid URI syntax", err2); } catch (MalformedURLException err3) { throw new XPathException("Resolved URL is malformed", err3); } catch (UnknownServiceException err5) { throw new XPathException("Specified protocol does not allow output", err5); } catch (IOException err4) { throw new XPathException("Cannot open connection to specified URL", err4); } } /** * Create an output file (unless it already exists) and return a reference to it as a Result object * @param absoluteURI the URI of the output file (which should use the "file" scheme * @return a Result object referencing this output file * @throws XPathException */ public static synchronized Result makeOutputFile(URI absoluteURI) throws XPathException { File newFile = new File(absoluteURI); try { if (!newFile.exists()) { File directory = newFile.getParentFile(); if (directory != null && !directory.exists()) { directory.mkdirs(); } newFile.createNewFile(); } return new StreamResult(newFile); } catch (IOException err) { throw new XPathException("Failed to create output file " + absoluteURI, err); } } /** * Signal completion of the result document. This method is called by the system * when the result document has been successfully written. It allows the resolver * to perform tidy-up actions such as closing output streams, or firing off * processes that take this result tree as input. Note that the OutputURIResolver * is stateless, so the original href is supplied to identify the document * that has been completed. */ public void close(Result result) throws XPathException { if (result instanceof StreamResult) { OutputStream stream = ((StreamResult)result).getOutputStream(); if (stream != null) { try { stream.close(); } catch (java.io.IOException err) { throw new XPathException("Failed while closing output file", err); } } } } // public static void main(String[] args) { // System.err.println("supplied base file: " + args[0]); // System.err.println("relative URI: " + args[1]); // System.err.println("base URI: " + new File(args[0]).toURI().toString()); // System.err.println("resolved URI: " + new File(args[0]).toURI().resolve(args[1]).toString()); // } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/event/LocationCopier.java0000644000175000017500000000544611033112257022306 0ustar eugeneeugenepackage net.sf.saxon.event; import net.sf.saxon.om.NodeInfo; /** * A Receiver that can be inserted into an event pipeline to copy location information. * The class acts as a LocationProvider, so it supports getSystemId() and getLineNumber() methods; * the location returned can vary for each node, and is set by the class generating the events. * The class is used when it is necessary to copy a subtree along with its location information; * for example, when copying an inline schema within a stylesheet to a separate schema document. */ public class LocationCopier extends ProxyReceiver implements CopyInformee, LocationProvider { private int lineNumber; public LocationCopier() { } public LocationCopier(Receiver nextReceiver) { setUnderlyingReceiver(nextReceiver); } public void setPipelineConfiguration(PipelineConfiguration pipe) { PipelineConfiguration pipe2 = new PipelineConfiguration(pipe); pipe2.setLocationProvider(this); super.setPipelineConfiguration(pipe2); } /** * Provide information about the node being copied. This method is called immediately before * the startElement call for the element node in question. * * @param element the node being copied, which must be an element node */ public void notifyElementNode(NodeInfo element) { setSystemId(element.getBaseURI()); setLineNumber(element.getLineNumber()); } /** * Set the line number * @param lineNumber the line number */ private void setLineNumber(int lineNumber) { this.lineNumber = lineNumber; } /** * Get the line number * @return the line number most recently set */ public int getLineNumber() { return lineNumber; } public String getSystemId(long locationId) { return getSystemId(); } public int getLineNumber(long locationId) { return getLineNumber(); } public int getColumnNumber(long locationId) { return -1; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): None // saxonb-9.1.0.8/bj/net/sf/saxon/event/NoOpenStartTagException.java0000644000175000017500000001052011033112257024110 0ustar eugeneeugenepackage net.sf.saxon.event; import net.sf.saxon.Configuration; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.Type; /** * Exception indicating that an attribute or namespace node has been written when * there is no open element to write it to */ public class NoOpenStartTagException extends XPathException { /** * Static factory method to create the exception * @param nodeKind the kind of node being created (attribute or namespace) * @param name the name of the node being created * @param hostLanguage XSLT or XQuery (error codes are different in the two cases) * @param parentIsDocument true if the nodes are being added to a document node (rather than an element) * @param isSerializing true if the document is being created in the process of serialization * @return the constructed exception object */ public static NoOpenStartTagException makeNoOpenStartTagException( int nodeKind, String name, int hostLanguage, boolean parentIsDocument, boolean isSerializing) { String message; String errorCode; if (parentIsDocument) { if (isSerializing) { String kind = (nodeKind == Type.ATTRIBUTE ? "attribute" : "namespace"); String article = (nodeKind == Type.ATTRIBUTE ? "an " : "a "); if (hostLanguage == Configuration.XSLT ) { message = "Cannot have " + article + kind + " node (" + name + ") whose parent is a document node"; errorCode = "XTDE0420"; } else { message = "Cannot serialize a free-standing " + kind + " node (" + name + ')'; errorCode = "SENR0001"; } } else { String kind = (nodeKind == Type.ATTRIBUTE ? "an attribute" : "a namespace"); message = "Cannot create " + kind + " node (" + name + ") whose parent is a document node"; errorCode = (hostLanguage == Configuration.XSLT ? "XTDE0420" : "XPTY0004"); } } else { String kind = (nodeKind == Type.ATTRIBUTE ? "An attribute" : "A namespace"); message = kind + " node (" + name + ") cannot be created after the children of the containing element"; errorCode = (hostLanguage == Configuration.XSLT ? "XTDE0410" : "XQTY0024"); } NoOpenStartTagException err = new NoOpenStartTagException(message); err.setErrorCode(errorCode); return err; } public NoOpenStartTagException(String message) { super(message); } // public NoOpenStartTagException(int nodeKind, String name, int hostLanguage, boolean topLevel, boolean isSerializing) { // // The contorted conditional here is because super() has to be at the start of the method // super((topLevel ? // (isSerializing ? // "Cannot serialize ") // ("Cannot create " + // (nodeKind==Type.ATTRIBUTE ? "an attribute" : "a namespace") + // " node (" + name + ") whose parent is a document node") // : // (nodeKind==net.sf.saxon.type.Type.ATTRIBUTE ? "An attribute" : "A namespace") + // " node (" + name + ") cannot be created after the children of the containing element" // )); // if (hostLanguage == Configuration.XSLT) { // setErrorCode(topLevel ? "XTDE0420" : "XTDE0410"); // } else { // setErrorCode(topLevel ? "XPTY0004" : "XQTY0024"); // } // } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. //saxonb-9.1.0.8/bj/net/sf/saxon/event/HTMLTagHashSet.java0000644000175000017500000000506411033112257022050 0ustar eugeneeugenepackage net.sf.saxon.event; /** * A simple class for testing membership of a fixed set of case-insensitive ASCII strings. * The class must be initialised with enough space for all the strings, * it will go into an infinite loop if it fills. The string matching is case-blind, * using an algorithm that works only for ASCII. * * The class implements part of the java.util.Set interface; it could be replaced with * an implementation of java.util.Set together with a class that implemented a customized * equals() method. */ public class HTMLTagHashSet { String[] strings; int size; public HTMLTagHashSet(int size) { strings = new String[size]; this.size = size; } public void add(String s) { int hash = (hashCode(s) & 0x7fffffff) % size; while(true) { if (strings[hash]==null) { strings[hash] = s; return; } if (strings[hash].equalsIgnoreCase(s)) { return; } hash = (hash + 1) % size; } } public boolean contains(String s) { int hash = (hashCode(s) & 0x7fffffff) % size; while(true) { if (strings[hash]==null) { return false; } if (strings[hash].equalsIgnoreCase(s)) { return true; } hash = (hash + 1) % size; } } private int hashCode(String s) { // get a hashcode that doesn't depend on the case of characters. // This relies on the fact that char & 0xDF is case-blind in ASCII int hash = 0; int limit = s.length(); if (limit>24) limit = 24; for (int i=0; i *

    The system identifier is optional if the source does not * get its data from a URL, but it may still be useful to provide one. * The application can use a system identifier, for example, to resolve * relative URIs and to include in error messages and warnings.

    * @param systemId The system identifier as a URL string. */ public void setSystemId(String systemId) { this.systemId = systemId; } /** * Get the system identifier that was set with setSystemId. * @return The system identifier that was set with setSystemId, or null * if setSystemId was not called. */ public String getSystemId() { return systemId; } /** * Supply events to a Receiver. * @param out the Receiver to which events will be sent. It is the caller's responsibility * to initialize the receiver with a PipelineConfiguration, and to call the open() and close() * methods on the receiver before and after calling this send() method. */ public abstract void send(Receiver out) throws XPathException; } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/event/SaxonLocator.java0000644000175000017500000000225411033112257022002 0ustar eugeneeugenepackage net.sf.saxon.event; import org.xml.sax.Locator; import javax.xml.transform.SourceLocator; /** * SaxonLocator: this interface exists to unify the SAX Locator and JAXP SourceLocator interfaces, * which are identical. It extends both interfaces. Therefore, anything * that implements SaxonLocator can be used both in SAX and in JAXP interfaces. */ public interface SaxonLocator extends Locator, SourceLocator, LocationProvider {} // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/event/ComplexContentOutputter.java0000644000175000017500000005350711102653225024275 0ustar eugeneeugenepackage net.sf.saxon.event; import net.sf.saxon.Configuration; import net.sf.saxon.trans.Err; import net.sf.saxon.expr.ExpressionLocation; import net.sf.saxon.om.*; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.Type; import net.sf.saxon.value.AtomicValue; /** * This class is used for generating complex content, that is, the content of an * element or document node. It enforces the rules on the order of events within * complex content (attributes and namespaces must come first), and it implements * part of the namespace fixup rules, in particular, it ensures that there is a * namespace node for the namespace used in the element name and in each attribute * name. * *

    The same ComplexContentOutputter may be used for generating an entire XML * document; it is not necessary to create a new outputter for each element node.

    * * @author Michael H. Kay */ public final class ComplexContentOutputter extends SequenceReceiver { private Receiver nextReceiver; // the next receiver in the output pipeline private int pendingStartTag = -2; // -2 means we are at the top level, or immediately within a document node // -1 means we are in the content of an element node whose start tag is complete private int level = -1; // records the number of startDocument or startElement events // that have not yet been closed. Note that startDocument and startElement // events may be arbitrarily nested; startDocument and endDocument // are ignored unless they occur at the outermost level, except that they // still change the level number private boolean[] currentLevelIsDocument = new boolean[20]; private Boolean elementIsInNullNamespace; private int[] pendingAttCode = new int[20]; private int[] pendingAttType = new int[20]; private String[] pendingAttValue = new String[20]; private int[] pendingAttLocation = new int[20]; private int[] pendingAttProp = new int[20]; private int pendingAttListSize = 0; private int[] pendingNSList = new int[20]; private int pendingNSListSize = 0; private int currentSimpleType = -1; // any other value means we are currently writing an // element of a particular simple type private int startElementProperties; private int startElementLocationId; private boolean declaresDefaultNamespace; private int hostLanguage = Configuration.XSLT; private boolean started = false; /** * Create a ComplexContentOutputter */ public ComplexContentOutputter() {} public void setPipelineConfiguration(PipelineConfiguration pipe) { if (pipelineConfiguration != pipe) { pipelineConfiguration = pipe; if (nextReceiver != null) { nextReceiver.setPipelineConfiguration(pipe); } } } /** * Set the host language * @param language the host language, for example {@link Configuration#XQUERY} */ public void setHostLanguage(int language) { hostLanguage = language; } /** * Set the receiver (to handle the next stage in the pipeline) directly * @param receiver the receiver to handle the next stage in the pipeline */ public void setReceiver(Receiver receiver) { this.nextReceiver = receiver; } /** * Test whether any content has been written to this ComplexContentOutputter * @return true if content has been written */ public boolean contentHasBeenWritten() { return started; } /** * Start the output process */ public void open() throws XPathException { nextReceiver.open(); previousAtomic = false; } /** * Start of a document node. */ public void startDocument(int properties) throws XPathException { level++; if (level == 0) { nextReceiver.startDocument(properties); } else if (pendingStartTag >= 0) { startContent(); pendingStartTag = -2; } previousAtomic = false; if (currentLevelIsDocument.length < level+1) { boolean[] b2 = new boolean[level*2]; System.arraycopy(currentLevelIsDocument, 0, b2, 0, level); currentLevelIsDocument = b2; } currentLevelIsDocument[level] = true; } /** * Notify the end of a document node */ public void endDocument() throws XPathException { if (level == 0) { nextReceiver.endDocument(); } level--; } /** * Produce text content output.
    * Special characters are escaped using XML/HTML conventions if the output format * requires it. * @param s The String to be output * @exception XPathException for any failure */ public void characters(CharSequence s, int locationId, int properties) throws XPathException { previousAtomic = false; if (s==null) return; int len = s.length(); if (len==0) return; if (pendingStartTag >= 0) { startContent(); } nextReceiver.characters(s, locationId, properties); } /** * Output an element start tag.
    * The actual output of the tag is deferred until all attributes have been output * using attribute(). * @param nameCode The element name code */ public void startElement(int nameCode, int typeCode, int locationId, int properties) throws XPathException { // System.err.println("StartElement " + nameCode); level++; started = true; if (pendingStartTag >= 0) { startContent(); } startElementProperties = properties; startElementLocationId = locationId; pendingAttListSize = 0; pendingNSListSize = 0; pendingStartTag = nameCode; elementIsInNullNamespace = null; // meaning not yet computed declaresDefaultNamespace = false; currentSimpleType = typeCode; previousAtomic = false; if (currentLevelIsDocument.length < level+1) { boolean[] b2 = new boolean[level*2]; System.arraycopy(currentLevelIsDocument, 0, b2, 0, level); currentLevelIsDocument = b2; } currentLevelIsDocument[level] = false; } /** * Output a namespace declaration.
    * This is added to a list of pending namespaces for the current start tag. * If there is already another declaration of the same prefix, this one is * ignored, unless the REJECT_DUPLICATES flag is set, in which case this is an error. * Note that unlike SAX2 startPrefixMapping(), this call is made AFTER writing the start tag. * @param nscode The namespace code * @throws XPathException if there is no start tag to write to (created using writeStartTag), * or if character content has been written since the start tag was written. */ public void namespace(int nscode, int properties) throws XPathException { // System.err.println("Write namespace prefix=" + (nscode>>16) + " uri=" + (nscode&0xffff)); NamePool pool = getNamePool(); if (pendingStartTag < 0) { throw NoOpenStartTagException.makeNoOpenStartTagException( Type.NAMESPACE, pool.getPrefixFromNamespaceCode(nscode), hostLanguage, pendingStartTag == -2, getPipelineConfiguration().isSerializing() ); } // elimination of namespaces already present on an outer element of the // result tree is done by the NamespaceReducer. // Handle declarations whose prefix is duplicated for this element. boolean rejectDuplicates = (properties & ReceiverOptions.REJECT_DUPLICATES) != 0; for (int i=0; i>16) == (pendingNSList[i]>>16)) { if (rejectDuplicates) { String prefix = pool.getPrefixFromNamespaceCode(nscode); String uri1 = pool.getURIFromNamespaceCode(nscode); String uri2 = pool.getURIFromNamespaceCode(pendingNSList[i]); XPathException err = new XPathException("Cannot create two namespace nodes with the same prefix mapped to different URIs (prefix=" + (prefix.length() == 0 ? "\"\"" : prefix) + ", URI=" + (uri1.length() == 0 ? "\"\"" : uri1) + ", URI=" + (uri2.length() == 0 ? "\"\"" : uri2) + ")"); err.setErrorCode("XTDE0430"); throw err; } else { // same prefix, do a quick exit return; } } } // It is an error to output a namespace node for the default namespace if the element // itself is in the null namespace, as the resulting element could not be serialized if (((nscode>>16) == 0) && ((nscode&0xffff)!=0)) { declaresDefaultNamespace = true; if (elementIsInNullNamespace == null) { elementIsInNullNamespace = Boolean.valueOf( pool.getURI(pendingStartTag).equals(NamespaceConstant.NULL)); } if (elementIsInNullNamespace.booleanValue()) { XPathException err = new XPathException("Cannot output a namespace node for the default namespace when the element is in no namespace"); err.setErrorCode("XTDE0440"); throw err; } } // if it's not a duplicate namespace, add it to the list for this start tag if (pendingNSListSize+1 > pendingNSList.length) { int[] newlist = new int[pendingNSListSize * 2]; System.arraycopy(pendingNSList, 0, newlist, 0, pendingNSListSize); pendingNSList = newlist; } pendingNSList[pendingNSListSize++] = nscode; previousAtomic = false; } /** * Output an attribute value.
    * This is added to a list of pending attributes for the current start tag, overwriting * any previous attribute with the same name.
    * This method should NOT be used to output namespace declarations.
    * @param nameCode The name of the attribute * @param value The value of the attribute * @param properties Bit fields containing properties of the attribute to be written * @throws XPathException if there is no start tag to write to (created using writeStartTag), * or if character content has been written since the start tag was written. */ public void attribute(int nameCode, int typeCode, CharSequence value, int locationId, int properties) throws XPathException { //System.err.println("Write attribute " + nameCode + "=" + value + " to Outputter " + this); if (pendingStartTag < 0) { // The complexity here is in identifying the right error message and error code XPathException err = NoOpenStartTagException.makeNoOpenStartTagException( Type.ATTRIBUTE, getNamePool().getDisplayName(nameCode), hostLanguage, level<0 || currentLevelIsDocument[level], getPipelineConfiguration().isSerializing()); LocationProvider lp = getPipelineConfiguration().getLocationProvider(); if (lp != null) { err.setLocator(new ExpressionLocation(lp, locationId)); } throw err; } // if this is a duplicate attribute, overwrite the original, unless // the REJECT_DUPLICATES option is set. for (int a=0; a= pendingAttCode.length) { int[] attCode2 = new int[pendingAttListSize*2]; int[] attType2 = new int[pendingAttListSize*2]; String[] attValue2 = new String[pendingAttListSize*2]; int[] attLoc2 = new int[pendingAttListSize*2]; int[] attProp2 = new int[pendingAttListSize*2]; System.arraycopy(pendingAttCode, 0, attCode2, 0, pendingAttListSize); System.arraycopy(pendingAttType, 0, attType2, 0, pendingAttListSize); System.arraycopy(pendingAttValue, 0, attValue2, 0, pendingAttListSize); System.arraycopy(pendingAttLocation, 0, attLoc2, 0, pendingAttListSize); System.arraycopy(pendingAttProp, 0, attProp2, 0, pendingAttListSize); pendingAttCode = attCode2; pendingAttType = attType2; pendingAttValue = attValue2; pendingAttLocation = attLoc2; pendingAttProp = attProp2; } pendingAttCode[pendingAttListSize] = nameCode; pendingAttType[pendingAttListSize] = typeCode; pendingAttValue[pendingAttListSize] = value.toString(); pendingAttLocation[pendingAttListSize] = locationId; pendingAttProp[pendingAttListSize] = properties; pendingAttListSize++; previousAtomic = false; } /** * Check that the prefix for an element or attribute is acceptable, allocating a substitute * prefix if not. The prefix is acceptable unless a namespace declaration has been * written that assignes this prefix to a different namespace URI. This method * also checks that the element or attribute namespace has been declared, and declares it * if not. * @param nameCode the proposed name, including proposed prefix * @param seq sequence number, used for generating a substitute prefix when necessary * @return a nameCode to use in place of the proposed nameCode (or the original nameCode * if no change is needed) */ private int checkProposedPrefix(int nameCode, int seq) throws XPathException { NamePool namePool = getNamePool(); int nscode = namePool.getNamespaceCode(nameCode); if (nscode == -1) { // avoid calling allocate where possible, because it's synchronized nscode = namePool.allocateNamespaceCode(nameCode); } int nsprefix = nscode>>16; for (int i=0; i>16)) { // same prefix if ((nscode & 0xffff) == (pendingNSList[i] & 0xffff)) { // same URI return nameCode; // all is well } else { String prefix = getSubstitutePrefix(nscode, seq); int newCode = namePool.allocate( prefix, namePool.getURI(nameCode), namePool.getLocalName(nameCode)); namespace(namePool.allocateNamespaceCode(newCode), 0); return newCode; } } } // no declaration of this prefix: declare it now namespace(nscode, 0); return nameCode; } /** * It is possible for a single output element to use the same prefix to refer to different * namespaces. In this case we have to generate an alternative prefix for uniqueness. The * one we generate is based on the sequential position of the element/attribute: this is * designed to ensure both uniqueness (with a high probability) and repeatability * @param nscode the proposed namespace code * @param seq sequence number for use in the substitute prefix * @return a prefix to use in place of the one originally proposed */ private String getSubstitutePrefix(int nscode, int seq) { String prefix = getNamePool().getPrefixFromNamespaceCode(nscode); return prefix + '_' + seq; } /** * Output an element end tag. */ public void endElement() throws XPathException { //System.err.println("Write end tag " + this + " : " + name); if (pendingStartTag >= 0) { startContent(); } else { pendingStartTag = -2; } // write the end tag nextReceiver.endElement(); level--; previousAtomic = false; } /** * Write a comment */ public void comment(CharSequence comment, int locationId, int properties) throws XPathException { if (pendingStartTag >= 0) { startContent(); } nextReceiver.comment(comment, locationId, properties); previousAtomic = false; } /** * Write a processing instruction */ public void processingInstruction(String target, CharSequence data, int locationId, int properties) throws XPathException { if (pendingStartTag >= 0) { startContent(); } nextReceiver.processingInstruction(target, data, locationId, properties); previousAtomic = false; } /** * Append an arbitrary item (node or atomic value) to the output * @param item the item to be appended * @param locationId the location of the calling instruction, for diagnostics * @param copyNamespaces if the item is an element node, this indicates whether its namespaces * need to be copied. Values are {@link net.sf.saxon.om.NodeInfo#ALL_NAMESPACES}, {@link net.sf.saxon.om.NodeInfo#LOCAL_NAMESPACES}, * {@link net.sf.saxon.om.NodeInfo#NO_NAMESPACES} */ public void append(Item item, int locationId, int copyNamespaces) throws XPathException { if (item == null) { //return; } else if (item instanceof AtomicValue) { if (previousAtomic) { characters(" ", locationId, 0); } characters(item.getStringValueCS(), locationId, 0); previousAtomic = true; } else if (((NodeInfo)item).getNodeKind() == Type.DOCUMENT) { startDocument(0); SequenceIterator iter = ((NodeInfo)item).iterateAxis(Axis.CHILD); while (true) { Item it = iter.next(); if (it == null) break; append(it, locationId, copyNamespaces); } endDocument(); previousAtomic = false; } else { try { ((NodeInfo)item).copy(this, copyNamespaces, true, locationId); } catch (CopyNamespaceSensitiveException e) { e.setErrorCode((hostLanguage == Configuration.XSLT ? "XTTE0950" : "XQTY0086")); throw e; } previousAtomic = false; } } /** * Close the output */ public void close() throws XPathException { // System.err.println("Close " + this + " using emitter " + emitter.getClass()); nextReceiver.close(); previousAtomic = false; } /** * Flush out a pending start tag */ public void startContent() throws XPathException { if (pendingStartTag < 0) { // this can happen if the method is called from outside, // e.g. from a SequenceOutputter earlier in the pipeline return; } started = true; int props = startElementProperties; int elcode = pendingStartTag; if (declaresDefaultNamespace || NamePool.getPrefixIndex(elcode) != 0) { // skip this check if the element is unprefixed and no xmlns="abc" declaration has been encountered elcode = checkProposedPrefix(pendingStartTag, 0); props = startElementProperties | ReceiverOptions.NAMESPACE_OK; } nextReceiver.startElement(elcode, currentSimpleType, startElementLocationId, props); for (int a=0; a= propertyStack.length) { int[] p2 = new int[level*2]; System.arraycopy(propertyStack, 0, p2, 0, propertyStack.length); propertyStack = p2; } propertyStack[level] = tagProps; isInlineTag = (tagProps & IS_INLINE) != 0; inFormattedTag = inFormattedTag || ((tagProps & IS_FORMATTED) != 0); if (!isInlineTag && !inFormattedTag && !afterInline && !afterFormatted) { indent(); } nextReceiver.startElement(nameCode, typeCode, locationId, properties); level++; sameLine = true; afterInline = false; afterFormatted = false; } /** * Output element end tag */ public void endElement() throws XPathException { level--; boolean thisInline = (propertyStack[level] & IS_INLINE) != 0; boolean thisFormatted = (propertyStack[level] & IS_FORMATTED) != 0; if (!thisInline && !thisFormatted && !afterInline && !sameLine && !afterFormatted && !inFormattedTag) { indent(); afterInline = false; afterFormatted = false; } else { afterInline = thisInline; afterFormatted = thisFormatted; } nextReceiver.endElement(); inFormattedTag = inFormattedTag && !thisFormatted; sameLine = false; } /** * Output character data */ public void characters(CharSequence chars, int locationId, int properties) throws XPathException { if (inFormattedTag || (properties & ReceiverOptions.USE_NULL_MARKERS) != 0) { // don't split the text if in a tag such as
    , or if the text contains the result of
                // expanding a character map
                nextReceiver.characters(chars, locationId, properties);
            } else {
                // otherwise try to split long lines into multiple lines
                int lastNL = 0;
                for (int i=0; i 120 && chars.charAt(i)==' ')) {
                        sameLine = false;
                        nextReceiver.characters(chars.subSequence(lastNL, i), locationId, properties);
                        indent();
                        lastNL = i+1;
                        while (lastNL= indentChars.length) {
                int increment = 5 * indentSpaces;
                if (spaces + 1 > indentChars.length + increment) {
                    increment += spaces + 1;
                }
                char[] c2 = new char[indentChars.length + increment];
                System.arraycopy(indentChars, 0, c2, 0, indentChars.length);
                Arrays.fill(c2, indentChars.length, c2.length, ' ');
                indentChars = c2;
            }
            nextReceiver.characters(new CharSlice(indentChars, 0, spaces+1), 0, 0);
            sameLine = false;
        }
    
    };
    
    //
    // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
    // you may not use this file except in compliance with the License. You may obtain a copy of the
    // License at http://www.mozilla.org/MPL/
    //
    // Software distributed under the License is distributed on an "AS IS" basis,
    // WITHOUT WARRANTY OF ANY KIND, either express or implied.
    // See the License for the specific language governing rights and limitations under the License.
    //
    // The Original Code is: all this file.
    //
    // The Initial Developer of the Original Code is Michael H. Kay.
    //
    // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
    //
    // Contributor(s): none.
    //
    
    saxonb-9.1.0.8/bj/net/sf/saxon/event/CommentStripper.java0000644000175000017500000000701611033112257022522 0ustar  eugeneeugenepackage net.sf.saxon.event;
    
    import net.sf.saxon.trans.XPathException;
    import net.sf.saxon.om.FastStringBuffer;
    import net.sf.saxon.tinytree.CompressedWhitespace;
    
    /**
      * The CommentStripper class is a filter that removes all comments and processing instructions.
      * It also concatenates text nodes that are split by comments and PIs. This follows the rules for
      * processing stylesheets.
      * @author Michael H. Kay
      */
    
    
    public class CommentStripper extends ProxyReceiver {
    
        private CompressedWhitespace savedWhitespace = null;
        private FastStringBuffer buffer = new FastStringBuffer(200);
    
        /**
        * Default constructor for use in subclasses
        */
    
        public CommentStripper() {}
        static int seq = 0;
    
        public void startElement (int nameCode, int typeCode, int locationId, int properties)
        throws XPathException {
            flush();
            nextReceiver.startElement(nameCode, typeCode, locationId, properties);
        }
    
        /**
        * Callback interface for SAX: not for application use
        */
    
        public void endElement () throws XPathException {
            flush();
            nextReceiver.endElement();
        }
    
        /**
         * Handle a text node. Because we're often handling stylesheets on this path, whitespace text
         * nodes will often be stripped but we can't strip them immediately because of the case
         * [element]   [!-- comment --]text[/element], where the space before the comment is considered
         * significant. But it's worth going to some effort to avoid uncompressing the whitespace in the
         * more common case, so that it can easily be detected and stripped downstream.
        */
    
        public void characters (CharSequence chars, int locationId, int properties) throws XPathException {
            if (chars instanceof CompressedWhitespace) {
                if (buffer.length() == 0 && savedWhitespace == null) {
                    savedWhitespace = (CompressedWhitespace)chars;
                } else {
                    ((CompressedWhitespace)chars).uncompress(buffer);
                }
            } else {
                if (savedWhitespace != null) {
                    savedWhitespace.uncompress(buffer);
                    savedWhitespace = null;
                }
                buffer.append(chars);
            }
    
        }
    
        /**
        * Remove comments
        */
    
        public void comment (CharSequence chars, int locationId, int properties) {}
    
        /**
        * Remove processing instructions
        */
    
        public void processingInstruction(String name, CharSequence data, int locationId, int properties) {}
    
        /**
        * Flush the character buffer
        */
    
        private void flush() throws XPathException {
            if (buffer.length() > 0) {
                nextReceiver.characters(buffer, 0, 0);
            } else if (savedWhitespace != null) {
                nextReceiver.characters(savedWhitespace, 0, 0);
            }
            savedWhitespace = null;
            buffer.setLength(0);
        }
    
    }
    
    //
    // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
    // you may not use this file except in compliance with the License. You may obtain a copy of the
    // License at http://www.mozilla.org/MPL/
    //
    // Software distributed under the License is distributed on an "AS IS" basis,
    // WITHOUT WARRANTY OF ANY KIND, either express or implied.
    // See the License for the specific language governing rights and limitations under the License.
    //
    // The Original Code is: all this file.
    //
    // The Initial Developer of the Original Code is Michael H. Kay.
    //
    // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
    //
    // Contributor(s): none.
    //
    saxonb-9.1.0.8/bj/net/sf/saxon/event/XHTMLEmitter.java0000644000175000017500000000460611033112257021617 0ustar  eugeneeugenepackage net.sf.saxon.event;
    
    import net.sf.saxon.om.NamePool;
    import net.sf.saxon.om.NamespaceConstant;
    import net.sf.saxon.sort.IntHashSet;
    import net.sf.saxon.trans.XPathException;
    
    
    /**
      * XHTMLEmitter is an Emitter that generates XHTML output.
      * It is the same as XMLEmitter except that it follows the legacy HTML browser
      * compatibility rules: for example, generating empty elements such as [BR /], and
      * using [p][/p] for empty paragraphs rather than [p/]
      */
    
    public class XHTMLEmitter extends XMLEmitter {
    
        /**
        * Table of XHTML tags that have no closing tag
        */
    
        IntHashSet emptyTags = new IntHashSet(31);
    
        private static String[] emptyTagNames = {
            "area", "base", "basefont", "br", "col", "frame", "hr", "img", "input", "isindex", "link", "meta", "param"
        };
    
        /**
         * Do the real work of starting the document. This happens when the first
         * content is written.
         *
         * @throws net.sf.saxon.trans.XPathException
         *
         */
    
        protected void openDocument() throws XPathException {
            NamePool pool = getPipelineConfiguration().getConfiguration().getNamePool();
            for (int i=0; i";
            } else {
                return ">';
            }
        }
    
    }
    
    //
    // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
    // you may not use this file except in compliance with the License. You may obtain a copy of the
    // License at http://www.mozilla.org/MPL/
    //
    // Software distributed under the License is distributed on an "AS IS" basis,
    // WITHOUT WARRANTY OF ANY KIND, either express or implied.
    // See the License for the specific language governing rights and limitations under the License.
    //
    // The Original Code is: all this file.
    //
    // The Initial Developer of the Original Code is Michael H. Kay.
    //
    // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
    //
    // Contributor(s): none.
    //
    saxonb-9.1.0.8/bj/net/sf/saxon/event/DocumentSender.java0000644000175000017500000000627211033112257022311 0ustar  eugeneeugenepackage net.sf.saxon.event;
    
    import net.sf.saxon.om.NodeInfo;
    import net.sf.saxon.trans.XPathException;
    import net.sf.saxon.type.Type;
    
    /**
     * Sends an entire document to a Receiver.
     *
     * @author Ruud Diterwich, integrated by Michael Kay
     */
    
    public class DocumentSender implements SaxonLocator {
    
    	private NodeInfo top;
    
        /**
        * Create a DocumentSender, which takes an input document tree and generates
        * a stream of events for a Receiver
        * @param top the document or element node to be turned into a stream of events
        */
    
    	public DocumentSender(NodeInfo top) {
    		this.top = top;
            int kind = top.getNodeKind();
            if (kind != Type.DOCUMENT && kind != Type.ELEMENT) {
                throw new IllegalArgumentException("DocumentSender can only handle document or element nodes");
            }
    	}
    
        /**
        * Send the entire document to the receiver
        */
    
    	public void send(Receiver receiver) throws XPathException {
    
            PipelineConfiguration pipe = receiver.getPipelineConfiguration();
            if (top.getNamePool() != pipe.getConfiguration().getNamePool()
                    && !(receiver instanceof NamePoolConverter)) {
                throw new IllegalArgumentException("DocumentSender source and target must use the same NamePool");
            }
    
    		// set system id
            if (pipe.getLocationProvider() == null) {
    		    receiver.setSystemId(top.getSystemId());
    	        pipe.setLocationProvider(this);
            }
    
    		// start event stream
    		receiver.open();
    
    		// copy the contents of the document
            receiver.startDocument(0);
    		top.copy(receiver, NodeInfo.ALL_NAMESPACES, true, 0);
            receiver.endDocument();
    
    		// end event stream
    		receiver.close();
    	}
    
        // Implement the SAX Locator interface. This is needed to pass the base URI of nodes
        // to the receiver. We don't attempt to preserve the original base URI of each individual
        // node as it is copied, only the base URI of the document as a whole.
    
    	public int getColumnNumber() {
    		return -1;
    	}
    
    	public int getLineNumber() {
    		return -1;
    	}
    
    	public String getPublicId() {
    		return null;
    	}
    
    	public String getSystemId() {
    		return top.getSystemId();
    	}
    
        public String getSystemId(long locationId) {
            return getSystemId();
        }
    
        public int getLineNumber(long locationId) {
            return getLineNumber();
        }
    
        public int getColumnNumber(long locationId) {
            return getColumnNumber();
        }
    
    }
    //
    // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
    // you may not use this file except in compliance with the License. You may obtain a copy of the
    // License at http://www.mozilla.org/MPL/
    //
    // Software distributed under the License is distributed on an "AS IS" basis,
    // WITHOUT WARRANTY OF ANY KIND, either express or implied.
    // See the License for the specific language governing rights and limitations under the License.
    //
    // The Original Code is: all this file.
    //
    // The Initial Developer of the Original Code is Michael H. Kay.
    //
    // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
    //
    // Contributor(s): none.
    //saxonb-9.1.0.8/bj/net/sf/saxon/event/HTMLURIEscaper.java0000644000175000017500000002060711033112257022017 0ustar  eugeneeugenepackage net.sf.saxon.event;
    import net.sf.saxon.charcode.UnicodeCharacterSet;
    import net.sf.saxon.om.FastStringBuffer;
    import net.sf.saxon.om.NamePool;
    import net.sf.saxon.trans.XPathException;
    import net.sf.saxon.codenorm.Normalizer;
    
    import java.util.HashMap;
    
    /**
      * This class is used as a filter on the serialization pipeline; it performs the function
      * of escaping URI-valued attributes in HTML
      * @author Michael H. Kay
      */
    
    public class HTMLURIEscaper extends ProxyReceiver {
    
        /**
        * Table of attributes whose value is a URL
        */
    
        // we use two HashMaps to avoid unnecessary string concatenations
    
        private static HTMLTagHashSet urlAttributes = new HTMLTagHashSet(47);
        private static HTMLTagHashSet urlCombinations = new HTMLTagHashSet(101);
    
        static {
            setUrlAttribute("form", "action");
            setUrlAttribute("object", "archive");
            setUrlAttribute("body", "background");
            setUrlAttribute("q", "cite");
            setUrlAttribute("blockquote", "cite");
            setUrlAttribute("del", "cite");
            setUrlAttribute("ins", "cite");
            setUrlAttribute("object", "classid");
            setUrlAttribute("object", "codebase");
            setUrlAttribute("applet", "codebase");
            setUrlAttribute("object", "data");
            setUrlAttribute("button", "datasrc");
            setUrlAttribute("div", "datasrc");
            setUrlAttribute("input", "datasrc");
            setUrlAttribute("object", "datasrc");
            setUrlAttribute("select", "datasrc");
            setUrlAttribute("span", "datasrc");
            setUrlAttribute("table", "datasrc");
            setUrlAttribute("textarea", "datasrc");
            setUrlAttribute("script", "for");
            setUrlAttribute("a", "href");
            setUrlAttribute("a", "name");       // see second note in section B.2.1 of HTML 4 specification
            setUrlAttribute("area", "href");
            setUrlAttribute("link", "href");
            setUrlAttribute("base", "href");
            setUrlAttribute("img", "longdesc");
            setUrlAttribute("frame", "longdesc");
            setUrlAttribute("iframe", "longdesc");
            setUrlAttribute("head", "profile");
            setUrlAttribute("script", "src");
            setUrlAttribute("input", "src");
            setUrlAttribute("frame", "src");
            setUrlAttribute("iframe", "src");
            setUrlAttribute("img", "src");
            setUrlAttribute("img", "usemap");
            setUrlAttribute("input", "usemap");
            setUrlAttribute("object", "usemap");
        }
    
        private static void setUrlAttribute(String element, String attribute) {
            urlAttributes.add(attribute);
            urlCombinations.add(element + '+' + attribute);
        }
    
        private HashMap urlAttributeCache = new HashMap(30);
    
        public boolean isUrlAttribute(int element, int attribute) {
            Long key = new Long(((long)element)<<32 | (long)attribute);
            Boolean result = (Boolean)urlAttributeCache.get(key);
            if (result != null) {
                return result.booleanValue();
            }
            if (pool == null) {
                pool = getNamePool();
            }
            String attributeName = pool.getDisplayName(attribute);
            if (!urlAttributes.contains(attributeName)) {
                urlAttributeCache.put(key, Boolean.FALSE);
                return false;
            }
            String elementName = pool.getDisplayName(element);
            boolean b = urlCombinations.contains(elementName + '+' + attributeName);
            urlAttributeCache.put(key, Boolean.valueOf(b));
            return b;
        }
    
        protected int currentElement;
        protected boolean escapeURIAttributes = true;
        protected NamePool pool;
    
         /**
         * Start of a document node.
         */
    
        public void startDocument(int properties) throws XPathException {
            nextReceiver.startDocument(properties);
            pool = getPipelineConfiguration().getConfiguration().getNamePool();
        }
    
        /**
         * Notify the start of an element
         *
         * @param nameCode   integer code identifying the name of the element within the name pool.
         * @param typeCode   integer code identifying the element's type within the name pool.
         * @param properties properties of the element node
         */
    
        public void startElement(int nameCode, int typeCode, int locationId, int properties) throws XPathException {
            currentElement = nameCode;
            nextReceiver.startElement(nameCode, typeCode, locationId, properties);
        }
    
        /**
         * Notify an attribute. Attributes are notified after the startElement event, and before any
         * children. Namespaces and attributes may be intermingled.
         *
         * @param nameCode   The name of the attribute, as held in the name pool
         * @param typeCode   The type of the attribute, as held in the name pool
         * @param properties Bit significant value. The following bits are defined:
         *                   
    DISABLE_ESCAPING
    Disable escaping for this attribute
    *
    NO_SPECIAL_CHARACTERS
    Attribute value contains no special characters
    * @throws IllegalStateException: attempt to output an attribute when there is no open element * start tag */ public void attribute(int nameCode, int typeCode, CharSequence value, int locationId, int properties) throws XPathException { if (escapeURIAttributes && isUrlAttribute(currentElement, nameCode) && (properties & ReceiverOptions.DISABLE_ESCAPING) == 0) { nextReceiver.attribute(nameCode, typeCode, escapeURL(value, true), locationId, properties | ReceiverOptions.DISABLE_CHARACTER_MAPS); } else { nextReceiver.attribute(nameCode, typeCode, value, locationId, properties); } } /** * Escape a URI according to the HTML rules: that is, a non-ASCII character (specifically, * a character outside the range 32 - 126) is replaced by the %HH encoding of the octets in * its UTF-8 representation * @param url the URI to be escaped * @param normalize * @return the URI after escaping non-ASCII characters */ public static CharSequence escapeURL(CharSequence url, boolean normalize) { // optimize for the common case where the string is all ASCII characters for (int i=url.length()-1; i>=0; i--) { char ch = url.charAt(i); if (ch<32 || ch>126) { if (normalize) { CharSequence normalized = new Normalizer(Normalizer.C).normalize(url); return reallyEscapeURL(normalized); } else { return reallyEscapeURL(url); } } } return url; } private static CharSequence reallyEscapeURL(CharSequence url) { FastStringBuffer sb = new FastStringBuffer(url.length() + 20); final String hex = "0123456789ABCDEF"; byte[] array = new byte[4]; for (int i=0; i126) { int used = UnicodeCharacterSet.getUTF8Encoding(ch, (i+1 < url.length() ? url.charAt(i+1): ' '), array); for (int b=0; b=0 ? array[b] : 256 + array[b]); int v = ((int)array[b]) & 0xff; sb.append('%'); sb.append(hex.charAt(v/16)); sb.append(hex.charAt(v%16)); } } else { sb.append(ch); } } return sb; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/event/UnicodeNormalizer.java0000644000175000017500000000465411033112257023025 0ustar eugeneeugenepackage net.sf.saxon.event; import net.sf.saxon.codenorm.Normalizer; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.Whitespace; /** * UnicodeNormalizer: This ProxyReceiver performs unicode normalization on the contents * of attribute and text nodes. * * @author Michael Kay */ public class UnicodeNormalizer extends ProxyReceiver { private Normalizer normalizer; public UnicodeNormalizer(String form) throws XPathException { byte fb; if (form.equals("NFC")) { fb = Normalizer.C; } else if (form.equals("NFD")) { fb = Normalizer.D; } else if (form.equals("NFKC")) { fb = Normalizer.KC; } else if (form.equals("NFKD")) { fb = Normalizer.KD; } else { XPathException err = new XPathException("Unknown normalization form " + form); err.setErrorCode("SESU0011"); throw err; } normalizer = new Normalizer(fb); } /** * Output an attribute */ public void attribute(int nameCode, int typeCode, CharSequence value, int locationId, int properties) throws XPathException { nextReceiver.attribute(nameCode, typeCode, normalizer.normalize(value), locationId, properties); } /** * Output character data */ public void characters(CharSequence chars, int locationId, int properties) throws XPathException { if (Whitespace.isWhite(chars)) { nextReceiver.characters(chars, locationId, properties); } else { nextReceiver.characters(normalizer.normalize(chars), locationId, properties); } } }; // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/event/XMLIndenter.java0000644000175000017500000002275411033112257021526 0ustar eugeneeugenepackage net.sf.saxon.event; import net.sf.saxon.om.NamePool; import net.sf.saxon.om.StandardNames; import net.sf.saxon.sort.IntSet; import net.sf.saxon.sort.IntHashSet; import net.sf.saxon.tinytree.CharSlice; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ComplexType; import net.sf.saxon.type.SchemaType; import net.sf.saxon.value.Whitespace; import javax.xml.transform.OutputKeys; import java.util.Arrays; import java.util.Properties; import java.util.StringTokenizer; /** * XMLIndenter: This ProxyReceiver indents elements, by adding character data where appropriate. * The character data is always added as "ignorable white space", that is, it is never added * adjacent to existing character data. * * @author Michael Kay */ public class XMLIndenter extends ProxyReceiver { private int level = 0; private int indentSpaces = 3; //private String indentChars = "\n "; private char[] indentChars = {'\n', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '}; private boolean sameline = false; private boolean afterStartTag = false; private boolean afterEndTag = true; private boolean allWhite = true; private int line = 0; // line and column measure the number of lines and columns private int column = 0; // .. in whitespace text nodes between tags private int suppressedAtLevel = -1; private int xmlspace; private IntSet suppressedElements = null; private IntSet doubleSpacedElements = null; /** * Create an XML Indenter */ public XMLIndenter() { } /** * Set the properties for this indenter * @param props the serialization properties */ public void setOutputProperties(Properties props) { String s = props.getProperty(SaxonOutputKeys.INDENT_SPACES); if (s==null) { indentSpaces = 3; } else { try { indentSpaces = Integer.parseInt(Whitespace.trim(s)); } catch (NumberFormatException err) { indentSpaces = 3; } } String omit = props.getProperty(OutputKeys.OMIT_XML_DECLARATION); afterEndTag = omit==null || !Whitespace.trim(omit).equals("yes") || props.getProperty(OutputKeys.DOCTYPE_SYSTEM)!=null ; s = props.getProperty(SaxonOutputKeys.SUPPRESS_INDENTATION); if (s != null) { suppressedElements = new IntHashSet(8); NamePool pool = getNamePool(); StringTokenizer st = new StringTokenizer(s, " \t\r\n"); while (st.hasMoreTokens()) { String clarkName = st.nextToken(); int fp = pool.allocateClarkName(clarkName); suppressedElements.add(fp); } } s = props.getProperty(SaxonOutputKeys.DOUBLE_SPACE); if (s != null) { doubleSpacedElements = new IntHashSet(8); NamePool pool = getNamePool(); StringTokenizer st = new StringTokenizer(s, " \t\r\n"); while (st.hasMoreTokens()) { String clarkName = st.nextToken(); int fp = pool.allocateClarkName(clarkName); doubleSpacedElements.add(fp); } } } /** * Start of document */ public void open() throws XPathException { nextReceiver.open(); //xmlspace = getNamePool().allocate("xml", NamespaceConstant.XML, "space") & 0xfffff; xmlspace = StandardNames.XML_SPACE; } /** * Output element start tag */ public void startElement(int nameCode, int typeCode, int locationId, int properties) throws XPathException { if (afterStartTag || afterEndTag) { if (doubleSpacedElements != null && doubleSpacedElements.contains(nameCode&NamePool.FP_MASK)) { nextReceiver.characters("\n", 0, 0); line = 0; column = 0; } indent(); } nextReceiver.startElement(nameCode, typeCode, locationId, properties); level++; sameline = true; afterStartTag = true; afterEndTag = false; allWhite = true; line = 0; SchemaType type; if (suppressedElements != null && suppressedElements.contains(nameCode&NamePool.FP_MASK)) { suppressedAtLevel = level; } if (typeCode >= 1024 && suppressedAtLevel < 0 && ((type = getConfiguration().getSchemaType(typeCode)) != null && type.isComplexType() && ((ComplexType)type).isMixedContent())) { // suppress indentation for elements with mixed content. (Note this also suppresses // indentation for all descendants of such elements. We could be smarter than this.) suppressedAtLevel = level; } } /** * Output an attribute */ public void attribute(int nameCode, int typeCode, CharSequence value, int locationId, int properties) throws XPathException { if ((nameCode & NamePool.FP_MASK) == xmlspace && value.equals("preserve") && suppressedAtLevel < 0) { // Note, we are suppressing indentation within an xml:space="preserve" region even if a descendant // specifies xml:space="default suppressedAtLevel = level; } nextReceiver.attribute(nameCode, typeCode, value, locationId, properties); } /** * Output element end tag */ public void endElement() throws XPathException { level--; if (afterEndTag && !sameline) { indent(); } nextReceiver.endElement(); sameline = false; afterEndTag = true; afterStartTag = false; allWhite = true; line = 0; if (level == (suppressedAtLevel - 1)) { suppressedAtLevel = -1; // remove the suppression of indentation } } /** * Output a processing instruction */ public void processingInstruction(String target, CharSequence data, int locationId, int properties) throws XPathException { if (afterEndTag) { indent(); } nextReceiver.processingInstruction(target, data, locationId, properties); afterStartTag = false; afterEndTag = false; } /** * Output character data */ public void characters(CharSequence chars, int locationId, int properties) throws XPathException { for (int i=0; i= 0) { // indentation has been suppressed (e.g. by xmlspace="preserve") return; } int spaces = level * indentSpaces; if (line>0) { spaces -= column; if (spaces <= 0) { return; // there's already enough white space, don't add more } } if (spaces+2 >= indentChars.length) { int increment = 5 * indentSpaces; if (spaces + 2 > indentChars.length + increment) { increment += spaces + 2; } char[] c2 = new char[indentChars.length + increment]; System.arraycopy(indentChars, 0, c2, 0, indentChars.length); Arrays.fill(c2, indentChars.length, c2.length, ' '); indentChars = c2; } // output the initial newline character only if line==0 int start = (line == 0 ? 0 : 1); //super.characters(indentChars.subSequence(start, start+spaces+1), 0, ReceiverOptions.NO_SPECIAL_CHARS); nextReceiver.characters(new CharSlice(indentChars, start, spaces+1), 0, ReceiverOptions.NO_SPECIAL_CHARS); sameline = false; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/event/StartTagBuffer.java0000644000175000017500000004204211033112257022250 0ustar eugeneeugenepackage net.sf.saxon.event; import net.sf.saxon.om.*; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.Type; import net.sf.saxon.tinytree.TinyBuilder; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /** * StartTagBuffer is a ProxyReceiver that buffers attributes and namespace events within a start tag. * It maintains details of the namespace context, and a full set of attribute information, on behalf * of other filters that need access to namespace information or need to process attributes in arbitrary * order. * *

    StartTagBuffer also implements namespace fixup (the process of creating namespace nodes|bindings on behalf * of constructed element and attribute nodes). Although this would be done anyway, further down the pipeline, * it has to be done early in the case of a validating pipeline, because the namespace bindings must be created * before any namespace-sensitive attribute content is validated.

    * *

    The StartTagBuffer also allows error conditions to be buffered. This is because the XSIAttributeHandler * validates attributes such as xsi:type and xsi:nil before attempting to match its parent element against * a particle of its containing type. It is possible that the parent element will match a wildcard particle * with processContents="skip", in which case an invalid xsi:type or xsi:nil attribute is not an error.

    */ public class StartTagBuffer extends ProxyReceiver implements NamespaceResolver { // Details of the pending element event int elementNameCode; int elementTypeCode; int elementLocationId; int elementProperties; // Details of pending attribute events AttributeCollectionImpl bufferedAttributes; private boolean acceptAttributes; private boolean inDocument; // We keep track of namespaces. The namespaces // array holds a list of all namespaces currently declared (organised as pairs of entries, // prefix followed by URI). The stack contains an entry for each element currently open; the // value on the stack is an Integer giving the number of namespaces added to the main // namespace stack by that element. private int[] namespaces = new int[50]; // all namespace codes currently declared private int namespacesSize = 0; // all namespaces currently declared private int[] countStack = new int[50]; private int depth = 0; private int attCount = 0; // We can make an element node representing this start tag for use in evaluation xs:alternative // (conditional type assignment) expressions. Once this is done, we keep it. private NodeInfo elementNode; /** * Set the pipeline configuration * @param pipe the pipeline configuration */ public void setPipelineConfiguration(PipelineConfiguration pipe) { super.setPipelineConfiguration(pipe); bufferedAttributes = new AttributeCollectionImpl(pipe.getConfiguration()); } /** * Start of a document node. */ public void startDocument(int properties) throws XPathException { // a document node in the content sequence of an element is ignored. However, we need // to stop attributes being created within the document node. if (depth == 0) { depth++; super.startDocument(properties); } acceptAttributes = false; inDocument = true; // we ought to clear this on endDocument, but it only affects diagnostics } /** * Notify the end of a document node */ public void endDocument() throws XPathException { if (depth == 1) { depth--; super.endDocument(); } } /** * startElement */ public void startElement(int nameCode, int typeCode, int locationId, int properties) throws XPathException { elementNameCode = nameCode; elementTypeCode = typeCode; elementLocationId = locationId; elementProperties = properties; bufferedAttributes.clear(); // Record the current height of the namespace list so it can be reset at endElement time countStack[depth] = 0; if (++depth >= countStack.length) { int[] newstack = new int[depth*2]; System.arraycopy(countStack, 0, newstack, 0, depth); countStack = newstack; } // Ensure that the element namespace is output, unless this is done // automatically by the caller (which is true, for example, for a literal // result element). acceptAttributes = true; inDocument = false; if ((properties & ReceiverOptions.NAMESPACE_OK) == 0) { namespace(getNamePool().allocateNamespaceCode(nameCode), 0); } attCount = 0; elementNode = null; } public void namespace(int namespaceCode, int properties) throws XPathException { if (!acceptAttributes) { throw NoOpenStartTagException.makeNoOpenStartTagException( Type.NAMESPACE, getNamePool().getPrefixFromNamespaceCode(namespaceCode), getPipelineConfiguration().getHostLanguage(), inDocument, false); } // avoid duplicates for (int n=0; nDISABLE_ESCAPING
    Disable escaping for this attribute
    *
    NO_SPECIAL_CHARACTERS
    Attribute value contains no special characters
    * @throws IllegalStateException: attempt to output an attribute when there is no open element * start tag */ public void attribute(int nameCode, int typeCode, CharSequence value, int locationId, int properties) throws XPathException { if (!acceptAttributes) { throw NoOpenStartTagException.makeNoOpenStartTagException( Type.ATTRIBUTE, getNamePool().getDisplayName(nameCode), getPipelineConfiguration().getHostLanguage(), inDocument, false); } // Perform namespace fixup for the attribute if (((properties & ReceiverOptions.NAMESPACE_OK) == 0) && NamePool.getPrefixIndex(nameCode) != 0) { // non-null prefix nameCode = checkProposedPrefix(nameCode, attCount++); } bufferedAttributes.addAttribute(nameCode, typeCode, value.toString(), locationId, properties); // Note: we're relying on the fact that AttributeCollection can hold two attributes of the same name // and maintain their order, because the check for duplicate attributes is not done until later in the // pipeline. We validate both the attributes (see Bugzilla #4600 which legitimizes this.) } /** * Add a namespace declaration (or undeclaration) to the stack * @param nscode the namepool namespace code for the declaration */ private void addToStack(int nscode) { // expand the stack if necessary if (namespacesSize+1 >= namespaces.length) { int[] newlist = new int[namespacesSize*2]; System.arraycopy(namespaces, 0, newlist, 0, namespacesSize); namespaces = newlist; } namespaces[namespacesSize++] = nscode; } /** * startContent: Add any namespace undeclarations needed to stop * namespaces being inherited from parent elements */ public void startContent() throws XPathException { nextReceiver.startElement(elementNameCode, elementTypeCode, elementLocationId, elementProperties | ReceiverOptions.NAMESPACE_OK); declareNamespacesForStartElement(); final int length = bufferedAttributes.getLength(); for (int i=0; i 0; } /** * Get the value of the current attribute with a given nameCode * @param nameCode the name of the required attribute * @return the attribute value, or null if the attribute is not present */ public String getAttribute(int nameCode) { return bufferedAttributes.getValueByFingerprint(nameCode & 0xfffff); } /** * Get the URI code corresponding to a given prefix code, by searching the * in-scope namespaces. This is a service provided to subclasses. * @param prefixCode the 16-bit prefix code required * @return the 16-bit URI code, or -1 if the prefix is not bound to any namespace */ protected short getURICode(short prefixCode) { for (int i=namespacesSize-1; i>=0; i--) { if ((namespaces[i]>>16) == (prefixCode)) { final short uriCode = (short)(namespaces[i]&0xffff); if (uriCode == 0) { // we've found a namespace undeclaration, so it's as if the prefix weren't there at all break; } return uriCode; } } if (prefixCode == 0) { return 0; // by default, no prefix means no namespace URI } else { return -1; } } /** * Get the namespace URI corresponding to a given prefix. Return null * if the prefix is not in scope. * * @param prefix the namespace prefix * @param useDefault true if the default namespace is to be used when the * prefix is "" * @return the uri for the namespace, or null if the prefix is not in scope */ public String getURIForPrefix(String prefix, boolean useDefault) { NamePool pool = getNamePool(); if ((prefix==null || prefix.length()==0) && !useDefault) { return ""; } else if ("xml".equals(prefix)) { return NamespaceConstant.XML; } else { short prefixCode = pool.getCodeForPrefix(prefix); short uriCode = getURICode(prefixCode); if (uriCode == -1) { return null; } return pool.getURIFromURICode(uriCode); } } /** * Get an iterator over all the prefixes declared in this namespace context. This will include * the default namespace (prefix="") and the XML namespace where appropriate */ public Iterator iteratePrefixes() { NamePool pool = getNamePool(); List prefixes = new ArrayList(namespacesSize); for (int i=namespacesSize-1; i>=0; i--) { String prefix = pool.getPrefixFromNamespaceCode(namespaces[i]); if (!prefixes.contains(prefix)) { prefixes.add(prefix); } } prefixes.add("xml"); return prefixes.iterator(); } /** * Check that the prefix for an element or attribute is acceptable, allocating a substitute * prefix if not. The prefix is acceptable unless a namespace declaration has been * written that assignes this prefix to a different namespace URI. This method * also checks that the element or attribute namespace has been declared, and declares it * if not. * @param nameCode the proposed element or attribute name * @param seq sequence number of attribute, used for generating distinctive prefixes * @return the actual allocated name, which may be different. */ private int checkProposedPrefix(int nameCode, int seq) throws XPathException { NamePool namePool = getNamePool(); int nscode = namePool.getNamespaceCode(nameCode); if (nscode == -1) { // avoid calling allocate where possible, because it's synchronized nscode = namePool.allocateNamespaceCode(nameCode); } int nsprefix = nscode>>16; short existingURICode = getURICode((short)nsprefix); if (existingURICode == -1) { // prefix has not been declared: declare it now (namespace fixup) namespace(nscode, 0); return nameCode; } else { if ((nscode & 0xffff) == existingURICode) { // prefix is already bound to this URI return nameCode; // all is well } else { // conflict: prefix is currently bound to a different URI String prefix = getSubstitutePrefix(nscode, seq); int newCode = namePool.allocate( prefix, namePool.getURI(nameCode), namePool.getLocalName(nameCode)); namespace(namePool.allocateNamespaceCode(newCode), 0); return newCode; } } } /** * It is possible for a single output element to use the same prefix to refer to different * namespaces. In this case we have to generate an alternative prefix for uniqueness. The * one we generate is based on the sequential position of the element/attribute: this is * designed to ensure both uniqueness (with a high probability) and repeatability * @param nscode the namespace code of the proposed element or attribute name * @param seq sequence number of attribute, used for generating distinctive prefixes * @return the actual allocated name, which may be different. */ private String getSubstitutePrefix(int nscode, int seq) { String prefix = getNamePool().getPrefixFromNamespaceCode(nscode); return prefix + '_' + seq; } /** * Get an element node representing the element whose start tag this is, as required * for implementing conditional type assignment * @return an element node. This contains all the required namespaces and attributes, and has no children; * it is untyped, as are the attributes. */ public NodeInfo getElementNode() throws XPathException { if (elementNode == null) { int len = bufferedAttributes.getLength(); TinyBuilder builder = new TinyBuilder(); builder.setSizeParameters(new int[]{2, len+2, namespacesSize+2, 16}); builder.setPipelineConfiguration(getPipelineConfiguration()); builder.open(); builder.startElement(elementNameCode, StandardNames.XS_UNTYPED_ATOMIC, 0, 0); for (int i=0; iWhen the ContentHandler is used to receive the results of a query or stylesheet, * the information supplied by the standard methods such as {@link #getSystemId} and * {@link #getLineNumber} relates to the position of the expression/instruction in the stylesheet * or query that caused the relevant nodes to be output.

    * *

    If the ContentHandler is used in other contexts, for example as the destination of an * IdentityTransformer, the information reflects the position in the source document.

    * *

    If the output property saxon:supply-source-locator was set to the * value "yes" (which in turn requires that tracing was enabled at compile time), the Locator will * also contain information about the current location in the source document (specifically, the position * of the context node). This will not always be 100% accurate, since there is some buffering of events * in the output pipeline: it reflects the context node at the time the event reaches the ContentHandler, * which may not be the same as the context node at the time the relevant instruction was executed; * however, it still provides some information that may be useful for diagnostics.

    */ public class ContentHandlerProxyLocator implements Locator { private ContentHandlerProxy parent = null; /** * Create the Locator for a ContentHandlerProxy * @param parent the ContentHandlerProxy */ public ContentHandlerProxyLocator(ContentHandlerProxy parent) { this.parent = parent; } // previously ContentHandlerProxy implemented Locator directly. However, this caused a clash // over the semantics of getSystemId(), which is inherited from both Receiver and Locator. // The getSystemId() method in the Receiver interface identifies the URI of the document represented // by the event stream. The getSystemId() method in this class typically returns the URI of the stylesheet // or query module that generated the event. /** * Get the Public ID * @return null (always) */ public String getPublicId() { return null; } /** * Get the System ID * @return the system ID giving the location in the query or stylesheet of the most recent event notified */ public String getSystemId() { final LocationProvider locationProvider = parent.getLocationProvider(); if (locationProvider == null) { return null; } else { return locationProvider.getSystemId(parent.getCurrentLocationId()); } } /** * Get the line number * @return the line number giving the location of the most recent event notified */ public int getLineNumber() { final LocationProvider locationProvider = parent.getLocationProvider(); if (locationProvider == null) { return -1; } else { return locationProvider.getLineNumber(parent.getCurrentLocationId()); } } /** * Get the column number * @return -1 (always) */ public int getColumnNumber() { return -1; } /** * Get the current item stack. This is a Stack, whose members are objects of class * {@link net.sf.saxon.om.Item}. The top item in the stack is the context node or atomic value; items * further down the stack represent previous context node or atomic value * @return the stack of context items */ public Stack getContextItemStack() { final ContentHandlerProxy.ContentHandlerProxyTraceListener traceListener = parent.getTraceListener(); if (traceListener == null) { return null; } else { return traceListener.getContextItemStack(); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/event/Receiver.java0000644000175000017500000002442611033112257021137 0ustar eugeneeugenepackage net.sf.saxon.event; import net.sf.saxon.trans.XPathException; import javax.xml.transform.Result; /** * Receiver: This interface represents a recipient of XML tree-walking (push) events. It is * based on SAX2's ContentHandler, but adapted to handle additional events, and * to use Saxon's name pool. Namespaces and Attributes are handled by separate events * following the startElement event. Schema types can be defined for elements and attributes. *

    * The Receiver interface is an important internal interface within Saxon, and provides a powerful * mechanism for integrating Saxon with other applications. It has been designed with extensibility * and stability in mind. However, it should be considered as an interface designed primarily for * internal use, and not as a completely stable part of the public Saxon API. *

    * @author Michael H. Kay */ public interface Receiver extends Result { /** * Set the pipeline configuration * @param config the pipeline configuration */ public void setPipelineConfiguration(PipelineConfiguration config); /** * Get the pipeline configuration * @return the pipeline configuration */ public PipelineConfiguration getPipelineConfiguration(); /** * Set the System ID of the tree represented by this event stream * @param systemId the system ID (which is used as the base URI of the nodes * if there is no xml:base attribute) */ public void setSystemId(String systemId); /** * Notify the start of the event stream */ public void open() throws XPathException; /** * Notify the start of a document node * @param properties bit-significant integer indicating properties of the document node. * The definitions of the bits are in class {@link ReceiverOptions} */ public void startDocument(int properties) throws XPathException; /** * Notify the end of a document node */ public void endDocument() throws XPathException; /** * Notify an unparsed entity URI. * @param name The name of the unparsed entity * @param systemID The system identifier of the unparsed entity * @param publicID The public identifier of the unparsed entity */ public void setUnparsedEntity(String name, String systemID, String publicID) throws XPathException; /** * Notify the start of an element * @param nameCode integer code identifying the name of the element within the name pool. * @param typeCode integer code identifying the element's type within the name pool. The value -1 * indicates the default type, xs:untyped. * @param locationId an integer which can be interpreted using a {@link net.sf.saxon.event.LocationProvider} to return * information such as line number and system ID. If no location information is available, * the value zero is supplied. * @param properties bit-significant properties of the element node. If there are no revelant * properties, zero is supplied. The definitions of the bits are in class {@link net.sf.saxon.event.ReceiverOptions} */ public void startElement(int nameCode, int typeCode, int locationId, int properties) throws XPathException; /** * Notify a namespace. Namespaces are notified after the startElement event, and before * any children for the element. The namespaces that are reported are only required * to include those that are different from the parent element. The events represent namespace * declarations and undeclarations rather than in-scope namespace nodes: an undeclaration is represented * by a namespace code of zero. If the sequence of namespace events contains two * A namespace must not conflict with any namespaces already used for element or attribute names. * @param namespaceCode an integer: the top half is a prefix code, the bottom half a URI code. * These may be translated into an actual prefix and URI using the name pool. A prefix code of * zero represents the empty prefix (that is, the default namespace). A URI code of zero represents * a URI of "", that is, a namespace undeclaration. * @param properties The most important property is REJECT_DUPLICATES. If this property is set, the * namespace declaration will be rejected if it conflicts with a previous declaration of the same * prefix. If the property is not set, the namespace declaration will be ignored if it conflicts * with a previous declaration. This reflects the fact that when copying a tree, namespaces for child * elements are emitted before the namespaces of their parent element. Unfortunately this conflicts * with the XSLT rule for complex content construction, where the recovery action in the event of * conflicts is to take the namespace that comes last. XSLT therefore doesn't recover from this error: * it sets the REJECT_DUPLICATES flag, and this is treated as a hard error. */ public void namespace(int namespaceCode, int properties) throws XPathException; /** * Notify an attribute. Attributes are notified after the startElement event, and before any * children. Namespaces and attributes may be intermingled. * @param nameCode The name of the attribute, as held in the name pool * @param typeCode The type of the attribute, as held in the name pool. The additional bit * NodeInfo.IS_DTD_TYPE may be set to indicate a DTD-derived type. * @param value the string value of the attribute * @param locationId an integer which can be interpreted using a {@link net.sf.saxon.event.LocationProvider} to return * information such as line number and system ID. If no location information is available, * the value zero is supplied. * @param properties Bit significant value. The following bits are defined: *

    DISABLE_ESCAPING
    Disable escaping for this attribute
    *
    NO_SPECIAL_CHARACTERS
    Attribute value contains no special characters
    * @throws IllegalStateException: attempt to output an attribute when there is no open element * start tag */ public void attribute(int nameCode, int typeCode, CharSequence value, int locationId, int properties) throws XPathException; /** * Notify the start of the content, that is, the completion of all attributes and namespaces. * Note that the initial receiver of output from XSLT instructions will not receive this event, * it has to detect it itself. Note that this event is reported for every element even if it has * no attributes, no namespaces, and no content. */ public void startContent() throws XPathException; /** * Notify the end of an element. The receiver must maintain a stack if it needs to know which * element is ending. */ public void endElement() throws XPathException; /** * Notify character data. Note that some receivers may require the character data to be * sent in a single event, but in general this is not a requirement. * @param chars The characters * @param locationId an integer which can be interpreted using a {@link net.sf.saxon.event.LocationProvider} * to return information such as line number and system ID. If no location information is available, * the value zero is supplied. * @param properties Bit significant value. The following bits are defined: *
    DISABLE_ESCAPING
    Disable escaping for this text node
    *
    USE_CDATA
    Output as a CDATA section
    */ public void characters(CharSequence chars, int locationId, int properties) throws XPathException; /** * Output a processing instruction * @param name The PI name. This must be a legal name (it will not be checked). * @param data The data portion of the processing instruction * @param locationId an integer which can be interpreted using a {@link LocationProvider} to return * information such as line number and system ID. If no location information is available, * the value zero is supplied. * @param properties Additional information about the PI. The following bits are * defined: *
    CHECKED
    Data is known to be legal (e.g. doesn't contain "?>")
    * @throws IllegalArgumentException: the content is invalid for an XML processing instruction */ public void processingInstruction(String name, CharSequence data, int locationId, int properties) throws XPathException; /** * Notify a comment. Comments are only notified if they are outside the DTD. * @param content The content of the comment * @param locationId an integer which can be interpreted using a {@link LocationProvider} to return * information such as line number and system ID. If no location information is available, * the value zero is supplied. * @param properties Additional information about the comment. The following bits are * defined: *
    CHECKED
    Comment is known to be legal (e.g. doesn't contain "--")
    * @throws IllegalArgumentException: the content is invalid for an XML comment */ public void comment(CharSequence content, int locationId, int properties) throws XPathException; /** * Notify the end of the event stream */ public void close() throws XPathException; } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/event/NamePoolConverter.java0000644000175000017500000000573611033112257023000 0ustar eugeneeugenepackage net.sf.saxon.event; import net.sf.saxon.om.NamePool; import net.sf.saxon.trans.XPathException; /** * This class is a filter that passes all Receiver events through unchanged, * except that it changes namecodes to allow for the source and the destination * using different NamePools. This is necessary when a stylesheet has been constructed * as a general document (e.g. as the result of a transformation) and is passed to * newTemplates() to be compiled as a stylesheet. * * @author Michael Kay */ public class NamePoolConverter extends ProxyReceiver { NamePool oldPool; NamePool newPool; /** * Constructor */ public NamePoolConverter(NamePool oldPool, NamePool newPool) { this.oldPool = oldPool; this.newPool = newPool; } /** * Set the underlying emitter. This call is mandatory before using the Emitter. * This version is modified from that of the parent class to avoid setting the namePool * of the destination Receiver. */ public void setUnderlyingReceiver(Receiver receiver) { nextReceiver = receiver; } /** * Output element start tag */ public void startElement(int nameCode, int typeCode, int locationId, int properties) throws XPathException { int nc = newPool.allocate(oldPool.getPrefix(nameCode), oldPool.getURI(nameCode), oldPool.getLocalName(nameCode)); nextReceiver.startElement(nc, typeCode, locationId, properties); } /** * Handle a namespace */ public void namespace(int namespaceCode, int properties) throws XPathException { int nc = newPool.allocateNamespaceCode(oldPool.getPrefixFromNamespaceCode(namespaceCode), oldPool.getURIFromNamespaceCode(namespaceCode)); nextReceiver.namespace(nc, properties); } /** * Handle an attribute */ public void attribute(int nameCode, int typeCode, CharSequence value, int locationId, int properties) throws XPathException { int nc = newPool.allocate(oldPool.getPrefix(nameCode), oldPool.getURI(nameCode), oldPool.getLocalName(nameCode)); nextReceiver.attribute(nc, typeCode, value, locationId, properties); } }; // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/event/ContentHandlerProxy.java0000644000175000017500000005462511033112257023351 0ustar eugeneeugenepackage net.sf.saxon.event; import net.sf.saxon.Configuration; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.AttributeCollectionImpl; import net.sf.saxon.om.Item; import net.sf.saxon.om.NamePool; import net.sf.saxon.om.NamespaceConstant; import net.sf.saxon.trace.InstructionInfo; import net.sf.saxon.trace.TraceListener; import net.sf.saxon.trans.SaxonErrorCode; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.SchemaException; import net.sf.saxon.value.Whitespace; import org.xml.sax.ContentHandler; import org.xml.sax.Locator; import org.xml.sax.SAXException; import org.xml.sax.ext.LexicalHandler; import javax.xml.transform.Result; import java.util.Properties; import java.util.Stack; /** * A ContentHandlerProxy is a Receiver that converts events into the form expected by an * underlying SAX2 ContentHandler. Relevant events (notably comments) can also be * fed to a LexicalHandler. *

    * Note that in general the output passed to a Receiver * corresponds to an External General Parsed Entity. A SAX2 ContentHandler only expects * to deal with well-formed XML documents, so we only pass it the contents of the first * element encountered, unless the saxon:require-well-formed output property is set to "no". *

    * This ContentHandlerProxy provides no access to type information. For a ContentHandler that * makes type information available, see {@link com.saxonica.jaxp.TypedContentHandler} *

    * The ContentHandlerProxy can also be nominated as a TraceListener, to receive notification * of trace events. This will be done automatically if the option setTraceListener( */ public class ContentHandlerProxy implements Receiver { private PipelineConfiguration pipe; private String systemId; protected ContentHandler handler; protected LexicalHandler lexicalHandler; private LocationProvider locationProvider; private int depth = 0; private boolean requireWellFormed = false; private boolean undeclareNamespaces = false; private Stack elementStack = new Stack(); private Stack namespaceStack = new Stack(); private ContentHandlerProxyTraceListener traceListener; protected AttributeCollectionImpl pendingAttributes; private int pendingElement = -1; private long currentLocationId; // MARKER is a value added to the namespace stack at the start of an element, so that we know how // far to unwind the stack on an end-element event. private static final String MARKER = "##"; /** * Set the underlying content handler. This call is mandatory before using this Receiver. * If the content handler is an instance of {@link LexicalHandler}, then it will also receive * notification of lexical events such as comments. * @param handler the SAX content handler to which all events will be directed */ public void setUnderlyingContentHandler(ContentHandler handler) { this.handler = handler; if (handler instanceof LexicalHandler) { lexicalHandler = (LexicalHandler)handler; } } /** * Get the underlying content handler * @return the SAX content handler to which all events are being directed */ public ContentHandler getUnderlyingContentHandler() { return handler; } /** * Set the Lexical Handler to be used. If called, this must be called AFTER * setUnderlyingContentHandler() * @param handler the SAX lexical handler to which lexical events (such as comments) will * be notified. */ public void setLexicalHandler(LexicalHandler handler) { lexicalHandler = handler; } /** * Set the pipeline configuration * @param pipe the pipeline configuration */ public void setPipelineConfiguration(PipelineConfiguration pipe) { this.pipe = pipe; locationProvider = pipe.getLocationProvider(); } /** * Get the pipeline configuration */ public PipelineConfiguration getPipelineConfiguration() { return pipe; } /** * Get the Saxon configuration * @return the Saxon configuration */ public Configuration getConfiguration() { return pipe.getConfiguration(); } /** * Set the System ID of the destination tree * @param systemId the system ID (effectively the base URI) */ public void setSystemId(String systemId) { this.systemId = systemId; } /** * Get the System ID of the destination tree * @return the system ID (effectively the base URI) */ public String getSystemId() { return systemId; } /** * Get the associated TraceListener that receives notification of trace events * @return the trace listener. If there is no existing trace listener, then a new one * will be created. */ public ContentHandlerProxyTraceListener getTraceListener() { if (traceListener == null) { traceListener = new ContentHandlerProxyTraceListener(); } return traceListener; } /** * Get the location provider * @return the location provider, used to map location ids to actual URIs and line numbers */ public LocationProvider getLocationProvider() { return locationProvider; } /** * Get the current location identifier * @return the location identifier of the most recent event. This can be translated to real * location information by passing it to the location provider. */ public long getCurrentLocationId() { return currentLocationId; } /** * Notify an unparsed entity URI. This implementation does nothing: the event is ignored. * * @param name The name of the unparsed entity * @param systemID The system identifier of the unparsed entity * @param publicID The public identifier of the unparsed entity */ public void setUnparsedEntity(String name, String systemID, String publicID) throws XPathException { // no-op } /** * Set the output details. * @param details the serialization properties. The only values used by this implementation are * {@link SaxonOutputKeys#REQUIRE_WELL_FORMED} and {@link SaxonOutputKeys#UNDECLARE_PREFIXES}. */ public void setOutputProperties(Properties details) throws XPathException { String prop = details.getProperty(SaxonOutputKeys.REQUIRE_WELL_FORMED); if (prop != null) { requireWellFormed = prop.equals("yes"); } prop = details.getProperty(SaxonOutputKeys.UNDECLARE_PREFIXES); if (prop != null) { undeclareNamespaces = prop.equals("yes"); } } /** * Ask whether the content handler can handle a stream of events that is merely * well-balanced, or whether it can only handle a well-formed sequence. * @return true if the content handler requires the event stream to represent a well-formed * XML document (containing exactly one top-level element node and no top-level text nodes) */ public boolean isRequireWellFormed() { return requireWellFormed; } /** * Set whether the content handler can handle a stream of events that is merely * well-balanced, or whether it can only handle a well-formed sequence. The default is false. * @param wellFormed set to true if the content handler requires the event stream to represent a well-formed * XML document (containing exactly one top-level element node and no top-level text nodes). Otherwise, * multiple top-level elements and text nodes are allowed, as in the XDM model. */ public void setRequireWellFormed(boolean wellFormed) { requireWellFormed = wellFormed; } /** * Ask whether namespace undeclaration events (for a non-null prefix) should be notified. * The default is no, because some ContentHandlers (e.g. JDOM) can't cope with them. * * @return true if namespace undeclarations (xmlns:p="") are to be output */ public boolean isUndeclareNamespaces() { return undeclareNamespaces; } /** * Set whether namespace undeclaration events (for a non-null prefix) should be notified. * The default is no, because some ContentHandlers (e.g. JDOM) can't cope with them. * * @param undeclareNamespaces true if namespace undeclarations (xmlns:p="") are to be output */ public void setUndeclareNamespaces(boolean undeclareNamespaces) { this.undeclareNamespaces = undeclareNamespaces; } /** * Notify the start of the event stream */ public void open() throws XPathException { pendingAttributes = new AttributeCollectionImpl(getPipelineConfiguration().getConfiguration()); if (handler == null) { throw new IllegalStateException("ContentHandlerProxy.open(): no underlying handler provided"); } try { locationProvider = getPipelineConfiguration().getLocationProvider(); pendingAttributes.setLocationProvider(locationProvider); Locator locator = new ContentHandlerProxyLocator(this); handler.setDocumentLocator(locator); handler.startDocument(); } catch (SAXException err) { handleSAXException(err); } depth = 0; } /** * Notify the end of the event stream */ public void close() throws XPathException { try { handler.endDocument(); } catch (SAXException err) { handleSAXException(err); } } /** * Notify the start of the document. */ public void startDocument(int properties) throws XPathException { } /** * Notify the end of the document */ public void endDocument() throws XPathException { } /** * Notify the start of an element */ public void startElement(int nameCode, int typeCode, int locationId, int properties) throws XPathException { depth++; if (depth <= 0 && requireWellFormed) { notifyNotWellFormed(); } pendingElement = nameCode; currentLocationId = locationId; namespaceStack.push(MARKER); } /** * Notify a namespace. Namespaces are notified after the startElement event, and before * any children for the element. */ public void namespace(int namespaceCode, int properties) throws XPathException { if (namespaceCode == NamespaceConstant.XML_NAMESPACE_CODE) { return; } NamePool pool = pipe.getConfiguration().getNamePool(); String prefix = pool.getPrefixFromNamespaceCode(namespaceCode); String uri = pool.getURIFromNamespaceCode(namespaceCode); if ((!undeclareNamespaces) && uri.length()==0 && !(prefix.length()==0)) { // This is a namespace undeclaration, but the ContentHandler doesn't want to know about undeclarations return; } try { handler.startPrefixMapping(prefix, uri); namespaceStack.push(prefix); } catch (SAXException err) { handleSAXException(err); } } /** * Notify an attribute. Attributes are notified after the startElement event, and before any * children. */ public void attribute(int nameCode, int typeCode, CharSequence value, int locationId, int properties) throws XPathException { int index = pendingAttributes.getIndexByFingerprint(nameCode & 0xfffff); if (index < 0) { pendingAttributes.addAttribute(nameCode, typeCode, value.toString(), locationId, properties); } else { pendingAttributes.setAttribute(index, nameCode, typeCode, value.toString(), locationId, properties); } } /** * Notify the start of the content, that is, the completion of all attributes and namespaces. * Note that the initial receiver of output from XSLT instructions will not receive this event, * it has to detect it itself. Note that this event is reported for every element even if it has * no attributes, no namespaces, and no content. */ public void startContent() throws XPathException { try { NamePool namePool = pipe.getConfiguration().getNamePool(); if (depth > 0 || !requireWellFormed) { String uri = namePool.getURI(pendingElement); String localName = namePool.getLocalName(pendingElement); String qname = namePool.getDisplayName(pendingElement); handler.startElement(uri, localName, qname, pendingAttributes); elementStack.push(uri); elementStack.push(localName); elementStack.push(qname); pendingAttributes.clear(); pendingElement = -1; } } catch (SAXException err) { handleSAXException(err); } } /** * End of element */ public void endElement() throws XPathException { if (depth > 0) { try { String qname = (String)elementStack.pop(); String localName = (String)elementStack.pop(); String uri = (String)elementStack.pop(); handler.endElement(uri, localName, qname); } catch (SAXException err) { handleSAXException(err); } } while (true) { String prefix = (String)namespaceStack.pop(); if (prefix.equals(MARKER)) { break; } try { handler.endPrefixMapping(prefix); } catch (SAXException err) { handleSAXException(err); } } depth--; // if this was the outermost element, and well formed output is required // then no further elements will be processed if (requireWellFormed && depth <= 0) { depth = Integer.MIN_VALUE; // crude but effective } } /** * Character data */ public void characters(CharSequence chars, int locationId, int properties) throws XPathException { currentLocationId = locationId; boolean disable = ((properties & ReceiverOptions.DISABLE_ESCAPING) != 0); if (disable) { setEscaping(false); } try { if (depth <= 0 && requireWellFormed) { if (Whitespace.isWhite(chars)) { // ignore top-level white space } else { notifyNotWellFormed(); } } else { handler.characters(chars.toString().toCharArray(), 0, chars.length()); } } catch (SAXException err) { handleSAXException(err); } if (disable) { setEscaping(true); } } /** * The following function is called when it is found that the output is not a well-formed document. * Unless the ContentHandler accepts "balanced content", this is a fatal error. */ protected void notifyNotWellFormed() throws XPathException { XPathException err = new XPathException("The result tree cannot be supplied to the ContentHandler because it is not well-formed XML"); err.setErrorCode(SaxonErrorCode.SXCH0002); throw err; } /** * Processing Instruction */ public void processingInstruction(String target, CharSequence data, int locationId, int properties) throws XPathException { currentLocationId = locationId; try { handler.processingInstruction(target, data.toString()); } catch (SAXException err) { handleSAXException(err); } } /** * Output a comment. Passes it on to the ContentHandler provided that the ContentHandler * is also a SAX2 LexicalHandler. */ public void comment(CharSequence chars, int locationId, int properties) throws XPathException { currentLocationId = locationId; try { if (lexicalHandler != null) { lexicalHandler.comment(chars.toString().toCharArray(), 0, chars.length()); } } catch (SAXException err) { handleSAXException(err); } } /** * Switch escaping on or off. This is called when the XSLT disable-output-escaping attribute * is used to switch escaping on or off. It is not called for other sections of output (e.g. * element names) where escaping is inappropriate. The action, as defined in JAXP 1.1, is * to notify the request to the Content Handler using a processing instruction. * @param escaping true if escaping is to be switched on, false to switch it off */ private void setEscaping(boolean escaping) { try { handler.processingInstruction( (escaping ? Result.PI_ENABLE_OUTPUT_ESCAPING : PI_DISABLE_OUTPUT_ESCAPING), ""); } catch (SAXException err) { throw new AssertionError(err); } } /** * Handle a SAXException thrown by the ContentHandler * @param err the exception to be handler * @throws XPathException always */ private void handleSAXException(SAXException err) throws XPathException { Exception nested = err.getException(); if (nested instanceof XPathException) { throw (XPathException)nested; } else if (nested instanceof SchemaException) { throw new XPathException(nested); } else { XPathException de = new XPathException(err); de.setErrorCode(SaxonErrorCode.SXCH0003); throw de; } } /** * Create a TraceListener that will collect information about the current * location in the source document. This is used to provide information * to the receiving application for diagnostic purposes. */ public class ContentHandlerProxyTraceListener implements TraceListener { private Stack contextItemStack; /** * Get the context item stack * @return the context item stack */ public Stack getContextItemStack() { return contextItemStack; } /** * Method called at the start of execution, that is, when the run-time transformation starts */ public void open() { contextItemStack = new Stack(); } /** * Method called at the end of execution, that is, when the run-time execution ends */ public void close() { contextItemStack = null; } /** * Method that is called when an instruction in the stylesheet gets processed. * * @param instruction gives information about the instruction being * executed, and about the context in which it is executed. This object is mutable, * so if information from the InstructionInfo is to be retained, it must be copied. */ public void enter(InstructionInfo instruction, XPathContext context) { // do nothing } /** * Method that is called after processing an instruction of the stylesheet, * that is, after any child instructions have been processed. * * @param instruction gives the same information that was supplied to the * enter method, though it is not necessarily the same object. Note that the * line number of the instruction is that of the start tag in the source stylesheet, * not the line number of the end tag. */ public void leave(InstructionInfo instruction) { // do nothing } /** * Method that is called by an instruction that changes the current item * in the source document: that is, xsl:for-each, xsl:apply-templates, xsl:for-each-group. * The method is called after the enter method for the relevant instruction, and is called * once for each item processed. * * @param currentItem the new current item. Item objects are not mutable; it is safe to retain * a reference to the Item for later use. */ public void startCurrentItem(Item currentItem) { if (contextItemStack == null) { open(); } contextItemStack.push(currentItem); } /** * Method that is called when an instruction has finished processing a new current item * and is ready to select a new current item or revert to the previous current item. * The method will be called before the leave() method for the instruction that made this * item current. * * @param currentItem the item that was current, whose processing is now complete. This will represent * the same underlying item as the corresponding startCurrentItem() call, though it will * not necessarily be the same actual object. */ public void endCurrentItem(Item currentItem) { contextItemStack.pop(); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/event/MessageWarner.java0000644000175000017500000000442711033112257022135 0ustar eugeneeugenepackage net.sf.saxon.event; import net.sf.saxon.trans.XPathException; import javax.xml.transform.ErrorListener; import javax.xml.transform.TransformerException; import java.io.StringWriter; /** * MessageWarner is a user-selectable receiver for XSLT xsl:message output. It causes xsl:message output * to be notified to the warning() method of the JAXP ErrorListener, or to the error() method if * terminate="yes" is specified. This behaviour is specified in recent versions of the JAXP interface * specifications, but it is not the default behaviour, for backwards compatibility reasons. * *

    The text of the message that is sent to the ErrorListener is an XML serialization of the actual * message content.

    */ public class MessageWarner extends XMLEmitter { boolean abort = false; public void startDocument(int properties) throws XPathException { setWriter(new StringWriter()); abort = (properties & ReceiverOptions.TERMINATE) != 0; super.startDocument(properties); } public void endDocument() throws XPathException { ErrorListener listener = getPipelineConfiguration().getErrorListener(); XPathException de = new XPathException(getWriter().toString()); de.setErrorCode("XTMM9000"); try { if (abort) { listener.error(de); } else { listener.warning(de); } } catch (TransformerException te) { throw XPathException.makeXPathException(te); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/event/XHTMLIndenter.java0000644000175000017500000000523011033112257021750 0ustar eugeneeugenepackage net.sf.saxon.event; import net.sf.saxon.om.NamePool; import net.sf.saxon.om.NamespaceConstant; import net.sf.saxon.sort.IntHashSet; /** * XHTMLIndenter: This class indents XHTML elements, by adding whitespace * character data where appropriate. This class differs from its superclass, * HTMLIndenter, only in the way it classifies elements as being inline or * formatted elements: unlike the HTML indenter, it requires the element names * to be in lower case and to be in the XHTML namespace. * * @author Michael Kay */ public class XHTMLIndenter extends HTMLIndenter { private IntHashSet inlineTagSet; private IntHashSet formattedTagSet; /** * Create an XHTML indenter */ public XHTMLIndenter() { } /** * Classify an element name as inline, formatted, or both or neither. * This method is overridden in the XHTML indenter * @param nameCode the element name * @return a bit-significant integer containing flags IS_INLINE and/or IS_FORMATTED */ protected int classifyTag(int nameCode) { if (inlineTagSet == null) { NamePool pool = getNamePool(); inlineTagSet = new IntHashSet(50); formattedTagSet = new IntHashSet(10); for (int i=0; i * * The interface is deliberately designed to be as close as possible to the * standard SAX2 ContentHandler interface, however, it allows additional * information to be made available. * * An Emitter is a Receiver, specifically it is a Receiver that can direct output * to a Writer or OutputStream, using serialization properties defined in a Properties * object. */ public abstract class Emitter implements Result, Receiver { protected PipelineConfiguration pipelineConfig; protected NamePool namePool; protected String systemId; protected StreamResult streamResult; protected Writer writer; protected OutputStream outputStream; protected Properties outputProperties; protected CharacterSet characterSet = null; protected boolean allCharactersEncodable = false; /** * Set the pipelineConfiguration */ public void setPipelineConfiguration(PipelineConfiguration pipe) { pipelineConfig = pipe; namePool = pipe.getConfiguration().getNamePool(); } /** * Get the pipeline configuration used for this document */ public PipelineConfiguration getPipelineConfiguration() { return pipelineConfig; } /** * Get the configuration used for this document * @return the configuration */ public Configuration getConfiguration() { return pipelineConfig.getConfiguration(); } /** * Set the System ID * @param systemId the system identifier (=base URI) */ public void setSystemId(String systemId) { this.systemId = systemId; } /** * Get the System ID */ public String getSystemId() { return systemId; } /** * Set output properties * @param details the output serialization properties */ public void setOutputProperties(Properties details) throws XPathException { if (characterSet==null) { characterSet = CharacterSetFactory.getCharacterSet(details, getPipelineConfiguration()); allCharactersEncodable = (characterSet instanceof UnicodeCharacterSet); } outputProperties = details; } /** * Get the output properties * @return the output serialization properties */ public Properties getOutputProperties() { return outputProperties; } /** * Set the StreamResult acting as the output destination of the Emitter * @param result the output destination */ public void setStreamResult(StreamResult result) throws XPathException { streamResult = result; if (systemId == null) { systemId = result.getSystemId(); } } /** * Make a Writer for this Emitter to use, given a StreamResult. */ protected void makeWriter() throws XPathException { if (writer != null) { return; } if (streamResult == null) { throw new IllegalStateException("Emitter must have either a Writer or a StreamResult to write to"); } writer = streamResult.getWriter(); if (writer == null) { OutputStream os = streamResult.getOutputStream(); if (os != null) { setOutputStream(os); } } if (writer == null) { String uriString = streamResult.getSystemId(); if (uriString == null) { throw new XPathException("No system ID supplied for result file"); } try { URI uri = new URI(uriString); if (!uri.isAbsolute()) { try { uri = new File(uriString).getAbsoluteFile().toURI(); } catch (Exception e) { // if we fail, we'll get another exception } } File file = new File(uri); setOutputStream(new FileOutputStream(file)); // Set the outputstream in the StreamResult object so that the // call on OutputURIResolver.close() can close it streamResult.setOutputStream(outputStream); } catch (FileNotFoundException fnf) { throw new XPathException(fnf); } catch (URISyntaxException use) { throw new XPathException(use); } catch (IllegalArgumentException iae) { // for example, the system ID doesn't use the file: scheme throw new XPathException(iae); } } } /** * Determine whether the Emitter wants a Writer for character output or * an OutputStream for binary output. The standard Emitters all use a Writer, so * this returns true; but a subclass can override this if it wants to use an OutputStream * @return true if a Writer is needed, as distinct from an OutputStream */ public boolean usesWriter() { return true; } /** * Set the output destination as a character stream * @param writer the Writer to use as an output destination */ public void setWriter(Writer writer) throws XPathException { this.writer = writer; // If the writer uses a known encoding, change the encoding in the XML declaration // to match. Any encoding actually specified in xsl:output is ignored, because encoding // is being done by the user-supplied Writer, and not by Saxon itself. if (writer instanceof OutputStreamWriter && outputProperties != null) { String enc = ((OutputStreamWriter)writer).getEncoding(); //System.err.println("Java encoding: " + enc); outputProperties.setProperty(OutputKeys.ENCODING, enc); characterSet = CharacterSetFactory.getCharacterSet(outputProperties, getPipelineConfiguration()); allCharactersEncodable = (characterSet instanceof UnicodeCharacterSet); } } /** * Get the output writer * @return the Writer being used as an output destination, if any */ public Writer getWriter() { return writer; } /** * Set the output destination as a byte stream. *

    Note that if a specific encoding (other than the default, UTF-8) is required, then * {@link #setOutputProperties(java.util.Properties)} must be called before calling * this method.

    * @param stream the OutputStream being used as an output destination */ public void setOutputStream(OutputStream stream) throws XPathException { outputStream = stream; // If the user supplied an OutputStream, but the Emitter is written to // use a Writer (this is the most common case), then we create a Writer // to wrap the supplied OutputStream; the complications are to ensure that // the character encoding is correct. if (usesWriter()) { if (outputProperties == null) { outputProperties = new Properties(); } String encoding = outputProperties.getProperty(OutputKeys.ENCODING); if (encoding==null) { encoding = "UTF8"; allCharactersEncodable = true; } else if (encoding.equalsIgnoreCase("UTF-8")) { encoding = "UTF8"; allCharactersEncodable = true; } else if (encoding.equalsIgnoreCase("UTF-16")) { encoding = "UTF16"; } String byteOrderMark = outputProperties.getProperty(SaxonOutputKeys.BYTE_ORDER_MARK); if ("no".equals(byteOrderMark) && "UTF16".equals(encoding)) { // Java always writes a bom for UTF-16, so if the user doesn't want one, use utf16-be encoding = "UTF-16BE"; } if (characterSet instanceof PluggableCharacterSet) { encoding = ((PluggableCharacterSet)characterSet).getEncodingName(); } while (true) { try { String javaEncoding = encoding; if (encoding.equalsIgnoreCase("iso-646") || encoding.equalsIgnoreCase("iso646")) { javaEncoding = "US-ASCII"; } writer = new BufferedWriter( new OutputStreamWriter( outputStream, javaEncoding)); break; } catch (Exception err) { if (encoding.equalsIgnoreCase("UTF8")) { throw new XPathException("Failed to create a UTF8 output writer"); } XPathException de = new XPathException("Encoding " + encoding + " is not supported: using UTF8"); de.setErrorCode("SESU0007"); try { getPipelineConfiguration().getErrorListener().error(de); } catch (TransformerException e) { throw XPathException.makeXPathException(e); } encoding = "UTF8"; characterSet = UnicodeCharacterSet.getInstance(); allCharactersEncodable = true; outputProperties.setProperty(OutputKeys.ENCODING, "UTF-8"); } } } } /** * Get the output stream * @return the OutputStream being used as an output destination, if any */ public OutputStream getOutputStream() { return outputStream; } /** * Set unparsed entity URI. Needed to satisfy the Receiver interface, but not used, * because unparsed entities can occur only in input documents, not in output documents. * @param name the entity name * @param uri the entity system ID * @param publicId the entity public ID */ public void setUnparsedEntity(String name, String uri, String publicId) throws XPathException {} } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/event/ReceivingContentHandler.java0000644000175000017500000006560211151077401024142 0ustar eugeneeugenepackage net.sf.saxon.event; import net.sf.saxon.Configuration; import net.sf.saxon.FeatureKeys; import net.sf.saxon.expr.ExpressionLocation; import net.sf.saxon.om.NameChecker; import net.sf.saxon.om.NamePool; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.om.StandardNames; import net.sf.saxon.tinytree.CharSlice; import net.sf.saxon.tinytree.CompressedWhitespace; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ValidationException; import net.sf.saxon.value.Whitespace; import org.xml.sax.*; import org.xml.sax.ext.LexicalHandler; import javax.xml.transform.Result; import javax.xml.transform.TransformerException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.URI; import java.net.URISyntaxException; import java.util.HashMap; /** * ReceivingContentHandler is a glue class that provides a standard SAX ContentHandler * interface to a Saxon Receiver. To achieve this it needs to map names supplied * as strings to numeric name codes, for which purpose it needs access to a name * pool. The class also performs the function of assembling adjacent text nodes. *

    The class was previously named ContentEmitter.

    *

    If the input stream contains the processing instructions assigned by JAXP to switch * disable-output-escaping on or off, these will be reflected in properties set in the corresponding * characters events. In this case adjacent text nodes will not be combined. * @author Michael H. Kay */ public class ReceivingContentHandler implements ContentHandler, LexicalHandler, DTDHandler //, SaxonLocator, SourceLocationProvider { private NamePool pool; private PipelineConfiguration pipe; private Receiver receiver; private boolean inDTD = false; // true while processing the DTD private Locator locator; // a SAX Locator private LocalLocator localLocator = new LocalLocator(); // buffer for accumulating character data, until the next markup event is received private char[] buffer = new char[512]; private int charsUsed = 0; private CharSlice slice = new CharSlice(buffer, 0, 0); // array for accumulating namespace information private int[] namespaces = new int[20]; private int namespacesUsed = 0; // determine whether ignorable whitespace is ignored private boolean ignoreIgnorable = false; // determine whether DTD attribute types are retained private boolean retainDTDAttributeTypes = false; // determine whether DTD attribute value defaults should be suppressed private boolean suppressDTDAttributeDefaults = false; // indicate that escaping is allowed to be disabled using the JAXP-defined processing instructions private boolean allowDisableOutputEscaping = false; // indicate that escaping is disabled private boolean escapingDisabled = false; /** * A local cache is used to avoid allocating namecodes for the same name more than once. * This reduces contention on the NamePool. This is a two-level hashmap: the first level * has the namespace URI as its key, and returns a HashMap which maps lexical QNames to integer * namecodes. */ private HashMap cache = new HashMap(10); private HashMap noNamespaceMap; private static Class attributes2class; private static Method isSpecifiedMethod; /** * Create a ReceivingContentHandler and initialise variables */ public ReceivingContentHandler() { } /** * Set the ReceivingContentHandler to its initial state, except for the local name cache, * which is retained */ public void reset() { pipe = null; pool = null; receiver = null; ignoreIgnorable = false; retainDTDAttributeTypes = false; charsUsed = 0; slice.setLength(0); namespacesUsed = 0; locator = null; allowDisableOutputEscaping = false; escapingDisabled = false; } /** * Set the receiver to which events are passed. ReceivingContentHandler is essentially a translator * that takes SAX events as input and produces Saxon Receiver events as output; these Receiver events * are passed to the supplied Receiver * @param receiver the Receiver of events */ public void setReceiver(Receiver receiver) { this.receiver = receiver; //receiver = new TracingFilter(receiver); } /** * Set the pipeline configuration * @param pipe the pipeline configuration. This holds a reference to the Saxon configuration, as well as * information that can vary from one pipeline to another, for example the LocationProvider which resolves * the location of events in a source document */ public void setPipelineConfiguration(PipelineConfiguration pipe) { this.pipe = pipe; pipe.setLocationProvider(localLocator); Configuration config = pipe.getConfiguration(); pool = config.getNamePool(); ignoreIgnorable = config.getStripsWhiteSpace() != Whitespace.NONE; retainDTDAttributeTypes = config.isRetainDTDAttributeTypes(); suppressDTDAttributeDefaults = !pipe.isExpandAttributeDefaults(); Boolean b = (Boolean)config.getConfigurationProperty(FeatureKeys.USE_PI_DISABLE_OUTPUT_ESCAPING); allowDisableOutputEscaping = b.booleanValue(); } /** * Get the pipeline configuration * @return the pipeline configuration as supplied to {@link #setPipelineConfiguration(PipelineConfiguration)} */ public PipelineConfiguration getPipelineConfiguration() { return pipe; } /** * Get the Configuration object * @return the Saxon configuration */ public Configuration getConfiguration() { return pipe.getConfiguration(); } /** * Set whether "ignorable whitespace" should be ignored. This method is effective only * if called after setPipelineConfiguration, since the default value is taken from the * configuration. * @param ignore true if ignorable whitespace (whitespace in element content that is notified * via the {@link #ignorableWhitespace(char[], int, int)} method) should be ignored, false if * it should be treated as ordinary text. */ public void setIgnoreIgnorableWhitespace(boolean ignore) { ignoreIgnorable = ignore; } /** * Determine whether "ignorable whitespace" is ignored. This returns the value that was set * using {@link #setIgnoreIgnorableWhitespace} if that has been called; otherwise the value * from the configuration. * @return true if ignorable whitespace is being ignored */ public boolean isIgnoringIgnorableWhitespace() { return ignoreIgnorable; } /** * Receive notification of the beginning of a document. */ public void startDocument () throws SAXException { // System.err.println("ReceivingContentHandler#startDocument"); try { charsUsed = 0; namespacesUsed = 0; pipe.setLocationProvider(localLocator); receiver.setPipelineConfiguration(pipe); receiver.open(); receiver.startDocument(0); } catch (XPathException err) { throw new SAXException(err); } } /** * Receive notification of the end of a document */ public void endDocument () throws SAXException { // System.err.println("RCH: end document"); try { flush(); receiver.endDocument(); receiver.close(); } catch (ValidationException err) { err.setLocator(locator); throw new SAXException(err); } catch (XPathException err) { throw new SAXException(err); } } /** * Supply a locator that can be called to give information about location in the source document * being parsed. */ public void setDocumentLocator (Locator locator) { this.locator = locator; } /** * Notify a namespace prefix to URI binding */ public void startPrefixMapping(String prefix, String uri) throws SAXException { //System.err.println("StartPrefixMapping " + prefix + "=" + uri); if (prefix.equals("xmlns")) { // the binding xmlns:xmlns="http://www.w3.org/2000/xmlns/" // should never be reported, but it's been known to happen return; } if (namespacesUsed >= namespaces.length) { int[] n2 = new int[namespacesUsed * 2]; System.arraycopy(namespaces, 0, n2, 0, namespacesUsed); namespaces = n2; } namespaces[namespacesUsed++] = pool.allocateNamespaceCode(prefix, uri); } /** * Notify that a namespace binding is going out of scope */ public void endPrefixMapping(String prefix) throws SAXException {} /** * Notify an element start event, including all the associated attributes */ public void startElement (String uri, String localname, String rawname, Attributes atts) throws SAXException { // System.err.println("ReceivingContentHandler#startElement " + // uri + "," + localname + "," + rawname + // " at line " + locator.getLineNumber() + " of " + locator.getSystemId()); //for (int a=0; a buffer.length) { char[] newbuffer = new char[buffer.length*2]; System.arraycopy(buffer, 0, newbuffer, 0, charsUsed); buffer = newbuffer; slice = new CharSlice(buffer, 0, 0); } System.arraycopy(ch, start, buffer, charsUsed, length); charsUsed += length; } /** * Report character data classified as "Ignorable whitespace", that is, whitespace text nodes * appearing as children of elements with an element-only content model */ public void ignorableWhitespace (char ch[], int start, int length) throws SAXException { if (!ignoreIgnorable) { characters(ch, start, length); } } /** * Notify the existence of a processing instruction */ public void processingInstruction (String name, String remainder) throws SAXException { try { flush(); if (!inDTD) { if (name==null) { // trick used by the old James Clark xp parser to notify a comment comment(remainder.toCharArray(), 0, remainder.length()); } else { // some parsers allow through PI names containing colons if (!getConfiguration().getNameChecker().isValidNCName(name)) { throw new SAXException("Invalid processing instruction name (" + name + ')'); } if (allowDisableOutputEscaping) { if (name.equals(Result.PI_DISABLE_OUTPUT_ESCAPING)) { //flush(); escapingDisabled = true; return; } else if (name.equals(Result.PI_ENABLE_OUTPUT_ESCAPING)) { //flush(); escapingDisabled = false; return; } } receiver.processingInstruction(name, Whitespace.removeLeadingWhitespace(remainder), 0, 0); } } } catch (XPathException err) { throw new SAXException(err); } } /** * Notify the existence of a comment. Note that in SAX this is part of LexicalHandler interface * rather than the ContentHandler interface. */ public void comment (char ch[], int start, int length) throws SAXException { try { flush(); if (!inDTD) { receiver.comment(new CharSlice(ch, start, length), 0, 0); } } catch (XPathException err) { throw new SAXException(err); } } /** * Flush buffer for accumulated character data */ private void flush() throws XPathException { if (charsUsed > 0) { slice.setLength(charsUsed); CharSequence cs = CompressedWhitespace.compress(slice); receiver.characters(cs, 0, escapingDisabled ? ReceiverOptions.DISABLE_ESCAPING : ReceiverOptions.WHOLE_TEXT_NODE); charsUsed = 0; escapingDisabled = false; } } /** * Notify a skipped entity. Saxon ignores this event */ public void skippedEntity(String name) throws SAXException {} // No-op methods to satisfy lexical handler interface /** * Register the start of the DTD. Saxon ignores the DTD; however, it needs to know when the DTD starts and * ends so that it can ignore comments in the DTD, which are reported like any other comment, but which * are skipped because they are not part of the XPath data model */ public void startDTD (String name, String publicId, String systemId) throws SAXException { inDTD = true; } /** * Register the end of the DTD. Comments in the DTD are skipped because they * are not part of the XPath data model */ public void endDTD () throws SAXException { inDTD = false; } public void startEntity (String name) throws SAXException {} public void endEntity (String name) throws SAXException {} public void startCDATA () throws SAXException {} public void endCDATA () throws SAXException {} ////////////////////////////////////////////////////////////////////////////// // Implement DTDHandler interface ////////////////////////////////////////////////////////////////////////////// public void notationDecl( String name, String publicId, String systemId) throws SAXException {} public void unparsedEntityDecl( String name, String publicId, String systemId, String notationName) throws SAXException { //System.err.println("Unparsed entity " + name + "=" + systemId); // Some SAX parsers report the systemId as written. We need to turn it into // an absolute URL. String uri = systemId; if (locator!=null) { try { URI suppliedURI = new URI(systemId); if (!suppliedURI.isAbsolute()) { String baseURI = locator.getSystemId(); if (baseURI != null) { URI absoluteURI = new URI(baseURI).resolve(systemId); uri = absoluteURI.toString(); } } } catch (URISyntaxException err) { uri = systemId; // fallback } } try { receiver.setUnparsedEntity(name, uri, publicId); } catch (XPathException err) { throw new SAXException(err); } } private class LocalLocator implements SaxonLocator, SourceLocationProvider { // This class is needed to bridge a SAX Locator to a JAXP SourceLocator /** * Return the system identifier for the current document event. * @return A string containing the system identifier, or * null if none is available. */ public String getSystemId() { return (locator == null ? null : locator.getSystemId()); } /** * Return the public identifier for the current document event. * @return A string containing the public identifier, or * null if none is available. */ public String getPublicId() { return (locator==null ? null : locator.getPublicId()); } /** * Return the line number where the current document event ends. * @return The line number, or -1 if none is available. */ public int getLineNumber() { return (locator==null ? -1 : locator.getLineNumber()); } /** * Return the character position where the current document event ends. * @return The column number, or -1 if none is available. */ public int getColumnNumber() { return (locator==null ? -1 : locator.getColumnNumber()); } /** * Get the line number within the document or module containing a particular location * * @param locationId identifier of the location in question (as passed down the Receiver pipeline) * @return the line number within the document or module. */ public int getLineNumber(long locationId) { return (locator==null ? -1 : locator.getLineNumber()); } public int getColumnNumber(long locationId) { return (locator==null ? -1 : locator.getColumnNumber()); } /** * Get the URI of the document or module containing a particular location * * @param locationId identifier of the location in question (as passed down the Receiver pipeline) * @return the URI of the document or module. */ public String getSystemId(long locationId) { return (locator == null ? null : locator.getSystemId()); } } } // end of class ReceivingContentHandler // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/event/XML10ContentChecker.java0000644000175000017500000001525611033112257023015 0ustar eugeneeugenepackage net.sf.saxon.event; import net.sf.saxon.trans.Err; import net.sf.saxon.charcode.UTF16; import net.sf.saxon.charcode.XMLCharacterData; import net.sf.saxon.expr.ExpressionLocation; import net.sf.saxon.om.Name10Checker; import net.sf.saxon.om.NameChecker; import net.sf.saxon.om.NamePool; import net.sf.saxon.sort.IntHashSet; import net.sf.saxon.trans.XPathException; /** * This class is used on the serialization pipeline to check that the document conforms * to XML 1.0 rules. It is placed on the pipeline only when the configuration permits * XML 1.1 constructs, but the particular output document is being serialized as XML 1.0 */ public class XML10ContentChecker extends ProxyReceiver { private NameChecker checker = Name10Checker.getInstance(); private NamePool pool; private IntHashSet cache = new IntHashSet(100); public void setPipelineConfiguration(PipelineConfiguration pipe) { pool = pipe.getConfiguration().getNamePool(); super.setPipelineConfiguration(pipe); } /** * Notify the start of an element * * @param nameCode integer code identifying the name of the element within the name pool. * @param typeCode integer code identifying the element's type within the name pool. * @param properties properties of the element node */ public void startElement(int nameCode, int typeCode, int locationId, int properties) throws XPathException { if (!cache.contains(nameCode)) { if (!checker.isValidNCName(pool.getLocalName(nameCode))) { XPathException err = new XPathException("Invalid XML 1.0 element name " + Err.wrap(pool.getLocalName(nameCode), Err.ELEMENT)); err.setErrorCode("SERE0005"); err.setLocator(new ExpressionLocation(getPipelineConfiguration().getLocationProvider(), locationId)); throw err; } cache.add(nameCode); } nextReceiver.startElement(nameCode, typeCode, locationId, properties); } /** * Notify an attribute. Attributes are notified after the startElement event, and before any * children. Namespaces and attributes may be intermingled. * * @param nameCode The name of the attribute, as held in the name pool * @param typeCode The type of the attribute, as held in the name pool * @param properties Bit significant value. The following bits are defined: *

    DISABLE_ESCAPING
    Disable escaping for this attribute
    *
    NO_SPECIAL_CHARACTERS
    Attribute value contains no special characters
    * @throws IllegalStateException: attempt to output an attribute when there is no open element * start tag */ public void attribute(int nameCode, int typeCode, CharSequence value, int locationId, int properties) throws XPathException { if (!cache.contains(nameCode)) { if (!checker.isValidNCName(pool.getLocalName(nameCode))) { XPathException err = new XPathException("Invalid XML 1.0 attribute name " + Err.wrap(pool.getLocalName(nameCode), Err.ATTRIBUTE)); err.setErrorCode("SERE0005"); err.setLocator(new ExpressionLocation(getPipelineConfiguration().getLocationProvider(), locationId)); throw err; } cache.add(nameCode); } checkString(value, locationId); nextReceiver.attribute(nameCode, typeCode, value, locationId, properties); } /** * Character data */ public void characters(CharSequence chars, int locationId, int properties) throws XPathException { checkString(chars, locationId); nextReceiver.characters(chars, locationId, properties); } /** * Output a comment */ public void comment(CharSequence chars, int locationId, int properties) throws XPathException { checkString(chars, locationId); nextReceiver.comment(chars, locationId, properties); } /** * Processing Instruction */ public void processingInstruction(String target, CharSequence data, int locationId, int properties) throws XPathException { if (!checker.isValidNCName(target)) { XPathException err = new XPathException("Invalid XML 1.0 processing instruction name " + Err.wrap(target)); err.setErrorCode("SERE0005"); err.setLocator(new ExpressionLocation(getPipelineConfiguration().getLocationProvider(), locationId)); throw err; } checkString(data, locationId); nextReceiver.processingInstruction(target, data, locationId, properties); } /** * Check that a string consists of valid XML 1.0 characters (UTF-16 encoded) * @param in the string to be checked * @param locationId the location of the string */ private void checkString(CharSequence in, long locationId) throws XPathException { final int len = in.length(); for (int c=0; cIf atomic items are appended to the sequence, then adjacent atomic items are * turned in to a text node by converting them to strings and adding a single space * as a separator.

    * *

    If a document node is appended to the sequence, then the document node is ignored * and its children are appended to the sequence.

    * *

    If any other node is appended to the sequence, then it is pushed to the result * as a sequence of Receiver events, which may involve walking recursively through the * contents of a tree.

    */ public class TreeReceiver extends SequenceReceiver { private Receiver nextReceiver; private int level = 0; private boolean[] isDocumentLevel = new boolean[20]; // The sequence of events can include startElement/endElement pairs or startDocument/endDocument // pairs at any level. A startDocument/endDocument pair is essentially ignored except at the // outermost level, except that a namespace or attribute node cannot be sent when we're at a // document level. See for example schema90963-err.xsl private boolean inStartTag = false; /** * Create a TreeReceiver * @param nextInChain the receiver to which events will be directed, after * expanding append events into more primitive tree-based events */ public TreeReceiver(Receiver nextInChain) { nextReceiver = nextInChain; previousAtomic = false; setPipelineConfiguration(nextInChain.getPipelineConfiguration()); } public void setSystemId(String systemId) { if (systemId != null && !systemId.equals(this.systemId)) { this.systemId = systemId; if (nextReceiver != null) { nextReceiver.setSystemId(systemId); } } } public void setPipelineConfiguration(PipelineConfiguration pipe) { if (pipelineConfiguration != pipe) { pipelineConfiguration = pipe; if (nextReceiver != null) { nextReceiver.setPipelineConfiguration(pipe); } } } /** * Get the underlying Receiver (that is, the next one in the pipeline) * @return the underlying Receiver */ public Receiver getUnderlyingReceiver() { return nextReceiver; } /** * Start of event sequence */ public void open() throws XPathException { if (nextReceiver == null) { throw new IllegalStateException("TreeReceiver.open(): no underlying receiver provided"); } nextReceiver.open(); previousAtomic = false; } /** * End of event sequence */ public void close() throws XPathException { if (nextReceiver != null) { nextReceiver.close(); } previousAtomic = false; } /** * Start of a document node. */ public void startDocument(int properties) throws XPathException { if (level == 0) { nextReceiver.startDocument(properties); } if (isDocumentLevel.length - 1 < level) { boolean[] d2 = new boolean[level*2]; System.arraycopy(isDocumentLevel, 0, d2, 0, level); isDocumentLevel = d2; } isDocumentLevel[level++] = true; } /** * Notify the end of a document node */ public void endDocument() throws XPathException { level--; if (level == 0) { nextReceiver.endDocument(); } } /** * Notify the start of an element * @param nameCode integer code identifying the name of the element within the name pool. * @param typeCode integer code identifying the element's type within the name pool. * @param properties bit-significant properties of the element node */ public void startElement(int nameCode, int typeCode, int locationId, int properties) throws XPathException { if (inStartTag) { startContent(); } inStartTag = true; nextReceiver.startElement(nameCode, typeCode, locationId, properties); previousAtomic = false; if (isDocumentLevel.length - 1 < level) { boolean[] d2 = new boolean[level*2]; System.arraycopy(isDocumentLevel, 0, d2, 0, level); isDocumentLevel = d2; } isDocumentLevel[level++] = false; } /** * Notify a namespace. Namespaces are notified after the startElement event, and before * any children for the element. The namespaces that are reported are only required * to include those that are different from the parent element; however, duplicates may be reported. * A namespace must not conflict with any namespaces already used for element or attribute names. * @param namespaceCode an integer: the top half is a prefix code, the bottom half a URI code. * These may be translated into an actual prefix and URI using the name pool. A prefix code of * zero represents the empty prefix (that is, the default namespace). A URI code of zero represents * a URI of "", that is, a namespace undeclaration. * @throws IllegalStateException: attempt to output a namespace when there is no open element * start tag */ public void namespace(int namespaceCode, int properties) throws XPathException { boolean documentLevel = level==0 || isDocumentLevel[level-1]; if (documentLevel || !inStartTag) { throw NoOpenStartTagException.makeNoOpenStartTagException( Type.NAMESPACE, getNamePool().getPrefixFromNamespaceCode(namespaceCode), getPipelineConfiguration().getHostLanguage(), documentLevel, getPipelineConfiguration().isSerializing()); } nextReceiver.namespace(namespaceCode, properties); previousAtomic = false; } /** * Notify an attribute. Attributes are notified after the startElement event, and before any * children. Namespaces and attributes may be intermingled. * @param nameCode The name of the attribute, as held in the name pool * @param typeCode The type of the attribute, as held in the name pool * @param properties Bit significant value. The following bits are defined: *
    DISABLE_ESCAPING
    Disable escaping for this attribute
    *
    NO_SPECIAL_CHARACTERS
    Attribute value contains no special characters
    * @throws IllegalStateException: attempt to output an attribute when there is no open element * start tag */ public void attribute(int nameCode, int typeCode, CharSequence value, int locationId, int properties) throws XPathException { boolean documentLevel = level==0 || isDocumentLevel[level-1]; if (documentLevel || !inStartTag) { throw NoOpenStartTagException.makeNoOpenStartTagException( Type.ATTRIBUTE, getNamePool().getDisplayName(nameCode), getPipelineConfiguration().getHostLanguage(), documentLevel, getPipelineConfiguration().isSerializing()); } nextReceiver.attribute(nameCode, typeCode, value, locationId, properties); previousAtomic = false; } /** * Notify the start of the content, that is, the completion of all attributes and namespaces. * Note that the initial receiver of output from XSLT instructions will not receive this event, * it has to detect it itself. Note that this event is reported for every element even if it has * no attributes, no namespaces, and no content. */ public void startContent() throws XPathException { inStartTag = false; nextReceiver.startContent(); previousAtomic = false; } /** * End of element */ public void endElement() throws XPathException { if (inStartTag) { startContent(); } nextReceiver.endElement(); previousAtomic = false; level--; } /** * Character data */ public void characters(CharSequence chars, int locationId, int properties) throws XPathException { if (chars.length() > 0) { if (inStartTag) { startContent(); } nextReceiver.characters(chars, locationId, properties); } previousAtomic = false; } /** * Processing Instruction */ public void processingInstruction(String target, CharSequence data, int locationId, int properties) throws XPathException { if (inStartTag) { startContent(); } nextReceiver.processingInstruction(target, data, locationId, properties); previousAtomic = false; } /** * Output a comment */ public void comment(CharSequence chars, int locationId, int properties) throws XPathException { if (inStartTag) { startContent(); } nextReceiver.comment(chars, locationId, properties); previousAtomic = false; } /** * Set the URI for an unparsed entity in the document. */ public void setUnparsedEntity(String name, String uri, String publicId) throws XPathException { nextReceiver.setUnparsedEntity(name, uri, publicId); } /** * Append an arbitrary item (node or atomic value) to the output */ public void append(Item item, int locationId, int copyNamespaces) throws XPathException { if (item instanceof AtomicValue) { if (previousAtomic) { characters(" ", locationId, 0); } characters(item.getStringValueCS(), locationId, 0); previousAtomic = true; } else if (((NodeInfo)item).getNodeKind() == Type.DOCUMENT) { startDocument(0); // needed to ensure that illegal namespaces or attributes in the content are caught SequenceIterator iter = ((NodeInfo)item).iterateAxis(Axis.CHILD); while (true) { Item it = iter.next(); if (it == null) break; append(it, locationId, copyNamespaces); } previousAtomic = false; endDocument(); } else { ((NodeInfo)item).copy(this, copyNamespaces, true, locationId); previousAtomic = false; } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/event/ImplicitResultChecker.java0000644000175000017500000000767411033112257023637 0ustar eugeneeugenepackage net.sf.saxon.event; import net.sf.saxon.trans.XPathException; import net.sf.saxon.Controller; /** * This filter is inserted into the serializer pipeline when serializing an implicit XSLT result tree, that * is, one that is created without use of xsl:result-document. Its main purpose is to check, if and only if * the result destination is actually written to, that it does not conflict with an explicit result destination * with the same URI. It also ensures that the output destination is opened before it is first written to. */ public class ImplicitResultChecker extends ProxyReceiver { private boolean clean = true; private boolean open = false; private Controller controller; /** * Create an ImplicitResultChecker. This is a filter on the output pipeline. * @param next the next receiver on the pipeline * @param controller the controller of the XSLT transformation */ public ImplicitResultChecker(Receiver next, Controller controller) { setUnderlyingReceiver(next); this.controller = controller; } public void open() throws XPathException { super.open(); open = true; } public void startDocument(int properties) throws XPathException { if (!open) { open(); } nextReceiver.startDocument(properties); } public void startElement(int nameCode, int typeCode, int locationId, int properties) throws XPathException { if (clean) { firstContent(); } nextReceiver.startElement(nameCode, typeCode, locationId, properties); } public void characters(CharSequence chars, int locationId, int properties) throws XPathException { if (clean) { firstContent(); } nextReceiver.characters(chars, locationId, properties); } public void processingInstruction(String target, CharSequence data, int locationId, int properties) throws XPathException { if (clean) { firstContent(); } nextReceiver.processingInstruction(target, data, locationId, properties); } public void comment(CharSequence chars, int locationId, int properties) throws XPathException { if (clean) { firstContent(); } nextReceiver.comment(chars, locationId, properties); } /** * This method does the real work. It is called when the first output is written to the implicit output * destination, and checks that no explicit result document has been written to the same URI * as the implicit result document * @throws XPathException */ private void firstContent() throws XPathException { controller.checkImplicitResultTree(); if (!open) { open(); startDocument(0); } clean = false; } public void close() throws XPathException { // If we haven't written any output, do the close only if no explicit result document has been written. // This will cause a file to be created and perhaps an XML declaration to be written if (!clean || !controller.hasThereBeenAnExplicitResultDocument()) { if (!open) { open(); } nextReceiver.close(); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/event/CopyNamespaceSensitiveException.java0000644000175000017500000000215111033112257025662 0ustar eugeneeugenepackage net.sf.saxon.event; import net.sf.saxon.trans.XPathException; /** * Exception indicating that an attempt was made to copy namespace-sensitive content * without copying its associated namespaces */ public class CopyNamespaceSensitiveException extends XPathException { public CopyNamespaceSensitiveException(String message) { super(message); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. //saxonb-9.1.0.8/bj/net/sf/saxon/event/SaxonOutputKeys.java0000644000175000017500000003423111033112257022533 0ustar eugeneeugenepackage net.sf.saxon.event; import net.sf.saxon.trans.Err; import net.sf.saxon.om.NameChecker; import net.sf.saxon.trans.XPathException; import javax.xml.transform.OutputKeys; import java.util.StringTokenizer; /** * Provides string constants that can be used to set * output properties for a Transformer, or to retrieve * output properties from a Transformer or Templates object. * * These keys are private Saxon keys that supplement the standard keys * defined in javax.xml.transform.OutputKeys. As well as Saxon extension * attributes, the list includes new attributes defined in XSLT 2.0 which * are not yet supported in JAXP */ public class SaxonOutputKeys { /** * This class is not instantiated */ private SaxonOutputKeys() {} /** * String constant representing the saxon:xquery output method name */ public static final String SAXON_XQUERY_METHOD = "{http://saxon.sf.net/}xquery"; /** * saxon:indentSpaces = integer. * *

    Defines the number of spaces used for indentation of output

    */ public static final String INDENT_SPACES = "{http://saxon.sf.net/}indent-spaces"; /** * saxon:suppress-indentation = list of element names * *

    Defines elements within which no indentation will occur

    */ public static final String SUPPRESS_INDENTATION = "{http://saxon.sf.net/}suppress-indentation"; /** * saxon:double-space = list of element names * *

    Defines elements that will have an extra blank line added before the start tag, in addition * to normal indentation

    */ public static final String DOUBLE_SPACE = "{http://saxon.sf.net/}double-space"; /** * stylesheet-version. This serialization parameter is set automatically by the XSLT processor * to the value of the version attribute on the principal stylesheet module. */ public static final String STYLESHEET_VERSION = "{http://saxon.sf.net/}stylesheet-version"; /** * use-character-map = list-of-qnames. * *

    Defines the character maps used in this output definition. The QNames * are represented in Clark notation as {uri}local-name.

    */ public static final String USE_CHARACTER_MAPS = "use-character-maps"; /** * include-content-type = "yes" | "no". This attribute is defined in XSLT 2.0 * *

    Indicates whether the META tag is to be added to HTML output

    */ public static final String INCLUDE_CONTENT_TYPE = "include-content-type"; /** * undeclare-prefixes = "yes" | "no". This attribute is defined in XSLT 2.0 * *

    Indicates XML 1.1 namespace undeclarations are to be output when required

    */ public static final String UNDECLARE_PREFIXES = "undeclare-prefixes"; /** * escape-uri-attributes = "yes" | "no". This attribute is defined in XSLT 2.0 * *

    Indicates whether HTML attributes of type URI are to be URI-escaped

    */ public static final String ESCAPE_URI_ATTRIBUTES = "escape-uri-attributes"; /** * representation = rep1[;rep2]. * *

    Indicates the preferred way of representing non-ASCII characters in HTML * and XML output. rep1 is for characters in the range 128-256, rep2 for those * above 256.

    */ public static final String CHARACTER_REPRESENTATION = "{http://saxon.sf.net/}character-representation"; /** * saxon:next-in-chain = URI. * *

    Indicates that the output is to be piped into another XSLT stylesheet * to perform another transformation. The auxiliary property NEXT_IN_CHAIN_BASE_URI * records the base URI of the stylesheet element where this attribute was found.

    */ public static final String NEXT_IN_CHAIN = "{http://saxon.sf.net/}next-in-chain"; public static final String NEXT_IN_CHAIN_BASE_URI = "{http://saxon.sf.net/}next-in-chain-base-uri"; /** * byte-order-mark = yes|no. * *

    Indicates whether UTF-8/UTF-16 output is to start with a byte order mark. Values are "yes" or "no", * default is "no" */ public static final String BYTE_ORDER_MARK = "byte-order-mark"; /** * normalization-form = NFC|NFD|NFKC|NFKD|non. * *

    Indicates that a given Unicode normalization form (or no normalization) is required. */ public static final String NORMALIZATION_FORM = "normalization-form"; /** * supply-source-locator = yes|no. * *

    If set to "yes", and the output is being sent to a SAXResult (or to a user-supplied content handler), * indicates that the SAX Locator made available to the ContentHandler will contain information about the * location of the context node in the source document as well as the location in the stylesheet or query.

    */ public static final String SUPPLY_SOURCE_LOCATOR = "{http://saxon.sf.net/}supply-source-locator"; /** * saxon:require-well-formed = yes|no. * *

    Indicates whether a user-supplied ContentHandler requires the stream of SAX events to be * well-formed (that is, to have a single element node and no text nodes as children of the root). * The default is "no".

    */ public static final String REQUIRE_WELL_FORMED = "{http://saxon.sf.net/}require-well-formed"; /** * wrap="yes"|"no". *

    * This property is only available in the XQuery API. The value "yes" indicates that the result * sequence produced by the query is to be wrapped, that is, each item in the result is represented * as a separate element. This format allows any sequence to be represented as an XML document, * including for example sequences consisting of parentless attribute nodes. */ public static final String WRAP = "{http://saxon.sf.net/}wrap-result-sequence"; /** * Property used internally to identify the XSLT implicit result document */ public static final String IMPLICIT_RESULT_DOCUMENT = "{http://saxon.sf.net/}implicit-result-document"; /** * Check that a supplied output property is valid. * @param key the name of the property * @param value the value of the property. This may be set to null, in which case no validation takes place. * The value must be in JAXP format, that is, with lexical QNames expanded to Clark names * @param checker the NameChecker to be used for validating QNames * @throws XPathException if the property name or value is invalid */ public static void checkOutputProperty(String key, String value, NameChecker checker) throws XPathException { if (!key.startsWith("{") || key.startsWith("{http://saxon.sf.net/}" )) { if (key.equals(BYTE_ORDER_MARK)) { if (value != null) { checkYesOrNo(key, value); } } else if (key.equals(OutputKeys.CDATA_SECTION_ELEMENTS)) { if (value != null) { checkListOfClarkNames(key, value, checker); } } else if (key.equals(OutputKeys.DOCTYPE_PUBLIC)) { // no constraints } else if (key.equals(OutputKeys.DOCTYPE_SYSTEM)) { // no constraints } else if (key.equals(OutputKeys.ENCODING)) { // no constraints } else if (key.equals(ESCAPE_URI_ATTRIBUTES) || key.equals("escape-uri-attibutes")) { // constant was misspelled in 9.0 and earlier releases if (value != null) { checkYesOrNo(key, value); } } else if (key.equals(INCLUDE_CONTENT_TYPE)) { if (value != null) { checkYesOrNo(key, value); } } else if (key.equals(OutputKeys.INDENT)) { if (value != null) { checkYesOrNo(key, value); } } else if (key.equals(OutputKeys.MEDIA_TYPE)) { // no constraints } else if (key.equals(OutputKeys.METHOD)) { if (value != null) { checkMethod(value, checker); } } else if (key.equals(NORMALIZATION_FORM)) { if (value != null) { checkNormalizationForm(value); } } else if (key.equals(OutputKeys.OMIT_XML_DECLARATION)) { if (value != null) { checkYesOrNo(key, value); } } else if (key.equals(OutputKeys.STANDALONE)) { if (value != null && !value.equals("omit")) { checkYesOrNo(key, value); } } else if (key.equals(UNDECLARE_PREFIXES)) { if (value != null) { checkYesOrNo(key, value); } } else if (key.equals(USE_CHARACTER_MAPS)) { if (value != null) { checkListOfClarkNames(key, value, checker); } } else if (key.equals(OutputKeys.VERSION)) { // no constraints } else if (key.equals(STYLESHEET_VERSION)) { // no constraints } else if (key.equals(INDENT_SPACES)) { if (value != null) { checkNonNegativeInteger(key, value); } } else if (key.equals(CHARACTER_REPRESENTATION)) { // no validation performed } else if (key.equals(NEXT_IN_CHAIN)) { // no validation performed } else if (key.equals(NEXT_IN_CHAIN_BASE_URI)) { // no validation performed } else if (key.equals(REQUIRE_WELL_FORMED)) { if (value != null) { checkYesOrNo(key, value); } } else if (key.equals(SUPPRESS_INDENTATION)) { if (value != null) { checkListOfClarkNames(key, value, checker); } } else if (key.equals(DOUBLE_SPACE)) { if (value != null) { checkListOfClarkNames(key, value, checker); } } else if (key.equals(WRAP)) { if (value != null) { checkYesOrNo(key, value); } } else if (key.equals(SUPPLY_SOURCE_LOCATOR)) { if (value != null) { checkYesOrNo(key, value); } } else { throw new XPathException("Unknown serialization parameter " + Err.wrap(key)); } } else { //return; } } private static void checkYesOrNo(String key, String value) throws XPathException { if ("yes".equals(value) || "no".equals(value)) { // OK } else { throw new XPathException("Serialization parameter " + Err.wrap(key) + " must have the value yes or no"); } } private static void checkMethod(String value, NameChecker checker) throws XPathException { if ("xml".equals(value)) return; if ("html".equals(value)) return; if ("xhtml".equals(value)) return; if ("text".equals(value)) return; if (isValidClarkName(value, checker)) return; throw new XPathException("Invalid value for serialization method: " + "must be xml, html, xhtml, text, or a QName in '{uri}local' form"); } private static void checkNormalizationForm(String value) throws XPathException { if ("NFC".equals(value)) return; if ("NFD".equals(value)) return; if ("NFKC".equals(value)) return; if ("NFKD".equals(value)) return; if ("fully-normalized".equals(value)) return; if ("none".equals(value)) return; throw new XPathException("Invalid value for normalization-form: " + "must be NFC, NFD, NFKC, NFKD, fully-normalized, or none"); } private static boolean isValidClarkName(String value, NameChecker checker) { if (value.charAt(0) != '{') { return false; } int closer = value.indexOf('}'); return closer >= 2 && closer != value.length() - 1 && checker.isValidNCName(value.substring(closer + 1)); } private static void checkNonNegativeInteger(String key, String value) throws XPathException { try { int n = Integer.parseInt(value); if (n < 0) { throw new XPathException("Value of " + Err.wrap(key) + " must be a non-negative integer"); } } catch (NumberFormatException err) { throw new XPathException("Value of " + Err.wrap(key) + " must be a non-negative integer"); } } private static void checkListOfClarkNames(String key, String value, NameChecker checker) throws XPathException { StringTokenizer tok = new StringTokenizer(value, " \t\n\r", false); while (tok.hasMoreTokens()) { String s = tok.nextToken(); if (isValidClarkName(s, checker) || checker.isValidNCName(s)) { // ok } else { throw new XPathException("Value of " + Err.wrap(key) + " must be a list of QNames in '{uri}local' notation"); } } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. //saxonb-9.1.0.8/bj/net/sf/saxon/event/SerializerFactory.java0000644000175000017500000006562111041513037023036 0ustar eugeneeugenepackage net.sf.saxon.event; import net.sf.saxon.Configuration; import net.sf.saxon.Controller; import net.sf.saxon.om.ExternalObjectModel; import net.sf.saxon.om.NamespaceConstant; import net.sf.saxon.trans.SaxonErrorCode; import net.sf.saxon.trans.XPathException; import javax.xml.transform.OutputKeys; import javax.xml.transform.Result; import javax.xml.transform.dom.DOMResult; import javax.xml.transform.sax.SAXResult; import javax.xml.transform.stream.StreamResult; import java.io.Serializable; import java.util.List; import java.util.Properties; /** * Helper class to construct a serialization pipeline for a given result destination * and a given set of output properties. The pipeline is represented by a Receiver object * to which result tree events are sent. * * Since Saxon 8.8 is is possible to write a subclass of SerializerFactory and register it * with the Configuration, allowing customisation of the Serializer pipeline. * * The class includes methods for instantiating each of the components used on the Serialization * pipeline. This allows a customized SerializerFactory to replace any or all of these components * by subclasses that refine the behaviour. * */ // renamed in Saxon 8.7 - previously named ResultWrapper // changed in Saxon 8.8 to be instantiable, and registered with the Configuration public class SerializerFactory implements Serializable { /** * Create a SerializerFactory */ public SerializerFactory() { } /** * Get a Receiver that wraps a given Result object. Saxon calls this method to construct * a serialization pipeline. The method can be overridden in a subclass; alternatively, the * subclass can override the various methods used to instantiate components of the serialization * pipeline. * *

    Note that this method ignores the {@link net.sf.saxon.event.SaxonOutputKeys#WRAP} output property. If * wrapped output is required, the user must create a {@link net.sf.saxon.query.SequenceWrapper} directly.

    * * @param result The final destination of the serialized output. Usually a StreamResult, * but other kinds of Result are possible. * @param pipe The PipelineConfiguration. * @param props The serialization properties * @return the newly constructed Receiver that performs the required serialization */ public Receiver getReceiver(Result result, PipelineConfiguration pipe, Properties props) throws XPathException { if (result instanceof Emitter) { if (((Emitter)result).getOutputProperties() == null) { ((Emitter)result).setOutputProperties(props); } return (Emitter)result; } else if (result instanceof Receiver) { Receiver receiver = (Receiver)result; receiver.setSystemId(result.getSystemId()); receiver.setPipelineConfiguration(pipe); return receiver; } else if (result instanceof SAXResult) { ContentHandlerProxy proxy = newContentHandlerProxy(); proxy.setUnderlyingContentHandler(((SAXResult)result).getHandler()); proxy.setPipelineConfiguration(pipe); proxy.setOutputProperties(props); if ("yes".equals(props.getProperty(SaxonOutputKeys.SUPPLY_SOURCE_LOCATOR))) { if (pipe.getConfiguration().isCompileWithTracing()) { pipe.getController().addTraceListener(proxy.getTraceListener()); } else { XPathException de = new XPathException("Cannot use saxon:supply-source-locator unless tracing was enabled at compile time"); de.setErrorCode(SaxonErrorCode.SXSE0002); throw de; } } //proxy.open(); return proxy; } else if (result instanceof StreamResult) { // The "target" is the start of the output pipeline, the Receiver that // instructions will actually write to (except that other things like a // NamespaceReducer may get added in front of it). The "emitter" is the // last thing in the output pipeline, the Receiver that actually generates // characters or bytes that are written to the StreamResult. Receiver target; String method = props.getProperty(OutputKeys.METHOD); if (method==null) { target = newUncommittedSerializer(result, props); target.setPipelineConfiguration(pipe); return target; } Emitter emitter; CharacterMapExpander characterMapExpander = null; String useMaps = props.getProperty(SaxonOutputKeys.USE_CHARACTER_MAPS); if (useMaps != null) { Controller controller = (pipe == null ? null : pipe.getController()); if (controller == null) { XPathException de = new XPathException("Cannot use character maps in an environment with no Controller"); de.setErrorCode(SaxonErrorCode.SXSE0001); throw de; } characterMapExpander = controller.makeCharacterMapExpander(useMaps, this); characterMapExpander.setPipelineConfiguration(pipe); } ProxyReceiver normalizer = null; String normForm = props.getProperty(SaxonOutputKeys.NORMALIZATION_FORM); if (normForm != null && !normForm.equals("none")) { normalizer = newUnicodeNormalizer(pipe, props); } if ("html".equals(method)) { emitter = newHTMLEmitter(); emitter.setPipelineConfiguration(pipe); target = createHTMLSerializer(emitter, props, pipe, characterMapExpander, normalizer); } else if ("xml".equals(method)) { emitter = newXMLEmitter(); emitter.setPipelineConfiguration(pipe); target = createXMLSerializer(emitter, props, pipe, characterMapExpander, normalizer); } else if ("xhtml".equals(method)) { emitter = newXHTMLEmitter(); emitter.setPipelineConfiguration(pipe); target = createXHTMLSerializer(emitter, props, pipe, characterMapExpander, normalizer); } else if ("text".equals(method)) { emitter = newTEXTEmitter(); emitter.setPipelineConfiguration(pipe); target = createTextSerializer(emitter, props, pipe, characterMapExpander, normalizer); } else if (SaxonOutputKeys.SAXON_XQUERY_METHOD.equals(method)) { emitter = new XQueryEmitter(); emitter.setPipelineConfiguration(pipe); props.setProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); target = createXMLSerializer(emitter, props, pipe, characterMapExpander, normalizer); } else { Receiver userReceiver; if (pipe == null) { throw new XPathException("Unsupported serialization method " + method); } else { userReceiver = createUserDefinedOutputMethod(method, props, pipe); target = userReceiver; if (userReceiver instanceof Emitter) { emitter = (Emitter)userReceiver; } else { return userReceiver; } } } emitter.setOutputProperties(props); StreamResult sr = (StreamResult)result; emitter.setStreamResult(sr); return target; } else { if (pipe != null) { // try to find an external object model that knows this kind of Result List externalObjectModels = pipe.getConfiguration().getExternalObjectModels(); for (int m=0; m0) { ProxyReceiver filter = newCDATAFilter(pipe, props); filter.setUnderlyingReceiver(target); target = filter; } if (!"no".equals(props.getProperty(SaxonOutputKeys.ESCAPE_URI_ATTRIBUTES))) { ProxyReceiver escaper = newHTMLURIEscaper(pipe, props); escaper.setUnderlyingReceiver(target); target = escaper; } if (!"no".equals(props.getProperty(SaxonOutputKeys.INCLUDE_CONTENT_TYPE))) { ProxyReceiver mta = newXHTMLMetaTagAdjuster(pipe, props); mta.setUnderlyingReceiver(target); target=mta; } return target; } /** * Create a serialization pipeline to implement the XML output method. This method is protected * so that it can be customized in a user-written SerializerFactory * @param emitter the emitter at the end of the pipeline (created using the method {@link #newXHTMLEmitter} * @param props the serialization properties * @param pipe the pipeline configuration information * @param characterMapExpander the filter to be used for expanding character maps defined in the stylesheet * @param normalizer the filter used for Unicode normalization * @return a Receiver acting as the entry point to the serialization pipeline * @throws XPathException if a failure occurs */ protected Receiver createXMLSerializer( Emitter emitter, Properties props, PipelineConfiguration pipe, CharacterMapExpander characterMapExpander, ProxyReceiver normalizer) throws XPathException { Receiver target; target = emitter; if ("1.0".equals(props.getProperty(OutputKeys.VERSION)) && pipe.getConfiguration().getXMLVersion() == Configuration.XML11) { // Check result meets XML 1.0 constraints if configuration allows XML 1.1 input but // this result document must conform to 1.0 ProxyReceiver in = newXML10ContentChecker(pipe, props); in.setUnderlyingReceiver(target); target=in; } if ("yes".equals(props.getProperty(OutputKeys.INDENT))) { ProxyReceiver in = newXMLIndenter(pipe, props); in.setUnderlyingReceiver(target); target=in; } if (normalizer != null) { normalizer.setUnderlyingReceiver(target); target = normalizer; } if (characterMapExpander != null) { characterMapExpander.setUnderlyingReceiver(target); target = characterMapExpander; } String cdataElements = props.getProperty(OutputKeys.CDATA_SECTION_ELEMENTS); if (cdataElements!=null && cdataElements.length()>0) { ProxyReceiver filter = newCDATAFilter(pipe, props); filter.setUnderlyingReceiver(target); target = filter; } return target; } /** * Create a serialization pipeline to implement a user-defined output method. This method is protected * so that it can be customized in a user-written SerializerFactory * @param method the name of the user-defined output method, as a QName in Clark format * (that is "{uri}local"). * @param props the serialization properties * @param pipe the pipeline configuration information * @return a Receiver acting as the entry point to the serialization pipeline * @throws XPathException if a failure occurs */ protected Receiver createUserDefinedOutputMethod(String method, Properties props, PipelineConfiguration pipe) throws XPathException { Receiver userReceiver;// See if this output method is recognized by the Configuration userReceiver = pipe.getConfiguration().makeEmitter(method, pipe.getController()); userReceiver.setPipelineConfiguration(pipe); if (userReceiver instanceof ContentHandlerProxy && "yes".equals(props.getProperty(SaxonOutputKeys.SUPPLY_SOURCE_LOCATOR))) { if (pipe.getConfiguration().isCompileWithTracing()) { pipe.getController().addTraceListener( ((ContentHandlerProxy)userReceiver).getTraceListener()); } else { XPathException de = new XPathException( "Cannot use saxon:supply-source-locator unless tracing was enabled at compile time"); de.setErrorCode(SaxonErrorCode.SXSE0002); throw de; } } return userReceiver; } /** * Create a ContentHandlerProxy. This method exists so that it can be overridden in a subclass. * @return the newly created ContentHandlerProxy. */ protected ContentHandlerProxy newContentHandlerProxy() { return new ContentHandlerProxy(); } /** * Create an UncommittedSerializer. This method exists so that it can be overridden in a subclass. * @param result the result destination * @param properties the serialization properties * @return the newly created UncommittedSerializer. */ protected UncommittedSerializer newUncommittedSerializer(Result result, Properties properties) { return new UncommittedSerializer(result, properties); } /** * Create a new XML Emitter. This method exists so that it can be overridden in a subclass. * @return the newly created XML emitter. */ protected Emitter newXMLEmitter() { return new XMLEmitter(); } /** * Create a new HTML Emitter. This method exists so that it can be overridden in a subclass. * @return the newly created HTML emitter. */ protected Emitter newHTMLEmitter() { return new HTMLEmitter(); } /** * Create a new XHTML Emitter. This method exists so that it can be overridden in a subclass. * @return the newly created XHTML emitter. */ protected Emitter newXHTMLEmitter() { return new XHTMLEmitter(); } /** * Create a new Text Emitter. This method exists so that it can be overridden in a subclass. * @return the newly created text emitter. */ protected Emitter newTEXTEmitter() { return new TEXTEmitter(); } /** * Create a new XML Indenter. This method exists so that it can be overridden in a subclass. * @param pipe the pipeline configuration * @param outputProperties the serialization parameters * @return the newly created XML indenter. */ protected ProxyReceiver newXMLIndenter(PipelineConfiguration pipe, Properties outputProperties) { XMLIndenter r = new XMLIndenter(); r.setPipelineConfiguration(pipe); r.setOutputProperties(outputProperties); return r; } /** * Create a new HTML Indenter. This method exists so that it can be overridden in a subclass. * @param pipe the pipeline configuration * @param outputProperties the serialization parameters * @return the newly created HTML indenter. */ protected ProxyReceiver newHTMLIndenter(PipelineConfiguration pipe, Properties outputProperties) { HTMLIndenter r = new HTMLIndenter(); r.setPipelineConfiguration(pipe); r.setOutputProperties(outputProperties); return r; } /** * Create a new XHTML Indenter. This method exists so that it can be overridden in a subclass. * @param pipe the pipeline configuration * @param outputProperties the serialization parameters * @return the newly created XHTML indenter. */ protected ProxyReceiver newXHTMLIndenter(PipelineConfiguration pipe, Properties outputProperties) { XHTMLIndenter r = new XHTMLIndenter(); r.setPipelineConfiguration(pipe); r.setOutputProperties(outputProperties); return r; } /** * Create a new XHTML MetaTagAdjuster, responsible for insertion, removal, or replacement of meta * elements. This method exists so that it can be overridden in a subclass. * @param pipe the pipeline configuration * @param outputProperties the serialization parameters * @return the newly created XHTML MetaTagAdjuster. */ protected MetaTagAdjuster newXHTMLMetaTagAdjuster(PipelineConfiguration pipe, Properties outputProperties) { MetaTagAdjuster r = new MetaTagAdjuster(); r.setPipelineConfiguration(pipe); r.setOutputProperties(outputProperties); r.setIsXHTML(true); return r; } /** * Create a new XHTML MetaTagAdjuster, responsible for insertion, removal, or replacement of meta * elements. This method exists so that it can be overridden in a subclass. * @param pipe the pipeline configuration * @param outputProperties the serialization parameters * @return the newly created HTML MetaTagAdjuster. */ protected MetaTagAdjuster newHTMLMetaTagAdjuster(PipelineConfiguration pipe, Properties outputProperties) { MetaTagAdjuster r = new MetaTagAdjuster(); r.setPipelineConfiguration(pipe); r.setOutputProperties(outputProperties); r.setIsXHTML(false); return r; } /** * Create a new HTML URI Escaper, responsible for percent-encoding of URIs in * HTML output documents. This method exists so that it can be overridden in a subclass. * @param pipe the pipeline configuration * @param outputProperties the serialization parameters * @return the newly created HTML URI escaper. */ protected ProxyReceiver newHTMLURIEscaper(PipelineConfiguration pipe, Properties outputProperties) { HTMLURIEscaper r = new HTMLURIEscaper(); r.setPipelineConfiguration(pipe); return r; } /** * Create a new CDATA Filter, responsible for insertion of CDATA sections where required. * This method exists so that it can be overridden in a subclass. * @param pipe the pipeline configuration * @param outputProperties the serialization parameters * @return the newly created CDATA filter. */ protected ProxyReceiver newCDATAFilter(PipelineConfiguration pipe, Properties outputProperties) throws XPathException { CDATAFilter r = new CDATAFilter(); r.setPipelineConfiguration(pipe); r.setOutputProperties(outputProperties); return r; } /** * Create a new XML 1.0 content checker, responsible for checking that the output conforms to * XML 1.0 rules (this is used only if the Configuration supports XML 1.1 but the specific output * file requires XML 1.0). This method exists so that it can be overridden in a subclass. * @param pipe the pipeline configuration * @param outputProperties the serialization parameters * @return the newly created XML 1.0 content checker. */ protected ProxyReceiver newXML10ContentChecker(PipelineConfiguration pipe, Properties outputProperties) { XML10ContentChecker r = new XML10ContentChecker(); r.setPipelineConfiguration(pipe); return r; } /** * Create a Unicode Normalizer. This method exists so that it can be overridden in a subclass. * @param pipe the pipeline configuration * @param outputProperties the serialization parameters * @return the newly created Unicode normalizer. */ protected ProxyReceiver newUnicodeNormalizer(PipelineConfiguration pipe, Properties outputProperties) throws XPathException { String normForm = outputProperties.getProperty(SaxonOutputKeys.NORMALIZATION_FORM); UnicodeNormalizer r = new UnicodeNormalizer(normForm); r.setPipelineConfiguration(pipe); return r; } /** * Create a new CharacterMapExpander. This method exists so that it can be overridden in a subclass. * @return the newly created CharacterMapExpander. */ public CharacterMapExpander newCharacterMapExpander() { return new CharacterMapExpander(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. //saxonb-9.1.0.8/bj/net/sf/saxon/event/SequenceOutputter.java0000644000175000017500000001005711033112257023072 0ustar eugeneeugenepackage net.sf.saxon.event; import net.sf.saxon.om.*; import net.sf.saxon.value.EmptySequence; import net.sf.saxon.value.SequenceExtent; import net.sf.saxon.Controller; import java.util.ArrayList; /** * This outputter is used when writing a sequence of atomic values and nodes, that * is, when xsl:variable is used with content and an "as" attribute. The outputter * builds the sequence and provides access to it. (It isn't really an outputter at all, * it doesn't pass the events to anyone, it merely constructs the sequence in memory * and provides access to it). Note that the event sequence can include calls such as * startElement and endElement that require trees to be built. If nodes such as attributes * and text nodes are received while an element is being constructed, the nodes are added * to the tree. Otherwise, "orphan" nodes (nodes with no parent) are created and added * directly to the sequence. * *

    This class is not used to build temporary trees. For that, the ComplexContentOutputter * is used.

    * * * @author Michael H. Kay */ public final class SequenceOutputter extends SequenceWriter { private ArrayList list; private Controller controller; // enables the SequenceOutputter to be reused /** * Create a new SequenceOutputter */ public SequenceOutputter() { this.list = new ArrayList(50); } public SequenceOutputter(Controller controller, int estimatedSize) { this.list = new ArrayList(estimatedSize); this.controller = controller; } public SequenceOutputter(Controller controller) { this.list = new ArrayList(50); this.controller = controller; } /** * Clear the contents of the SequenceOutputter and make it available for reuse */ public void reset() { list = new ArrayList(Math.max(list.size()+10, 50)); if (controller != null && adviseReuse()) { controller.reuseSequenceOutputter(this); } } /** * Abstract method to be supplied by subclasses: output one item in the sequence. */ public void write(Item item) { list.add(item); } /** * Get the sequence that has been built */ public ValueRepresentation getSequence() { switch (list.size()) { case 0: return EmptySequence.getInstance(); case 1: return (Item)list.get(0); default: return new SequenceExtent(list); } } /** * Get an iterator over the sequence of items that has been constructed */ public SequenceIterator iterate() { if (list.isEmpty()) { return EmptyIterator.getInstance(); } else { return new ListIterator(list); } } /** * Get the list containing the sequence of items */ public ArrayList getList() { return list; } /** * Get the first item in the sequence that has been built */ public Item getFirstItem() { if (list.isEmpty()) { return null; } else { return (Item)list.get(0); } } /** * Get the last item in the sequence that has been built, and remove it */ public Item popLastItem() { if (list.isEmpty()) { return null; } else { return (Item)list.remove(list.size()-1); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/event/CopyInformee.java0000644000175000017500000000262411033112257021766 0ustar eugeneeugenepackage net.sf.saxon.event; import net.sf.saxon.om.NodeInfo; /** * A CopyInformee is a Receiver that receives extra information while a tree is being copied. Specifically, * each time an element node is copied to the receiver, before calling the startElement() method, the copying * code will first call notifyElementNode(), giving the Receiver extra information about the element currently * being copied. */ public interface CopyInformee extends Receiver { /** * Provide information about the node being copied. This method is called immediately before * the startElement call for the element node in question. * @param element the node being copied, which must be an element node */ public void notifyElementNode(NodeInfo element); } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/event/Builder.java0000644000175000017500000002542011033112257020754 0ustar eugeneeugenepackage net.sf.saxon.event; import net.sf.saxon.AugmentedSource; import net.sf.saxon.Configuration; import net.sf.saxon.om.DocumentInfo; import net.sf.saxon.om.NamePool; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.om.StrippedDocument; import net.sf.saxon.tinytree.TinyBuilder; import net.sf.saxon.tinytree.TinyDocumentImpl; import net.sf.saxon.trans.XPathException; import net.sf.saxon.tree.TreeBuilder; import javax.xml.transform.Source; import javax.xml.transform.dom.DOMSource; import java.util.Date; /** * The abstract Builder class is responsible for taking a stream of SAX events * and constructing a Document tree. There is one concrete subclass for each * tree implementation. * @author Michael H. Kay */ public abstract class Builder implements Receiver { /** * Constant denoting a request for the default tree model */ public static final int UNSPECIFIED_TREE_MODEL = -1; /** * Constant denoting the "linked tree" in which each node is represented as an object */ public static final int LINKED_TREE = 0; /** * Alternative constant denoting the "linked tree" in which each node is represented as an object * Retained for backwards compatibility */ public static final int STANDARD_TREE = 0; /** * Constant denoting the "tiny tree" in which the tree is represented internally using arrays of integers */ public static final int TINY_TREE = 1; protected PipelineConfiguration pipe; protected Configuration config; protected NamePool namePool; protected String systemId; protected String baseURI; protected NodeInfo currentRoot; protected boolean lineNumbering = false; protected boolean started = false; protected boolean timing = false; private boolean open = false; private long startTime; /** * create a Builder and initialise variables */ public Builder() { } public void setPipelineConfiguration(PipelineConfiguration pipe) { //System.err.println("Builder#setPipelineConfiguration pipe = " + pipe); // if (pipe == null) { // new NullPointerException("pipe not initialized").printStackTrace(); // } this.pipe = pipe; config = pipe.getConfiguration(); namePool = config.getNamePool(); lineNumbering = (lineNumbering || config.isLineNumbering()); } public PipelineConfiguration getPipelineConfiguration () { return pipe; } /** * Get the Configuration * @return the Saxon configuration */ public Configuration getConfiguration() { return config; } /** * The SystemId is equivalent to the document-uri property defined in the XDM data model. * It should be set only in the case of a document that is potentially retrievable via this URI. * This means it should not be set in the case of a temporary tree constructed in the course of * executing a query or transformation. * @param systemId the SystemId, that is, the document-uri. */ public void setSystemId(String systemId) { this.systemId = systemId; } /** * The SystemId is equivalent to the document-uri property defined in the XDM data model. * It should be set only in the case of a document that is potentially retrievable via this URI. * This means the value will be null in the case of a temporary tree constructed in the course of * executing a query or transformation. * @return the SystemId, that is, the document-uri. */ public String getSystemId() { return systemId; } /** * Set the base URI of the document node of the tree being constructed by this builder * @param baseURI the base URI */ public void setBaseURI(String baseURI) { this.baseURI = baseURI; } /** * Get the base URI of the document node of the tree being constructed by this builder * @return the base URI */ public String getBaseURI() { return baseURI; } ///////////////////////////////////////////////////////////////////////// // Methods setting and getting options for building the tree ///////////////////////////////////////////////////////////////////////// /** * Set line numbering on or off * @param lineNumbering set to true if line numbers are to be maintained for nodes in the tree being * constructed. */ public void setLineNumbering(boolean lineNumbering) { this.lineNumbering = lineNumbering; } /** * Set timing option on or off * @param on set to true to turn timing on. This causes the builder to display statistical information * about the tree that is constructed. It corresponds to the command line -t option */ public void setTiming(boolean on) { timing = on; } /** * Get timing option * @return true if timing information has been requested */ public boolean isTiming() { return timing; } public void open() throws XPathException { if (timing && !open) { System.err.println("Building tree for " + getSystemId() + " using " + getClass()); startTime = (new Date()).getTime(); } open = true; } public void close() throws XPathException { if (timing && open) { long endTime = (new Date()).getTime(); System.err.println("Tree built in " + (endTime - startTime) + " milliseconds"); if (currentRoot instanceof TinyDocumentImpl) { ((TinyDocumentImpl)currentRoot).showSize(); } startTime = endTime; } open = false; } /** * Start of a document node. * This event is ignored: we simply add the contained elements to the current document */ public void startDocument(int properties) throws XPathException { } /** * Notify the end of a document node */ public void endDocument() throws XPathException { } /** * Get the current root node. This will normally be a document node, but if the root of the tree * is an element node, it can be an element. * @return the root of the tree that is currently being built, or that has been most recently built * using this builder */ public NodeInfo getCurrentRoot() { return currentRoot; } /** * Reset the builder to its initial state. The most important effect of calling this * method (implemented in subclasses) is to release any links to the constructed document * tree, allowing the memory occupied by the tree to released by the garbage collector even * if the Builder is still in memory. This can happen because the Builder is referenced from a * parser in the Configuration's parser pool. */ public void reset() { pipe = null; config = null; namePool = null; systemId = null; baseURI = null; currentRoot = null; lineNumbering = false; started = false; timing = false; open = false; } /** * Static method to build a document from any kind of Source object. If the source * is already in the form of a tree, it is wrapped as required. *

    The preferred way to construct a document tree from a Source object is to * use the method {@link Configuration#buildDocument}.

    * @param source Any javax.xml.transform.Source object * @param stripper A stripper object, if whitespace text nodes are to be stripped; * otherwise null. * @param config The Configuration object * @return the NodeInfo of the start node in the resulting document object. */ public static NodeInfo build(Source source, Stripper stripper, Configuration config) throws XPathException { return build(source, stripper, config.makePipelineConfiguration()); } /** * Static method to build a document from any kind of Source object. If the source * is already in the form of a tree, it is wrapped as required. *

    The preferred way to construct a document tree from a Source object is to * use the method {@link Configuration#buildDocument}.

    * @param source Any javax.xml.transform.Source object * @param stripper A stripper object, if whitespace text nodes are to be stripped; * otherwise null. * @param pipe The PipelineConfiguration object * @return the NodeInfo of the start node in the resulting document object. */ public static NodeInfo build(Source source, Stripper stripper, PipelineConfiguration pipe) throws XPathException { Configuration config = pipe.getConfiguration(); if (source == null) { throw new NullPointerException("Source supplied to builder cannot be null"); } NodeInfo start; if (source instanceof DOMSource || source instanceof NodeInfo) { start = config.unravel(source); if (stripper != null) { DocumentInfo docInfo = start.getDocumentRoot(); StrippedDocument strippedDoc = new StrippedDocument(docInfo, stripper); start = strippedDoc.wrap(start); } } else { // we have a SAXSource or StreamSource Builder b; if (config.getTreeModel() == Builder.TINY_TREE) { b = new TinyBuilder(); } else { b = new TreeBuilder(); } b.setPipelineConfiguration(pipe); if (config.isLineNumbering() || (source instanceof AugmentedSource && ((AugmentedSource)source).isLineNumbering())) { b.setLineNumbering(true); } Receiver receiver = b; if (stripper != null) { stripper.setUnderlyingReceiver(b); receiver = stripper; } try { new Sender(pipe).send(source, receiver); } catch (XPathException err) { throw XPathException.makeXPathException(err); } start = b.getCurrentRoot(); b.reset(); } return start; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/event/Stripper.java0000644000175000017500000002305511033112257021200 0ustar eugeneeugenepackage net.sf.saxon.event; import net.sf.saxon.Controller; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.om.Orphan; import net.sf.saxon.om.StandardNames; import net.sf.saxon.trans.Mode; import net.sf.saxon.trans.Rule; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ComplexType; import net.sf.saxon.type.SchemaType; import net.sf.saxon.type.Type; import net.sf.saxon.value.Whitespace; /** * The Stripper class maintains details of which elements need to be stripped. * The code is written to act as a SAX-like filter to do the stripping. * @author Michael H. Kay */ public class Stripper extends ProxyReceiver { private boolean preserveAll; // true if all elements have whitespace preserved private boolean stripAll; // true if all whitespace nodes are stripped // stripStack is used to hold information used while stripping nodes. We avoid allocating // space on the tree itself to keep the size of nodes down. Each entry on the stack is two // booleans, one indicates the current value of xml-space is "preserve", the other indicates // that we are in a space-preserving element. // We implement our own stack to avoid the overhead of allocating objects. The two booleans // are held as the ls bits of a byte. private byte[] stripStack = new byte[100]; private int top = 0; // We use a collection of rules to determine whether to strip spaces; a collection // of rules is known as a Mode. (We are reusing the code for template rule matching) private Mode stripperMode; // Mode expects to test an Element, so we create a dummy element for it to test private Orphan element; // Stripper needs a context (a) for evaluating patterns // and (b) to provide reporting of rule conflicts. private XPathContext context; /** * Default constructor for use in subclasses */ protected Stripper() {} /** * create a Stripper and initialise variables * @param stripperRules defines which elements have whitespace stripped. If * null, all whitespace is preserved. */ public Stripper(Mode stripperRules) { stripperMode = stripperRules; preserveAll = (stripperRules==null); stripAll = false; } /** * Set the XPath context */ public void setXPathContext(XPathContext context) { this.context = context; } /** * Get a clean copy of this stripper */ public Stripper getAnother() { Stripper clone = new Stripper(stripperMode); clone.setPipelineConfiguration(getPipelineConfiguration()); clone.stripAll = stripAll; clone.preserveAll = preserveAll; return clone; } /** * Specify that all whitespace nodes are to be stripped */ public void setStripAll() { preserveAll = false; stripAll = true; } /** * Determine if all whitespace is to be stripped (in this case, no further testing * is needed) */ public boolean getStripAll() { return stripAll; } public void setPipelineConfiguration(PipelineConfiguration pipe) { if (pipe != null) { super.setPipelineConfiguration(pipe); if (context == null) { Controller controller = pipe.getController(); if (controller != null) { context = controller.newXPathContext(); } } if (element == null) { element = new Orphan(pipe.getConfiguration()); element.setNodeKind(Type.ELEMENT); } } } /** * Decide whether an element is in the set of white-space preserving element types * @param nameCode Identifies the name of the element whose whitespace is to * be preserved * @return ALWAYS_PRESERVE if the element is in the set of white-space preserving * element types, ALWAYS_STRIP if the element is to be stripped regardless of the * xml:space setting, and STRIP_DEFAULT otherwise */ public byte isSpacePreserving(int nameCode) throws XPathException { //try { if (preserveAll) return ALWAYS_PRESERVE; if (stripAll) return STRIP_DEFAULT; element.setNameCode(nameCode); Rule rule = stripperMode.getRule(element, context); if (rule==null) return ALWAYS_PRESERVE; return (((Boolean)rule.getAction()).booleanValue() ? ALWAYS_PRESERVE : STRIP_DEFAULT); // } catch (XPathException err) { // return ALWAYS_PRESERVE; // } } public static final byte ALWAYS_PRESERVE = 0x01; // whitespace always preserved (e.g. xsl:text) public static final byte ALWAYS_STRIP = 0x02; // whitespace always stripped (e.g. xsl:choose) public static final byte STRIP_DEFAULT = 0x00; // no special action public static final byte PRESERVE_PARENT = 0x04; // parent element specifies xml:space="preserve" public static final byte CANNOT_STRIP = 0x08; // type annotation indicates simple typed content /** * Decide whether an element is in the set of white-space preserving element types. * This version of the method is useful in cases where getting the namecode of the * element is potentially expensive, e.g. with DOM nodes. * @param element Identifies the element whose whitespace is possibly to * be preserved * @return ALWAYS_PRESERVE if the element is in the set of white-space preserving * element types, ALWAYS_STRIP if the element is to be stripped regardless of the * xml:space setting, and STRIP_DEFAULT otherwise */ public byte isSpacePreserving(NodeInfo element) throws XPathException { // try { if (preserveAll) return ALWAYS_PRESERVE; if (stripAll) return STRIP_DEFAULT; Rule rule = stripperMode.getRule(element, context); if (rule==null) return ALWAYS_PRESERVE; return (((Boolean)rule.getAction()).booleanValue() ? ALWAYS_PRESERVE : STRIP_DEFAULT); // } catch (XPathException err) { // return ALWAYS_PRESERVE; // } } /** * Callback interface for SAX: not for application use */ public void open () throws XPathException { // System.err.println("Stripper#startDocument()"); top = 0; stripStack[top] = ALWAYS_PRESERVE; // {xml:preserve = false, preserve this element = true} super.open(); } public void startElement (int nameCode, int typeCode, int locationId, int properties) throws XPathException { // System.err.println("startElement " + nameCode); nextReceiver.startElement(nameCode, typeCode, locationId, properties); byte preserveParent = stripStack[top]; byte preserve = (byte)(preserveParent & PRESERVE_PARENT); byte elementStrip = isSpacePreserving(nameCode); if (elementStrip == ALWAYS_PRESERVE) { preserve |= ALWAYS_PRESERVE; } else if (elementStrip == ALWAYS_STRIP) { preserve |= ALWAYS_STRIP; } if (preserve == 0 && typeCode != -1 && typeCode != StandardNames.XS_UNTYPED) { // if the element has simple content, whitespace stripping is disabled SchemaType type = getConfiguration().getSchemaType(typeCode); if (type.isSimpleType() || ((ComplexType)type).isSimpleContent()) { preserve |= CANNOT_STRIP; } } // put "preserve" value on top of stack top++; if (top >= stripStack.length) { byte[] newStack = new byte[top*2]; System.arraycopy(stripStack, 0, newStack, 0, top); stripStack = newStack; } stripStack[top] = preserve; } public void attribute(int nameCode, int typeCode, CharSequence value, int locationId, int properties) throws XPathException { // test for xml:space="preserve" | "default" if ((nameCode & 0xfffff) == StandardNames.XML_SPACE) { if (value.toString().equals("preserve")) { stripStack[top] |= PRESERVE_PARENT; } else { stripStack[top] &= ~PRESERVE_PARENT; } } nextReceiver.attribute(nameCode, typeCode, value, locationId, properties); } /** * Handle an end-of-element event */ public void endElement () throws XPathException { nextReceiver.endElement(); top--; } /** * Handle a text node */ public void characters (CharSequence chars, int locationId, int properties) throws XPathException { // assume adjacent chunks of text are already concatenated if (((((stripStack[top] & (ALWAYS_PRESERVE | PRESERVE_PARENT | CANNOT_STRIP)) != 0) && (stripStack[top] & ALWAYS_STRIP) == 0) || !Whitespace.isWhite(chars)) && chars.length() > 0) { nextReceiver.characters(chars, locationId, properties); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/event/MessageEmitter.java0000644000175000017500000000300111033112257022273 0ustar eugeneeugenepackage net.sf.saxon.event; import net.sf.saxon.trans.XPathException; /** * MessageEmitter is the default Receiver for xsl:message output. * It is the same as XMLEmitter except for an extra newline at the end of the message */ public class MessageEmitter extends XMLEmitter { public void endDocument() throws XPathException { try { writer.write('\n'); } catch (java.io.IOException err) { throw new XPathException(err); } super.close(); } public void close() throws XPathException { try { if (writer != null) { writer.flush(); } } catch (java.io.IOException err) { throw new XPathException(err); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/event/HTMLEmitter.java0000644000175000017500000007017311136334262021477 0ustar eugeneeugenepackage net.sf.saxon.event; import net.sf.saxon.tinytree.CompressedWhitespace; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.Whitespace; import javax.xml.transform.OutputKeys; /** * This class generates HTML output * @author Michael H. Kay */ public class HTMLEmitter extends XMLEmitter { /** * Preferred character representations */ private static final int REP_NATIVE = 0; private static final int REP_ENTITY = 1; private static final int REP_DECIMAL = 2; private static final int REP_HEX = 3; private int nonASCIIRepresentation = REP_NATIVE; private int excludedRepresentation = REP_ENTITY; private int inScript; private boolean started = false; private String elementName; private short uriCode; /** * Decode preferred representation * @param rep string containing preferred representation (native, entity, decimal, or hex) * @return integer code for the preferred representation */ private static int representationCode(String rep) { if (rep.equalsIgnoreCase("native")) return REP_NATIVE; if (rep.equalsIgnoreCase("entity")) return REP_ENTITY; if (rep.equalsIgnoreCase("decimal")) return REP_DECIMAL; if (rep.equalsIgnoreCase("hex")) return REP_HEX; return REP_ENTITY; } /** * Table of HTML tags that have no closing tag */ static HTMLTagHashSet emptyTags = new HTMLTagHashSet(31); static { setEmptyTag("area"); setEmptyTag("base"); setEmptyTag("basefont"); setEmptyTag("br"); setEmptyTag("col"); setEmptyTag("frame"); setEmptyTag("hr"); setEmptyTag("img"); setEmptyTag("input"); setEmptyTag("isindex"); setEmptyTag("link"); setEmptyTag("meta"); setEmptyTag("param"); } private static void setEmptyTag(String tag) { emptyTags.add(tag); } protected static boolean isEmptyTag(String tag) { return emptyTags.contains(tag); } /** * Table of boolean attributes */ // we use two HashMaps to avoid unnecessary string concatenations private static HTMLTagHashSet booleanAttributes = new HTMLTagHashSet(31); private static HTMLTagHashSet booleanCombinations = new HTMLTagHashSet(53); static { setBooleanAttribute("area", "nohref"); setBooleanAttribute("button", "disabled"); setBooleanAttribute("dir", "compact"); setBooleanAttribute("dl", "compact"); setBooleanAttribute("frame", "noresize"); setBooleanAttribute("hr", "noshade"); setBooleanAttribute("img", "ismap"); setBooleanAttribute("input", "checked"); setBooleanAttribute("input", "disabled"); setBooleanAttribute("input", "readonly"); setBooleanAttribute("menu", "compact"); setBooleanAttribute("object", "declare"); setBooleanAttribute("ol", "compact"); setBooleanAttribute("optgroup", "disabled"); setBooleanAttribute("option", "selected"); setBooleanAttribute("option", "disabled"); setBooleanAttribute("script", "defer"); setBooleanAttribute("select", "multiple"); setBooleanAttribute("select", "disabled"); setBooleanAttribute("td", "nowrap"); setBooleanAttribute("textarea", "disabled"); setBooleanAttribute("textarea", "readonly"); setBooleanAttribute("th", "nowrap"); setBooleanAttribute("ul", "compact"); } private static void setBooleanAttribute(String element, String attribute) { booleanAttributes.add(attribute); booleanCombinations.add(element + '+' + attribute); } private static boolean isBooleanAttribute(String element, String attribute, String value) { return attribute.equalsIgnoreCase(value) && booleanAttributes.contains(attribute) && booleanCombinations.contains(element + '+' + attribute); } /** * Constructor */ public HTMLEmitter() { } /** * Output start of document */ public void open() throws XPathException {} protected void openDocument() throws XPathException { if (writer==null) { makeWriter(); } if (started) return; started = true; // This method is sometimes called twice, especially during an identity transform // This check stops two DOCTYPE declarations being output. String version = outputProperties.getProperty(OutputKeys.VERSION); if (version != null && !(version.equals("4.0") || version.equals("4.01"))) { XPathException err = new XPathException("Unsupported HTML version: " + version); err.setErrorCode("SESU0013"); throw err; } String byteOrderMark = outputProperties.getProperty(SaxonOutputKeys.BYTE_ORDER_MARK); if ("yes".equals(byteOrderMark) && "UTF-8".equalsIgnoreCase(outputProperties.getProperty(OutputKeys.ENCODING))) { try { writer.write('\uFEFF'); } catch (java.io.IOException err) { // Might be an encoding exception; just ignore it } } String systemId = outputProperties.getProperty(OutputKeys.DOCTYPE_SYSTEM); String publicId = outputProperties.getProperty(OutputKeys.DOCTYPE_PUBLIC); if (systemId!=null || publicId!=null) { writeDocType("html", systemId, publicId); } empty = false; inScript = -1000000; // Handle saxon:character-representation String representation = outputProperties.getProperty( SaxonOutputKeys.CHARACTER_REPRESENTATION); if (representation != null) { String nonASCIIrep; String excludedRep; int semi = representation.indexOf(';'); if (semi < 0) { nonASCIIrep = Whitespace.trim(representation); excludedRep = nonASCIIrep; } else { nonASCIIrep = Whitespace.trim(representation.substring(0, semi)); excludedRep = Whitespace.trim(representation.substring(semi+1)); } nonASCIIRepresentation = representationCode(nonASCIIrep); excludedRepresentation = representationCode(excludedRep); if (excludedRepresentation == REP_NATIVE) { excludedRepresentation = REP_ENTITY; } } } /** * Output element start tag */ public void startElement(int nameCode, int typeCode, int locationId, int properties) throws XPathException { super.startElement(nameCode, typeCode, locationId, properties); uriCode = namePool.getURICode(nameCode); elementName = (String)elementStack.peek(); if (uriCode==0 && ( elementName.equalsIgnoreCase("script") || elementName.equalsIgnoreCase("style"))) { inScript = 0; } inScript++; } public void startContent() throws XPathException { closeStartTag(); // prevent syntax } /** * Write attribute name=value pair. Overrides the XML behaviour if the name and value * are the same (we assume this is a boolean attribute to be minimised), or if the value is * a URL. */ protected void writeAttribute(int elCode, String attname, CharSequence value, int properties) throws XPathException { try { if (uriCode==0) { if (isBooleanAttribute(elementName, attname, value.toString())) { writer.write(attname); return; } } super.writeAttribute(elCode, attname, value, properties); } catch (java.io.IOException err) { throw new XPathException(err); } } /** * Escape characters. Overrides the XML behaviour */ protected void writeEscape(final CharSequence chars, final boolean inAttribute) throws java.io.IOException, XPathException { int segstart = 0; final boolean[] specialChars = (inAttribute ? specialInAtt : specialInText); if (chars instanceof CompressedWhitespace) { ((CompressedWhitespace)chars).writeEscape(specialChars, writer); return; } boolean disabled = false; while (segstart < chars.length()) { int i = segstart; // find a maximal sequence of "ordinary" characters if (nonASCIIRepresentation == REP_NATIVE) { char c; while (i < chars.length() && ((c = chars.charAt(i)) < 127 ? !specialChars[c] : (characterSet.inCharset(c) && c > 160) ) ) { i++; } } else { char c; while (i < chars.length() && (c = chars.charAt(i)) < 127 && !specialChars[c]) { i++; } } // if this was the whole string, output the string and quit if (i == chars.length()) { if (segstart == 0) { writeCharSequence(chars); } else { writeCharSequence(chars.subSequence(segstart, i)); } return; } // otherwise, output this sequence and continue if (i > segstart) { writeCharSequence(chars.subSequence(segstart, i)); } final char c = chars.charAt(i); if (c==0) { // used to switch escaping on and off disabled = !disabled; } else if (disabled) { writer.write(c); } else if (c<=127) { // handle a special ASCII character if (inAttribute) { if (c=='<') { writer.write('<'); // not escaped } else if (c=='>') { writer.write(">"); // recommended for older browsers } else if (c=='&') { if (i+1') { writer.write(">"); // changed to allow for "]]>" } else if (c=='&') { writer.write("&"); } else if (c=='\r') { writer.write(" "); } } } else if (c==160) { // always output NBSP as an entity reference writer.write(" "); } else if (c>=127 && c<160) { // these control characters are illegal in HTML XPathException err = new XPathException("Illegal HTML character: decimal " + (int)c); err.setErrorCode("SERE0014"); throw err; } else if (c>=55296 && c<=56319) { //handle surrogate pair //A surrogate pair is two consecutive Unicode characters. The first //is in the range D800 to DBFF, the second is in the range DC00 to DFFF. //To compute the numeric value of the character corresponding to a surrogate //pair, use this formula (all numbers are hex): //(FirstChar - D800) * 400 + (SecondChar - DC00) + 10000 // we'll trust the data to be sound int charval = (((int)c - 55296) * 1024) + ((int)chars.charAt(i+1) - 56320) + 65536; outputCharacterReference(charval); i++; } else if (characterSet.inCharset(c)) { switch(nonASCIIRepresentation) { case REP_NATIVE: writer.write(c); break; case REP_ENTITY: if (c>160 && c<=255) { // if chararacter in iso-8859-1, use an entity reference writer.write('&'); writer.write(latin1Entities[(int)c-160]); writer.write(';'); break; } // else fall through case REP_DECIMAL: preferHex = false; outputCharacterReference(c); break; case REP_HEX: preferHex = true; // fall through default: outputCharacterReference(c); break; } } else { // Character not present in encoding switch(excludedRepresentation) { case REP_ENTITY: if (c>160 && c<=255) { // if chararacter in iso-8859-1, use an entity reference writer.write('&'); writer.write(latin1Entities[(int)c-160]); writer.write(';'); break; } // else fall through case REP_NATIVE: case REP_DECIMAL: preferHex = false; outputCharacterReference(c); break; case REP_HEX: preferHex = true; // fall through default: outputCharacterReference(c); break; } } segstart = ++i; } } /** * Output an element end tag. */ public void endElement() throws XPathException { String name = (String)elementStack.peek(); inScript--; if (inScript==0) { inScript = -1000000; } if (isEmptyTag(name) && uriCode==0) { // no end tag required elementStack.pop(); } else { super.endElement(); } } /** * Character data. */ public void characters (CharSequence chars, int locationId, int properties) throws XPathException { int options = properties; if (inScript>0) { options |= ReceiverOptions.DISABLE_ESCAPING; } super.characters(chars, locationId, options); } /** * Handle a processing instruction. */ public void processingInstruction (String target, CharSequence data, int locationId, int properties) throws XPathException { if (empty) { openDocument(); } for (int i=0; i') { XPathException err = new XPathException("A processing instruction in HTML must not contain a > character"); err.setErrorCode("SERE0015"); throw err; } } try { writer.write("'); } catch (java.io.IOException err) { throw new XPathException(err); } } private static final String[] latin1Entities = { "nbsp", // " " -- no-break space = non-breaking space, // U+00A0 ISOnum --> "iexcl", // "¡" -- inverted exclamation mark, U+00A1 ISOnum --> "cent", // "¢" -- cent sign, U+00A2 ISOnum --> "pound", // "£" -- pound sign, U+00A3 ISOnum --> "curren", // "¤" -- currency sign, U+00A4 ISOnum --> "yen", // "¥" -- yen sign = yuan sign, U+00A5 ISOnum --> "brvbar", // "¦" -- broken bar = broken vertical bar, // U+00A6 ISOnum --> "sect", // "§" -- section sign, U+00A7 ISOnum --> "uml", // "¨" -- diaeresis = spacing diaeresis, // U+00A8 ISOdia --> "copy", // "©" -- copyright sign, U+00A9 ISOnum --> "ordf", // "ª" -- feminine ordinal indicator, U+00AA ISOnum --> "laquo", // "«" -- left-pointing double angle quotation mark // = left pointing guillemet, U+00AB ISOnum --> "not", // "¬" -- not sign, U+00AC ISOnum --> "shy", // "­" -- soft hyphen = discretionary hyphen, // U+00AD ISOnum --> "reg", // "®" -- registered sign = registered trade mark sign, // U+00AE ISOnum --> "macr", // "¯" -- macron = spacing macron = overline // = APL overbar, U+00AF ISOdia --> "deg", // "°" -- degree sign, U+00B0 ISOnum --> "plusmn", // "±" -- plus-minus sign = plus-or-minus sign, // U+00B1 ISOnum --> "sup2", // "²" -- superscript two = superscript digit two // = squared, U+00B2 ISOnum --> "sup3", // "³" -- superscript three = superscript digit three // = cubed, U+00B3 ISOnum --> "acute", // "´" -- acute accent = spacing acute, // U+00B4 ISOdia --> "micro", // "µ" -- micro sign, U+00B5 ISOnum --> "para", // "¶" -- pilcrow sign = paragraph sign, // U+00B6 ISOnum --> "middot", // "·" -- middle dot = Georgian comma // = Greek middle dot, U+00B7 ISOnum --> "cedil", // "¸" -- cedilla = spacing cedilla, U+00B8 ISOdia --> "sup1", // "¹" -- superscript one = superscript digit one, // U+00B9 ISOnum --> "ordm", // "º" -- masculine ordinal indicator, // U+00BA ISOnum --> "raquo", // "»" -- right-pointing double angle quotation mark // = right pointing guillemet, U+00BB ISOnum --> "frac14", // "¼" -- vulgar fraction one quarter // = fraction one quarter, U+00BC ISOnum --> "frac12", // "½" -- vulgar fraction one half // = fraction one half, U+00BD ISOnum --> "frac34", // "¾" -- vulgar fraction three quarters // = fraction three quarters, U+00BE ISOnum --> "iquest", // "¿" -- inverted question mark // = turned question mark, U+00BF ISOnum --> "Agrave", // "À" -- latin capital letter A with grave // = latin capital letter A grave, // U+00C0 ISOlat1 --> "Aacute", // "Á" -- latin capital letter A with acute, // U+00C1 ISOlat1 --> "Acirc", // "Â" -- latin capital letter A with circumflex, // U+00C2 ISOlat1 --> "Atilde", // "Ã" -- latin capital letter A with tilde, // U+00C3 ISOlat1 --> "Auml", // "Ä" -- latin capital letter A with diaeresis, // U+00C4 ISOlat1 --> "Aring", // "Å" -- latin capital letter A with ring above // = latin capital letter A ring, // U+00C5 ISOlat1 --> "AElig", // "Æ" -- latin capital letter AE // = latin capital ligature AE, // U+00C6 ISOlat1 --> "Ccedil", // "Ç" -- latin capital letter C with cedilla, // U+00C7 ISOlat1 --> "Egrave", // "È" -- latin capital letter E with grave, // U+00C8 ISOlat1 --> "Eacute", // "É" -- latin capital letter E with acute, // U+00C9 ISOlat1 --> "Ecirc", // "Ê" -- latin capital letter E with circumflex, // U+00CA ISOlat1 --> "Euml", // "Ë" -- latin capital letter E with diaeresis, // U+00CB ISOlat1 --> "Igrave", // "Ì" -- latin capital letter I with grave, // U+00CC ISOlat1 --> "Iacute", // "Í" -- latin capital letter I with acute, // U+00CD ISOlat1 --> "Icirc", // "Î" -- latin capital letter I with circumflex, // U+00CE ISOlat1 --> "Iuml", // "Ï" -- latin capital letter I with diaeresis, // U+00CF ISOlat1 --> "ETH", // "Ð" -- latin capital letter ETH, U+00D0 ISOlat1 --> "Ntilde", // "Ñ" -- latin capital letter N with tilde, // U+00D1 ISOlat1 --> "Ograve", // "Ò" -- latin capital letter O with grave, // U+00D2 ISOlat1 --> "Oacute", // "Ó" -- latin capital letter O with acute, // U+00D3 ISOlat1 --> "Ocirc", // "Ô" -- latin capital letter O with circumflex, // U+00D4 ISOlat1 --> "Otilde", // "Õ" -- latin capital letter O with tilde, // U+00D5 ISOlat1 --> "Ouml", // "Ö" -- latin capital letter O with diaeresis, // U+00D6 ISOlat1 --> "times", // "×" -- multiplication sign, U+00D7 ISOnum --> "Oslash", // "Ø" -- latin capital letter O with stroke // = latin capital letter O slash, // U+00D8 ISOlat1 --> "Ugrave", // "Ù" -- latin capital letter U with grave, // U+00D9 ISOlat1 --> "Uacute", // "Ú" -- latin capital letter U with acute, // U+00DA ISOlat1 --> "Ucirc", // "Û" -- latin capital letter U with circumflex, // U+00DB ISOlat1 --> "Uuml", // "Ü" -- latin capital letter U with diaeresis, // U+00DC ISOlat1 --> "Yacute", // "Ý" -- latin capital letter Y with acute, // U+00DD ISOlat1 --> "THORN", // "Þ" -- latin capital letter THORN, // U+00DE ISOlat1 --> "szlig", // "ß" -- latin small letter sharp s = ess-zed, // U+00DF ISOlat1 --> "agrave", // "à" -- latin small letter a with grave // = latin small letter a grave, // U+00E0 ISOlat1 --> "aacute", // "á" -- latin small letter a with acute, // U+00E1 ISOlat1 --> "acirc", // "â" -- latin small letter a with circumflex, // U+00E2 ISOlat1 --> "atilde", // "ã" -- latin small letter a with tilde, // U+00E3 ISOlat1 --> "auml", // "ä" -- latin small letter a with diaeresis, // U+00E4 ISOlat1 --> "aring", // "å" -- latin small letter a with ring above // = latin small letter a ring, // U+00E5 ISOlat1 --> "aelig", // "æ" -- latin small letter ae // = latin small ligature ae, U+00E6 ISOlat1 --> "ccedil", // "ç" -- latin small letter c with cedilla, // U+00E7 ISOlat1 --> "egrave", // "è" -- latin small letter e with grave, // U+00E8 ISOlat1 --> "eacute", // "é" -- latin small letter e with acute, // U+00E9 ISOlat1 --> "ecirc", // "ê" -- latin small letter e with circumflex, // U+00EA ISOlat1 --> "euml", // "ë" -- latin small letter e with diaeresis, // U+00EB ISOlat1 --> "igrave", // "ì" -- latin small letter i with grave, // U+00EC ISOlat1 --> "iacute", // "í" -- latin small letter i with acute, // U+00ED ISOlat1 --> "icirc", // "î" -- latin small letter i with circumflex, // U+00EE ISOlat1 --> "iuml", // "ï" -- latin small letter i with diaeresis, // U+00EF ISOlat1 --> "eth", // "ð" -- latin small letter eth, U+00F0 ISOlat1 --> "ntilde", // "ñ" -- latin small letter n with tilde, // U+00F1 ISOlat1 --> "ograve", // "ò" -- latin small letter o with grave, // U+00F2 ISOlat1 --> "oacute", // "ó" -- latin small letter o with acute, // U+00F3 ISOlat1 --> "ocirc", // "ô" -- latin small letter o with circumflex, // U+00F4 ISOlat1 --> "otilde", // "õ" -- latin small letter o with tilde, // U+00F5 ISOlat1 --> "ouml", // "ö" -- latin small letter o with diaeresis, // U+00F6 ISOlat1 --> "divide", // "÷" -- division sign, U+00F7 ISOnum --> "oslash", // "ø" -- latin small letter o with stroke, // = latin small letter o slash, // U+00F8 ISOlat1 --> "ugrave", // "ù" -- latin small letter u with grave, // U+00F9 ISOlat1 --> "uacute", // "ú" -- latin small letter u with acute, // U+00FA ISOlat1 --> "ucirc", // "û" -- latin small letter u with circumflex, // U+00FB ISOlat1 --> "uuml", // "ü" -- latin small letter u with diaeresis, // U+00FC ISOlat1 --> "yacute", // "ý" -- latin small letter y with acute, // U+00FD ISOlat1 --> "thorn", // "þ" -- latin small letter thorn, // U+00FE ISOlat1 --> "yuml" // "ÿ" -- latin small letter y with diaeresis, // U+00FF ISOlat1 --> }; } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/event/PIGrabber.java0000644000175000017500000001306011033112257021160 0ustar eugeneeugenepackage net.sf.saxon.event; import net.sf.saxon.Configuration; import net.sf.saxon.StandardURIResolver; import net.sf.saxon.om.ProcInstParser; import net.sf.saxon.trans.XPathException; import javax.xml.transform.Source; import javax.xml.transform.TransformerException; import javax.xml.transform.URIResolver; import javax.xml.transform.sax.SAXSource; import java.util.ArrayList; /** * The PIGrabber class is a Receiver that looks for xml-stylesheet processing * instructions and tests whether they match specified criteria; for those that do, it creates * an InputSource object referring to the relevant stylesheet * @author Michael H. Kay */ public class PIGrabber extends ProxyReceiver { private Configuration config = null; private String reqMedia = null; private String reqTitle = null; private String baseURI = null; private URIResolver uriResolver = null; private ArrayList stylesheets = new ArrayList(); private boolean terminated = false; public void setFactory(Configuration config) { this.config = config; } public void setCriteria(String media, String title, String charset) { this.reqMedia = media; this.reqTitle = title; } /** * Set the base URI */ public void setBaseURI(String uri) { baseURI = uri; } /** * Set the URI resolver to be used for the href attribute */ public void setURIResolver(URIResolver resolver) { uriResolver = resolver; } public void open() { nextReceiver = new Sink(); } /** * Abort the parse when the first start element tag is found */ public void startElement (int namecode, int typecode, int locationId, int properties) throws XPathException { terminated = true; // abort the parse when the first start element tag is found throw new XPathException("#start#"); } /** * Determine whether the parse terminated because the first start element tag was found */ public boolean isTerminated() { return terminated; } /** * Handle xml-stylesheet PI */ public void processingInstruction(String target, CharSequence data, int locationId, int properties) throws XPathException { if (target.equals("xml-stylesheet")) { String value = data.toString(); String piMedia = ProcInstParser.getPseudoAttribute(value, "media"); String piTitle = ProcInstParser.getPseudoAttribute(value, "title"); String piType = ProcInstParser.getPseudoAttribute(value, "type"); String piAlternate = ProcInstParser.getPseudoAttribute(value, "alternate"); if (piType==null) return; // System.err.println("Found xml-stylesheet media=" + piMedia + " title=" + piTitle); if ( (piType.equals("text/xml") || piType.equals("application/xml") || piType.equals("text/xsl") || piType.equals("applicaton/xsl") || piType.equals("application/xml+xslt")) && (reqMedia==null || piMedia==null || reqMedia.equals(piMedia)) && ( ( piTitle==null && (piAlternate==null || piAlternate.equals("no"))) || ( reqTitle==null ) || ( piTitle!=null && piTitle.equals(reqTitle) ) ) ) { String href = ProcInstParser.getPseudoAttribute(value, "href"); if (href==null) { throw new XPathException("xml-stylesheet PI has no href attribute"); } // System.err.println("Adding " + href); if (piTitle==null && (piAlternate==null || piAlternate.equals("no"))) { stylesheets.add(0, href); } else { stylesheets.add(href); } } else { //System.err.println("No match on required media=" + reqMedia + " title=" + reqTitle ); } } } /** * Return list of stylesheets that matched, as an array of Source objects * @return null if there were no matching stylesheets. * @throws net.sf.saxon.trans.XPathException if a URI cannot be resolved */ public Source[] getAssociatedStylesheets() throws TransformerException { if (stylesheets.size()==0) { return null; } if (uriResolver==null) { uriResolver = new StandardURIResolver(config); } Source[] result = new Source[stylesheets.size()]; for (int i=0; iafter the startElement event, and before * any children for the element. The namespaces that are reported are only required * to include those that are different from the parent element; however, duplicates may be reported. * A namespace must not conflict with any namespaces already used for element or attribute names. * * @param namespaceCode an integer: the top half is a prefix code, the bottom half a URI code. * These may be translated into an actual prefix and URI using the name pool. A prefix code of * zero represents the empty prefix (that is, the default namespace). A URI code of zero represents * a URI of "", that is, a namespace undeclaration. * @throws java.lang.IllegalStateException: * attempt to output a namespace when there is no open element * start tag */ public void namespace(int namespaceCode, int properties) throws XPathException { } /** * Notify an attribute. Attributes are notified after the startElement event, and before any * children. Namespaces and attributes may be intermingled. * * @param nameCode The name of the attribute, as held in the name pool * @param typeCode The type of the attribute, as held in the name pool * @param properties Bit significant value. The following bits are defined: *
    DISABLE_ESCAPING
    Disable escaping for this attribute
    *
    NO_SPECIAL_CHARACTERS
    Attribute value contains no special characters
    * @throws java.lang.IllegalStateException: * attempt to output an attribute when there is no open element * start tag */ public void attribute(int nameCode, int typeCode, CharSequence value, int locationId, int properties) throws XPathException { } /** * Notify the start of the content, that is, the completion of all attributes and namespaces. * Note that the initial receiver of output from XSLT instructions will not receive this event, * it has to detect it itself. Note that this event is reported for every element even if it has * no attributes, no namespaces, and no content. */ public void startContent() throws XPathException { } /** * End of element */ public void endElement() throws XPathException { } /** * Character data */ public void characters(CharSequence chars, int locationId, int properties) throws XPathException { } /** * Processing Instruction */ public void processingInstruction(String target, CharSequence data, int locationId, int properties) throws XPathException { } /** * Output a comment */ public void comment(CharSequence chars, int locationId, int properties) throws XPathException { } /** * Append an arbitrary item (node or atomic value) to the output * * @param item the item to be appended * @param locationId the location of the calling instruction, for diagnostics * @param copyNamespaces if the item is an element node, this indicates whether its namespaces * need to be copied. Values are {@link net.sf.saxon.om.NodeInfo#ALL_NAMESPACES}, * {@link net.sf.saxon.om.NodeInfo#LOCAL_NAMESPACES}, {@link net.sf.saxon.om.NodeInfo#NO_NAMESPACES} */ public void append(Item item, int locationId, int copyNamespaces) throws XPathException { } /** * Set the URI for an unparsed entity in the document. */ public void setUnparsedEntity(String name, String uri, String publicId) throws XPathException { } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/event/SequenceWriter.java0000644000175000017500000002742511110361551022341 0ustar eugeneeugenepackage net.sf.saxon.event; import net.sf.saxon.om.*; import net.sf.saxon.tinytree.TinyBuilder; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.Type; import net.sf.saxon.value.AtomicValue; /** * This outputter is used when writing a sequence of atomic values and nodes, for * example, when xsl:variable is used with content and an "as" attribute. The outputter * builds the sequence; the concrete subclass is responsible for deciding what to do with the * resulting items. * *

    This class is not used to build temporary trees. For that, the ComplexContentOutputter * is used.

    * * * @author Michael H. Kay */ public abstract class SequenceWriter extends SequenceReceiver { private Receiver outputter = null; private Builder builder = null; private int level = 0; private boolean inStartTag = false; //private boolean buildForUpdate = false; /** * Indicate whether the tree that is built needs to support update operations * @param forUpdate true if update operations are to be supported */ // public void setBuildForUpdate(boolean forUpdate) { // buildForUpdate = forUpdate; // } /** * Ask whether the tree that is built needs to support update operations * @return true if update operations are to be supported */ // public boolean isBuildForUpdate() { // return buildForUpdate; // } /** * Abstract method to be supplied by subclasses: output one item in the sequence. * @param item the item to be written to the sequence */ public abstract void write(Item item) throws XPathException; /** * Start of a document node. */ public void startDocument(int properties) throws XPathException { if (outputter==null) { createTree(); } if (level++ == 0) { outputter.startDocument(properties); } } /** * Create a TinyTree to hold a document or element node. * @throws net.sf.saxon.trans.XPathException */ private void createTree() throws XPathException { PipelineConfiguration pipe = getPipelineConfiguration(); builder = pipe.getController().makeBuilder(); builder.setPipelineConfiguration(pipe); builder.setSystemId(getSystemId()); builder.setTiming(false); NamespaceReducer reducer = new NamespaceReducer(); reducer.setUnderlyingReceiver(builder); reducer.setPipelineConfiguration(getPipelineConfiguration()); ComplexContentOutputter cco = new ComplexContentOutputter(); cco.setHostLanguage(getPipelineConfiguration().getHostLanguage()); cco.setPipelineConfiguration(getPipelineConfiguration()); cco.setReceiver(reducer); outputter = cco; outputter.setSystemId(systemId); outputter.setPipelineConfiguration(getPipelineConfiguration()); outputter.open(); } /** * Decide whether reuse of the SequenceWriter is advisable * @return true if reuse is considered advisable */ protected boolean adviseReuse() { return builder instanceof TinyBuilder && ((TinyBuilder)builder).getTree().getNumberOfNodes() < 20000; } /** * Notify the end of a document node */ public void endDocument() throws XPathException { if (--level == 0) { outputter.endDocument(); DocumentInfo doc = (DocumentInfo)builder.getCurrentRoot(); // add the constructed document to the result sequence append(doc, 0, NodeInfo.ALL_NAMESPACES); } previousAtomic = false; } /** * Output an element start tag. * @param nameCode The element name code - a code held in the Name Pool * @param typeCode Integer code identifying the type of this element. Zero identifies the default * type, that is xs:anyType * @param properties bit-significant flags indicating any special information */ public void startElement(int nameCode, int typeCode, int locationId, int properties) throws XPathException { if (inStartTag) { startContent(); } if (outputter==null) { createTree(); } outputter.startElement(nameCode, typeCode, locationId, properties); level++; inStartTag = true; previousAtomic = false; } /** * Output an element end tag. */ public void endElement() throws XPathException { if (inStartTag) { startContent(); } outputter.endElement(); if (--level == 0) { outputter.close(); NodeInfo element = builder.getCurrentRoot(); append(element, 0, NodeInfo.ALL_NAMESPACES); } previousAtomic = false; } /** * Output a namespace declaration.
    * This is added to a list of pending namespaces for the current start tag. * If there is already another declaration of the same prefix, this one is * ignored. * Note that unlike SAX2 startPrefixMapping(), this call is made AFTER writing the start tag. * @param nscode The namespace code * @param properties Allows special properties to be passed if required * @throws net.sf.saxon.trans.XPathException if there is no start tag to write to (created using writeStartTag), * or if character content has been written since the start tag was written. */ public void namespace(int nscode, int properties) throws XPathException { if (level == 0) { NamePool namePool = getNamePool(); Orphan o = new Orphan(getConfiguration()); o.setNodeKind(Type.NAMESPACE); o.setNameCode(namePool.allocate("", "", namePool.getPrefixFromNamespaceCode(nscode))); o.setStringValue(namePool.getURIFromNamespaceCode(nscode)); append(o, 0, NodeInfo.ALL_NAMESPACES); } else { outputter.namespace(nscode, properties); } previousAtomic = false; } /** * Output an attribute value.
    * @param nameCode An integer code representing the name of the attribute, as held in the Name Pool * @param typeCode Integer code identifying the type annotation of the attribute; zero represents * the default type (xs:untypedAtomic) * @param value The value of the attribute * @param properties Bit significant flags for passing extra information to the serializer, e.g. * to disable escaping * @throws net.sf.saxon.trans.XPathException if there is no start tag to write to (created using writeStartTag), * or if character content has been written since the start tag was written. */ public void attribute(int nameCode, int typeCode, CharSequence value, int locationId, int properties) throws XPathException { if (level == 0) { Orphan o = new Orphan(getConfiguration()); o.setNodeKind(Type.ATTRIBUTE); o.setNameCode(nameCode); o.setStringValue(value); o.setTypeAnnotation(typeCode); append(o, locationId, NodeInfo.ALL_NAMESPACES); } else { outputter.attribute(nameCode, typeCode, value, locationId, properties); } previousAtomic = false; } /** * The startContent() event is notified after all namespaces and attributes of an element * have been notified, and before any child nodes are notified. * @throws net.sf.saxon.trans.XPathException for any failure */ public void startContent() throws XPathException { inStartTag = false; outputter.startContent(); previousAtomic = false; } /** * Produce text content output.
    * @param s The String to be output * @param properties bit-significant flags for extra information, e.g. disable-output-escaping * @throws net.sf.saxon.trans.XPathException for any failure */ public void characters(CharSequence s, int locationId, int properties) throws XPathException { if (level == 0) { Orphan o = new Orphan(getConfiguration()); o.setNodeKind(Type.TEXT); o.setStringValue(s); append(o, locationId, NodeInfo.ALL_NAMESPACES); } else { if (s.length() > 0) { if (inStartTag) { startContent(); } outputter.characters(s, locationId, properties); } } previousAtomic = false; } /** * Write a comment. */ public void comment(CharSequence comment, int locationId, int properties) throws XPathException { if (inStartTag) { startContent(); } if (level == 0) { Orphan o = new Orphan(getConfiguration()); o.setNodeKind(Type.COMMENT); o.setStringValue(comment); append(o, locationId, NodeInfo.ALL_NAMESPACES); } else { outputter.comment(comment, locationId, properties); } previousAtomic = false; } /** * Write a processing instruction * No-op in this implementation */ public void processingInstruction(String target, CharSequence data, int locationId, int properties) throws XPathException { if (inStartTag) { startContent(); } if (level == 0) { Orphan o = new Orphan(getConfiguration()); o.setNameCode(getNamePool().allocate("", "", target)); o.setNodeKind(Type.PROCESSING_INSTRUCTION); o.setStringValue(data); append(o, locationId, NodeInfo.ALL_NAMESPACES); } else { outputter.processingInstruction(target, data, locationId, properties); } previousAtomic = false; } /** * Close the output */ public void close() throws XPathException { previousAtomic = false; if (outputter != null) { outputter.close(); } } /** * Append an item to the sequence, performing any necessary type-checking and conversion */ public void append(Item item, int locationId, int copyNamespaces) throws XPathException { if (item==null) { return; } if (level==0) { write(item); previousAtomic = false; } else { if (item instanceof AtomicValue) { // If an atomic value is written to a tree, and the previous item was also // an atomic value, then add a single space to separate them if (previousAtomic) { outputter.characters(" ", 0, 0); } outputter.characters(item.getStringValueCS(), 0, 0); previousAtomic = true; } else { ((NodeInfo)item).copy(outputter, NodeInfo.ALL_NAMESPACES, true, locationId); previousAtomic = false; } } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. //saxonb-9.1.0.8/bj/net/sf/saxon/event/TEXTEmitter.java0000644000175000017500000001034011173044235021504 0ustar eugeneeugenepackage net.sf.saxon.event; import net.sf.saxon.trans.XPathException; import net.sf.saxon.charcode.UnicodeCharacterSet; import javax.xml.transform.OutputKeys; /** * This class generates TEXT output * @author Michael H. Kay */ public class TEXTEmitter extends XMLEmitter { /** * Start of the document. */ public void open () throws XPathException {} protected void openDocument() throws XPathException { if (writer==null) { makeWriter(); } if (characterSet==null) { characterSet = UnicodeCharacterSet.getInstance(); } // Write a BOM if requested String encoding = outputProperties.getProperty(OutputKeys.ENCODING); if (encoding==null || encoding.equalsIgnoreCase("utf8")) { encoding = "UTF-8"; } String byteOrderMark = outputProperties.getProperty(SaxonOutputKeys.BYTE_ORDER_MARK); if ("yes".equals(byteOrderMark) && ( "UTF-8".equalsIgnoreCase(encoding) || "UTF-16LE".equalsIgnoreCase(encoding) || "UTF-16BE".equalsIgnoreCase(encoding))) { try { writer.write('\uFEFF'); empty = false; } catch (java.io.IOException err) { // Might be an encoding exception; just ignore it } } } /** * Output the XML declaration. This implementation does nothing. */ public void writeDeclaration() throws XPathException {} /** * Produce output using the current Writer.
    * Special characters are not escaped. * @param chars Character sequence to be output * @param properties bit fields holding special properties of the characters * @exception XPathException for any failure */ public void characters(CharSequence chars, int locationId, int properties) throws XPathException { if (empty) { openDocument(); } if ((properties & ReceiverOptions.NO_SPECIAL_CHARS) == 0) { int badchar = testCharacters(chars); if (badchar != 0) { throw new XPathException( "Output character not available in this encoding (decimal " + badchar + ")"); } } try { writer.write(chars.toString()); } catch (java.io.IOException err) { throw new XPathException(err); } } /** * Output an element start tag.
    * Does nothing with this output method. * @param nameCode The element name (tag) * @param typeCode The type annotation * @param properties Bit fields holding any special properties of the element */ public void startElement(int nameCode, int typeCode, int locationId, int properties) { // no-op } public void namespace(int namespaceCode, int properties) {} public void attribute(int nameCode, int typeCode, CharSequence value, int locationId, int properties) {} /** * Output an element end tag.
    * Does nothing with this output method. */ public void endElement() { // no-op } /** * Output a processing instruction.
    * Does nothing with this output method. */ public void processingInstruction(String name, CharSequence value, int locationId, int properties) throws XPathException {} /** * Output a comment.
    * Does nothing with this output method. */ public void comment(CharSequence chars, int locationId, int properties) throws XPathException {} } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/event/SequenceCopier.java0000644000175000017500000000270511033112257022301 0ustar eugeneeugenepackage net.sf.saxon.event; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.om.Item; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.trans.XPathException; /** * Copies a sequence, supplied as a SequenceIterator, to a push pipeline, represented by * a SequenceReceiver */ public class SequenceCopier { private SequenceCopier() { } public static void copySequence(SequenceIterator in, SequenceReceiver out) throws XPathException { out.open(); while (true) { Item item = in.next(); if (item == null) { break; } out.append(item, 0, NodeInfo.ALL_NAMESPACES); } out.close(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/event/XHTMLURIEscaper.java0000644000175000017500000001437411033112257022153 0ustar eugeneeugenepackage net.sf.saxon.event; import net.sf.saxon.om.NamePool; import net.sf.saxon.om.NamespaceConstant; import net.sf.saxon.trans.XPathException; import net.sf.saxon.codenorm.Normalizer; import java.util.HashSet; /** * This class performs URI escaping for the XHTML output method. The logic for performing escaping * is the same as the HTML output method, but the way in which attributes are identified for escaping * is different, because XHTML is case-sensitive. */ public class XHTMLURIEscaper extends HTMLURIEscaper { /** * Table of attributes whose value is a URL */ private HashSet urlTable; private synchronized void buildURIAttributeTable() { // Reuse the attribute table for all XHTMLEmitters sharing the same namepool NamePool pool = getPipelineConfiguration().getConfiguration().getNamePool(); urlTable = (HashSet)pool.getClientData(this.getClass()); if (urlTable == null) { urlTable = new HashSet(40); pool.setClientData(this.getClass(), urlTable); } setUrlAttribute(pool, "form", "action"); setUrlAttribute(pool, "object", "archive"); setUrlAttribute(pool, "body", "background"); setUrlAttribute(pool, "q", "cite"); setUrlAttribute(pool, "blockquote", "cite"); setUrlAttribute(pool, "del", "cite"); setUrlAttribute(pool, "ins", "cite"); setUrlAttribute(pool, "object", "classid"); setUrlAttribute(pool, "object", "codebase"); setUrlAttribute(pool, "applet", "codebase"); setUrlAttribute(pool, "object", "data"); setUrlAttribute(pool, "button", "datasrc"); setUrlAttribute(pool, "div", "datasrc"); setUrlAttribute(pool, "input", "datasrc"); setUrlAttribute(pool, "object", "datasrc"); setUrlAttribute(pool, "select", "datasrc"); setUrlAttribute(pool, "span", "datasrc"); setUrlAttribute(pool, "table", "datasrc"); setUrlAttribute(pool, "textarea", "datasrc"); setUrlAttribute(pool, "script", "for"); setUrlAttribute(pool, "a", "href"); setUrlAttribute(pool, "a", "name"); // see second note in section B.2.1 of HTML 4 specification setUrlAttribute(pool, "area", "href"); setUrlAttribute(pool, "link", "href"); setUrlAttribute(pool, "base", "href"); setUrlAttribute(pool, "img", "longdesc"); setUrlAttribute(pool, "frame", "longdesc"); setUrlAttribute(pool, "iframe", "longdesc"); setUrlAttribute(pool, "head", "profile"); setUrlAttribute(pool, "script", "src"); setUrlAttribute(pool, "input", "src"); setUrlAttribute(pool, "frame", "src"); setUrlAttribute(pool, "iframe", "src"); setUrlAttribute(pool, "img", "src"); setUrlAttribute(pool, "img", "usemap"); setUrlAttribute(pool, "input", "usemap"); setUrlAttribute(pool, "object", "usemap"); } private void setUrlAttribute(NamePool pool, String element, String attribute) { int elcode = pool.allocate("", NamespaceConstant.XHTML, element) & NamePool.FP_MASK; int atcode = pool.allocate("", "", attribute) & NamePool.FP_MASK; Long key = new Long(((long)elcode)<<32 | (long)atcode); urlTable.add(key); } /** * Determine whether a given attribute is a URL attribute */ private boolean isURLAttribute(int elcode, int atcode) { elcode = elcode & NamePool.FP_MASK; atcode = atcode & NamePool.FP_MASK; Long key = new Long(((long)elcode)<<32 | (long)atcode); return urlTable.contains(key); } /** * Do the real work of starting the document. This happens when the first * content is written. * * @throws net.sf.saxon.trans.XPathException * */ public void open() throws XPathException { super.open(); if (escapeURIAttributes) { buildURIAttributeTable(); } } /** * Notify an attribute. Attributes are notified after the startElement event, and before any * children. Namespaces and attributes may be intermingled. * * @param nameCode The name of the attribute, as held in the name pool * @param typeCode The type of the attribute, as held in the name pool * @param properties Bit significant value. The following bits are defined: *
    DISABLE_ESCAPING
    Disable escaping for this attribute
    *
    NO_SPECIAL_CHARACTERS
    Attribute value contains no special characters
    * @throws IllegalStateException: attempt to output an attribute when there is no open element * start tag */ public void attribute(int nameCode, int typeCode, CharSequence value, int locationId, int properties) throws XPathException { if (escapeURIAttributes && isURLAttribute(currentElement, nameCode) && (properties & ReceiverOptions.DISABLE_ESCAPING) == 0) { CharSequence normalized = new Normalizer(Normalizer.C).normalize(value); getUnderlyingReceiver().attribute( nameCode, typeCode, HTMLURIEscaper.escapeURL(normalized, true), locationId, properties | ReceiverOptions.DISABLE_CHARACTER_MAPS); } else { getUnderlyingReceiver().attribute( nameCode, typeCode, value, locationId, properties); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/event/ParseOptions.java0000644000175000017500000003035411033112257022016 0ustar eugeneeugenepackage net.sf.saxon.event; import net.sf.saxon.om.StructuredQName; import net.sf.saxon.om.Validation; import net.sf.saxon.type.SchemaType; import org.xml.sax.XMLReader; import javax.xml.transform.ErrorListener; import java.util.ArrayList; import java.util.List; /** * This class defines options for parsing a source document */ public class ParseOptions { private int schemaValidation = Validation.DEFAULT; private int dtdValidation = Validation.DEFAULT; private StructuredQName topLevelElement; private SchemaType topLevelType; private XMLReader parser = null; private Boolean wrapDocument = null; private int treeModel = Builder.UNSPECIFIED_TREE_MODEL; private int stripSpace; private Boolean lineNumbering = null; private Boolean xIncludeAware = null; private boolean pleaseClose = false; private ErrorListener errorListener = null; private List filters = null; private boolean sourceIsXQJ = false; /** * Add a filter to the list of filters to be applied to the raw input * @param filter the filter to be added */ public void addFilter(ProxyReceiver filter) { if (filters == null) { filters = new ArrayList(5); } filters.add(filter); } /** * Get the list of filters to be applied to the input. Returns null if there are no filters. * @return the list of filters, if there are any */ public List getFilters() { return filters; } /** * Set the space-stripping action to be applied to the source document * @param stripAction one of {@link net.sf.saxon.value.Whitespace#IGNORABLE}, * {@link net.sf.saxon.value.Whitespace#ALL}, or {@link net.sf.saxon.value.Whitespace#NONE} */ public void setStripSpace(int stripAction) { stripSpace = stripAction; } /** * Get the space-stripping action to be applied to the source document * @return one of {@link net.sf.saxon.value.Whitespace#IGNORABLE}, * {@link net.sf.saxon.value.Whitespace#ALL}, or {@link net.sf.saxon.value.Whitespace#NONE} */ public int getStripSpace() { return stripSpace; } /** * Set the tree model to use. Default is the tiny tree * @param model one of {@link net.sf.saxon.event.Builder#TINY_TREE} or * {@link net.sf.saxon.event.Builder#LINKED_TREE} */ public void setTreeModel(int model) { if (model != Builder.TINY_TREE && model != Builder.LINKED_TREE) { throw new IllegalArgumentException("model must be Builder.TINY_TREE or Builder.LINKED_TREE"); } treeModel = model; } /** * Get the tree model that will be used. * @return one of {@link net.sf.saxon.event.Builder#TINY_TREE} or {@link net.sf.saxon.event.Builder#LINKED_TREE}, * or {link Builder#UNSPECIFIED_TREE_MODEL} if no call on setTreeModel() has been made */ public int getTreeModel() { return treeModel; } /** * Set whether or not schema validation of this source is required * @param option one of {@link net.sf.saxon.om.Validation#STRICT}, * {@link net.sf.saxon.om.Validation#LAX}, {@link net.sf.saxon.om.Validation#STRIP}, * {@link net.sf.saxon.om.Validation#PRESERVE}, {@link net.sf.saxon.om.Validation#DEFAULT} */ public void setSchemaValidationMode(int option) { schemaValidation = option; } /** * Get whether or not schema validation of this source is required * @return the validation mode requested, or {@link net.sf.saxon.om.Validation#DEFAULT} * to use the default validation mode from the Configuration. */ public int getSchemaValidationMode() { return schemaValidation; } /** * Set the name of the top-level element for validation. * If a top-level element is set then the document * being validated must have this as its outermost element * @param elementName the QName of the required top-level element, or null to unset the value */ public void setTopLevelElement(StructuredQName elementName) { topLevelElement = elementName; } /** * Get the name of the top-level element for validation. * If a top-level element is set then the document * being validated must have this as its outermost element * @return the QName of the required top-level element, or null if no value is set * @since 9.0 */ public StructuredQName getTopLevelElement() { return topLevelElement; } /** * Set the type of the top-level element for validation. * If this is set then the document element is validated against this type * @param type the schema type required for the document element, or null to unset the value */ public void setTopLevelType(SchemaType type) { topLevelType = type; } /** * Get the type of the document element for validation. * If this is set then the document element of the document * being validated must have this type * @return the type of the required top-level element, or null if no value is set */ public SchemaType getTopLevelType() { return topLevelType; } /** * Set whether or not DTD validation of this source is required * @param option one of {@link net.sf.saxon.om.Validation#STRICT}, * {@link net.sf.saxon.om.Validation#STRIP}, {@link net.sf.saxon.om.Validation#DEFAULT} */ public void setDTDValidationMode(int option) { dtdValidation = option; } /** * Get whether or not DTD validation of this source is required * @return the validation mode requested, or {@link net.sf.saxon.om.Validation#DEFAULT} * to use the default validation mode from the Configuration. */ public int getDTDValidationMode() { return dtdValidation; } /** * Set whether line numbers are to be maintained in the constructed document * @param lineNumbering true if line numbers are to be maintained */ public void setLineNumbering(boolean lineNumbering) { this.lineNumbering = Boolean.valueOf(lineNumbering); } /** * Get whether line numbers are to be maintained in the constructed document * @return true if line numbers are maintained */ public boolean isLineNumbering() { return lineNumbering != null && lineNumbering.booleanValue(); } /** * Determine whether setLineNumbering() has been called * @return true if setLineNumbering() has been called */ public boolean isLineNumberingSet() { return lineNumbering != null; } /** * Set the SAX parser (XMLReader) to be used * @param parser the SAX parser */ public void setXMLReader(XMLReader parser) { this.parser = parser; } /** * Get the SAX parser (XMLReader) to be used * @return the parser */ public XMLReader getXMLReader() { return parser; } /** * Assuming that the contained Source is a node in a tree, indicate whether a tree should be created * as a view of this supplied tree, or as a copy. * @param wrap if true, the node in the supplied Source is wrapped, to create a view. If false, the node * and its contained subtree is copied. If null, the system default is chosen. */ public void setWrapDocument(Boolean wrap) { wrapDocument = wrap; } /** Assuming that the contained Source is a node in a tree, determine whether a tree will be created * as a view of this supplied tree, or as a copy. * @return if true, the node in the supplied Source is wrapped, to create a view. If false, the node * and its contained subtree is copied. If null, the system default is chosen. * @since 8.8 */ public Boolean getWrapDocument() { return wrapDocument; } /** *

    Set state of XInclude processing.

    *

    *

    If XInclude markup is found in the document instance, should it be * processed as specified in * XML Inclusions (XInclude) Version 1.0.

    *

    *

    XInclude processing defaults to false.

    * * @param state Set XInclude processing to true or * false * @since 8.9 */ public void setXIncludeAware(boolean state) { xIncludeAware = Boolean.valueOf(state); } /** *

    Determine whether setXIncludeAware() has been called.

    * * @return true if setXIncludeAware() has been called */ public boolean isXIncludeAwareSet() { return (xIncludeAware != null); } /** *

    Get state of XInclude processing.

    * * @return current state of XInclude processing. Default value is false. */ public boolean isXIncludeAware() { return xIncludeAware != null && xIncludeAware.booleanValue(); } /** * Set an ErrorListener to be used when parsing * @param listener the ErrorListener to be used */ public void setErrorListener(ErrorListener listener) { errorListener = listener; } /** * Get the ErrorListener that will be used when parsing * @return the ErrorListener, if one has been set using {@link #setErrorListener}, * otherwise null. */ public ErrorListener getErrorListener() { return errorListener; } /** * Set whether or not the user of this Source is encouraged to close it as soon as reading is finished. * Normally the expectation is that any Stream in a StreamSource will be closed by the component that * created the Stream. However, in the case of a Source returned by a URIResolver, there is no suitable * interface (the URIResolver has no opportunity to close the stream). Also, in some cases such as reading * of stylesheet modules, it is possible to close the stream long before control is returned to the caller * who supplied it. This tends to make a difference on .NET, where a file often can't be opened if there * is a stream attached to it. * @param close true if the source should be closed as soon as it has been consumed */ public void setPleaseCloseAfterUse(boolean close) { pleaseClose = close; } /** * Determine whether or not the user of this Source is encouraged to close it as soon as reading is * finished. * @return true if the source should be closed as soon as it has been consumed */ public boolean isPleaseCloseAfterUse() { return pleaseClose; } /** * Indicate that this Source is supporting the weird XQJ createItemFromDocument(XMLReader) method. * This contains a preinitialized XMLReader that needs to be invoked in a special way * @param flag set to true if this is a special XQJ SAXSource */ public void setSourceIsXQJ(boolean flag) { sourceIsXQJ = flag; } /** * Ask whether this Source is supporting the weird XQJ createItemFromDocument(XMLReader) method. * This contains a preinitialized XMLReader that needs to be invoked in a special way * @return true if this is a special XQJ SAXSource */ public boolean sourceIsXQJ() { return sourceIsXQJ; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. //saxonb-9.1.0.8/bj/net/sf/saxon/event/UncommittedSerializer.java0000644000175000017500000001720111033112257023706 0ustar eugeneeugenepackage net.sf.saxon.event; import net.sf.saxon.om.NamespaceConstant; import net.sf.saxon.om.NamePool; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.Type; import net.sf.saxon.value.Whitespace; import javax.xml.transform.OutputKeys; import javax.xml.transform.Result; import java.util.ArrayList; import java.util.List; import java.util.Properties; /** * This class is used when the decision on which serialization method to use has to be delayed until the first * element is read. It buffers comments and processing instructions until that happens; then when the first * element arrives it creates a real serialization pipeline and uses that for future output. * @author Michael H. Kay */ public class UncommittedSerializer extends ProxyReceiver { boolean committed = false; List pending = null; Result finalResult; Properties outputProperties; /** * Create an uncommitted Serializer * @param finalResult the output destination * @param outputProperties the serialization properties */ public UncommittedSerializer(Result finalResult, Properties outputProperties) { this.finalResult = finalResult; this.outputProperties = outputProperties; setUnderlyingReceiver(new Sink()); } public void open() throws XPathException { committed = false; } /** * End of document */ public void close() throws XPathException { // empty output: must send a beginDocument()/endDocument() pair to the content handler if (!committed) { switchToMethod("xml"); } getUnderlyingReceiver().close(); } /** * Produce character output using the current Writer.
    */ public void characters(CharSequence chars, int locationId, int properties) throws XPathException { if (committed) { getUnderlyingReceiver().characters(chars, locationId, properties); } else { if (pending==null) { pending = new ArrayList(10); } PendingNode node = new PendingNode(); node.kind = Type.TEXT; node.name = null; node.content = chars.toString(); // needs to be immutable node.locationId = locationId; node.properties = properties; pending.add(node); if (!Whitespace.isWhite(chars)) { switchToMethod("xml"); } } } /** * Processing Instruction */ public void processingInstruction(String target, CharSequence data, int locationId, int properties) throws XPathException { if (committed) { getUnderlyingReceiver().processingInstruction(target, data, locationId, properties); } else { if (pending==null) { pending = new ArrayList(10); } PendingNode node = new PendingNode(); node.kind = Type.PROCESSING_INSTRUCTION; node.name = target; node.content = data; node.locationId = locationId; node.properties = properties; pending.add(node); } } /** * Output a comment */ public void comment (CharSequence chars, int locationId, int properties) throws XPathException { if (committed) { getUnderlyingReceiver().comment(chars, locationId, properties); } else { if (pending==null) { pending=new ArrayList(10); } PendingNode node = new PendingNode(); node.kind = Type.COMMENT; node.name = null; node.content = chars; node.locationId = locationId; node.properties = properties; pending.add(node); } } /** * Output an element start tag.
    * This can only be called once: it switches to a substitute output generator for XML, XHTML, or HTML, * depending on the element name. * @param nameCode The element name (tag) * @param typeCode The type annotation * @param properties Bit field holding special properties of the element */ public void startElement(int nameCode, int typeCode, int locationId, int properties) throws XPathException { if (!committed) { NamePool namePool = getNamePool(); String name = namePool.getLocalName(nameCode); short uriCode = namePool.getURICode(nameCode); if (name.equalsIgnoreCase("html") && uriCode==NamespaceConstant.NULL_CODE) { switchToMethod("html"); } else if (name.equals("html") && namePool.getURIFromURICode(uriCode).equals(NamespaceConstant.XHTML)) { String version = outputProperties.getProperty(SaxonOutputKeys.STYLESHEET_VERSION); if ("1".equals(version)) { switchToMethod("xml"); } else { switchToMethod("xhtml"); } } else { switchToMethod("xml"); } } getUnderlyingReceiver().startElement(nameCode, typeCode, locationId, properties); } /** * Switch to a specific emitter once the output method is known * @param method the method to switch to (xml, html, xhtml) */ private void switchToMethod(String method) throws XPathException { Properties newProperties = new Properties(outputProperties); newProperties.setProperty(OutputKeys.METHOD, method); SerializerFactory sf = getConfiguration().getSerializerFactory(); Receiver target = sf.getReceiver(finalResult, getPipelineConfiguration(), newProperties); committed = true; target.open(); target.startDocument(0); if (pending!=null) { for (int i = 0; i < pending.size(); i++) { PendingNode node = (PendingNode)pending.get(i); switch (node.kind) { case Type.COMMENT: target.comment(node.content, node.locationId, node.properties); break; case Type.PROCESSING_INSTRUCTION: target.processingInstruction(node.name, node.content, node.locationId, node.properties); break; case Type.TEXT: target.characters(node.content, node.locationId, node.properties); break; } } pending = null; } setUnderlyingReceiver(target); } /** * A text, comment, or PI node that hasn't been output yet because we don't yet know what output * method to use */ private static final class PendingNode { int kind; String name; CharSequence content; int properties; int locationId; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/event/XQueryEmitter.java0000644000175000017500000000563711033112257022165 0ustar eugeneeugenepackage net.sf.saxon.event; import net.sf.saxon.trans.XPathException; import net.sf.saxon.om.FastStringBuffer; import java.io.IOException; /** * The XQueryEmitter is designed to serialize an XQuery that was originally embedded in an * XML document. It is a variant of the XMLEmitter, and differs in that the operators <, >, <=, >=, <<, and << * are output without escaping. They are recognized by virtue of the fact that they appear in text or attribute * content between curly braces but not in quotes. */ public class XQueryEmitter extends XMLEmitter { /** * Write contents of array to current writer, after escaping special characters. * This method converts the XML special characters (such as < and &) into their * predefined entities. * * @param chars The character sequence containing the string * @param inAttribute Set to true if the text is in an attribute value */ protected void writeEscape(final CharSequence chars, final boolean inAttribute) throws IOException, XPathException { boolean inBraces = false; FastStringBuffer buff = new FastStringBuffer(chars.length()); for (int i=0; iafter the startElement event, and before * any children for the element. The namespaces that are reported are only required * to include those that are different from the parent element; however, duplicates may be reported. * A namespace must not conflict with any namespaces already used for element or attribute names. * * @param namespaceCode an integer: the top half is a prefix code, the bottom half a URI code. * These may be translated into an actual prefix and URI using the name pool. A prefix code of * zero represents the empty prefix (that is, the default namespace). A URI code of zero represents * a URI of "", that is, a namespace undeclaration. * @throws IllegalStateException: attempt to output a namespace when there is no open element * start tag */ public void namespace(int namespaceCode, int properties) throws XPathException { seq1.namespace(namespaceCode, properties); seq2.namespace(namespaceCode, properties); } /** * Notify an attribute. Attributes are notified after the startElement event, and before any * children. Namespaces and attributes may be intermingled. * * @param nameCode The name of the attribute, as held in the name pool * @param typeCode The type of the attribute, as held in the name pool * @param locationId an integer which can be interpreted using a LocationMap to return * information such as line number and system ID. If no location information is available, * the value zero is supplied. * @param properties Bit significant value. The following bits are defined: *
    DISABLE_ESCAPING
    Disable escaping for this attribute
    *
    NO_SPECIAL_CHARACTERS
    Attribute value contains no special characters
    * @throws IllegalStateException: attempt to output an attribute when there is no open element * start tag */ public void attribute(int nameCode, int typeCode, CharSequence value, int locationId, int properties) throws XPathException { seq1.attribute(nameCode, typeCode, value, locationId, properties); seq2.attribute(nameCode, typeCode, value, locationId, properties); } /** * Notify the start of the content, that is, the completion of all attributes and namespaces. * Note that the initial receiver of output from XSLT instructions will not receive this event, * it has to detect it itself. Note that this event is reported for every element even if it has * no attributes, no namespaces, and no content. */ public void startContent() throws XPathException { seq1.startContent(); seq2.startContent(); } /** * Notify the end of an element. The receiver must maintain a stack if it needs to know which * element is ending. */ public void endElement() throws XPathException { seq1.endElement(); seq2.endElement(); } /** * Notify character data. Note that some receivers may require the character data to be * sent in a single event, but in general this is not a requirement. * * @param chars The characters * @param locationId an integer which can be interpreted using a LocationMap to return * information such as line number and system ID. If no location information is available, * the value zero is supplied. * @param properties Bit significant value. The following bits are defined: *
    DISABLE_ESCAPING
    Disable escaping for this text node
    *
    USE_CDATA
    Output as a CDATA section
    */ public void characters(CharSequence chars, int locationId, int properties) throws XPathException { seq1.characters(chars, locationId, properties); seq2.characters(chars, locationId, properties); } /** * Output a processing instruction * * @param name The PI name. This must be a legal name (it will not be checked). * @param data The data portion of the processing instruction * @param locationId an integer which can be interpreted using a LocationMap to return * information such as line number and system ID. If no location information is available, * the value zero is supplied. * @param properties Additional information about the PI. The following bits are * defined: *
    CHECKED
    Data is known to be legal (e.g. doesn't contain "?>")
    * @throws IllegalArgumentException: the content is invalid for an XML processing instruction */ public void processingInstruction(String name, CharSequence data, int locationId, int properties) throws XPathException { seq1.processingInstruction(name, data, locationId, properties); seq2.processingInstruction(name, data, locationId, properties); } /** * Notify a comment. Comments are only notified if they are outside the DTD. * * @param content The content of the comment * @param locationId an integer which can be interpreted using a LocationMap to return * information such as line number and system ID. If no location information is available, * the value zero is supplied. * @param properties Additional information about the comment. The following bits are * defined: *
    CHECKED
    Comment is known to be legal (e.g. doesn't contain "--")
    * @throws IllegalArgumentException: the content is invalid for an XML comment */ public void comment(CharSequence content, int locationId, int properties) throws XPathException { seq1.comment(content, locationId, properties); seq2.comment(content, locationId, properties); } /** * Notify the end of the event stream */ public void close() throws XPathException { seq1.close(); seq2.close(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/event/NamespaceReducer.java0000644000175000017500000002540611033112257022600 0ustar eugeneeugenepackage net.sf.saxon.event; import net.sf.saxon.om.NamePool; import net.sf.saxon.om.NamespaceConstant; import net.sf.saxon.om.NamespaceResolver; import net.sf.saxon.trans.XPathException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /** * NamespaceReducer is a ProxyReceiver responsible for removing duplicate namespace * declarations. It also ensures that an xmlns="" undeclaration is output when * necessary. Used on its own, the NamespaceReducer simply eliminates unwanted * namespace declarations. It can also be subclassed, in which case the subclass * can use the services of the NamespaceReducer to resolve QNames. *

    * The NamespaceReducer also validates namespace-sensitive content. */ public class NamespaceReducer extends ProxyReceiver implements NamespaceResolver { // We keep track of namespaces to avoid outputting duplicate declarations. The namespaces // array holds a list of all namespaces currently declared (organised as pairs of entries, // prefix followed by URI). The countStack contains an entry for each element currently open; the // value on the stack is an integer giving the number of namespaces added to the main // namespace stack by that element. private int[] namespaces = new int[50]; // all namespace codes currently declared private int namespacesSize = 0; // all namespaces currently declared private int[] countStack = new int[50]; private int depth = 0; // Creating an element does not automatically inherit the namespaces of the containing element. // When the DISINHERIT property is set on startElement(), this indicates that the namespaces // on that element are not to be automatically inherited by its children. So startElement() // stacks a boolean flag indicating whether the children are to disinherit the parent's namespaces. private boolean[] disinheritStack = new boolean[50]; // When a child element does not inherit the namespaces of its parent, it acquires undeclarations // to indicate this fact. This array keeps track of the undeclarations that need to be added to the // current child element. private int[] pendingUndeclarations = null; /** * Create a NamespaceReducer */ public NamespaceReducer() {} /** * Create a NamespaceReducer with a given destination Receiver * @param base the Receiver to which events will be passed after namespace reduction */ public NamespaceReducer(Receiver base) { setUnderlyingReceiver(base); if (pipelineConfiguration == null) { pipelineConfiguration = base.getPipelineConfiguration(); } } /** * startElement. This call removes redundant namespace declarations, and * possibly adds an xmlns="" undeclaration. */ public void startElement(int nameCode, int typeCode, int locationId, int properties) throws XPathException { nextReceiver.startElement(nameCode, typeCode, locationId, properties); // If the parent element specified inherit=no, keep a list of namespaces that need to be // undeclared if (depth>0 && disinheritStack[depth-1]) { pendingUndeclarations = new int[namespacesSize]; System.arraycopy(namespaces, 0, pendingUndeclarations, 0, namespacesSize); } else { pendingUndeclarations = null; } // Record the current height of the namespace list so it can be reset at endElement time countStack[depth] = 0; disinheritStack[depth] = (properties & ReceiverOptions.DISINHERIT_NAMESPACES) != 0; if (++depth >= countStack.length) { int[] newstack = new int[depth*2]; System.arraycopy(countStack, 0, newstack, 0, depth); boolean[] disStack2 = new boolean[depth*2]; System.arraycopy(disinheritStack, 0, disStack2, 0, depth); countStack = newstack; disinheritStack = disStack2; } // Ensure that the element namespace is output, unless this is done // automatically by the caller (which is true, for example, for a literal // result element). if ((properties & ReceiverOptions.NAMESPACE_OK) == 0) { namespace(getNamePool().allocateNamespaceCode(nameCode), 0); } } /** * Output a namespace node (binding) * @param namespaceCode encapsulates the prefix and URI * @param properties the properties of the namespace binding * @throws XPathException */ public void namespace(int namespaceCode, int properties) throws XPathException { // Keep the namespace only if it is actually needed if (isNeeded(namespaceCode)) { addToStack(namespaceCode); countStack[depth - 1]++; nextReceiver.namespace(namespaceCode, properties); } } /** * Determine whether a namespace declaration is needed * @param nscode the namespace code * @return true if the namespace is needed: that is, if it not the XML namespace, is not a duplicate, * and is not a redundant xmlns="". */ private boolean isNeeded(int nscode) { if (nscode==NamespaceConstant.XML_NAMESPACE_CODE) { // Ignore the XML namespace return false; } // First cancel any pending undeclaration of this namespace prefix (there may be more than one) if (pendingUndeclarations != null) { for (int p=0; p>16) == (pendingUndeclarations[p]>>16)) { pendingUndeclarations[p] = -1; //break; } } } for (int i=namespacesSize-1; i>=0; i--) { if (namespaces[i]==nscode) { // it's a duplicate so we don't need it return false; } if ((namespaces[i]>>16) == (nscode>>16)) { // same prefix, different URI. return true; } } // we need it unless it's a redundant xmlns="" return (nscode != NamespaceConstant.NULL_NAMESPACE_CODE); } /** * Add a namespace declaration to the stack * @param nscode the namespace code to be added */ private void addToStack(int nscode) { // expand the stack if necessary if (namespacesSize+1 >= namespaces.length) { int[] newlist = new int[namespacesSize*2]; System.arraycopy(namespaces, 0, newlist, 0, namespacesSize); namespaces = newlist; } namespaces[namespacesSize++] = nscode; } /** * startContent: Add any namespace undeclarations needed to stop * namespaces being inherited from parent elements */ public void startContent() throws XPathException { if (pendingUndeclarations != null) { for (int i=0; i=0; i--) { if ((namespaces[i]>>16) == (prefixCode)) { return (short)(namespaces[i]&0xffff); } } if (prefixCode == 0) { return 0; // by default, no prefix means no namespace URI } else { return -1; } } /** * Get the namespace URI corresponding to a given prefix. Return null * if the prefix is not in scope. * * @param prefix the namespace prefix * @param useDefault true if the default namespace is to be used when the * prefix is "" * @return the uri for the namespace, or null if the prefix is not in scope */ public String getURIForPrefix(String prefix, boolean useDefault) { NamePool pool = getNamePool(); if ((prefix==null || prefix.length()==0) && !useDefault) { return ""; } else if ("xml".equals(prefix)) { return NamespaceConstant.XML; } else { short prefixCode = pool.getCodeForPrefix(prefix); short uriCode = getURICode(prefixCode); if (uriCode == -1) { return null; } return pool.getURIFromURICode(uriCode); } } /** * Get an iterator over all the prefixes declared in this namespace context. This will include * the default namespace (prefix="") and the XML namespace where appropriate */ public Iterator iteratePrefixes() { NamePool pool = getNamePool(); List prefixes = new ArrayList(namespacesSize); for (int i=namespacesSize-1; i>=0; i--) { String prefix = pool.getPrefixFromNamespaceCode(namespaces[i]); if (!prefixes.contains(prefix)) { prefixes.add(prefix); } } prefixes.add("xml"); return prefixes.iterator(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/event/CharacterMapExpander.java0000644000175000017500000001661311033112257023413 0ustar eugeneeugenepackage net.sf.saxon.event; import net.sf.saxon.om.FastStringBuffer; import net.sf.saxon.sort.IntHashMap; import net.sf.saxon.sort.IntIterator; import net.sf.saxon.trans.XPathException; import net.sf.saxon.tinytree.CompressedWhitespace; import net.sf.saxon.value.Whitespace; import net.sf.saxon.charcode.UTF16; import java.util.List; /** * CharacterMapExpander: This ProxyReceiver expands characters occurring in a character map, * as specified by the XSLT 2.0 xsl:character-map declaration * * @author Michael Kay */ public class CharacterMapExpander extends ProxyReceiver { private IntHashMap charMap; private int min = Integer.MAX_VALUE; // the lowest mapped character private int max = 0; // the highest mapped character private boolean mapsWhitespace = false; private boolean useNullMarkers = true; /** * Set the character maps to be used by this CharacterMapExpander. * They are merged into a single character map if there is more than one. */ public void setCharacterMaps(List maps) { // merge the character maps, allowing definitions in a later map // to overwrite definitions in an earlier map. (Note, we don't really // need to do this if there is only one map, but we want to scan the keys // anyway to extract the mimimum and maximum mapped characters.) charMap = new IntHashMap(64); for (int i = 0; i < maps.size(); i++) { IntHashMap hashMap = (IntHashMap)maps.get(i); IntIterator keys = hashMap.keyIterator(); while (keys.hasNext()) { int next = keys.next(); if (next < min) { min = next; } if (next > max) { max = next; } if (!mapsWhitespace && Whitespace.isWhitespace(next)) { mapsWhitespace = true; } charMap.put(next, hashMap.get(next)); } } if (min > 0xD800) { // if all the mapped characters are above the BMP, we need to check // surrogates min = 0xD800; } } /** * Indicate whether the result of character mapping should be marked using NUL * characters to prevent subsequent XML or HTML character escaping */ public void setUseNullMarkers(boolean use) { useNullMarkers = use; } /** * Output an attribute */ public void attribute(int nameCode, int typeCode, CharSequence value, int locationId, int properties) throws XPathException { if ((properties & ReceiverOptions.DISABLE_CHARACTER_MAPS) == 0) { CharSequence mapped = map(value, useNullMarkers); if (mapped == value) { // no mapping was done nextReceiver.attribute(nameCode, typeCode, value, locationId, properties); } else { nextReceiver.attribute(nameCode, typeCode, mapped, locationId, (properties | ReceiverOptions.USE_NULL_MARKERS) & ~ReceiverOptions.NO_SPECIAL_CHARS); } } else { nextReceiver.attribute(nameCode, typeCode, value, locationId, properties); } } /** * Output character data */ public void characters(CharSequence chars, int locationId, int properties) throws XPathException { if ((properties & ReceiverOptions.DISABLE_ESCAPING) == 0) { CharSequence mapped = map(chars, useNullMarkers); if (mapped != chars) { properties = (properties | ReceiverOptions.USE_NULL_MARKERS) & ~ReceiverOptions.NO_SPECIAL_CHARS; } nextReceiver.characters(mapped, locationId, properties); } else { // if the user requests disable-output-escaping, this overrides the character // mapping nextReceiver.characters(chars, locationId, properties); } } /** * Perform the character mappping * @param in the input string to be mapped * @param insertNulls true if null (0) characters are to be inserted before * and after replacement characters. This is done to signal * that output escaping of these characters is disabled. The flag is set to true when writing * XML or HTML, but to false when writing TEXT. */ private CharSequence map(CharSequence in, boolean insertNulls) { if ((!mapsWhitespace) && in instanceof CompressedWhitespace) { return in; } // First scan the string to see if there are any possible mapped // characters; if not, don't bother creating the new buffer boolean move = false; for (int i=0; i= min && c <= max) { move = true; break; } } if (!move) { return in; } FastStringBuffer buffer = new FastStringBuffer(in.length()*2); int i = 0; while(i < in.length()) { char c = in.charAt(i++); if (c >= min && c <= max) { if (UTF16.isHighSurrogate(c)) { // assume the string is properly formed char d = in.charAt(i++); int s = UTF16.combinePair(c, d); String rep = (String)charMap.get(s); if (rep == null) { buffer.append(c); buffer.append(d); } else { if (insertNulls) { buffer.append((char)0); buffer.append(rep); buffer.append((char)0); } else { buffer.append(rep); } } } else { String rep = (String)charMap.get(c); if (rep == null) { buffer.append(c); } else { if (insertNulls) { buffer.append((char)0); buffer.append(rep); buffer.append((char)0); } else { buffer.append(rep); } } } } else { buffer.append(c); } } return buffer; } }; // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/event/CDATAFilter.java0000644000175000017500000002235111033112257021350 0ustar eugeneeugenepackage net.sf.saxon.event; import net.sf.saxon.charcode.CharacterSet; import net.sf.saxon.charcode.CharacterSetFactory; import net.sf.saxon.charcode.UTF16; import net.sf.saxon.om.FastStringBuffer; import net.sf.saxon.tinytree.CharSlice; import net.sf.saxon.trans.XPathException; import javax.xml.transform.OutputKeys; import java.util.Properties; import java.util.Stack; import java.util.StringTokenizer; /** * CDATAFilter: This ProxyEmitter converts character data to CDATA sections, * if the character data belongs to one of a set of element types to be handled this way. * * @author Michael Kay */ public class CDATAFilter extends ProxyReceiver { private FastStringBuffer buffer = new FastStringBuffer(256); private Stack stack = new Stack(); private int[] nameList; // fingerprints of cdata elements private CharacterSet characterSet; /** * Create a CDATA Filter */ public CDATAFilter() { } /** * Set the properties for this CDATA filter * @param details the output properties */ public void setOutputProperties (Properties details) throws XPathException { nameList = getCdataElements(details); characterSet = CharacterSetFactory.getCharacterSet(details, getPipelineConfiguration()); } /** * Output element start tag */ public void startElement(int nameCode, int typeCode, int locationId, int properties) throws XPathException { flush(); stack.push(new Integer(nameCode & 0xfffff)); nextReceiver.startElement(nameCode, typeCode, locationId, properties); } /** * Output element end tag */ public void endElement() throws XPathException { flush(); stack.pop(); nextReceiver.endElement(); } /** * Output a processing instruction */ public void processingInstruction(String target, CharSequence data, int locationId, int properties) throws XPathException { flush(); nextReceiver.processingInstruction(target, data, locationId, properties); } /** * Output character data */ public void characters(CharSequence chars, int locationId, int properties) throws XPathException { if ((properties & ReceiverOptions.DISABLE_ESCAPING) == 0) { buffer.append(chars.toString()); } else { // if the user requests disable-output-escaping, this overrides the CDATA request. We end // the CDATA section and output the characters as supplied. flush(); nextReceiver.characters(chars, locationId, properties); } } /** * Output a comment */ public void comment(CharSequence chars, int locationId, int properties) throws XPathException { flush(); nextReceiver.comment(chars, locationId, properties); } /** * Flush the buffer containing accumulated character data, * generating it as CDATA where appropriate */ private void flush() throws XPathException { boolean cdata; int end = buffer.length(); if (end==0) return; if (stack.isEmpty()) { cdata = false; // text is not part of any element } else { int fprint = ((Integer)stack.peek()).intValue(); cdata = isCDATA(fprint); } if (cdata) { // Check that the buffer doesn't include a character not available in the current // encoding int start = 0; int k = 0; while ( k < end ) { int next = buffer.charAt(k); int skip = 1; if (UTF16.isHighSurrogate((char)next)) { next = UTF16.combinePair((char)next, buffer.charAt(k+1)); skip = 2; } if (next != 0 && characterSet.inCharset(next)) { k++; } else { // flush out the preceding characters as CDATA char[] array = new char[k-start]; buffer.getChars(start, k, array, 0); flushCDATA(array, k-start); while (k < end) { // output consecutive non-encodable characters // before restarting the CDATA section //super.characters(CharBuffer.wrap(buffer, k, k+skip), 0, 0); nextReceiver.characters(buffer.subSequence(k, k+skip), 0, ReceiverOptions.DISABLE_CHARACTER_MAPS); // was: (..., ReceiverOptions.DISABLE_ESCAPING); k += skip; if (k >= end) { break; } next = buffer.charAt(k); skip = 1; if (UTF16.isHighSurrogate((char)next)) { next = UTF16.combinePair((char)next, buffer.charAt(k+1)); skip = 2; } if (characterSet.inCharset(next)) { break; } } start=k; } } char[] rest = new char[end-start]; buffer.getChars(start, end, rest, 0); flushCDATA(rest, end-start); } else { nextReceiver.characters(buffer, 0, 0); } buffer.setLength(0); } /** * Output an array as a CDATA section. At this stage we have checked that all the characters * are OK, but we haven't checked that there is no "]]>" sequence in the data * @param array the data to be output * @param len the number of characters in the array actually used */ private void flushCDATA(char[] array, int len) throws XPathException { if (len == 0) { return; } final int chprop = ReceiverOptions.DISABLE_ESCAPING | ReceiverOptions.DISABLE_CHARACTER_MAPS; nextReceiver.characters("" // Also get rid of any zero bytes inserted by character map expansion int i=0; int doneto=0; while (i') { nextReceiver.characters(new CharSlice(array, doneto, i+2-doneto), 0, chprop); nextReceiver.characters("]]>", 0, chprop); } /** * See if a particular element is a CDATA element * @param fingerprint identifies the name of element we are interested * @return true if this element is included in cdata-section-elements */ private boolean isCDATA(int fingerprint) { for (int i=0; i Package overview for net.sf.saxon.event

    This package provides classes that feed SAX-like events from one tree to another. Many of these classes are associated with serializing the output of a stylesheet, but there are also classes for building a tree from a stream of events, for stripping whitespace, and so on.

    The Receiver interface defines a class that accepts a stream of events, with one method defined for each kind of event. The events are modelled on the design of SAX, but adapted to the XPath data model and to the use of Saxon's NamePool. Attributes and namespaces are notified individually after the start of the relevant element.

    The immediate output of node constructors in a query or stylesheet goes to a SequenceReceiver. This is a subclass of Receiver that can handle an arbitrary sequence, containing atomic values as well as nodes. When constructing the content of an element, a ComplexContentOutputter is used; when constructing the content of a node such as a text node or attribute, a SequenceOutputter is used instead.

    The final destination of the push pipeline is sometimes a serializer, and sometimes a tree builder. The final serialization classes are subclasses of Emitter, but some of the serialization work (such as indentation or application of character maps) is done by other classes on the pipeline. These are generally constructed by extending the ProxyReceiver class.

    The Emitter is an abstract implementation of the Receiver interface. As well as supporting the Receiver interface, it provides methods for controlling the destination of serialized output (a Writer or OutputStream) and for setting serialization properties (in a Properties object). In practice nearly all the implementations of Receiver are currently subclasses of Emitter, but this may change in the future.

    The package includes emitters for the standard output methods xml, html, and text, and proxy emitters to allow a sequence of filters to be applied to the output.

    ,

    The class ContentHandlerProxy allows events to be converted into standard SAX events and sent to a SAX2 ContentHandler. Similarly, the class ProxyReceiver acts as a ContentHandler, accepting SAX2 events and feeding them into a Receiver pipeline.

    The class Builder is a Receiver that constructs a tree representation of the document in memory. There are two subclasses for Saxon's two native tree models. Other classes such as a Stripper and a NamespaceReducer are used to modify the document by adding filters to the pipeline.

    Saxon's schema validator is also implemented using this push pipeline model. The classes that perform schema validation, however, are part of a different package: com.saxonica.validate.


    Michael H. Kay
    Saxonica Limited
    9 February 2005

    saxonb-9.1.0.8/bj/net/sf/saxon/StandardErrorHandler.java0000644000175000017500000001154011033112257022313 0ustar eugeneeugenepackage net.sf.saxon; import net.sf.saxon.expr.ExpressionLocation; import net.sf.saxon.trans.SaxonErrorCode; import net.sf.saxon.trans.XPathException; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; import javax.xml.transform.ErrorListener; import javax.xml.transform.TransformerException; import java.io.PrintWriter; import java.io.Writer; public class StandardErrorHandler implements org.xml.sax.ErrorHandler { //////////////////////////////////////////////////////////////////////////// // Implement the org.xml.sax.ErrorHandler interface. //////////////////////////////////////////////////////////////////////////// private ErrorListener errorListener; private Writer errorOutput; private int errorCount = 0; public StandardErrorHandler(ErrorListener listener) { errorListener = listener; } /** * Set output for error messages produced by the default error handler. * The default error handler does not throw an exception * for parse errors or input I/O errors, rather it returns a result code and * writes diagnostics to a user-specified output writer, which defaults to * System.err
    * This call has no effect if setErrorHandler() has been called to supply a * user-defined error handler * @param writer The Writer to use for error messages */ public void setErrorOutput(Writer writer) { errorOutput = writer; } /** * Callback interface for SAX: not for application use */ public void warning (SAXParseException e) { if (errorListener != null) { try { // DTD validation errors are reported as warnings, but we treat them as fatal errorCount++; errorListener.warning(new TransformerException(e)); } catch (Exception err) {} } } /** * Callback interface for SAX: not for application use */ public void error (SAXParseException e) throws SAXException { //System.err.println("ErrorHandler.error " + e.getMessage()); reportError(e, false); } /** * Callback interface for SAX: not for application use */ public void fatalError (SAXParseException e) throws SAXException { //System.err.println("ErrorHandler.fatalError " + e.getMessage()); reportError(e, true); throw e; } /** * Common routine for SAX errors and fatal errors */ protected void reportError (SAXParseException e, boolean isFatal) { errorCount++; if (errorListener != null) { try { ExpressionLocation loc = new ExpressionLocation(e.getSystemId(), e.getLineNumber(), e.getColumnNumber()); XPathException err = new XPathException("Error reported by XML parser", loc, e); err.setErrorCode(SaxonErrorCode.SXXP0003); if (isFatal) { errorListener.fatalError(err); } else { errorListener.error(err); } } catch (Exception err) {} } else { try { if (errorOutput == null) { errorOutput = new PrintWriter(System.err); } String errcat = (isFatal ? "Fatal error" : "Error"); errorOutput.write(errcat + " reported by XML parser: " + e.getMessage() + '\n'); errorOutput.write(" URL: " + e.getSystemId() + '\n'); errorOutput.write(" Line: " + e.getLineNumber() + '\n'); errorOutput.write(" Column: " + e.getColumnNumber() + '\n'); errorOutput.flush(); } catch (Exception e2) { System.err.println(e); System.err.println(e2); e2.printStackTrace(); } } } /** * Return the number of errors (including warnings) reported * @return the number of errors and warnings */ public int getErrorCount() { return errorCount; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. //saxonb-9.1.0.8/bj/net/sf/saxon/Transform.java0000644000175000017500000016644611033112257020236 0ustar eugeneeugenepackage net.sf.saxon; import net.sf.saxon.event.Builder; import net.sf.saxon.event.Receiver; import net.sf.saxon.event.SaxonOutputKeys; import net.sf.saxon.instruct.TerminationException; import net.sf.saxon.om.Validation; import net.sf.saxon.trace.ExpressionPresenter; import net.sf.saxon.trace.TraceListener; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.UntypedAtomicValue; import org.xml.sax.InputSource; import org.xml.sax.XMLReader; import javax.xml.transform.*; import javax.xml.transform.sax.SAXSource; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; import java.io.File; import java.io.FileOutputStream; import java.io.OutputStream; import java.io.PrintStream; import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Properties; /** * This Transform class is the entry point to the Saxon XSLT Processor. This * class is provided to control the processor from the command line.

    *

    * The XSLT syntax supported conforms to the W3C XSLT 1.0 and XPath 1.0 recommendation. * Only the transformation language is implemented (not the formatting objects). * Saxon extensions are documented in the file extensions.html * * @author Michael H. Kay */ public class Transform { protected TransformerFactoryImpl factory; protected Configuration config; protected boolean useURLs = false; protected boolean showTime = false; protected int repeat = 1; String sourceParserName = null; /** * Main program, can be used directly from the command line. *

    The format is:

    *

    java net.sf.saxon.Transform [options] source-file style-file >output-file

    *

    followed by any number of parameters in the form {keyword=value}... which can be * referenced from within the stylesheet.

    *

    This program applies the XSL style sheet in style-file to the source XML document in source-file.

    * * @param args List of arguments supplied on operating system command line * @throws java.lang.Exception Indicates that a compile-time or * run-time error occurred */ public static void main(String args[]) throws java.lang.Exception { // the real work is delegated to another routine so that it can be used in a subclass (new Transform()).doTransform(args, "java net.sf.saxon.Transform"); } /** * Set the configuration in the TransformerFactory. This is designed to be * overridden in a subclass * @param schemaAware True if the transformation is to be schema-aware * @param className Name of the schema-aware Configuration class to be loaded. Designed for use by .NET; * can normally be null. */ public void setFactoryConfiguration(boolean schemaAware, String className) throws RuntimeException { if (schemaAware) { config = Configuration.makeSchemaAwareConfiguration(null, className); } else { config = new Configuration(); // In basic XSLT, all nodes are untyped when calling from the command line config.setAllNodesUntyped(true); } factory = new TransformerFactoryImpl(config); } /** * Support method for main program. This support method can also be invoked from subclasses * that support the same command line interface * * @param args the command-line arguments * @param command the form of the command as written by the user, to be used in error messages */ public void doTransform(String args[], String command) { String sourceFileName = null; String styleFileName = null; File outputFile = null; ArrayList parameterList = new ArrayList(20); String outputFileName = null; String initialMode = null; String initialTemplate = null; boolean useAssociatedStylesheet = false; boolean wholeDirectory = false; boolean precompiled = false; boolean dtdValidation = false; String styleParserName = null; boolean explain = false; String explainOutputFileName = null; String additionalSchemas = null; PrintStream traceDestination = System.err; boolean closeTraceDestination = false; boolean schemaAware = false; for (int i=0; i= args.length) { break; } if (args[i].charAt(0) == '-') { String option; String value = null; int colon = args[i].indexOf(':'); if (colon > 0 && colon < args[i].length() - 1) { option = args[i].substring(1, colon); value = args[i].substring(colon+1); } else { option = args[i].substring(1); } if (option.equals("a")) { useAssociatedStylesheet = true; i++; } else if (option.equals("c")) { precompiled = true; if (value != null) { styleFileName = value; } i++; } else if (option.equals("cr")) { i++; if (value == null) { if (args.length < i + 2) { badUsage(command, "No resolver after -cr"); } value = args[i++]; } Object resolver = config.getInstance(value, null); factory.setAttribute(FeatureKeys.COLLECTION_URI_RESOLVER, resolver); } else if (option.equals("ds")) { factory.setAttribute(FeatureKeys.TREE_MODEL, new Integer(Builder.LINKED_TREE)); i++; } else if (option.equals("dt")) { factory.setAttribute(FeatureKeys.TREE_MODEL, new Integer(Builder.TINY_TREE)); i++; } else if (option.equals("dtd")) { if (!("on".equals(value) || "off".equals(value))) { badUsage(command, "-dtd option must be -dtd:on or -dtd:off"); } factory.setAttribute(FeatureKeys.DTD_VALIDATION, Boolean.valueOf("on".equals(value))); i++; } else if (option.equals("expand")) { if (!("on".equals(value) || "off".equals(value))) { badUsage(command, "-expand option must be 'on' or 'off'"); } factory.setAttribute(FeatureKeys.EXPAND_ATTRIBUTE_DEFAULTS, Boolean.valueOf("on".equals(value))); i++; } else if (option.equals("explain")) { explain = true; explainOutputFileName = value; // may be omitted/null factory.setAttribute(FeatureKeys.TRACE_OPTIMIZER_DECISIONS, Boolean.TRUE); i++; } else if (option.equals("ext")) { if (!("on".equals(value) || "off".equals(value))) { badUsage(command, "-ext option must be -ext:on or -ext:off"); } factory.setAttribute(FeatureKeys.ALLOW_EXTERNAL_FUNCTIONS, Boolean.valueOf("on".equals(value))); i++; } else if (option.equals("im")) { i++; if (value == null) { if (args.length < i + 2) { badUsage(command, "No initial mode after -im"); } value = args[i++]; } initialMode = value; } else if (option.equals("it")) { i++; if (value == null) { if (args.length < i + 2) { badUsage(command, "No initial template after -it"); } value = args[i++]; } initialTemplate = value; } else if (option.equals("l")) { if (!(value==null || "on".equals(value) || "off".equals(value))) { badUsage(command, "-l option must be -l:on or -l:off"); } factory.setAttribute(FeatureKeys.LINE_NUMBERING, Boolean.valueOf(!"off".equals(value))); i++; } else if (option.equals("m")) { i++; if (value == null) { if (args.length < i + 2) { badUsage(command, "No message receiver class after -m"); } value = args[i++]; } factory.setAttribute(FeatureKeys.MESSAGE_EMITTER_CLASS, value); } else if (option.equals("noext")) { i++; factory.setAttribute(FeatureKeys.ALLOW_EXTERNAL_FUNCTIONS, Boolean.valueOf(false)); } else if (option.equals("novw")) { factory.setAttribute(FeatureKeys.VERSION_WARNING, Boolean.valueOf(false)); i++; } else if (option.equals("o")) { i++; if (value == null) { if (args.length < i + 2) { badUsage(command, "No output file name after -o"); } value = args[i++]; } outputFileName = value; } else if (option.equals("or")) { i++; if (value == null) { if (args.length < i + 2) { badUsage(command, "No output resolver class after -or"); } value = args[i++]; } String orclass = value; Object resolver = config.getInstance(orclass, null); factory.setAttribute(FeatureKeys.OUTPUT_URI_RESOLVER, resolver); } else if (option.equals("outval")) { if (schemaAware) { if (!(value==null || "recover".equals(value) || "fatal".equals(value))) { badUsage(command, "-outval option must be 'recover' or 'fatal'"); } factory.setAttribute(FeatureKeys.VALIDATION_WARNINGS, Boolean.valueOf("recover".equals(value))); } else { quit("The -outval option requires a schema-aware processor", 2); } i++; } else if (option.equals("p")) { i++; if (!(value==null || "on".equals(value) || "off".equals(value))) { badUsage(command, "-p option must be -p:on or -p:off"); } if (!"off".equals(value)) { //setPOption(config); config.setParameterizedURIResolver(); useURLs = true; } } else if (option.equals("r")) { i++; if (value == null) { if (args.length < i + 2) { badUsage(command, "No URIesolver class after -r"); } value = args[i++]; } factory.setURIResolver(config.makeURIResolver(value)); } else if (option.equals("repeat")) { i++; if (value == null) { badUsage(command, "No number after -repeat"); } else { try { repeat = Integer.parseInt(value); } catch (NumberFormatException err) { badUsage(command, "Bad number after -repeat"); } } } else if (option.equals("s")) { i++; if (value == null) { if (args.length < i + 2) { badUsage(command, "No source file name after -s"); } value = args[i++]; } sourceFileName = value; } else if (option.equals("sa")) { // already handled i++; } else if (option.equals("snone")) { factory.setAttribute(FeatureKeys.STRIP_WHITESPACE, "none"); i++; } else if (option.equals("sall")) { factory.setAttribute(FeatureKeys.STRIP_WHITESPACE, "all"); i++; } else if (option.equals("signorable")) { factory.setAttribute(FeatureKeys.STRIP_WHITESPACE, "ignorable"); i++; } else if (option.equals("strip")) { if ("none".equals(value) || "all".equals(value) || "ignorable".equals(value)) { factory.setAttribute(FeatureKeys.STRIP_WHITESPACE, value); i++; } else { badUsage(command, "-strip must be none, all, or ignorable"); } } else if (option.equals("t")) { if (!showTime) { // don't do it twice if the option appears twice System.err.println(config.getProductTitle()); System.err.println(Configuration.getPlatform().getPlatformVersion()); factory.setAttribute(FeatureKeys.TIMING, Boolean.valueOf(true)); showTime = true; } i++; } else if (option.equals("T")) { i++; TraceListener traceListener; if (value == null) { traceListener = new net.sf.saxon.trace.XSLTTraceListener(); } else { traceListener = config.makeTraceListener(value); } factory.setAttribute(FeatureKeys.TRACE_LISTENER, traceListener); factory.setAttribute(FeatureKeys.LINE_NUMBERING, Boolean.TRUE); } else if (option.equals("TJ")) { i++; factory.setAttribute(FeatureKeys.TRACE_EXTERNAL_FUNCTIONS, Boolean.TRUE); } else if (option.equals("TL")) { i++; if (args.length < i + 2) { badUsage(command, "No TraceListener class"); } TraceListener traceListener = config.makeTraceListener(args[i++]); factory.setAttribute(FeatureKeys.TRACE_LISTENER, traceListener); factory.setAttribute(FeatureKeys.LINE_NUMBERING, Boolean.TRUE); } else if (option.equals("TP")) { i++; TraceListener traceListener = new net.sf.saxon.trace.TimedTraceListener(); factory.setAttribute(FeatureKeys.TRACE_LISTENER, traceListener); factory.setAttribute(FeatureKeys.LINE_NUMBERING, Boolean.TRUE); } else if (option.equals("traceout")) { i++; if (value.equals("#err")) { // no action, this is the default } else if (value.equals("#out")) { traceDestination = System.out; } else if (value.equals("#null")) { traceDestination = null; } else { traceDestination = new PrintStream(new FileOutputStream(new File(value))); closeTraceDestination = true; } } else if (option.equals("tree")) { if ("linked".equals(value)) { factory.setAttribute(FeatureKeys.TREE_MODEL, new Integer(Builder.LINKED_TREE)); } else if ("tiny".equals(value)) { factory.setAttribute(FeatureKeys.TREE_MODEL, new Integer(Builder.TINY_TREE)); } else { badUsage(command, "-tree option must be 'linked' or 'tiny'"); } i++; } else if (option.equals("u")) { useURLs = true; i++; } else if (option.equals("v")) { factory.setAttribute(FeatureKeys.DTD_VALIDATION, Boolean.valueOf(true)); dtdValidation = true; i++; } else if (option.equals("val")) { if (!schemaAware) { badUsage(command, "The -val option requires a schema-aware processor"); } else if (value==null || "strict".equals(value)) { factory.setAttribute(FeatureKeys.SCHEMA_VALIDATION, new Integer(Validation.STRICT)); } else if ("lax".equals(value)) { factory.setAttribute(FeatureKeys.SCHEMA_VALIDATION, new Integer(Validation.LAX)); } else { badUsage(command, "-val option must be 'strict' or 'lax'"); } i++; } else if (option.equals("vlax")) { if (schemaAware) { factory.setAttribute(FeatureKeys.SCHEMA_VALIDATION, new Integer(Validation.LAX)); } else { quit("The -vlax option requires a schema-aware processor", 2); } i++; } else if (option.equals("versionmsg")) { if (!("on".equals(value) || "off".equals(value))) { badUsage(command, "-versionmsg option must be -versionmsg:on or -versionmsg:off"); } factory.setAttribute(FeatureKeys.VERSION_WARNING, Boolean.valueOf("on".equals(value))); i++; } else if (option.equals("vw")) { if (schemaAware) { factory.setAttribute(FeatureKeys.VALIDATION_WARNINGS, Boolean.valueOf(true)); } else { quit("The -vw option requires a schema-aware processor", 2); } i++; } else if (option.equals("warnings")) { if ("silent".equals(value)) { factory.setAttribute(FeatureKeys.RECOVERY_POLICY, new Integer(Configuration.RECOVER_SILENTLY)); } else if ("recover".equals(value)) { factory.setAttribute(FeatureKeys.RECOVERY_POLICY, new Integer(Configuration.RECOVER_WITH_WARNINGS)); } else if ("fatal".equals(value)) { factory.setAttribute(FeatureKeys.RECOVERY_POLICY, new Integer(Configuration.DO_NOT_RECOVER)); } i++; } else if (option.equals("w0")) { i++; factory.setAttribute(FeatureKeys.RECOVERY_POLICY, new Integer(Configuration.RECOVER_SILENTLY)); } else if (option.equals("w1")) { i++; factory.setAttribute(FeatureKeys.RECOVERY_POLICY, new Integer(Configuration.RECOVER_WITH_WARNINGS)); } else if (option.equals("w2")) { i++; factory.setAttribute(FeatureKeys.RECOVERY_POLICY, new Integer(Configuration.DO_NOT_RECOVER)); } else if (option.equals("x")) { i++; if (value == null) { if (args.length < i + 2) { badUsage(command, "No source parser class after -x"); } value = args[i++]; } sourceParserName = value; factory.setAttribute(FeatureKeys.SOURCE_PARSER_CLASS, sourceParserName); } else if (option.equals("xi")) { if (!(value==null || "on".equals(value) || "off".equals(value))) { badUsage(command, "-xi option must be -xi:on or -xi:off"); } if (!"off".equals(value)) { factory.setAttribute(FeatureKeys.XINCLUDE, Boolean.TRUE); } i++; } else if (option.equals("xmlversion")) { // XML 1.1 i++; if (!("1.0".equals(value) | "1.1".equals(value))) { badUsage(command, "-xmlversion must be 1.0 or 1.1"); } factory.setAttribute(FeatureKeys.XML_VERSION, value); } else if (option.equals("xsd")) { i++; additionalSchemas = value; } else if (option.equals("xsdversion")) { // XSD 1.1 i++; if (!("1.0".equals(value) | "1.1".equals(value))) { badUsage(command, "-xsdversion must be 1.0 or 1.1"); } config.setConfigurationProperty(FeatureKeys.XSD_VERSION, value); } else if (option.equals("xsiloc")) { i++; if ("off".equals(value)) { config.setConfigurationProperty(FeatureKeys.USE_XSI_SCHEMA_LOCATION, Boolean.FALSE); } else if ("on".equals(value)) { config.setConfigurationProperty(FeatureKeys.USE_XSI_SCHEMA_LOCATION, Boolean.TRUE); } else { badUsage(value, "format: -xsiloc:(on|off)"); } } else if (option.equals("xsl")) { i++; styleFileName = value; } else if (option.equals("y")) { i++; if (value == null) { if (args.length < i + 2) { badUsage(command, "No stylesheet parser class after -y"); } value = args[i++]; } styleParserName = value; factory.setAttribute(FeatureKeys.STYLE_PARSER_CLASS, value); } else if (option.equals("1.1")) { // XML 1.1 i++; factory.setAttribute(FeatureKeys.XML_VERSION, "1.1"); } else if (args[i].equals("-?")) { badUsage(command, ""); } else if (args[i].equals("-")) { break; // this means take the source from standard input } else { badUsage(command, "Unknown option " + args[i]); } } else { break; } } if (initialTemplate != null && useAssociatedStylesheet) { badUsage(command, "-it and -a options cannot be used together"); } if (initialTemplate == null && sourceFileName == null) { if (args.length < i + 1) { badUsage(command, "No source file name"); } sourceFileName = args[i++]; } if (!useAssociatedStylesheet && styleFileName == null) { if (args.length < i + 1) { badUsage(command, "No stylesheet file name"); } styleFileName = args[i++]; } for (int p = i; p < args.length; p++) { String arg = args[p]; int eq = arg.indexOf("="); if (eq < 1 || eq >= arg.length()) { badUsage(command, "Bad param=value pair on command line: " + arg); } parameterList.add(arg); } config.displayLicenseMessage(); if (additionalSchemas != null) { Query.loadAdditionalSchemas(config, additionalSchemas); } List sources = null; if (sourceFileName != null) { boolean useSAXSource = sourceParserName != null || dtdValidation; Object loaded = loadDocuments(sourceFileName, useURLs, config, useSAXSource); if (loaded instanceof List) { wholeDirectory = true; sources = (List)loaded; } else { wholeDirectory = false; sources = new ArrayList(1); sources.add(loaded); } sources = preprocess(sources); if (wholeDirectory) { if (outputFileName == null) { quit("To process a directory, -o must be specified", 2); } else if (outputFileName.equals(sourceFileName)) { quit("Output directory must be different from input", 2); } else { outputFile = new File(outputFileName); if (!outputFile.isDirectory()) { quit("Input is a directory, but output is not", 2); } } } } if (outputFileName != null && !wholeDirectory) { outputFile = new File(outputFileName); if (outputFile.isDirectory()) { quit("Output is a directory, but input is not", 2); } } if (useAssociatedStylesheet) { if (wholeDirectory) { processDirectoryAssoc(sources, outputFile, parameterList, initialMode, traceDestination); } else { processFileAssoc((Source)sources.get(0), null, outputFile, parameterList, initialMode, traceDestination); } } else { long startTime = (new Date()).getTime(); PreparedStylesheet sheet = null; if (precompiled) { try { sheet = PreparedStylesheet.loadCompiledStylesheet(config, styleFileName); if (showTime) { long endTime = (new Date()).getTime(); System.err.println("Stylesheet loading time: " + (endTime - startTime) + " milliseconds"); } } catch (Exception err) { err.printStackTrace(); } } else { Source styleSource; XMLReader styleParser = null; if (useURLs || styleFileName.startsWith("http:") || styleFileName.startsWith("file:")) { styleSource = config.getURIResolver().resolve(styleFileName, null); if (styleSource == null) { styleSource = config.getSystemURIResolver().resolve(styleFileName, null); } } else if (styleFileName.equals("-")) { // take input from stdin if (styleParserName == null) { styleSource = new StreamSource(System.in); } else if (Configuration.getPlatform().isJava()) { styleParser = config.getStyleParser(); styleSource = new SAXSource(styleParser, new InputSource(System.in)); } else { styleSource = new StreamSource(System.in); } } else { File sheetFile = new File(styleFileName); if (!sheetFile.exists()) { quit("Stylesheet file " + sheetFile + " does not exist", 2); } if (styleParserName == null) { styleSource = new StreamSource(sheetFile.toURI().toString()); } else { InputSource eis = new InputSource(sheetFile.toURI().toString()); styleParser = config.getStyleParser(); styleSource = new SAXSource(styleParser, eis); } } if (styleSource == null) { quit("URIResolver for stylesheet file must return a Source", 2); } sheet = (PreparedStylesheet)factory.newTemplates(styleSource); if (styleParser != null) { config.reuseStyleParser(styleParser); // pointless, because the Configuration won't be used again; but we want to set a good example } if (showTime) { long endTime = now(); System.err.println("Stylesheet compilation time: " + (endTime - startTime) + " milliseconds"); } if (explain) { OutputStream explainOutput; if (explainOutputFileName == null) { explainOutput = System.err; } else { explainOutput = new FileOutputStream(new File(explainOutputFileName)); } Properties props = new Properties(); props.setProperty(OutputKeys.METHOD, "xml"); props.setProperty(OutputKeys.INDENT, "yes"); props.setProperty(SaxonOutputKeys.INDENT_SPACES, "2"); Receiver diag = config.getSerializerFactory().getReceiver( new StreamResult(explainOutput), config.makePipelineConfiguration(), props); ExpressionPresenter expressionPresenter = new ExpressionPresenter(config, diag); sheet.explain(expressionPresenter); expressionPresenter.close(); } } if (wholeDirectory) { processDirectory(sources, sheet, outputFile, parameterList, initialTemplate, initialMode, traceDestination); } else { Source source = (sources == null ? null : (Source)sources.get(0)); processFile(source, sheet, outputFile, parameterList, initialTemplate, initialMode, traceDestination); } if (closeTraceDestination) { traceDestination.close(); } } } catch (TerminationException err) { quit(err.getMessage(), 1); } catch (TransformerConfigurationException err) { //err.printStackTrace(); quit(err.getMessage(), 2); } catch (TransformerException err) { //err.printStackTrace(); quit("Transformation failed: " + err.getMessage(), 2); } catch (TransformerFactoryConfigurationError err) { //err.printStackTrace(); quit("Transformation failed: " + err.getMessage(), 2); } catch (Exception err2) { err2.printStackTrace(); quit("Fatal error during transformation: " + err2.getClass().getName() + ": " + (err2.getMessage() == null ? " (no message)" : err2.getMessage()), 2); } //System.exit(0); } /** * Preprocess the list of sources. This method exists so that it can be * overridden in a subclass * @param sources the list of Source objects * @return a revised list of Source objects */ public List preprocess(List sources) throws XPathException { return sources; } /** * Get the configuration. * @return the Saxon configuration */ protected Configuration getConfiguration() { return config; } /** * Exit with a message * * @param message The message to be output * @param code The result code to be returned to the operating * system shell */ protected static void quit(String message, int code) { System.err.println(message); System.exit(code); } /** * Load a document, or all the documents in a directory, given a filename or URL * @param sourceFileName the name of the source file or directory * @param useURLs true if the filename argument is to be treated as a URI * @param config the Saxon configuration * @param useSAXSource true if the method should use a SAXSource rather than a StreamSource * @return if sourceFileName represents a single source document, return a Source object representing * that document. If sourceFileName represents a directory, return a List containing multiple Source * objects, one for each file in the directory. */ public static Object loadDocuments(String sourceFileName, boolean useURLs, Configuration config, boolean useSAXSource) throws TransformerException { Source sourceInput; XMLReader parser; if (useURLs || sourceFileName.startsWith("http:") || sourceFileName.startsWith("file:")) { sourceInput = config.getURIResolver().resolve(sourceFileName, null); if (sourceInput == null) { sourceInput = config.getSystemURIResolver().resolve(sourceFileName, null); } return sourceInput; } else if (sourceFileName.equals("-")) { // take input from stdin if (useSAXSource) { parser = config.getSourceParser(); sourceInput = new SAXSource(parser, new InputSource(System.in)); } else { sourceInput = new StreamSource(System.in); } return sourceInput; } else { File sourceFile = new File(sourceFileName); if (!sourceFile.exists()) { quit("Source file " + sourceFile + " does not exist", 2); } if (sourceFile.isDirectory()) { parser = config.getSourceParser(); List result = new ArrayList(20); String[] files = sourceFile.list(); for (int f = 0; f < files.length; f++) { File file = new File(sourceFile, files[f]); if (!file.isDirectory()) { if (useSAXSource) { InputSource eis = new InputSource(file.toURI().toString()); sourceInput = new SAXSource(parser, eis); // it's safe to use the same parser for each document, as they // will be processed one at a time. } else { sourceInput = new StreamSource(file.toURI().toString()); } result.add(sourceInput); } } return result; } else { if (useSAXSource) { InputSource eis = new InputSource(sourceFile.toURI().toString()); sourceInput = new SAXSource(config.getSourceParser(), eis); } else { sourceInput = new StreamSource(sourceFile.toURI().toString()); } return sourceInput; } } } /** * Process each file in the source directory using its own associated stylesheet * * @param sources The sources in the directory to be processed * @param outputDir The directory in which output files are to be * created * @param parameterList List of parameters to be supplied to each * transformation * @param initialMode Initial mode for executing each * transformation * @param traceDestination output destination for fn:trace() calls * @throws Exception when any error occurs during a transformation */ public void processDirectoryAssoc(List sources, File outputDir, ArrayList parameterList, String initialMode, PrintStream traceDestination) throws Exception { int failures = 0; for (int f = 0; f < sources.size(); f++) { Source source = (Source)sources.get(f); String localName = getLocalFileName(source); try { processFileAssoc(source, localName, outputDir, parameterList, initialMode, traceDestination); } catch (XPathException err) { failures++; System.err.println("While processing " + localName + ": " + err.getMessage() + '\n'); } } if (failures > 0) { throw new XPathException(failures + " transformation" + (failures == 1 ? "" : "s") + " failed"); } } /** * Make an output file in the output directory, with filename extension derived from the * media-type produced by the stylesheet * * @param directory The directory in which the file is to be created * @param localName The local name of the file within the * directory, excluding the file type suffix * @param sheet The Templates object identifying the stylesheet - * used to determine the output method, and hence the suffix to be * used for the filename * @return The newly created file */ private File makeOutputFile(File directory, String localName, Templates sheet) { String mediaType = sheet.getOutputProperties().getProperty(OutputKeys.MEDIA_TYPE); String suffix = ".xml"; if ("text/html".equals(mediaType)) { suffix = ".html"; } else if ("text/plain".equals(mediaType)) { suffix = ".txt"; } String prefix = localName; if (localName.endsWith(".xml") || localName.endsWith(".XML")) { prefix = localName.substring(0, localName.length() - 4); } return new File(directory, prefix + suffix); } /** * Process a single source file using its associated stylesheet(s) * * @param sourceInput Identifies the source file to be transformed * @param localName The local name of the file within the * directory, excluding the file type suffix * @param outputFile The output file to contain the results of the * transformation * @param parameterList List of parameters to be supplied to the * transformation * @param initialMode Initial mode for executing the transformation * @param traceDestination Destination for trace output * @throws XPathException If the transformation fails */ public void processFileAssoc(Source sourceInput, String localName, File outputFile, ArrayList parameterList, String initialMode, PrintStream traceDestination) throws TransformerException { if (showTime) { System.err.println("Processing " + sourceInput.getSystemId() + " using associated stylesheet"); } long startTime = now(); Source style = factory.getAssociatedStylesheet(sourceInput, null, null, null); Templates sheet = factory.newTemplates(style); if (showTime) { System.err.println("Prepared associated stylesheet " + style.getSystemId()); } Controller controller = newController(sheet, parameterList, traceDestination, initialMode, null); File outFile = outputFile; if (outFile != null && outFile.isDirectory()) { outFile = makeOutputFile(outFile, localName, sheet); } StreamResult result = (outFile == null ? new StreamResult(System.out) : new StreamResult(outFile.toURI().toString())); try { controller.transform(sourceInput, result); } catch (TerminationException err) { throw err; } catch (XPathException err) { // The error message will already have been displayed; don't do it twice throw new XPathException("Run-time errors were reported"); } if (showTime) { long endTime = now(); System.err.println("Execution time: " + (endTime - startTime) + " milliseconds"); } } /** * Create a new Controller. This method is protected so it can be overridden in a subclass, allowing additional * options to be set on the Controller * @param sheet The Templates object representing the compiled stylesheet * @param parameterList A list of "keyword=value" pairs representing parameter values, in their original * format from the command line, including any initial "+" or "!" qualifier * @param traceDestination destination for trace output * @param initialMode the initial mode for the transformation, as a Clark name. Can be null * @param initialTemplate the name of the initial template for the transformation, as a Clark name. Can be null * @return the newly constructed Controller to be used for the transformation * @throws TransformerException if any error occurs */ protected Controller newController( Templates sheet, ArrayList parameterList, PrintStream traceDestination, String initialMode, String initialTemplate) throws TransformerException { Controller controller = (Controller)sheet.newTransformer(); setParams(controller, parameterList); controller.setTraceFunctionDestination(traceDestination); if (initialMode != null) { controller.setInitialMode(initialMode); } if (initialTemplate != null) { controller.setInitialTemplate(initialTemplate); } return controller; } /** * Get current time in milliseconds * @return the current time in milliseconds since 1970 */ public static long now() { return System.currentTimeMillis(); } /** * Process each file in the source directory using the same supplied stylesheet * * @param sources The sources in the directory to be processed * @param sheet The Templates object identifying the stylesheet * @param outputDir The directory in which output files are to be * created * @param parameterList List of parameters to be supplied to each * transformation * @param initialTemplate Initial template for executing each * transformation * @param initialMode Initial mode for executing each * transformation * @param traceDestination Destination for output from fn:trace() calls * @throws XPathException when any error occurs during a * transformation */ public void processDirectory(List sources, Templates sheet, File outputDir, ArrayList parameterList, String initialTemplate, String initialMode, PrintStream traceDestination) throws TransformerException { int failures = 0; for (int f = 0; f < sources.size(); f++) { Source source = (Source)sources.get(f); String localName = getLocalFileName(source); try { File outputFile = makeOutputFile(outputDir, localName, sheet); processFile(source, sheet, outputFile, parameterList, initialTemplate, initialMode, traceDestination); } catch (XPathException err) { failures++; System.err.println("While processing " + localName + ": " + err.getMessage() + '\n'); } } if (failures > 0) { throw new XPathException(failures + " transformation" + (failures == 1 ? "" : "s") + " failed"); } } private static String getLocalFileName(Source source) { try { String path = new URI(source.getSystemId()).getPath(); while (true) { int sep = path.indexOf('/'); if (sep < 0) { return path; } else { path = path.substring(sep + 1); } } } catch (URISyntaxException err) { throw new IllegalArgumentException(err.getMessage()); } } /** * Process a single file using a supplied stylesheet * * @param source The source XML document to be transformed (maybe null if an initial template * is specified) * @param sheet The Templates object identifying the stylesheet * @param outputFile The output file to contain the results of the * transformation * @param parameterList List of parameters to be supplied to the * transformation * @param initialTemplate Initial template for executing each * transformation * @param initialMode Initial mode for executing the transformation * @param traceDestination Destination for output from fn:trace() function * @throws net.sf.saxon.trans.XPathException * If the transformation fails */ public void processFile(Source source, Templates sheet, File outputFile, ArrayList parameterList, String initialTemplate, String initialMode, PrintStream traceDestination) throws TransformerException { long totalTime = 0; int runs = 0; for (int r = 0; r < repeat; r++) { // repeat is for internal testing/timing if (showTime) { String msg = "Processing "; if (source != null) { msg += source.getSystemId(); } else { msg += " (no source document)"; } if (initialMode != null) { msg += " initial mode = " + initialMode; } if (initialTemplate != null) { msg += " initial template = " + initialTemplate; } System.err.println(msg); } long startTime = now(); runs++; Controller controller = newController(sheet, parameterList, traceDestination, initialMode, initialTemplate); Result result = (outputFile == null ? new StreamResult(System.out) : new StreamResult(outputFile.toURI().toString())); try { controller.transform(source, result); } catch (TerminationException err) { throw err; } catch (XPathException err) { // The message will already have been displayed; don't do it twice if (!err.hasBeenReported()) { err.printStackTrace(); } throw new XPathException("Run-time errors were reported"); } long endTime = now(); totalTime += (endTime - startTime); if (showTime) { System.err.println("Execution time: " + (endTime - startTime) + " milliseconds"); System.err.println("Memory used: " + (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory())); config.getNamePool().statistics(); if (repeat > 1) { System.err.println("-------------------------------"); Runtime.getRuntime().gc(); } } if (repeat == 999999 && totalTime > 60000) { break; } } if (repeat > 1) { System.err.println("*** Average execution time over " + runs + " runs: " + (totalTime / runs) + "ms"); } } /** * Supply the requested parameters to the transformer. This method is protected so that it can * be overridden in a subclass. * * @param controller The controller to be used for the transformation * @param parameterList A list of "keyword=value" pairs representing parameter values, in their original * format from the command line, including any initial "+" or "!" qualifier */ protected void setParams(Controller controller, ArrayList parameterList) throws TransformerException { for (int i = 0; i < parameterList.size(); i++) { String arg = (String)parameterList.get(i); int eq = arg.indexOf("="); String argname = arg.substring(0, eq); String argvalue = (eq == arg.length()-1 ? "" : arg.substring(eq + 1)); if (argname.startsWith("!")) { // parameters starting with "!" are taken as output properties controller.setOutputProperty(argname.substring(1), argvalue); } else if (argname.startsWith("+")) { // parameters starting with "+" are taken as input documents Object sources = loadDocuments(argvalue, useURLs, config, true); controller.setParameter(argname.substring(1), sources); } else { controller.setParameter(argname, new UntypedAtomicValue(argvalue)); } } } /** * Report incorrect usage of the command line, with a list of the options and arguments that are available * * @param name The name of the command being executed (allows subclassing) * @param message The error message */ protected void badUsage(String name, String message) { if (!"".equals(message)) { System.err.println(message); } if (!showTime) { System.err.println(config.getProductTitle()); } System.err.println("Usage: see http://www.saxonica.com/documentation/using-xsl/commandline.html"); System.err.println("Options: "); System.err.println(" -a Use xml-stylesheet PI, not style-doc argument"); System.err.println(" -c:filename Use compiled stylesheet from file"); System.err.println(" -cr:classname Use collection URI resolver class"); System.err.println(" -dtd:on|off Validate using DTD"); System.err.println(" -expand:on|off Expand defaults defined in schema/DTD"); System.err.println(" -explain[:filename] Display compiled expression tree"); System.err.println(" -ext:on|off Allow|Disallow external Java functions"); System.err.println(" -im:modename Initial mode"); System.err.println(" -it:template Initial template"); System.err.println(" -l:on|off Line numbering for source document"); System.err.println(" -m:classname Use message receiver class"); System.err.println(" -o:filename Output file or directory"); System.err.println(" -or:classname Use OutputURIResolver class"); System.err.println(" -outval:recover|fatal Handling of validation errors on result document"); System.err.println(" -p:on|off Recognize URI query parameters"); System.err.println(" -r:classname Use URIResolver class"); System.err.println(" -repeat:N Repeat N times for performance measurement"); System.err.println(" -s:filename Initial source document"); System.err.println(" -sa Schema-aware transformation"); System.err.println(" -strip:all|none|ignorable Strip whitespace text nodes"); System.err.println(" -t Display version and timing information"); System.err.println(" -T[:classname] Use TraceListener class"); System.err.println(" -TJ Trace calls to external Java functions"); System.err.println(" -tree:tiny|linked Select tree model"); System.err.println(" -traceout:file|#null Destination for fn:trace() output"); System.err.println(" -u Names are URLs not filenames"); System.err.println(" -val:strict|lax Validate using schema"); System.err.println(" -versionmsg:on|off Warn when using XSLT 1.0 stylesheet"); System.err.println(" -warnings:silent|recover|fatal Handling of recoverable errors"); System.err.println(" -x:classname Use specified SAX parser for source file"); System.err.println(" -xi:on|off Expand XInclude on all documents"); System.err.println(" -xmlversion:1.0|1.1 Version of XML to be handled"); System.err.println(" -xsd:file;file.. Additional schema documents to be loaded"); System.err.println(" -xsdversion:1.0|1.1 Version of XML Schema to be used"); System.err.println(" -xsiloc:on|off Take note of xsi:schemaLocation"); System.err.println(" -xsl:filename Stylesheet file"); System.err.println(" -y:classname Use specified SAX parser for stylesheet"); System.err.println(" -? Display this message "); System.err.println(" param=value Set stylesheet string parameter"); System.err.println(" +param=filename Set stylesheet document parameter"); System.err.println(" !option=value Set serialization option"); if ("".equals(message)) { System.exit(0); } else { System.exit(2); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): changes to allow source and/or stylesheet from stdin contributed by // Gunther Schadow [gunther@aurora.regenstrief.org] // saxonb-9.1.0.8/bj/net/sf/saxon/tinytree/0000755000175000017500000000000012216261743017253 5ustar eugeneeugenesaxonb-9.1.0.8/bj/net/sf/saxon/tinytree/TinyDocumentImpl.java0000644000175000017500000002103111033112257023346 0ustar eugeneeugenepackage net.sf.saxon.tinytree; import net.sf.saxon.Configuration; import net.sf.saxon.sort.IntHashMap; import net.sf.saxon.event.Receiver; import net.sf.saxon.om.*; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.Type; import java.util.*; /** * A node in the XML parse tree representing the Document itself (or equivalently, the root * node of the Document).

    */ public final class TinyDocumentImpl extends TinyParentNodeImpl implements DocumentInfo { private HashMap idTable = null; private IntHashMap elementList = null; private HashMap entityTable = null; private String baseURI = null; public TinyDocumentImpl(TinyTree tree) { this.tree = tree; nodeNr = tree.numberOfNodes; } /** * Get the tree containing this node */ public TinyTree getTree() { return tree; } /** * Set the Configuration that contains this document */ public void setConfiguration(Configuration config) { if (config != tree.getConfiguration()) { throw new IllegalArgumentException( "Configuration of document differs from that of the supporting TinyTree"); } } /** * Get the configuration previously set using setConfiguration */ public Configuration getConfiguration() { return tree.getConfiguration(); } /** * Set the system id of this node */ public void setSystemId(String uri) { tree.setSystemId(nodeNr, uri); } /** * Get the system id of this root node */ public String getSystemId() { return tree.getSystemId(nodeNr); } /** * Set the base URI of this document node */ public void setBaseURI(String uri) { baseURI = uri; } /** * Get the base URI of this root node. */ public String getBaseURI() { if (baseURI != null) { return baseURI; } return getSystemId(); } /** * Get the line number of this root node. * @return 0 always */ public int getLineNumber() { return 0; } /** * Return the type of node. * @return Type.DOCUMENT (always) */ public final int getNodeKind() { return Type.DOCUMENT; } /** * Find the parent node of this node. * @return The Node object describing the containing element or root node. */ public NodeInfo getParent() { return null; } /** * Get the root node * @return the NodeInfo that is the root of the tree - not necessarily a document node */ public NodeInfo getRoot() { return this; } /** * Get the root (document) node * @return the DocumentInfo representing the document node, or null if the * root of the tree is not a document node */ public DocumentInfo getDocumentRoot() { return this; } /** * Get a character string that uniquely identifies this node * @param buffer to contain an identifier based on the document number */ public void generateId(FastStringBuffer buffer) { buffer.append('d'); buffer.append(Integer.toString(getDocumentNumber())); } /** * Get a list of all elements with a given name. This is implemented * as a memo function: the first time it is called for a particular * element type, it remembers the result for next time. */ AxisIterator getAllElements(int fingerprint) { if (elementList==null) { elementList = new IntHashMap(20); } List list = (List)elementList.get(fingerprint); if (list==null) { list = getElementList(fingerprint); elementList.put(fingerprint, list); } return new NodeListIterator(list); } /** * Get a list containing all the elements with a given element name * @param fingerprint the fingerprint of the element name * @return list a List containing the TinyElementImpl objects */ List getElementList(int fingerprint) { int size = tree.getNumberOfNodes()/20; if (size > 100) { size = 100; } if (size < 20) { size = 20; } List list = new ArrayList(size); int i = nodeNr+1; try { while (tree.depth[i] != 0) { if (tree.nodeKind[i]==Type.ELEMENT && (tree.nameCode[i] & 0xfffff) == fingerprint) { list.add(tree.getNode(i)); } i++; } } catch (ArrayIndexOutOfBoundsException e) { // this shouldn't happen. If it does happen, it means the tree wasn't properly closed // during construction (there is no stopper node at the end). In this case, we'll recover return list; } return list; } /** * Register a unique element ID. Fails if there is already an element with that ID. * @param e The NodeInfo (always an element) having a particular unique ID value * @param id The unique ID value. The caller is responsible for checking that this * is a valid NCName. */ void registerID(NodeInfo e, String id) { if (idTable==null) { idTable = new HashMap(256); } // the XPath spec (5.2.1) says ignore the second ID if it's not unique NodeInfo old = (NodeInfo)idTable.get(id); if (old==null) { idTable.put(id, e); } } /** * Get the element with a given ID. * @param id The unique ID of the required element, previously registered using registerID() * @return The NodeInfo (always an Element) for the given ID if one has been registered, * otherwise null. */ public NodeInfo selectID(String id) { if (idTable==null) return null; // no ID values found return (NodeInfo)idTable.get(id); } /** * Set an unparsed entity URI associated with this document. For system use only, while * building the document. */ void setUnparsedEntity(String name, String uri, String publicId) { if (entityTable==null) { entityTable = new HashMap(20); } String[] ids = new String[2]; ids[0] = uri; ids[1] = publicId; entityTable.put(name, ids); } /** * Get the list of unparsed entities defined in this document * @return an Iterator, whose items are of type String, containing the names of all * unparsed entities defined in this document. If there are no unparsed entities or if the * information is not available then an empty iterator is returned */ public Iterator getUnparsedEntityNames() { if (entityTable == null) { return Collections.EMPTY_LIST.iterator(); } else { return entityTable.keySet().iterator(); } } /** * Get the unparsed entity with a given nameID if there is one, or null if not. If the entity * does not exist, return null. * @param name the name of the entity * @return if the entity exists, return an array of two Strings, the first holding the system ID * of the entity, the second holding the public */ public String[] getUnparsedEntity(String name) { if (entityTable==null) { return null; } return (String[])entityTable.get(name); } /** * Copy this node to a given outputter */ public void copy(Receiver out, int whichNamespaces, boolean copyAnnotations, int locationId) throws XPathException { out.startDocument(0); // output the children AxisIterator children = iterateAxis(Axis.CHILD); while (true) { NodeInfo n = (NodeInfo)children.next(); if (n == null) { break; } n.copy(out, whichNamespaces, copyAnnotations, locationId); } out.endDocument(); } public void showSize() { tree.showSize(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/tinytree/TinyAttributeCollection.java0000644000175000017500000002311511033112257024732 0ustar eugeneeugenepackage net.sf.saxon.tinytree; import net.sf.saxon.event.LocationProvider; import net.sf.saxon.om.AttributeCollection; import net.sf.saxon.om.NamePool; import net.sf.saxon.om.StandardNames; /** * An implementation of the AttributeCollection interface based directly on the * TinyTree data structure. */ public class TinyAttributeCollection implements AttributeCollection { int element; TinyTree tree; int firstAttribute; public TinyAttributeCollection(TinyTree tree, int element) { this.tree = tree; this.element = element; firstAttribute = tree.alpha[element]; } /** * Set the location provider. This must be set if the methods getSystemId() and getLineNumber() * are to be used to get location information for an attribute. */ public void setLocationProvider(LocationProvider provider) { // } /** * Return the number of attributes in the list. * * @return The number of attributes in the list. */ public int getLength() { int i = firstAttribute; while (i < tree.numberOfAttributes && tree.attParent[i] == element) { i++; } return i - firstAttribute; } /** * Get the namecode of an attribute (by position). * * @param index The position of the attribute in the list. * @return The display name of the attribute as a string, or null if there * is no attribute at that position. */ public int getNameCode(int index) { return tree.attCode[firstAttribute + index]; } /** * Get the type annotation of an attribute (by position). * * @param index The position of the attribute in the list. * @return The type annotation of the attribute as the fingerprint of the type name. * The bit {@link net.sf.saxon.om.NodeInfo#IS_DTD_TYPE} represents a DTD-derived type. */ public int getTypeAnnotation(int index) { if (tree.attTypeCode == null) { return StandardNames.XS_UNTYPED_ATOMIC; } return tree.attTypeCode[firstAttribute + index]; } /** * Get the locationID of an attribute (by position) * * @param index The position of the attribute in the list. * @return The location identifier of the attribute. This can be supplied * to a {@link net.sf.saxon.event.LocationProvider} in order to obtain the * actual system identifier and line number of the relevant location */ public int getLocationId(int index) { return 0; } /** * Get the systemId part of the location of an attribute, at a given index. *

    *

    Attribute location information is not available from a SAX parser, so this method * is not useful for getting the location of an attribute in a source document. However, * in a Saxon result document, the location information represents the location in the * stylesheet of the instruction used to generate this attribute, which is useful for * debugging.

    * * @param index the required attribute * @return the systemId of the location of the attribute */ public String getSystemId(int index) { return tree.getSystemId(element); } /** * Get the line number part of the location of an attribute, at a given index. *

    *

    Attribute location information is not available from a SAX parser, so this method * is not useful for getting the location of an attribute in a source document. However, * in a Saxon result document, the location information represents the location in the * stylesheet of the instruction used to generate this attribute, which is useful for * debugging.

    * * @param index the required attribute * @return the line number of the location of the attribute */ public int getLineNumber(int index) { return -1; } /** * Get the properties of an attribute (by position) * * @param index The position of the attribute in the list. * @return The properties of the attribute. This is a set * of bit-settings defined in class {@link net.sf.saxon.event.ReceiverOptions}. The * most interesting of these is {{@link net.sf.saxon.event.ReceiverOptions#DEFAULTED_ATTRIBUTE}, * which indicates an attribute that was added to an element as a result of schema validation. */ public int getProperties(int index) { return 0; } /** * Get the prefix of the name of an attribute (by position). * * @param index The position of the attribute in the list. * @return The prefix of the attribute name as a string, or null if there * is no attribute at that position. Returns "" for an attribute that * has no prefix. */ public String getPrefix(int index) { return tree.getNamePool().getPrefix(getNameCode(index)); } /** * Get the lexical QName of an attribute (by position). * * @param index The position of the attribute in the list. * @return The lexical QName of the attribute as a string, or null if there * is no attribute at that position. */ public String getQName(int index) { return tree.getNamePool().getDisplayName(getNameCode(index)); } /** * Get the local name of an attribute (by position). * * @param index The position of the attribute in the list. * @return The local name of the attribute as a string, or null if there * is no attribute at that position. */ public String getLocalName(int index) { return tree.getNamePool().getLocalName(getNameCode(index)); } /** * Get the namespace URI of an attribute (by position). * * @param index The position of the attribute in the list. * @return The local name of the attribute as a string, or null if there * is no attribute at that position. */ public String getURI(int index) { return tree.getNamePool().getURI(getNameCode(index)); } /** * Get the index of an attribute (by name). * * @param uri The namespace uri of the attribute. * @param localname The local name of the attribute. * @return The index position of the attribute, or -1 if there is no attribute with this name */ public int getIndex(String uri, String localname) { int fingerprint = tree.getNamePool().getFingerprint(uri, localname); return getIndexByFingerprint(fingerprint); } /** * Get the index, given the fingerprint * @param fingerprint the NamePool fingerprint of the required attribute name * @return The index position of the attribute, or -1 if there is no attribute with this name */ public int getIndexByFingerprint(int fingerprint) { int i = firstAttribute; while (tree.attParent[i] == element) { if ((tree.attCode[i] & NamePool.FP_MASK) == fingerprint) { return i - firstAttribute; } i++; } return -1; } /** * Get the attribute value using its fingerprint */ public String getValueByFingerprint(int fingerprint) { return getValue(getIndexByFingerprint(fingerprint)); } /** * Get the value of an attribute (by name). * * @param uri The namespace uri of the attribute. * @param localname The local name of the attribute. * @return The index position of the attribute */ public String getValue(String uri, String localname) { return getValue(getIndex(uri, localname)); } /** * Get the value of an attribute (by position). * * @param index The position of the attribute in the list. * @return The attribute value as a string, or null if * there is no attribute at that position. */ public String getValue(int index) { CharSequence cs = tree.attValue[firstAttribute + index]; return (cs==null ? null : cs.toString()); } /** * Determine whether a given attribute has the is-ID property set */ public boolean isId(int index) { return ((getTypeAnnotation(index) & NamePool.FP_MASK) == StandardNames.XS_ID) || ((getNameCode(index) & NamePool.FP_MASK) == StandardNames.XML_ID); } /** * Determine whether a given attribute has the is-idref property set */ public boolean isIdref(int index) { return ((getTypeAnnotation(index) & NamePool.FP_MASK) == StandardNames.XS_IDREF) || ((getTypeAnnotation(index) & NamePool.FP_MASK) == StandardNames.XS_IDREFS); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/tinytree/AttributeEnumeration.java0000644000175000017500000001270611033112257024265 0ustar eugeneeugenepackage net.sf.saxon.tinytree; import net.sf.saxon.om.*; import net.sf.saxon.pattern.NameTest; import net.sf.saxon.pattern.NodeTest; import net.sf.saxon.om.StandardNames; import net.sf.saxon.type.Type; import net.sf.saxon.value.Value; import net.sf.saxon.value.UntypedAtomicValue; import net.sf.saxon.value.StringValue; import net.sf.saxon.trans.XPathException; /** * AttributeEnumeration is an iterator over all the attribute nodes of an Element. */ final class AttributeEnumeration extends AxisIteratorImpl { private TinyTree tree; private int element; private NodeTest nodeTest; private int index; private int currentNodeNr; /** * Constructor. Note: this constructor will only be called if the relevant node * is an element and if it has one or more attributes. Otherwise an EmptyEnumeration * will be constructed instead. * @param tree: the containing TinyTree * @param element: the node number of the element whose attributes are required * @param nodeTest: condition to be applied to the names of the attributes selected */ AttributeEnumeration(TinyTree tree, int element, NodeTest nodeTest) { this.nodeTest = nodeTest; this.tree = tree; this.element = element; index = tree.alpha[element]; currentNodeNr = -1; } /** * Move to the next node in the iteration. */ public boolean moveNext() { while (true) { if (index >= tree.numberOfAttributes || tree.attParent[index] != element) { index = Integer.MAX_VALUE; current = null; position = -1; currentNodeNr = -1; return false; } int typeCode = tree.getAttributeAnnotation(index); if ((typeCode & NodeInfo.IS_DTD_TYPE) != 0) { typeCode = StandardNames.XS_UNTYPED_ATOMIC; } if (nodeTest.matches(Type.ATTRIBUTE, tree.attCode[index], typeCode)) { position++; currentNodeNr = index++; if (nodeTest instanceof NameTest) { // there can only be one match, so abandon the search after this node index = Integer.MAX_VALUE; } current = null; return true; } index++; } } /** * Get the next item in the sequence.
    * * @return the next Item. If there are no more nodes, return null. */ public Item next() { if (moveNext()) { current = tree.getAttributeNode(currentNodeNr); } else { current = null; } return current; } /** * Get the current node in the sequence. * * @return the node returned by the most recent call on next(), or the node on which we positioned using * moveNext() */ public Item current() { if (current == null) { if (currentNodeNr == -1) { return null; } else { current = tree.getAttributeNode(currentNodeNr); } } return current; } /** * Return the atomized value of the current node. * * @return the atomized value. * @throws NullPointerException if there is no current node */ public Value atomize() throws XPathException { if (currentNodeNr == -1) { throw new NullPointerException(); } int typeCode = tree.getAttributeAnnotation(currentNodeNr); if ((typeCode & NodeInfo.IS_DTD_TYPE) != 0) { typeCode = StandardNames.XS_UNTYPED_ATOMIC; } // optimization: avoid creating the Node object if not needed if (typeCode == StandardNames.XS_UNTYPED_ATOMIC) { return new UntypedAtomicValue(tree.attValue[currentNodeNr]); } else if (typeCode == StandardNames.XS_STRING) { return new StringValue(tree.attValue[currentNodeNr]); } else { return ((NodeInfo)current()).atomize(); } } /** * Return the string value of the current node. * * @return the string value, as an instance of CharSequence. * @throws NullPointerException if there is no current node */ public CharSequence getStringValue() { if (currentNodeNr == -1) { throw new NullPointerException(); } return tree.attValue[currentNodeNr]; } /** * Get another iteration over the same nodes */ public SequenceIterator getAnother() { return new AttributeEnumeration(tree, element, nodeTest); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/tinytree/LargeStringBuffer.java0000644000175000017500000002641111033112257023464 0ustar eugeneeugenepackage net.sf.saxon.tinytree; import net.sf.saxon.om.FastStringBuffer; import java.io.Writer; import java.io.Serializable; import java.util.List; import java.util.ArrayList; import java.util.Arrays; /** * This is an implementation of the JDK 1.4 CharSequence interface: it implements * a CharSequence as a list of arrays of characters (the individual arrays are known * as segments). When characters are appended, a new segment is started if the previous * array would otherwise overflow a threshold size (the maxAllocation size). *

    * This is more efficient than a buffer backed by a contiguous array of characters * in cases where the size is likely to grow very large, and where substring operations * are rare. As used within the TinyTree, the value of each text node is contiguous within * one segment, so extraction of the value of a text node is efficient. */ public final class LargeStringBuffer implements CharSequence, Serializable { // TODO:PERF with large documents the Arrays.binarySearch() cost can be noticeable. // It would be better if TinyTree addressed into this structure using segment+offset addressing. // 16 bits for each would do fine. private int minAllocation; private int maxAllocation; private List segments; // each segment is a FastStringBuffer private int[] startOffsets; // if startOffsets[23] is 123456, then the first // character in segment 23 is the 123456'th character // of the CharSequence value. private int length; // total length of the CharSequence /** * Create an empty LargeStringBuffer with default space allocation */ public LargeStringBuffer() { this(4096, 65536); } /** * Create an empty LargeStringBuffer * @param minAllocation initial allocation size for each segment (including the first). If minAllocation * exceeds maxAllocation, it is rounded down to the value of maxAllocation * @param maxAllocation maximum allocation size for each segment. When a segment reaches this * size, a new segment is created rather than appending more characters to the existing segment. * However, a segment may have size greater than maxAllocation if the data is appended in a single chunk * of size maxAllocation. */ public LargeStringBuffer(int minAllocation, int maxAllocation) { this.minAllocation = Math.min(minAllocation, maxAllocation); this.maxAllocation = maxAllocation; FastStringBuffer initial = new FastStringBuffer(minAllocation); segments = new ArrayList(4); segments.add(initial); startOffsets = new int[1]; startOffsets[0] = 0; length = 0; } /** * Append a CharSequence to this LargeStringBuffer * @param data the data to be appended */ public void append(CharSequence data) { final int increment = data.length(); if (increment == 0) { return; } FastStringBuffer last = ((FastStringBuffer)segments.get(segments.size()-1)); if (last.length() + increment <= maxAllocation) { last.append(data); } else { int[] s2 = new int[startOffsets.length+1]; System.arraycopy(startOffsets, 0, s2, 0, startOffsets.length); s2[startOffsets.length] = length; startOffsets = s2; last = new FastStringBuffer(Math.max(minAllocation, increment)); segments.add(last); last.append(data); } length += increment; } /** * Returns the length of this character sequence. The length is the number * of 16-bit UTF-16 characters in the sequence.

    * * @return the number of characters in this sequence */ public int length() { return length; } /** * Returns the character at the specified index. An index ranges from zero * to length() - 1. The first character of the sequence is at * index zero, the next at index one, and so on, as for array * indexing.

    * * @param index the index of the character to be returned * * @return the specified character * * @throws IndexOutOfBoundsException * if the index argument is negative or not less than * length() */ public char charAt(int index) { if (startOffsets.length == 1) { // optimize for small documents return ((FastStringBuffer)segments.get(0)).charAt(index); } if (index < 0 || index >= length) { throw new IndexOutOfBoundsException(index+""); } int seg = Arrays.binarySearch(startOffsets, index); if (seg >= 0) { return ((FastStringBuffer)segments.get(seg)).charAt(0); } seg = -seg - 2; final int offset = index - startOffsets[seg]; return ((FastStringBuffer)segments.get(seg)).charAt(offset); } /** * Returns a new character sequence that is a subsequence of this sequence. * The subsequence starts with the character at the specified index and * ends with the character at index end - 1. The length of the * returned sequence is end - start, so if start == end * then an empty sequence is returned.

    * * @param start the start index, inclusive * @param end the end index, exclusive * * @return the specified subsequence * * @throws IndexOutOfBoundsException * if start or end are negative, * if end is greater than length(), * or if start is greater than end */ public CharSequence subSequence(int start, int end) { if (startOffsets.length == 1) { // optimize for small documents return ((FastStringBuffer)segments.get(0)).subSequence(start, end); } if (start < 0 || end < 0 || end > length || start > end) { throw new IndexOutOfBoundsException("[" + start + ',' + end + ']'); } int seg0 = Arrays.binarySearch(startOffsets, start); int offset0; if (seg0 >= 0) { offset0 = 0; } else { seg0 = -seg0 - 2; offset0 = start - startOffsets[seg0]; } int seg1 = Arrays.binarySearch(startOffsets, end); int offset1; if (seg1 >= 0) { offset1 = 0; } else { seg1 = -seg1 - 2; offset1 = end - startOffsets[seg1]; } FastStringBuffer startSegment = (FastStringBuffer)segments.get(seg0); // We've had reports (28 Feb 2007) of an NPE here, which we couldn't reproduce. // The following code is designed to produce diagnostics if it ever happens again if (startSegment == null) { dumpDataStructure(); throw new NullPointerException("startSegment: subSequence(" + start + ", " + end + ")"); } if (seg0 == seg1) { // the required substring is all in one segment return startSegment.subSequence(offset0, offset1); } else { // copy the data into a new FastStringBuffer. This case should be exceptional FastStringBuffer sb = new FastStringBuffer(end - start); sb.append(startSegment.subSequence(offset0, startSegment.length())); for (int i=seg0+1; i 0) { sb.append(((FastStringBuffer)segments.get(seg1)).subSequence(0, offset1)); } return sb; } } /** * Convert to a string */ public String toString() { if (startOffsets.length == 1) { // optimize for small documents return segments.get(0).toString(); } FastStringBuffer sb = new FastStringBuffer(length); for (int i=0; i= 0 && tree.depth[nextNodeNr] == nextAncestorDepth) { if (nextAncestorDepth-- <= 0) { // bug 1121528 current = null; position = -1; return null; } nextNodeNr--; } } else { if (tree.depth[nextNodeNr] == 0) { current = null; position = -1; return null; } else { nextNodeNr--; } } if (test.matches(tree, nextNodeNr)) { position++; current = tree.getNode(nextNodeNr); return current; } if (tree.depth[nextNodeNr] == 0) { current = null; position = -1; return null; } } } /** * Get another enumeration of the same nodes */ public SequenceIterator getAnother() { return new PrecedingEnumeration(tree, startNode, test, includeAncestors); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/tinytree/AncestorEnumeration.java0000644000175000017500000000445311033112257024100 0ustar eugeneeugenepackage net.sf.saxon.tinytree; import net.sf.saxon.om.AxisIteratorImpl; import net.sf.saxon.om.Item; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.pattern.NodeTest; /** * This class enumerates the ancestor:: or ancestor-or-self:: axes, * starting at a given node. The start node will never be the root. */ final class AncestorEnumeration extends AxisIteratorImpl { private TinyNodeImpl startNode; private NodeTest test; private boolean includeSelf; public AncestorEnumeration(TinyNodeImpl node, NodeTest nodeTest, boolean includeSelf) { test = nodeTest; startNode = node; this.includeSelf = includeSelf; current = startNode; } public Item next() { if (position <= 0) { if (position < 0) { return null; } if (position==0 && includeSelf && test.matches(startNode)) { current = startNode; position = 1; return current; } } NodeInfo node = current.getParent(); while (node != null && !test.matches(node)) { node = node.getParent(); } current = node; if (node == null) { position = -1; } else { position++; } return current; } /** * Get another enumeration of the same nodes */ public SequenceIterator getAnother() { return new AncestorEnumeration(startNode, test, includeSelf); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/tinytree/DescendantEnumeration.java0000644000175000017500000000714611033112257024374 0ustar eugeneeugenepackage net.sf.saxon.tinytree; import net.sf.saxon.om.AxisIteratorImpl; import net.sf.saxon.om.Item; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.pattern.NodeTest; /** * This class supports both the descendant:: and descendant-or-self:: axes, which are * identical except for the route to the first candidate node. * It enumerates descendants of the specified node. * The calling code must ensure that the start node is not an attribute or namespace node. */ final class DescendantEnumeration extends AxisIteratorImpl { private TinyTree tree; private TinyNodeImpl startNode; private boolean includeSelf; private int nextNodeNr; private int startDepth; private NodeTest test; /** * Create an iterator over the descendant axis * @param doc the containing TinyTree * @param node the node whose descendants are required * @param nodeTest test to be satisfied by each returned node * @param includeSelf true if the start node is to be included */ DescendantEnumeration(TinyTree doc, TinyNodeImpl node, NodeTest nodeTest, boolean includeSelf) { tree = doc; startNode = node; this.includeSelf = includeSelf; test = nodeTest; nextNodeNr = node.nodeNr; startDepth = doc.depth[nextNodeNr]; } public Item next() { if (position==0 && includeSelf && test.matches(startNode)) { current = startNode; position++; return current; } do { nextNodeNr++; try { if (tree.depth[nextNodeNr] <= startDepth) { nextNodeNr = -1; current = null; position = -1; return null; } } catch (ArrayIndexOutOfBoundsException e) { // this shouldn't happen. If it does happen, it means the tree wasn't properly closed // during construction (there is no stopper node at the end). In this case, we'll recover // by returning end-of sequence //System.err.println("********* no stopper node **********"); nextNodeNr = -1; current = null; position = -1; return null; } } while (!test.matches(tree, nextNodeNr)); position++; // if (isAtomizing() && tree.getTypeAnnotation(nextNodeNr) == StandardNames.XDT_UNTYPED) { // current = tree.getAtomizedValueOfUntypedNode(nextNodeNr); // } else { current = tree.getNode(nextNodeNr); // } return current; } /** * Get another enumeration of the same nodes */ public SequenceIterator getAnother() { return new DescendantEnumeration(tree, startNode, test, includeSelf); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/tinytree/TinyBuilder.java0000644000175000017500000003610711033112257022346 0ustar eugeneeugenepackage net.sf.saxon.tinytree; import net.sf.saxon.event.Builder; import net.sf.saxon.event.LocationProvider; import net.sf.saxon.event.ReceiverOptions; import net.sf.saxon.event.SourceLocationProvider; import net.sf.saxon.om.FastStringBuffer; import net.sf.saxon.om.StandardNames; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.Type; /** * The TinyBuilder class is responsible for taking a stream of SAX events and constructing * a Document tree, using the "TinyTree" implementation. * * @author Michael H. Kay */ public class TinyBuilder extends Builder { public static final int PARENT_POINTER_INTERVAL = 10; // a lower value allocates more parent pointers which takes more space but reduces // the length of parent searches private TinyTree tree; private int currentDepth = 0; private int nodeNr = 0; // this is the local sequence within this document private boolean ended = false; private int[] sizeParameters; // estimate of number of nodes, attributes, namespaces, characters /** * Create a TinyTree builder */ public TinyBuilder() {} /** * Set the size parameters for the tree * @param params an array of four integers giving the expected number of non-attribute nodes, the expected * number of attributes, the expected number of namespace declarations, and the expected total length of * character data */ public void setSizeParameters(int[] params) { sizeParameters = params; } /** * Get the size parameters for the tree * @return an array of four integers giving the actual number of non-attribute nodes, the actual * number of attributes, the actual number of namespace declarations, and the actual total length of * character data */ public int[] getSizeParameters() { return new int[] {tree.numberOfNodes, tree.numberOfAttributes, tree.numberOfNamespaces, tree.getCharacterBuffer().length()}; } private int[] prevAtDepth = new int[100]; // this array is scaffolding used while constructing the tree, it is // not present in the final tree. For each level of the tree, it records the // node number of the most recent node at that level. private int[] siblingsAtDepth = new int[100]; // more scaffolding. For each level of the tree, this array records the // number of siblings processed at that level. When this exceeds a threshold value, // a dummy node is inserted into the arrays to contain a parent pointer: this it to // prevent excessively long searches for a parent node, which is normally found by // scanning the siblings. The value is then reset to zero. private boolean isIDElement = false; /** * Get the tree being built by this builder * @return the TinyTree */ public TinyTree getTree() { return tree; } /** * Open the event stream */ public void open() throws XPathException { if (started) { // this happens when using an IdentityTransformer return; } if (tree == null) { if (sizeParameters==null) { tree = new TinyTree(); } else { tree = new TinyTree(sizeParameters[0], sizeParameters[1], sizeParameters[2], sizeParameters[3]); } tree.setConfiguration(config); currentDepth = 0; if (lineNumbering) { tree.setLineNumbering(); } } super.open(); } /** * Write a document node to the tree */ public void startDocument (int properties) throws XPathException { // if (currentDepth == 0 && tree.numberOfNodes != 0) { // System.err.println("**** FOREST DOCUMENT ****"); // } if ((started && !ended) || currentDepth > 0) { // this happens when using an IdentityTransformer, or when copying a document node to form // the content of an element return; } started = true; ended = false; currentRoot = new TinyDocumentImpl(tree); TinyDocumentImpl doc = (TinyDocumentImpl)currentRoot; doc.setSystemId(getSystemId()); doc.setBaseURI(getBaseURI()); doc.setConfiguration(config); currentDepth = 0; int nodeNr = tree.addDocumentNode((TinyDocumentImpl)currentRoot); prevAtDepth[0] = nodeNr; prevAtDepth[1] = -1; siblingsAtDepth[0] = 0; siblingsAtDepth[1] = 0; tree.next[nodeNr] = -1; currentDepth++; super.startDocument(0); } /** * Callback interface for SAX: not for application use */ public void endDocument () throws XPathException { // System.err.println("TinyBuilder: " + this + " End document"); if (currentDepth > 1) return; // happens when copying a document node as the child of an element if (ended) return; // happens when using an IdentityTransformer ended = true; prevAtDepth[currentDepth] = -1; currentDepth--; } public void reset() { super.reset(); tree = null; currentDepth = 0; nodeNr = 0; ended = false; sizeParameters = null; } public void close() throws XPathException { //System.err.println("Tree.close " + tree + " size=" + tree.numberOfNodes); tree.addNode(Type.STOPPER, 0, 0, 0, -1); tree.condense(); super.close(); } /** * Notify the start tag of an element */ public void startElement (int nameCode, int typeCode, int locationId, int properties) throws XPathException { // if (currentDepth == 0 && tree.numberOfNodes != 0) { // System.err.println("**** FOREST ELEMENT **** trees=" + tree.rootIndexUsed ); // } // if the number of siblings exceeds a certain threshold, add a parent pointer, in the form // of a pseudo-node if (siblingsAtDepth[currentDepth] > PARENT_POINTER_INTERVAL) { nodeNr = tree.addNode(Type.PARENT_POINTER, currentDepth, prevAtDepth[currentDepth-1], 0, 0); int prev = prevAtDepth[currentDepth]; if (prev > 0) { tree.next[prev] = nodeNr; } tree.next[nodeNr] = prevAtDepth[currentDepth-1]; prevAtDepth[currentDepth] = nodeNr; siblingsAtDepth[currentDepth] = 0; } // now add the element node itself nodeNr = tree.addNode(Type.ELEMENT, currentDepth, -1, -1, nameCode); isIDElement = ((properties & ReceiverOptions.IS_ID) != 0); if (typeCode != StandardNames.XS_UNTYPED && typeCode != -1) { if ((properties & ReceiverOptions.NILLED_ELEMENT) != 0) { typeCode |= NodeInfo.IS_NILLED; } tree.setElementAnnotation(nodeNr, typeCode); if (!isIDElement && config.getTypeHierarchy().isIdCode(typeCode)) { isIDElement = true; } } if (currentDepth == 0) { prevAtDepth[0] = nodeNr; prevAtDepth[1] = -1; //tree.next[0] = -1; currentRoot = tree.getNode(nodeNr); } else { int prev = prevAtDepth[currentDepth]; if (prev > 0) { tree.next[prev] = nodeNr; } tree.next[nodeNr] = prevAtDepth[currentDepth - 1]; // *O* owner pointer in last sibling prevAtDepth[currentDepth] = nodeNr; siblingsAtDepth[currentDepth]++; } currentDepth++; if (currentDepth == prevAtDepth.length) { int[] p2 = new int[currentDepth*2]; System.arraycopy(prevAtDepth, 0, p2, 0, currentDepth); prevAtDepth = p2; p2 = new int[currentDepth*2]; System.arraycopy(siblingsAtDepth, 0, p2, 0, currentDepth); siblingsAtDepth = p2; } prevAtDepth[currentDepth] = -1; siblingsAtDepth[currentDepth] = 0; LocationProvider locator = pipe.getLocationProvider(); if (locator instanceof SourceLocationProvider) { tree.setSystemId(nodeNr, locator.getSystemId(locationId)); // if (lineNumbering) { // tree.setLineAndColumn(nodeNr, locator.getLineNumber(locationId), locator.getColumnNumber(locationId)); // } } else if (currentDepth == 1) { tree.setSystemId(nodeNr, systemId); } if (lineNumbering) { tree.setLineNumber(nodeNr, locator.getLineNumber(locationId), locator.getColumnNumber(locationId)); } } public void namespace(int namespaceCode, int properties) throws XPathException { tree.addNamespace( nodeNr, namespaceCode ); } public void attribute(int nameCode, int typeCode, CharSequence value, int locationId, int properties) throws XPathException { // System.err.println("attribute " + nameCode + "=" + value); tree.addAttribute(currentRoot, nodeNr, nameCode, typeCode, value, properties); } public void startContent() { nodeNr++; } /** * Callback interface for SAX: not for application use */ public void endElement() throws XPathException { // System.err.println("End element"); prevAtDepth[currentDepth] = -1; siblingsAtDepth[currentDepth] = 0; currentDepth--; if (isIDElement) { // we're relying on the fact that an ID element has no element children! tree.indexIDElement(currentRoot, prevAtDepth[currentDepth], config.getNameChecker()); isIDElement = false; } } /** * Get the last completed element node. This is used during checking of schema assertions, * which happens while the tree is still under construction. This method is called immediately after * a call on endElement(), and it returns the element that has just ended. * @return the last completed element node, that is, the element whose endElement event is the most recent * endElement event to be reported */ public NodeInfo getLastCompletedElement() { return tree.getNode(prevAtDepth[currentDepth]); // Note: reading an incomplete tree needs care if it constructs a prior index, etc. } /** * Callback interface for SAX: not for application use */ public void characters(CharSequence chars, int locationId, int properties) throws XPathException { // TODO:PERF when appropriate, point to an existing text node containing the same characters if (chars instanceof CompressedWhitespace && (properties & ReceiverOptions.WHOLE_TEXT_NODE) != 0) { long lvalue = ((CompressedWhitespace)chars).getCompressedValue(); nodeNr = tree.addNode(Type.WHITESPACE_TEXT, currentDepth, (int)(lvalue>>32), (int)(lvalue), -1); int prev = prevAtDepth[currentDepth]; if (prev > 0) { tree.next[prev] = nodeNr; } tree.next[nodeNr] = prevAtDepth[currentDepth - 1]; // *O* owner pointer in last sibling prevAtDepth[currentDepth] = nodeNr; siblingsAtDepth[currentDepth]++; return; } final int len = chars.length(); if (len>0) { int bufferStart = tree.getCharacterBuffer().length(); tree.appendChars(chars); int n=tree.numberOfNodes-1; if (tree.nodeKind[n] == Type.TEXT && tree.depth[n] == currentDepth) { // merge this text node with the previous text node tree.beta[n] += len; } else { nodeNr = tree.addNode(Type.TEXT, currentDepth, bufferStart, len, -1); int prev = prevAtDepth[currentDepth]; if (prev > 0) { tree.next[prev] = nodeNr; } tree.next[nodeNr] = prevAtDepth[currentDepth - 1]; // *O* owner pointer in last sibling prevAtDepth[currentDepth] = nodeNr; siblingsAtDepth[currentDepth]++; } } } /** * Callback interface for SAX: not for application use
    */ public void processingInstruction (String piname, CharSequence remainder, int locationId, int properties) throws XPathException { if (tree.commentBuffer==null) { tree.commentBuffer = new FastStringBuffer(200); } int s = tree.commentBuffer.length(); tree.commentBuffer.append(remainder.toString()); int nameCode = namePool.allocate("", "", piname); nodeNr = tree.addNode(Type.PROCESSING_INSTRUCTION, currentDepth, s, remainder.length(), nameCode); int prev = prevAtDepth[currentDepth]; if (prev > 0) { tree.next[prev] = nodeNr; } tree.next[nodeNr] = prevAtDepth[currentDepth - 1]; // *O* owner pointer in last sibling prevAtDepth[currentDepth] = nodeNr; siblingsAtDepth[currentDepth]++; LocationProvider locator = pipe.getLocationProvider(); if (locator instanceof SourceLocationProvider) { tree.setSystemId(nodeNr, locator.getSystemId(locationId)); if (lineNumbering) { tree.setLineNumber(nodeNr, locator.getLineNumber(locationId), locator.getColumnNumber(locationId)); } } } /** * Callback interface for SAX: not for application use */ public void comment (CharSequence chars, int locationId, int properties) throws XPathException { if (tree.commentBuffer==null) { tree.commentBuffer = new FastStringBuffer(200); } int s = tree.commentBuffer.length(); tree.commentBuffer.append(chars.toString()); nodeNr = tree.addNode(Type.COMMENT, currentDepth, s, chars.length(), -1); int prev = prevAtDepth[currentDepth]; if (prev > 0) { tree.next[prev] = nodeNr; } tree.next[nodeNr] = prevAtDepth[currentDepth - 1]; // *O* owner pointer in last sibling prevAtDepth[currentDepth] = nodeNr; siblingsAtDepth[currentDepth]++; } /** * Set an unparsed entity in the document */ public void setUnparsedEntity(String name, String uri, String publicId) { ((TinyDocumentImpl)currentRoot).setUnparsedEntity(name, uri, publicId); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/tinytree/TinyElementImpl.java0000644000175000017500000005154311033112257023174 0ustar eugeneeugenepackage net.sf.saxon.tinytree; import net.sf.saxon.Configuration; import net.sf.saxon.event.*; import net.sf.saxon.om.*; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.SchemaType; import net.sf.saxon.type.SimpleType; import net.sf.saxon.type.Type; /** * A node in the XML parse tree representing an XML element.

    * This class is an implementation of NodeInfo. The object is a wrapper around * one entry in the arrays maintained by the TinyTree. Note that the same node * might be represented by different TinyElementImpl objects at different times. * @author Michael H. Kay */ final class TinyElementImpl extends TinyParentNodeImpl { /** * Constructor - create a tiny element node * @param tree the Tinytree containing the node * @param nodeNr the node number */ public TinyElementImpl(TinyTree tree, int nodeNr) { this.tree = tree; this.nodeNr = nodeNr; } /** * Return the type of node. * @return Type.ELEMENT */ public final int getNodeKind() { return Type.ELEMENT; } /** * Get the base URI of this element node. This will be the same as the System ID unless * xml:base has been used. */ public String getBaseURI() { return Navigator.getBaseURI(this); } /** * Get the type annotation of this node, if any * Returns Type.UNTYPED_ANY if there is no type annotation */ public int getTypeAnnotation() { return tree.getTypeAnnotation(nodeNr) & NamePool.FP_MASK; } /** * Get all namespace undeclarations and undeclarations defined on this element. * * @param buffer If this is non-null, and the result array fits in this buffer, then the result * may overwrite the contents of this array, to avoid the cost of allocating a new array on the heap. * @return An array of integers representing the namespace declarations and undeclarations present on * this element. For a node other than an element, return null. Otherwise, the returned array is a * sequence of namespace codes, whose meaning may be interpreted by reference to the name pool. The * top half word of each namespace code represents the prefix, the bottom half represents the URI. * If the bottom half is zero, then this is a namespace undeclaration rather than a declaration. * The XML namespace is never included in the list. If the supplied array is larger than required, * then the first unused entry will be set to -1. *

    *

    For a node other than an element, the method returns null.

    */ public int[] getDeclaredNamespaces(int[] buffer) { return getDeclaredNamespaces(tree, nodeNr, buffer); } /** * Static method to get all namespace undeclarations and undeclarations defined on a given element, * without instantiating the node object. * @param tree The tree containing the given element node * @param nodeNr The node number of the given element node within the tinyTree * @param buffer If this is non-null, and the result array fits in this buffer, then the result * may overwrite the contents of this array, to avoid the cost of allocating a new array on the heap. * @return An array of integers representing the namespace declarations and undeclarations present on * this element. For a node other than an element, return null. Otherwise, the returned array is a * sequence of namespace codes, whose meaning may be interpreted by reference to the name pool. The * top half word of each namespace code represents the prefix, the bottom half represents the URI. * If the bottom half is zero, then this is a namespace undeclaration rather than a declaration. * The XML namespace is never included in the list. If the supplied array is larger than required, * then the first unused entry will be set to -1. *

    *

    For a node other than an element, the method returns null.

    */ static int[] getDeclaredNamespaces(TinyTree tree, int nodeNr, int[] buffer) { int ns = tree.beta[nodeNr]; // by convention if (ns>0 ) { int count = 0; while (ns < tree.numberOfNamespaces && tree.namespaceParent[ns] == nodeNr ) { count++; ns++; } if (count == 0) { return NodeInfo.EMPTY_NAMESPACE_LIST; } else if (buffer != null && count <= buffer.length) { System.arraycopy(tree.namespaceCode, tree.beta[nodeNr], buffer, 0, count); if (count < buffer.length) { buffer[count] = -1; } return buffer; } else { int[] array = new int[count]; System.arraycopy(tree.namespaceCode, tree.beta[nodeNr], array, 0, count); return array; } } else { return NodeInfo.EMPTY_NAMESPACE_LIST; } } /** * Get all the inscope namespaces for an element node. This method is better than the generic method * provided by {@link net.sf.saxon.om.NamespaceIterator} because it doesn't require the element node * (or its ancestors) to be instantiated as objects. * @param tree the TinyTree containing the element node whose in-scope namespaces are required * @param nodeNr the node number of the element node within the TinyTree. The caller is responsible * for ensuring that this is indeed an element node * @param buffer a buffer to hold the result, assuming it is large enough * @return an integer array of namespace codes representing the inscope namespaces of the given element. * The returned array will either be fully used, or it will contain a -1 entry marking the effective end * of the list of namespace codes. Note that only distinct declared namespaces are included in the result; * it does not contain any entries for namespace undeclarations or for overridden declarations. */ static int[] getInScopeNamespaces(TinyTree tree, int nodeNr, int[] buffer) { if (buffer == null || buffer.length == 0) { buffer = new int[10]; } buffer[0] = NamespaceConstant.XML_NAMESPACE_CODE; int used = 1; if (tree.usesNamespaces) { do { // gather the namespaces declared for this node int ns = tree.beta[nodeNr]; // by convention if (ns>0 ) { while (ns < tree.numberOfNamespaces && tree.namespaceParent[ns] == nodeNr ) { int nscode = tree.namespaceCode[ns]; // See if the prefix has already been declared; if so, this declaration is ignored short prefixCode = (short)(nscode >> 16); boolean duplicate = false; for (int i=0; i> 16) == prefixCode) { duplicate = true; break; } } if (!duplicate) { if (used >= buffer.length) { int[] b2 = new int[used*2]; System.arraycopy(buffer, 0, b2, 0, used); buffer = b2; } buffer[used++] = nscode; } ns++; } } // move on to the parent of this node nodeNr = getParentNodeNr(tree, nodeNr); } while (nodeNr != -1); // The list of namespaces we have built up includes undeclarations as well as declarations. // We now remove the undeclarations (which have a URI code of zero) int j = 0; for (int i=0; i nodeLevel; level--) { receiver.endElement(); } // new node level level = nodeLevel; // output depends on node kind switch (tree.nodeKind[next]) { case Type.ELEMENT : { // start element final int typeCode = (copyAnnotations ? tree.getTypeAnnotation(next): StandardNames.XS_UNTYPED); if (disallowNamespaceSensitiveContent) { if (config == null) { config = getConfiguration(); } checkNotNamespaceSensitive(config, typeCode); } if (setLocation) { ((CopyInformee)receiver).notifyElementNode(tree.getNode(next)); } receiver.startElement(tree.nameCode[next], typeCode, locationId, 0); // there is an element to close closePending = true; // output namespaces if (whichNamespaces != NO_NAMESPACES && tree.usesNamespaces) { if (first) { switch (whichNamespaces) { case NodeInfo.NO_NAMESPACES: break; case NodeInfo.LOCAL_NAMESPACES: int[] localNamespaces = getDeclaredNamespaces(null); for (int i=0; i0 ) { while (ns < tree.numberOfNamespaces && tree.namespaceParent[ns] == next ) { int nscode = tree.namespaceCode[ns]; receiver.namespace(nscode, 0); ns++; } } } } first = false; // output attributes int att = tree.alpha[next]; if (att >= 0) { while (att < tree.numberOfAttributes && tree.attParent[att] == next ) { int attCode = tree.attCode[att]; int attType = (copyAnnotations ? tree.getAttributeAnnotation(att) : StandardNames.XS_UNTYPED_ATOMIC); if (disallowNamespaceSensitiveContent) { if (config == null) { config = getConfiguration(); } checkNotNamespaceSensitive(config, attType); } receiver.attribute(attCode, attType, tree.attValue[att], locationId, 0); att++; } } // start content receiver.startContent(); break; } case Type.TEXT: { // don't close text nodes closePending = false; // output characters final CharSequence value = TinyTextImpl.getStringValue(tree, next); receiver.characters(value, locationId, ReceiverOptions.WHOLE_TEXT_NODE); break; } case Type.WHITESPACE_TEXT: { // don't close text nodes closePending = false; // output characters final CharSequence value = WhitespaceTextImpl.getStringValue(tree, next); receiver.characters(value, locationId, ReceiverOptions.WHOLE_TEXT_NODE); break; } case Type.COMMENT : { // don't close text nodes closePending = false; // output copy of comment int start = tree.alpha[next]; int len = tree.beta[next]; if (len>0) { receiver.comment(tree.commentBuffer.subSequence(start, start+len), locationId, 0); } else { receiver.comment("", 0, 0); } break; } case Type.PROCESSING_INSTRUCTION : { // don't close text nodes closePending = false; // output copy of PI NodeInfo pi = tree.getNode(next); receiver.processingInstruction(pi.getLocalPart(), pi.getStringValue(), locationId, 0); break; } case Type.PARENT_POINTER : { closePending = false; } } next++; } while (next < tree.numberOfNodes && tree.depth[next] > startLevel); // close all remaining elements if (closePending) { level++; } for (; level > startLevel; level--) { receiver.endElement(); } } private void checkNotNamespaceSensitive(Configuration config, final int typeCode) throws XPathException { SchemaType type = config.getSchemaType(typeCode & NamePool.FP_MASK); if (type instanceof SimpleType && ((SimpleType)type).isNamespaceSensitive()) { throw new CopyNamespaceSensitiveException( "Cannot copy QName or NOTATION values without copying namespaces"); // err.setErrorCode((language == Configuration.XSLT ? "XTTE0950" : "XQTY0086")); // throw err; } } // public void copyOLD(Receiver out, int whichNamespaces, boolean copyAnnotations) throws XPathException { // // int nc = getNameCode(); // int typeCode = (copyAnnotations ? getTypeAnnotation() : 0); // out.startElement(nc, typeCode, 0, 0); // // // output the namespaces // // if (whichNamespaces != NO_NAMESPACES) { // outputNamespaceNodes(out, whichNamespaces==ALL_NAMESPACES); // } // // // output the attributes // // int a = document.alpha[nodeNr]; // if (a >= 0) { // while (a < document.numberOfAttributes && document.attParent[a] == nodeNr) { // document.getAttributeNode(a).copy(out, NO_NAMESPACES, copyAnnotations, locationId); // a++; // } // } // // // output the children // // AxisIterator children = // iterateAxis(Axis.CHILD, AnyNodeTest.getInstance()); // // int childNamespaces = (whichNamespaces==NO_NAMESPACES ? NO_NAMESPACES : LOCAL_NAMESPACES); // while (true) { // NodeInfo next = (NodeInfo)children.next(); // if (next==null) break; // next.copy(out, childNamespaces, copyAnnotations, locationId); // } // out.endElement(); // } /** * Get the namespace URI corresponding to a given prefix. Return null * if the prefix is not in scope. * * @param prefix the namespace prefix. May be the zero-length string, indicating * that there is no prefix. This indicates either the default namespace or the * null namespace, depending on the value of useDefault. * @param useDefault true if the default namespace is to be used when the * prefix is "". If false, the method returns "" when the prefix is "". * @return the uri for the namespace, or null if the prefix is not in scope. * The "null namespace" is represented by the pseudo-URI "". */ public String getURIForPrefix(String prefix, boolean useDefault) { if (!useDefault && (prefix==null || prefix.length()==0)) { return ""; } int prefixCode = getNamePool().getCodeForPrefix(prefix); if (prefixCode == -1) { return null; } int ns = tree.beta[nodeNr]; // by convention if (ns>0 ) { while (ns < tree.numberOfNamespaces && tree.namespaceParent[ns] == nodeNr ) { int nscode = tree.namespaceCode[ns]; if ((nscode >> 16) == prefixCode) { int uriCode = nscode & 0xffff; if (uriCode == 0) { // this is a namespace undeclaration, so the prefix is not in scope if (prefixCode == 0) { // the namespace xmlns="" is always in scope return ""; } else { return null; } } else { return getNamePool().getURIFromURICode((short)uriCode); } } ns++; } } // now search the namespaces defined on the ancestor nodes. NodeInfo parent = getParent(); if (parent instanceof NamespaceResolver) { return ((NamespaceResolver)parent).getURIForPrefix(prefix, useDefault); } return null; } /** * Determine whether this node has the is-id property * * @return true if the node is an ID */ public boolean isId() { // this looks very inefficient, but the method isn't actually used... return getDocumentRoot().selectID(getStringValue()).isSameNodeInfo(this); } /** * Determine whether this node has the is-idref property * * @return true if the node is an IDREF or IDREFS element or attribute */ public boolean isIdref() { return tree.isIdrefElement(nodeNr); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // The new copy() routine (in version 7.4.1) is contributed by Ruud Diterwich // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/tinytree/TinyCommentImpl.java0000644000175000017500000000501511033112257023176 0ustar eugeneeugenepackage net.sf.saxon.tinytree; import net.sf.saxon.event.Receiver; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.Type; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.om.SingletonIterator; import net.sf.saxon.value.StringValue; import net.sf.saxon.value.Value; /** * TinyCommentImpl is an implementation of CommentInfo * @author Michael H. Kay */ final class TinyCommentImpl extends TinyNodeImpl { public TinyCommentImpl(TinyTree tree, int nodeNr) { this.tree = tree; this.nodeNr = nodeNr; } /** * Get the XPath string value of the comment */ public final String getStringValue() { int start = tree.alpha[nodeNr]; int len = tree.beta[nodeNr]; if (len==0) return ""; char[] dest = new char[len]; tree.commentBuffer.getChars(start, start+len, dest, 0); return new String(dest, 0, len); } /** * Get the typed value of this node. * Returns the string value, as an instance of xs:string */ public SequenceIterator getTypedValue() { return SingletonIterator.makeIterator(new StringValue(getStringValue())); } /** * Get the typed value of this node. * Returns the string value, as an instance of xs:string */ public Value atomize() { return new StringValue(getStringValue()); } /** * Get the node type * @return Type.COMMENT */ public final int getNodeKind() { return Type.COMMENT; } /** * Copy this node to a given outputter */ public void copy(Receiver out, int whichNamespaces, boolean copyAnnotations, int locationId) throws XPathException { out.comment(getStringValue(), 0, 0); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/tinytree/TinyParentNodeImpl.java0000644000175000017500000001061211033112257023632 0ustar eugeneeugenepackage net.sf.saxon.tinytree; import net.sf.saxon.type.Type; import net.sf.saxon.om.FastStringBuffer; /** * TinyParentNodeImpl is an implementation of a non-leaf node (specifically, an Element node * or a Document node) * @author Michael H. Kay */ abstract class TinyParentNodeImpl extends TinyNodeImpl { /** * Determine if the node has children. */ public final boolean hasChildNodes() { return (nodeNr+1 < tree.numberOfNodes && tree.depth[nodeNr+1] > tree.depth[nodeNr]); } /** * Return the string-value of the node, that is, the concatenation * of the character content of all descendent elements and text nodes. * @return the accumulated character content of the element, including descendant elements. */ public final String getStringValue() { return getStringValue(tree, nodeNr).toString(); } /** * Get the value of the item as a CharSequence. This is in some cases more efficient than * the version of the method that returns a String. */ public CharSequence getStringValueCS() { return getStringValue(tree, nodeNr); } /** * Get the string value of a node. This static method allows the string value of a node * to be obtained without instantiating the node as a Java object. The method also returns * a CharSequence rather than a string, which means it can sometimes avoid copying the * data. * @param tree The containing document * @param nodeNr identifies the node whose string value is required. This must be a * document or element node. The caller is trusted to ensure this. * @return the string value of the node, as a CharSequence */ public static CharSequence getStringValue(TinyTree tree, int nodeNr) { int level = tree.depth[nodeNr]; // note, we can't rely on the value being contiguously stored because of whitespace // nodes: the data for these may still be present. int next = nodeNr+1; // we optimize two special cases: firstly, where the node has no children, and secondly, // where it has a single text node as a child. if (tree.depth[next] <= level) { return ""; } else if (tree.nodeKind[next] == Type.TEXT && (next+1 >= tree.numberOfNodes || tree.depth[next+1] <= level)) { //int length = tree.beta[next]; //int start = tree.alpha[next]; //return new CharSlice(tree.charBuffer, start, length); //return tree.charBuffer.subSequence(start, start+length); return TinyTextImpl.getStringValue(tree, next); } // now handle the general case FastStringBuffer sb = null; while (next < tree.numberOfNodes && tree.depth[next] > level) { final byte kind = tree.nodeKind[next]; if (kind==Type.TEXT) { // int length = tree.beta[next]; // int start = tree.alpha[next]; if (sb==null) { sb = new FastStringBuffer(1024); } //sb.append(tree.charBuffer, start, length); //sb.append(tree.charBuffer.subSequence(start, start+length)); sb.append(TinyTextImpl.getStringValue(tree, next)); } else if (kind==Type.WHITESPACE_TEXT) { if (sb==null) { sb = new FastStringBuffer(1024); } WhitespaceTextImpl.appendStringValue(tree, next, sb); } next++; } if (sb==null) return ""; return sb.condense(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/tinytree/WhitespaceTextImpl.java0000644000175000017500000001005711033112257023673 0ustar eugeneeugenepackage net.sf.saxon.tinytree; import net.sf.saxon.event.Receiver; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.Type; import net.sf.saxon.om.FastStringBuffer; /** * A node in the XML parse tree representing a text node with compressed whitespace content * @author Michael H. Kay */ public final class WhitespaceTextImpl extends TinyNodeImpl { // TODO: make this class implement CharSequence directly, avoiding the need to create a CompressedWhitespace object /** * Create a compressed whitespace text node * @param tree the tree to contain the node * @param nodeNr the internal node number */ public WhitespaceTextImpl(TinyTree tree, int nodeNr) { this.tree = tree; this.nodeNr = nodeNr; } /** * Return the character value of the node. * @return the string value of the node */ public String getStringValue() { return getStringValueCS().toString(); } /** * Get the value of the item as a CharSequence. This is in some cases more efficient than * the version of the method that returns a String. For a WhitespaceTextImpl node, it avoids the * cost of decompressing the whitespace */ public CharSequence getStringValueCS() { long value = ((long)tree.alpha[nodeNr]<<32) | ((long)tree.beta[nodeNr] & 0xffffffffL); return new CompressedWhitespace(value); } /** * Static method to get the string value of a text node without first constructing the node object * @param tree the tree * @param nodeNr the node number of the text node * @return the string value of the text node */ public static CharSequence getStringValue(TinyTree tree, int nodeNr) { long value = ((long)tree.alpha[nodeNr]<<32) | ((long)tree.beta[nodeNr] & 0xffffffffL); return new CompressedWhitespace(value); } /** * Static method to get the string value of a text node and append it to a supplied buffer * without first constructing the node object * @param tree the tree * @param nodeNr the node number of the text node * @param buffer a buffer to which the string value will be appended */ public static void appendStringValue(TinyTree tree, int nodeNr, FastStringBuffer buffer) { long value = ((long)tree.alpha[nodeNr]<<32) | ((long)tree.beta[nodeNr] & 0xffffffffL); CompressedWhitespace.uncompress(value, buffer); } /** * Static method to get the "long" value representing the content of a whitespace text node * @param tree the TinyTree * @param nodeNr the internal node number * @return a value representing the compressed whitespace content * @see CompressedWhitespace */ public static long getLongValue(TinyTree tree, int nodeNr) { return ((long)tree.alpha[nodeNr]<<32) | ((long)tree.beta[nodeNr] & 0xffffffffL); } /** * Return the type of node. * @return Type.TEXT */ public final int getNodeKind() { return Type.TEXT; } /** * Copy this node to a given outputter */ public void copy(Receiver out, int whichNamespaces, boolean copyAnnotations, int locationId) throws XPathException { out.characters(getStringValueCS(), 0, 0); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/tinytree/TinyTreeEventIterator.java0000644000175000017500000001745711164364675024424 0ustar eugeneeugenepackage net.sf.saxon.tinytree; import net.sf.saxon.event.LocationProvider; import net.sf.saxon.event.PipelineConfiguration; import net.sf.saxon.evpull.*; import net.sf.saxon.om.NamespaceDeclarationsImpl; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.Type; /** * This implementation of the Saxon event-pull interface starts from a document, element, * text, comment, or processing-instruction node in a TinyTree, * and returns the events corresponding to that node and its descendants (including * their attributes and namespaces). The class performs the same function as * the general-purpose {@link net.sf.saxon.evpull.Decomposer} class, but is * specialized to exploit the TinyTree data structure: in particular, it never * materializes any Node objects. */ public class TinyTreeEventIterator implements EventIterator, LocationProvider { private int startNodeNr; private int currentNodeNr; //private int currentEvent; private int pendingEndEvents = 0; private boolean startAtDocument = false; private TinyTree tree; private PipelineConfiguration pipe; private int[] nsBuffer = new int[10]; /** * Create a TinyTreeEventIterator to return events associated with a tree or subtree * @param startNode the root of the tree or subtree. Must be a document or element node. * @param pipe the Saxon pipeline configuration * @throws IllegalArgumentException if the start node is an attribute or namespace node. */ public TinyTreeEventIterator(TinyNodeImpl startNode, PipelineConfiguration pipe) { this.pipe = pipe; this.pipe.setLocationProvider(this); int kind = startNode.getNodeKind(); if (kind != Type.DOCUMENT && kind != Type.ELEMENT) { throw new IllegalArgumentException("TinyTreeEventIterator must start at a document or element node"); } startNodeNr = startNode.nodeNr; currentNodeNr = startNodeNr; tree = startNode.tree; pendingEndEvents = 0; startAtDocument = (kind == Type.DOCUMENT); NamespaceDeclarationsImpl nsDeclarations = new NamespaceDeclarationsImpl(); nsDeclarations.setNamePool(startNode.getNamePool()); } /** * Set configuration information. This must only be called before any events * have been read. * @param pipe the pipeline configuration */ // public void setPipelineConfiguration(PipelineConfiguration pipe) { // this.pipe = pipe; // } /** * Get configuration information. * @return the pipeline configuration */ // public PipelineConfiguration getPipelineConfiguration() { // return pipe; // } /** * Get the next event * @return a PullEvent object representing the next event, or null when the sequence is exhausted */ public PullEvent next() throws XPathException { if (startNodeNr < 0) { // this is a signal that we've finished return null; } int thisDepth = tree.depth[currentNodeNr]; boolean lastNode = currentNodeNr + 1 >= tree.numberOfNodes; int nextDepth = (lastNode ? 0 : tree.depth[currentNodeNr+1]); boolean atEnd = (thisDepth <= tree.depth[startNodeNr] && currentNodeNr != startNodeNr); if (atEnd && pendingEndEvents == 1) { pendingEndEvents--; startNodeNr = -1; if (startAtDocument) { return EndDocumentEvent.getInstance(); } else { return EndElementEvent.getInstance(); } } if (pendingEndEvents > 0) { pendingEndEvents--; return EndElementEvent.getInstance(); } byte kind = tree.nodeKind[currentNodeNr]; switch (kind) { case Type.DOCUMENT: pendingEndEvents = thisDepth - nextDepth + 1; currentNodeNr++; return StartDocumentEvent.getInstance(); case Type.ELEMENT: pendingEndEvents = thisDepth - nextDepth + 1; StartElementEvent see = new StartElementEvent(pipe); see.setNameCode(tree.nameCode[currentNodeNr]); see.setTypeCode(tree.getTypeAnnotation(currentNodeNr)); see.setLocationId(currentNodeNr); // add the attributes int index = tree.alpha[currentNodeNr]; if (index >= 0) { while (index < tree.numberOfAttributes && tree.attParent[index] == currentNodeNr) { see.addAttribute(tree.getAttributeNode(index++)); } } if (currentNodeNr == startNodeNr) { // get all inscope namespaces for a top-level element in the sequence. see.setLocalNamespaces(TinyElementImpl.getInScopeNamespaces(tree, currentNodeNr, nsBuffer)); } else { // only namespace declarations (and undeclarations) on this element are required see.setLocalNamespaces(TinyElementImpl.getDeclaredNamespaces(tree, currentNodeNr, nsBuffer)); } currentNodeNr++; return see; case Type.TEXT: case Type.WHITESPACE_TEXT: case Type.COMMENT: case Type.PROCESSING_INSTRUCTION: pendingEndEvents = thisDepth - nextDepth; return tree.getNode(currentNodeNr++); case Type.PARENT_POINTER: currentNodeNr++; return next(); default: throw new IllegalStateException("Unknown node kind " + tree.nodeKind[currentNodeNr]); } } /** * Determine whether the EventIterator returns a flat sequence of events, or whether it can return * nested event iterators * * @return true if the next() method is guaranteed never to return an EventIterator */ public boolean isFlatSequence() { return true; } /** * Get location information: the system Id of the current start element event * @param locationId in this case, the node number in the tiny tree * @return the system Id of the node: that is its base URI, before taking xml:base into account */ public String getSystemId(long locationId) { return tree.getSystemId((int)locationId); } /** * Get location information: the line number of the current start element event * @param locationId in this case, the node number in the tiny tree * @return the line number of the node if known, or -1 otherwise */ public int getLineNumber(long locationId) { return tree.getLineNumber((int)locationId); } /** * Get location information: the column number of the current start element event * @param locationId in this case, the node number in the tiny tree * @return the column number of the node if known, or -1 otherwise */ public int getColumnNumber(long locationId) { return tree.getColumnNumber((int)locationId); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/tinytree/PrecedingSiblingEnumeration.java0000644000175000017500000000510711033112257025527 0ustar eugeneeugenepackage net.sf.saxon.tinytree; import net.sf.saxon.om.AxisIteratorImpl; import net.sf.saxon.om.Item; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.pattern.NodeTest; /** * This class supports the preceding-sibling axis. * The starting node must be an element, text node, comment, or processing instruction: * to ensure this, construct the enumeration using NodeInfo#getEnumeration() */ final class PrecedingSiblingEnumeration extends AxisIteratorImpl { private TinyTree document; private TinyNodeImpl startNode; private int nextNodeNr; private NodeTest test; private TinyNodeImpl parentNode; PrecedingSiblingEnumeration(TinyTree doc, TinyNodeImpl node, NodeTest nodeTest) { document = doc; document.ensurePriorIndex(); test = nodeTest; startNode = node; nextNodeNr = node.nodeNr; parentNode = node.parent; // doesn't matter if this is null (unknown) } public Item next() { if (nextNodeNr < 0) { // This check is needed because an errant caller can call next() again after hitting the end of sequence return null; } while (true) { nextNodeNr = document.prior[nextNodeNr]; if (nextNodeNr < 0) { current = null; position = -1; return null; } if (test.matches(document, nextNodeNr)) { position++; current = document.getNode(nextNodeNr); ((TinyNodeImpl)current).setParentNode(parentNode); return current; } } } /** * Get another enumeration of the same nodes */ public SequenceIterator getAnother() { return new PrecedingSiblingEnumeration(document, startNode, test); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/tinytree/SiblingEnumeration.java0000644000175000017500000002624111033112257023710 0ustar eugeneeugenepackage net.sf.saxon.tinytree; import net.sf.saxon.om.*; import net.sf.saxon.pattern.NodeTest; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.AtomicType; import net.sf.saxon.type.SchemaType; import net.sf.saxon.type.Type; import net.sf.saxon.value.StringValue; import net.sf.saxon.value.UntypedAtomicValue; import net.sf.saxon.value.Value; import net.sf.saxon.Configuration; /** * This class supports both the child:: and following-sibling:: axes, which are * identical except for the route to the first candidate node. * It enumerates either the children or the following siblings of the specified node. * In the case of children, the specified node must always * be a node that has children: to ensure this, construct the enumeration * using NodeInfo#getEnumeration() */ final class SiblingEnumeration extends AxisIteratorImpl implements LookaheadIterator { // NOTE: have experimented with a dedicated iterator for the child axis matching against // elements only, by fingerprint - no measurable improvement obtained. private TinyTree tree; private int nextNodeNr; private NodeTest test; private TinyNodeImpl startNode; private TinyNodeImpl parentNode; private boolean getChildren; private boolean needToAdvance = false; /** * Return an enumeration over children or siblings of the context node * @param tree The TinyTree containing the context node * @param node The context node, the start point for the iteration * @param nodeTest Test that the selected nodes must satisfy, or null indicating * that all nodes are selected * @param getChildren True if children of the context node are to be returned, false * if following siblings are required */ SiblingEnumeration(TinyTree tree, TinyNodeImpl node, NodeTest nodeTest, boolean getChildren) { this.tree = tree; test = nodeTest; startNode = node; this.getChildren = getChildren; if (getChildren) { // child:: axis parentNode = node; // move to first child // ASSERT: we don't invoke this code unless the node has children nextNodeNr = node.nodeNr + 1; } else { // following-sibling:: axis parentNode = (TinyNodeImpl)node.getParent(); if (parentNode == null) { nextNodeNr = -1; } else { // move to next sibling nextNodeNr = tree.next[node.nodeNr]; while (tree.nodeKind[nextNodeNr] == Type.PARENT_POINTER) { // skip dummy nodes nextNodeNr = tree.next[nextNodeNr]; } if (nextNodeNr < node.nodeNr) { // if "next" pointer goes backwards, it's really an owner pointer from the last sibling nextNodeNr = -1; } } } // check if this matches the conditions if (nextNodeNr >= 0 && nodeTest != null) { if (!nodeTest.matches(this.tree, nextNodeNr)) { needToAdvance = true; } } } public boolean moveNext() { // if needToAdvance == false, nextNodeNr already identifies the correct node. current = null; if (needToAdvance) { final int thisNode = nextNodeNr; if (test==null) { do { nextNodeNr = tree.next[nextNodeNr]; } while (tree.nodeKind[nextNodeNr] == Type.PARENT_POINTER); } else { do { nextNodeNr = tree.next[nextNodeNr]; } while ( nextNodeNr >= thisNode && !test.matches(tree, nextNodeNr)); } if (nextNodeNr < thisNode) { // indicates we've got to the last sibling nextNodeNr = -1; needToAdvance = false; current = null; position = -1; return false; } } if (nextNodeNr == -1) { return false; } needToAdvance = true; position++; return true; } /** * Return the next node in the sequence * @return the next node, or null if the end of the sequence is reached */ public Item next() { if (needToAdvance) { final int thisNode = nextNodeNr; if (test==null) { do { nextNodeNr = tree.next[nextNodeNr]; } while (tree.nodeKind[nextNodeNr] == Type.PARENT_POINTER); } else { do { nextNodeNr = tree.next[nextNodeNr]; } while ( nextNodeNr >= thisNode && !test.matches(tree, nextNodeNr)); } if (nextNodeNr < thisNode) { // indicates we've got to the last sibling nextNodeNr = -1; needToAdvance = false; current = null; position = -1; return null; } } if (nextNodeNr == -1) { return null; } needToAdvance = true; position++; current = tree.getNode(nextNodeNr); ((TinyNodeImpl)current).setParentNode(parentNode); return current; } /** * Get the current node in the sequence. * @return the node returned by the most recent call on next(), or the one on which we have positioned * using moveNext(). */ public Item current() { if (current == null) { if (nextNodeNr == -1) { return null; } else { current = tree.getNode(nextNodeNr); ((TinyNodeImpl)current).setParentNode(parentNode); } } return current; } /** * Test whether there are any more nodes to come. This method is used only when testing whether the * current item is the last in the sequence. It's not especially efficient, but is more efficient than * the alternative strategy which involves counting how many nodes there are in the sequence. * @return true if there are more items in the sequence */ public boolean hasNext() { int n = nextNodeNr; if (needToAdvance) { if (test==null) { do { n = tree.next[n]; } while (tree.nodeKind[n] == Type.PARENT_POINTER); } else { do { n = tree.next[n]; } while ( n >= nextNodeNr && !test.matches(tree, n)); } if (n < nextNodeNr) { // indicates we've got to the last sibling return false; } } return (n != -1); } /** * Return the atomized value of the current node. This is achieved in common cases without * actually instantiating the NodeInfo object * * @return the atomized value. * @throws NullPointerException if there is no current node */ public Value atomize() throws XPathException { int kind; try { kind = tree.nodeKind[nextNodeNr]; } catch (ArrayIndexOutOfBoundsException err) { throw new NullPointerException(); } switch (kind) { case Type.TEXT: { return new UntypedAtomicValue(TinyTextImpl.getStringValue(tree, nextNodeNr)); } case Type.WHITESPACE_TEXT: { return new UntypedAtomicValue(WhitespaceTextImpl.getStringValue(tree, nextNodeNr)); } case Type.ELEMENT: { int type = tree.getTypeAnnotation(nextNodeNr); switch (type) { case StandardNames.XS_UNTYPED: case StandardNames.XS_UNTYPED_ATOMIC: return tree.getAtomizedValueOfUntypedNode(nextNodeNr); case StandardNames.XS_STRING: return new StringValue(TinyParentNodeImpl.getStringValue(tree, nextNodeNr)); default: Configuration config = tree.getConfiguration(); SchemaType stype = config.getSchemaType(type); if (stype instanceof AtomicType && !((AtomicType)stype).isNamespaceSensitive()) { CharSequence value = TinyParentNodeImpl.getStringValue(tree, nextNodeNr); return StringValue.convertStringToAtomicType( value, (AtomicType)stype, config.getNameChecker() ).asAtomic(); } else { // do it the slow way: create the node return ((NodeInfo)current()).atomize(); } } } case Type.COMMENT: case Type.PROCESSING_INSTRUCTION: return tree.getAtomizedValueOfUntypedNode(nextNodeNr); default: return ((NodeInfo)current()).atomize(); } } /** * Return the string value of the current node. * * @return the string value, as an instance of CharSequence. * @throws NullPointerException if there is no current node */ public CharSequence getStringValue() { int kind; try { kind = tree.nodeKind[nextNodeNr]; } catch (ArrayIndexOutOfBoundsException err) { throw new NullPointerException(); } switch (kind) { case Type.TEXT: { return TinyTextImpl.getStringValue(tree, nextNodeNr); } case Type.WHITESPACE_TEXT: { return WhitespaceTextImpl.getStringValue(tree, nextNodeNr); } case Type.ELEMENT: { return TinyParentNodeImpl.getStringValue(tree, nextNodeNr); } default: return current().getStringValueCS(); } } /** * Get another enumeration of the same nodes */ public SequenceIterator getAnother() { return new SiblingEnumeration(tree, startNode, test, getChildren); } public int getProperties() { return LOOKAHEAD; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/tinytree/TinyTreeWalker.java0000644000175000017500000005562411033112257023032 0ustar eugeneeugenepackage net.sf.saxon.tinytree; import net.sf.saxon.event.PipelineConfiguration; import net.sf.saxon.om.*; import net.sf.saxon.pull.PullProvider; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.Type; import net.sf.saxon.value.AtomicValue; import net.sf.saxon.om.StandardNames; import net.sf.saxon.Controller; import net.sf.saxon.Configuration; import javax.xml.transform.SourceLocator; import java.util.List; /** * This implementation of the Saxon pull interface starts from a document, element, * text, comment, or processing-instruction node in a TinyTree, * and returns the events corresponding to that node and its descendants (including * their attributes and namespaces). The class performs the same function as * the general-purpose {@link net.sf.saxon.pull.TreeWalker} class, but is * specialized to exploit the TinyTree data structure: in particular, it never * materializes any Node objects. */ public class TinyTreeWalker implements PullProvider, SourceLocator { private int startNode; private int currentNode; private int currentEvent; private TinyTree tree; private PipelineConfiguration pipe; private NamespaceDeclarationsImpl nsDeclarations; private int[] nsBuffer = new int[10]; /** * Create a TinyTreeWalker to return events associated with a tree or subtree * @param startNode the root of the tree or subtree. Must be a document, element, text, * comment, or processing-instruction node. * @throws IllegalArgumentException if the start node is an attribute or namespace node. */ public TinyTreeWalker(TinyNodeImpl startNode) { int kind = startNode.getNodeKind(); if (kind == Type.ATTRIBUTE || kind == Type.NAMESPACE) { throw new IllegalArgumentException("TinyTreeWalker cannot start at an attribute or namespace node"); } this.startNode = startNode.nodeNr; tree = startNode.tree; nsDeclarations = new NamespaceDeclarationsImpl(); nsDeclarations.setNamePool(startNode.getNamePool()); } /** * Set configuration information. This must only be called before any events * have been read. */ public void setPipelineConfiguration(PipelineConfiguration pipe) { this.pipe = pipe; } /** * Get configuration information. */ public PipelineConfiguration getPipelineConfiguration() { return pipe; } /** * Get the next event * * @return an integer code indicating the type of event. The code * {@link #END_OF_INPUT} is returned if there are no more events to return. */ public int next() throws XPathException { switch(currentEvent) { case START_OF_INPUT: currentNode = startNode; switch (tree.nodeKind[currentNode]) { case Type.DOCUMENT: currentEvent = START_DOCUMENT; break; case Type.ELEMENT: currentEvent = START_ELEMENT; break; case Type.TEXT: case Type.WHITESPACE_TEXT: currentEvent = TEXT; break; case Type.COMMENT: currentEvent = COMMENT; break; case Type.PROCESSING_INSTRUCTION: currentEvent = PROCESSING_INSTRUCTION; break; case Type.PARENT_POINTER: throw new IllegalStateException("Current node is a parent-pointer pseudo-node"); } return currentEvent; case START_DOCUMENT: case START_ELEMENT: if (tree.depth[currentNode+1] > tree.depth[currentNode]) { // the current element or document has children: move to the first child switch (tree.nodeKind[++currentNode]) { case Type.ELEMENT: currentEvent = START_ELEMENT; break; case Type.TEXT: case Type.WHITESPACE_TEXT: currentEvent = TEXT; break; case Type.COMMENT: currentEvent = COMMENT; break; case Type.PROCESSING_INSTRUCTION: currentEvent = PROCESSING_INSTRUCTION; break; case Type.PARENT_POINTER: throw new IllegalStateException("First child node must not be a parent-pointer pseudo-node"); } return currentEvent; } else { if (currentEvent == START_DOCUMENT) { currentEvent = END_DOCUMENT; } else { currentEvent = END_ELEMENT; } return currentEvent; } case END_ELEMENT: case TEXT: case COMMENT: case PROCESSING_INSTRUCTION: if (currentNode == startNode) { currentEvent = END_OF_INPUT; return currentEvent; } int next = tree.next[currentNode]; if (next > currentNode) { // this node has a following sibling currentNode = tree.next[currentNode]; do { switch (tree.nodeKind[currentNode]) { case Type.ELEMENT: currentEvent = START_ELEMENT; break; case Type.TEXT: case Type.WHITESPACE_TEXT: currentEvent = TEXT; break; case Type.COMMENT: currentEvent = COMMENT; break; case Type.PROCESSING_INSTRUCTION: currentEvent = PROCESSING_INSTRUCTION; break; case Type.PARENT_POINTER: // skip this pseudo-node currentEvent = -1; currentNode++; break; } } while (currentEvent == -1); return currentEvent; } else { // return to the parent element or document currentNode = next; if (currentNode == -1) { // indicates we were at the END_ELEMENT of a parentless element node currentEvent = END_OF_INPUT; return currentEvent; } switch (tree.nodeKind[currentNode]) { case Type.ELEMENT: currentEvent = END_ELEMENT; break; case Type.DOCUMENT: currentEvent = END_DOCUMENT; break; } return currentEvent; } case ATTRIBUTE: case NAMESPACE: case END_DOCUMENT: currentEvent = END_OF_INPUT; return currentEvent; case END_OF_INPUT: throw new IllegalStateException("Cannot call next() when input is exhausted"); default: throw new IllegalStateException("Unrecognized event " + currentEvent); } } /** * Get the event most recently returned by next(), or by other calls that change * the position, for example getStringValue() and skipToMatchingEnd(). This * method does not change the position of the PullProvider. * * @return the current event */ public int current() { return currentEvent; } /** * Get the attributes associated with the current element. This method must * be called only after a START_ELEMENT event has been notified. The contents * of the returned AttributeCollection are guaranteed to remain unchanged * until the next START_ELEMENT event, but may be modified thereafter. The object * should not be modified by the client. *

    *

    Attributes may be read before or after reading the namespaces of an element, * but must not be read after the first child node has been read, or after calling * one of the methods skipToEnd(), getStringValue(), or getTypedValue().

    * * @return an AttributeCollection representing the attributes of the element * that has just been notified. */ public AttributeCollection getAttributes() throws XPathException { if (tree.nodeKind[currentNode] == Type.ELEMENT) { if (tree.alpha[currentNode] == -1) { return AttributeCollectionImpl.EMPTY_ATTRIBUTE_COLLECTION; } return new TinyAttributeCollection(tree, currentNode); } else { throw new IllegalStateException("getAttributes() called when current event is not ELEMENT_START"); } } /** * Get the namespace declarations associated with the current element. This method must * be called only after a START_ELEMENT event has been notified. In the case of a top-level * START_ELEMENT event (that is, an element that either has no parent node, or whose parent * is not included in the sequence being read), the NamespaceDeclarations object returned * will contain a namespace declaration for each namespace that is in-scope for this element * node. In the case of a non-top-level element, the NamespaceDeclarations will contain * a set of namespace declarations and undeclarations, representing the differences between * this element and its parent. *

    *

    It is permissible for this method to return namespace declarations that are redundant.

    *

    *

    The NamespaceDeclarations object is guaranteed to remain unchanged until the next START_ELEMENT * event, but may then be overwritten. The object should not be modified by the client.

    *

    *

    Namespaces may be read before or after reading the attributes of an element, * but must not be read after the first child node has been read, or after calling * one of the methods skipToEnd(), getStringValue(), or getTypedValue().

    * */ public NamespaceDeclarations getNamespaceDeclarations() throws XPathException { if (tree.nodeKind[currentNode] == Type.ELEMENT) { int[] decl; if (currentNode == startNode) { // get all inscope namespaces for a top-level element in the sequence. decl = TinyElementImpl.getInScopeNamespaces(tree, currentNode, nsBuffer); } else { // only namespace declarations (and undeclarations) on this element are required decl = TinyElementImpl.getDeclaredNamespaces(tree, currentNode, nsBuffer); } nsDeclarations.setNamespaceCodes(decl); return nsDeclarations; } throw new IllegalStateException("getNamespaceDeclarations() called when current event is not START_ELEMENT"); } /** * Skip the current subtree. This method may be called only immediately after * a START_DOCUMENT or START_ELEMENT event. This call returns the matching * END_DOCUMENT or END_ELEMENT event; the next call on next() will return * the event following the END_DOCUMENT or END_ELEMENT. */ public int skipToMatchingEnd() throws XPathException { // For this implementation, we simply leave the current node unchanged, and change // the current event switch (currentEvent) { case START_DOCUMENT: currentEvent = END_DOCUMENT; return currentEvent; case START_ELEMENT: currentEvent = END_ELEMENT; return currentEvent; default: throw new IllegalStateException( "Cannot call skipToMatchingEnd() except when at start of element or document"); } } /** * Close the event reader. This indicates that no further events are required. * It is not necessary to close an event reader after {@link #END_OF_INPUT} has * been reported, but it is recommended to close it if reading terminates * prematurely. Once an event reader has been closed, the effect of further * calls on next() is undefined. */ public void close() { // no action } /** * Get the namePool used to lookup all name codes and namespace codes * * @return the namePool */ public NamePool getNamePool() { return pipe.getConfiguration().getNamePool(); } /** * Get the nameCode identifying the name of the current node. This method * can be used after the {@link #START_ELEMENT}, {@link #PROCESSING_INSTRUCTION}, * {@link #ATTRIBUTE}, or {@link #NAMESPACE} events. With some PullProvider implementations, * including this one, it can also be used after {@link #END_ELEMENT}. * If called at other times, the result is undefined and may result in an IllegalStateException. * If called when the current node is an unnamed namespace node (a node representing the default namespace) * the returned value is -1. * @return the nameCode. The nameCode can be used to obtain the prefix, local name, * and namespace URI from the name pool. */ public int getNameCode() { switch (currentEvent) { case START_ELEMENT: case PROCESSING_INSTRUCTION: case END_ELEMENT: return tree.nameCode[currentNode]; default: throw new IllegalStateException("getNameCode() called when its value is undefined"); } } /** * Get the fingerprint of the name of the element. This is similar to the nameCode, except that * it does not contain any information about the prefix: so two elements with the same fingerprint * have the same name, excluding prefix. This method * can be used after the {@link #START_ELEMENT}, {@link #END_ELEMENT}, {@link #PROCESSING_INSTRUCTION}, * {@link #ATTRIBUTE}, or {@link #NAMESPACE} events. * If called at other times, the result is undefined and may result in an IllegalStateException. * If called when the current node is an unnamed namespace node (a node representing the default namespace) * the returned value is -1. * * @return the fingerprint. The fingerprint can be used to obtain the local name * and namespace URI from the name pool. */ public int getFingerprint() { int nc = getNameCode(); if (nc == -1) { return -1; } else { return nc & NamePool.FP_MASK; } } /** * Get the string value of the current attribute, text node, processing-instruction, * or atomic value. * This method cannot be used to obtain the string value of an element, or of a namespace * node. If the most recent event was anything other than {@link #START_ELEMENT}, {@link #TEXT}, * {@link #PROCESSING_INSTRUCTION}, or {@link #ATOMIC_VALUE}, the result is undefined. */ public CharSequence getStringValue() throws XPathException { switch (tree.nodeKind[currentNode]) { case Type.TEXT: return TinyTextImpl.getStringValue(tree, currentNode); case Type.WHITESPACE_TEXT: return WhitespaceTextImpl.getStringValue(tree, currentNode); case Type.COMMENT: case Type.PROCESSING_INSTRUCTION: // sufficiently rare that instantiating the node is OK return tree.getNode(currentNode).getStringValue(); case Type.ELEMENT: currentEvent = END_ELEMENT; return TinyParentNodeImpl.getStringValue(tree, currentNode); case Type.PARENT_POINTER: throw new IllegalStateException("Trying to get string value of a parent-pointer pseudo node"); } return null; } /** * Get an atomic value. This call may be used only when the last event reported was * ATOMIC_VALUE. This indicates that the PullProvider is reading a sequence that contains * a free-standing atomic value; it is never used when reading the content of a node. */ public AtomicValue getAtomicValue() { throw new IllegalStateException(); } /** * Get the type annotation of the current attribute or element node, or atomic value. * The result of this method is undefined unless the most recent event was START_ELEMENT, * START_CONTENT, ATTRIBUTE, or ATOMIC_VALUE. * * @return the type code. This code is the fingerprint of a type name, which may be * resolved to a {@link net.sf.saxon.type.SchemaType} by access to the Configuration. */ public int getTypeAnnotation() { if (tree.nodeKind[currentNode] != Type.ELEMENT) { throw new IllegalStateException("getTypeAnnotation() called when current event is not ELEMENT_START or "); } if (tree.typeCodeArray == null) { return StandardNames.XS_UNTYPED; } return tree.typeCodeArray[currentNode] & NamePool.FP_MASK; } /** * Get the location of the current event. * For an event stream representing a real document, the location information * should identify the location in the lexical XML source. For a constructed document, it should * identify the location in the query or stylesheet that caused the node to be created. * A value of null can be returned if no location information is available. */ public SourceLocator getSourceLocator() { return this; } /** * Return the public identifier for the current document event. *

    *

    The return value is the public identifier of the document * entity or of the external parsed entity in which the markup that * triggered the event appears.

    * * @return A string containing the public identifier, or * null if none is available. * @see #getSystemId */ public String getPublicId() { return null; } /** * Return the system identifier for the current document event. *

    *

    The return value is the system identifier of the document * entity or of the external parsed entity in which the markup that * triggered the event appears.

    *

    *

    If the system identifier is a URL, the parser must resolve it * fully before passing it to the application.

    * * @return A string containing the system identifier, or null * if none is available. * @see #getPublicId */ public String getSystemId() { return tree.getSystemId(currentNode); } /** * Return the line number where the current document event ends. *

    *

    Warning: The return value from the method * is intended only as an approximation for the sake of error * reporting; it is not intended to provide sufficient information * to edit the character content of the original XML document.

    *

    *

    The return value is an approximation of the line number * in the document entity or external parsed entity where the * markup that triggered the event appears.

    * * @return The line number, or -1 if none is available. * @see #getColumnNumber */ public int getLineNumber() { return tree.getLineNumber(currentNode); } /** * Return the character position where the current document event ends. *

    *

    Warning: The return value from the method * is intended only as an approximation for the sake of error * reporting; it is not intended to provide sufficient information * to edit the character content of the original XML document.

    *

    *

    The return value is an approximation of the column number * in the document entity or external parsed entity where the * markup that triggered the event appears.

    * * @return The column number, or -1 if none is available. * @see #getLineNumber */ public int getColumnNumber() { return -1; } /** * Get a list of unparsed entities. * * @return a list of unparsed entities, or null if the information is not available, or * an empty list if there are no unparsed entities. */ public List getUnparsedEntities() { return null; } public static void main(String[] args) throws Exception { Controller controller = new Controller(new Configuration()); TinyBuilder tb = (TinyBuilder)controller.makeBuilder(); tb.open(); NamePool p = tb.getConfiguration().getNamePool(); int code = p.allocate("a", "b", "c"); tb.startElement(code, -1, -1, -1); tb.endElement(); tb.startDocument(-1); tb.startElement(code, -1, -1, -1); tb.endElement(); tb.endDocument(); tb.close(); TinyTree tt = tb.getTree(); NodeInfo node = tb.getCurrentRoot(); TinyTreeWalker walker = new TinyTreeWalker((TinyNodeImpl)node); System.out.println(walker.next()); System.out.println(walker.next()); System.out.println(walker.next()); System.out.println(walker.next()); System.out.println(walker.next()); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. //saxonb-9.1.0.8/bj/net/sf/saxon/tinytree/CompressedWhitespace.java0000644000175000017500000002454411033112257024237 0ustar eugeneeugenepackage net.sf.saxon.tinytree; import net.sf.saxon.om.FastStringBuffer; import java.io.Writer; import java.io.OutputStream; /** * This class provides a compressed representation of a sequence of whitespace characters. The representation * is a sequence of bytes: in each byte the top two bits indicate which whitespace character is used * (x9, xA, xD, or x20) and the bottom six bits indicate the number of such characters. A zero byte is a filler. * We don't compress the sequence if it would occupy more than 8 bytes, because that's the space we've got available * in the TinyTree arrays. */ public class CompressedWhitespace implements CharSequence { private static char[] WHITE_CHARS = {0x09, 0x0A, 0x0D, 0x20}; private long value; public CompressedWhitespace(long compressedValue) { value = compressedValue; } /** * Attempt to compress a CharSequence * @param in the CharSequence to be compressed * @return the compressed sequence if it can be compressed; or the original CharSequence otherwise */ public static CharSequence compress(CharSequence in) { final int inlen = in.length(); if (inlen == 0) { return in; } int runlength = 1; int outlength = 0; for (int i=0; i= 0) { if (i == inlen-1 || c != in.charAt(i+1) || runlength == 63) { runlength = 1; outlength++; if (outlength > 8) { return in; } } else { runlength++; } } else { return in; } } int ix = 0; runlength = 1; int[] out = new int[outlength]; for (int i=0; i=0; s-=8) { byte b = (byte)((value >>>s) & 0xff); if (b == 0) { break; } char c = WHITE_CHARS[b>>>6 & 0x3]; int len = (b & 0x3f); buffer.ensureCapacity(len); for (int j=0; j=0; s-=8) { int c = (int)((val>>>s) & 0x3f); if (c == 0) { break; } count += c; } return count; } /** * Returns the char value at the specified index. An index ranges from zero * to length() - 1. The first char value of the sequence is at * index zero, the next at index one, and so on, as for array * indexing.

    *

    *

    If the char value specified by the index is a * surrogate, the surrogate * value is returned. * * @param index the index of the char value to be returned * @return the specified char value * @throws IndexOutOfBoundsException if the index argument is negative or not less than * length() */ public char charAt(int index) { int count = 0; final long val = value; for (int s=56; s>=0; s-=8) { byte b = (byte)((val>>>s) & 0xff); if (b == 0) { break; } count += (b & 0x3f); if (count > index) { return WHITE_CHARS[b>>>6 & 0x3]; } } throw new IndexOutOfBoundsException(index+""); } /** * Returns a new CharSequence that is a subsequence of this sequence. * The subsequence starts with the char value at the specified index and * ends with the char value at index end - 1. The length * (in chars) of the * returned sequence is end - start, so if start == end * then an empty sequence is returned.

    * * @param start the start index, inclusive * @param end the end index, exclusive * @return the specified subsequence * @throws IndexOutOfBoundsException if start or end are negative, * if end is greater than length(), * or if start is greater than end */ public CharSequence subSequence(int start, int end) { return uncompress(null).subSequence(start, end); } /** * Indicates whether some other object is "equal to" this one. */ public boolean equals(Object obj) { if (obj instanceof CompressedWhitespace) { return value == ((CompressedWhitespace)obj).value; } return uncompress(null).equals(obj); } /** * Returns a hash code value for the object. */ public int hashCode() { return uncompress(null).hashCode(); } /** * Returns a string representation of the object. */ public String toString() { return uncompress(null).toString(); } /** * Write the value to a Writer */ public void write(Writer writer) throws java.io.IOException { final long val = value; for (int s=56; s>=0; s-=8) { final byte b = (byte)((val>>>s) & 0xff); if (b == 0) { break; } final char c = WHITE_CHARS[b>>>6 & 0x3]; final int len = (b & 0x3f); for (int j=0; j=0; s-=8) { final byte b = (byte)((val>>>s) & 0xff); if (b == 0) { break; } final char c = WHITE_CHARS[b>>>6 & 0x3]; final int len = (b & 0x3f); if (specialChars[c]) { String e = ""; if (c=='\n') { e = " "; } else if (c=='\r') { e = " "; } else if (c=='\t') { e = " "; } for (int j=0; j=0; s-=8) { final byte b = (byte)((val>>>s) & 0xff); if (b == 0) { break; } final char c = WHITE_CHARS[b>>>6 & 0x3]; final int len = (b & 0x3f); if (specialChars[c]) { byte[] e; if (c=='\n') { e = ESCAPE_N; } else if (c=='\r') { e = ESCAPE_R; } else { e = ESCAPE_T; } for (int j=0; j?> . * @return the content of the processing instruction (in XDM this is the * same as its string value) */ public String getData() { return getStringValue(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/tinytree/FollowingEnumeration.java0000644000175000017500000000734111033112257024261 0ustar eugeneeugenepackage net.sf.saxon.tinytree; import net.sf.saxon.om.AxisIteratorImpl; import net.sf.saxon.om.Item; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.pattern.NodeTest; /** * Iterate over the following axis starting at a given node. * The start node must not be a namespace or attribute node. */ final class FollowingEnumeration extends AxisIteratorImpl { private TinyTree tree; private TinyNodeImpl startNode; private NodeTest test; private boolean includeDescendants; /** * Create an iterator over the following axis * @param doc the containing TinyTree * @param node the start node. If the actual start was an attribute or namespace node, this will * be the parent element of that attribute or namespace * @param nodeTest condition that all the returned nodes must satisfy * @param includeDescendants true if descendants of the start node are to be included. This will * be false if the actual start was an element node, true if it was an attribute or namespace node * (since the children of their parent follow the attribute or namespace in document order). */ public FollowingEnumeration(TinyTree doc, TinyNodeImpl node, NodeTest nodeTest, boolean includeDescendants) { tree = doc; test = nodeTest; startNode = node; this.includeDescendants = includeDescendants; } public Item next() { int nodeNr; if (position <= 0) { if (position < 0) { // already at end return null; } // first time call nodeNr = startNode.nodeNr; // skip the descendant nodes if any if (includeDescendants) { nodeNr++; } else { while (true) { int nextSib = tree.next[nodeNr]; if (nextSib > nodeNr) { nodeNr = nextSib; break; } else if (tree.depth[nextSib] == 0) { current = null; position = -1; return null; } else { nodeNr = nextSib; } } } } else { nodeNr = ((TinyNodeImpl)current).nodeNr + 1; } while (true) { if (tree.depth[nodeNr] == 0) { current = null; position = -1; return null; } if (test.matches(tree, nodeNr)) { position++; current = tree.getNode(nodeNr); return current; } nodeNr++; } } /** * Get another enumeration of the same nodes */ public SequenceIterator getAnother() { return new FollowingEnumeration(tree, startNode, test, includeDescendants); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/tinytree/CharSlice.java0000644000175000017500000001564111033112257021751 0ustar eugeneeugenepackage net.sf.saxon.tinytree; import java.io.Writer; import java.io.Serializable; /** * This is an implementation of the JDK 1.4 CharSequence interface: it implements * a CharSequence as a view of an array. The implementation relies on the array * being immutable: as a minimum, the caller is required to ensure that the array * contents will not change so long as the CharSlice remains in existence. * * This class should be more efficient than String because it avoids copying the * characters unnecessarily. * * The methods in the class don't check their arguments. Incorrect arguments will * generally result in exceptions from lower-level classes. * */ public final class CharSlice implements CharSequence, Serializable { private char[] array; private int offset; private int count; /** * Create a CharSlice that maps to the whole of a char[] array * @param array the char[] array */ public CharSlice(char[] array) { this.array = array; offset = 0; count = array.length; } /** * Create a CharSlice that maps to a section of a char[] array * @param array the char[] array * @param start position of the first character to be included * @param length number of characters to be included */ public CharSlice(char[] array, int start, int length) { this.array = array; offset = start; count = length; if (start + length > array.length) { throw new IndexOutOfBoundsException("start(" + start + ") + length(" + length + ") > size(" + array.length + ')'); } } /** * Returns the length of this character sequence. The length is the number * of 16-bit Unicode characters in the sequence.

    * * @return the number of characters in this sequence */ public int length() { return count; } /** * Set the length of this character sequence, without changing the array and start offset * to which it is bound * @param length the new length of the CharSlice (which must be less than the existing length, * though this is not enforced) */ public void setLength(int length) { count = length; } /** * Returns the character at the specified index. An index ranges from zero * to length() - 1. The first character of the sequence is at * index zero, the next at index one, and so on, as for array * indexing.

    * * @param index the index of the character to be returned * @return the specified character * @throws java.lang.IndexOutOfBoundsException * if the index argument is negative or not less than * length() */ public char charAt(int index) { return array[offset+index]; } /** * Returns a new character sequence that is a subsequence of this sequence. * The subsequence starts with the character at the specified index and * ends with the character at index end - 1. The length of the * returned sequence is end - start, so if start == end * then an empty sequence is returned.

    * * @param start the start index, inclusive * @param end the end index, exclusive * * @return the specified subsequence * * @throws java.lang.IndexOutOfBoundsException * if start or end are negative, * if end is greater than length(), * or if start is greater than end */ public CharSequence subSequence(int start, int end) { return new CharSlice(array, offset+start, end-start); } /** * Convert to a string */ public String toString() { return new String(array, offset, count); } /** * Compare equality */ public boolean equals(Object other) { return toString().equals(other); } /** * Generate a hash code */ public int hashCode() { // Same algorithm as String#hashCode(), but not cached int end = offset+count; int h = 0; for (int i = offset; i < end; i++) { h = 31 * h + array[i]; } return h; } /** * Get the index of a specific character in the sequence. Returns -1 if not found. * This method mimics {@link String#indexOf} * @param c the character to be found * @return the position of the first occurrence of that character, or -1 if not found. */ public int indexOf(char c) { int end = offset+count; for (int i = offset; i < end; i++) { if (array[i] == c) { return i-offset; } } return -1; } /** * Returns a new character sequence that is a subsequence of this sequence. * Unlike subSequence, this is guaranteed to return a String. * @param start position of the first character to be included (relative to the * start of the CharSlice, not the underlying array) * @param end position of the first character not to be included (relative * to the start of the CharSlice) * @return the substring, as a String object */ public String substring(int start, int end) { return new String(array, offset+start, end-start); } /** * Append the contents to another array at a given offset. The caller is responsible * for ensuring that sufficient space is available. * @param destination the array to which the characters will be copied * @param destOffset the offset in the target array where the copy will start */ public void copyTo(char[] destination, int destOffset) { System.arraycopy(array, offset, destination, destOffset, count); } /** * Write the value to a writer * @param writer the writer to be written to */ public void write(Writer writer) throws java.io.IOException { writer.write(array, offset, count); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none // saxonb-9.1.0.8/bj/net/sf/saxon/tinytree/TinyTextImpl.java0000644000175000017500000000550711033112257022526 0ustar eugeneeugenepackage net.sf.saxon.tinytree; import net.sf.saxon.event.Receiver; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.Type; /** * A node in the XML parse tree representing character content * @author Michael H. Kay */ public final class TinyTextImpl extends TinyNodeImpl { /** * Create a text node * @param tree the tree to contain the node * @param nodeNr the internal node number */ public TinyTextImpl(TinyTree tree, int nodeNr) { this.tree = tree; this.nodeNr = nodeNr; } /** * Return the character value of the node. * @return the string value of the node */ public String getStringValue() { int start = tree.alpha[nodeNr]; int len = tree.beta[nodeNr]; //return new String(tree.charBuffer, start, len); return tree.charBuffer.substring(start, start+len); } /** * Get the value of the item as a CharSequence. This is in some cases more efficient than * the version of the method that returns a String. */ public CharSequence getStringValueCS() { int start = tree.alpha[nodeNr]; int len = tree.beta[nodeNr]; return tree.charBuffer.subSequence(start, start+len); } /** * Static method to get the string value of a text node without first constructing the node object * @param tree the tree * @param nodeNr the node number of the text node * @return the string value of the text node */ public static CharSequence getStringValue(TinyTree tree, int nodeNr) { int start = tree.alpha[nodeNr]; int len = tree.beta[nodeNr]; //return new CharSlice(tree.charBuffer, start, len); return tree.charBuffer.subSequence(start, start+len); } /** * Return the type of node. * @return Type.TEXT */ public final int getNodeKind() { return Type.TEXT; } /** * Copy this node to a given outputter */ public void copy(Receiver out, int whichNamespaces, boolean copyAnnotations, int locationId) throws XPathException { out.characters(getStringValueCS(), 0, 0); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/tinytree/TinyNodeImpl.java0000644000175000017500000006407411072502077022501 0ustar eugeneeugenepackage net.sf.saxon.tinytree; import net.sf.saxon.Configuration; import net.sf.saxon.trans.Err; import net.sf.saxon.om.*; import net.sf.saxon.pattern.AnyNodeTest; import net.sf.saxon.pattern.NameTest; import net.sf.saxon.pattern.NodeTest; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.SchemaType; import net.sf.saxon.type.Type; import net.sf.saxon.value.UntypedAtomicValue; import net.sf.saxon.value.Value; import javax.xml.transform.SourceLocator; /** * A node in a TinyTree representing an XML element, character content, or attribute.

    * This is the top-level class in the implementation class hierarchy; it essentially contains * all those methods that can be defined using other primitive methods, without direct access * to data. * * @author Michael H. Kay */ public abstract class TinyNodeImpl implements NodeInfo, FingerprintedNode, SourceLocator { protected TinyTree tree; protected int nodeNr; protected TinyNodeImpl parent = null; /** * Chararacteristic letters to identify each type of node, indexed using the node type * values. These are used as the initial letter of the result of generate-id() */ public static final char[] NODE_LETTER = {'x', 'e', 'a', 't', 'x', 'x', 'x', 'p', 'c', 'r', 'x', 'x', 'x', 'n'}; /** * Get the value of the item as a CharSequence. This is in some cases more efficient than * the version of the method that returns a String. */ public CharSequence getStringValueCS() { return getStringValue(); } /** * Get the type annotation of this node, if any */ public int getTypeAnnotation() { return -1; } /** * Get the column number of the node. * The default implementation returns -1, meaning unknown */ public int getColumnNumber() { return tree.getColumnNumber(nodeNr); } /** * Get the public identifier of the document entity containing this node. * The default implementation returns null, meaning unknown */ public String getPublicId() { return null; } /** * Get the typed value of this node. * If there is no type annotation, we return the string value, as an instance * of xs:untypedAtomic */ public SequenceIterator getTypedValue() throws XPathException { int annotation = getTypeAnnotation(); if ((annotation & NodeInfo.IS_DTD_TYPE) != 0) { annotation = StandardNames.XS_UNTYPED_ATOMIC; } annotation &= NamePool.FP_MASK; if (annotation == -1 || annotation == StandardNames.XS_UNTYPED_ATOMIC || annotation == StandardNames.XS_UNTYPED) { return SingletonIterator.makeIterator(new UntypedAtomicValue(getStringValueCS())); } else { SchemaType stype = getConfiguration().getSchemaType(annotation); if (stype == null) { String typeName; try { typeName = getNamePool().getDisplayName(annotation); } catch (Exception err) { typeName = annotation + ""; } throw new XPathException("Unknown type annotation " + Err.wrap(typeName) + " in document instance"); } else { return stype.getTypedValue(this); } } } /** * Get the typed value. The result of this method will always be consistent with the method * {@link net.sf.saxon.om.Item#getTypedValue()}. However, this method is often more convenient and may be * more efficient, especially in the common case where the value is expected to be a singleton. * * @return the typed value. If requireSingleton is set to true, the result will always be an * AtomicValue. In other cases it may be a Value representing a sequence whose items are atomic * values. * @since 8.5 */ public Value atomize() throws XPathException { int annotation = getTypeAnnotation(); if ((annotation & NodeInfo.IS_DTD_TYPE) != 0) { annotation = StandardNames.XS_UNTYPED_ATOMIC; } if (annotation == -1 || annotation == StandardNames.XS_UNTYPED_ATOMIC || annotation == StandardNames.XS_UNTYPED) { return new UntypedAtomicValue(getStringValueCS()); } else { SchemaType stype = getConfiguration().getSchemaType(annotation); if (stype == null) { String typeName = getNamePool().getDisplayName(annotation); throw new XPathException("Unknown type annotation " + Err.wrap(typeName) + " in document instance"); } else { return stype.atomize(this); } } } /** * Set the system id of this node.
    * This method is present to ensure that * the class implements the javax.xml.transform.Source interface, so a node can * be used as the source of a transformation. */ public void setSystemId(String uri) { tree.setSystemId(nodeNr, uri); } /** * Set the parent of this node. Providing this information is useful, * if it is known, because otherwise getParent() has to search backwards * through the document. * @param parent the parent of this node */ protected void setParentNode(TinyNodeImpl parent) { this.parent = parent; } /** * Determine whether this is the same node as another node * * @return true if this Node object and the supplied Node object represent the * same node in the tree. */ public boolean isSameNodeInfo(NodeInfo other) { return this == other || (other instanceof TinyNodeImpl && tree == ((TinyNodeImpl)other).tree && nodeNr == ((TinyNodeImpl)other).nodeNr && getNodeKind() == other.getNodeKind()); } /** * The equals() method compares nodes for identity. It is defined to give the same result * as isSameNodeInfo(). * * @param other the node to be compared with this node * @return true if this NodeInfo object and the supplied NodeInfo object represent * the same node in the tree. * @since 8.7 Previously, the effect of the equals() method was not defined. Callers * should therefore be aware that third party implementations of the NodeInfo interface may * not implement the correct semantics. It is safer to use isSameNodeInfo() for this reason. * The equals() method has been defined because it is useful in contexts such as a Java Set or HashMap. */ public boolean equals(Object other) { return other instanceof NodeInfo && isSameNodeInfo((NodeInfo)other); } /** * The hashCode() method obeys the contract for hashCode(): that is, if two objects are equal * (represent the same node) then they must have the same hashCode() * * @since 8.7 Previously, the effect of the equals() and hashCode() methods was not defined. Callers * should therefore be aware that third party implementations of the NodeInfo interface may * not implement the correct semantics. */ public int hashCode() { return ((tree.getDocumentNumber() & 0x3ff) << 20) ^ nodeNr ^ (getNodeKind() << 14); } /** * Get the system ID for the entity containing the node. */ public String getSystemId() { return tree.getSystemId(nodeNr); } /** * Get the base URI for the node. Default implementation for child nodes gets * the base URI of the parent node. */ public String getBaseURI() { return (getParent()).getBaseURI(); } /** * Get the line number of the node within its source document entity */ public int getLineNumber() { return tree.getLineNumber(nodeNr); } /** * Get the node sequence number (in document order). Sequence numbers are monotonic but not * consecutive. The sequence number must be unique within the document (not, as in * previous releases, within the whole document collection). * For document nodes, elements, text nodes, comment nodes, and PIs, the sequence number * is a long with the sequential node number in the top half and zero in the bottom half. * The bottom half is used only for attributes and namespace. * @return the sequence number */ protected long getSequenceNumber() { return (long)nodeNr << 32; } /** * Determine the relative position of this node and another node, in document order. * The other node will always be in the same document. * * @param other The other node, whose position is to be compared with this node * @return -1 if this node precedes the other node, +1 if it follows the other * node, or 0 if they are the same node. (In this case, isSameNode() will always * return true, and the two nodes will produce the same result for generateId()) */ public final int compareOrder(NodeInfo other) { long a = getSequenceNumber(); if (other instanceof TinyNodeImpl) { long b = ((TinyNodeImpl)other).getSequenceNumber(); if (a < b) { return -1; } if (a > b) { return +1; } return 0; } else { // it must be a namespace node return 0 - other.compareOrder(this); } } /** * Get the fingerprint of the node, used for matching names */ public int getFingerprint() { int nc = getNameCode(); if (nc == -1) { return -1; } return nc & 0xfffff; } /** * Get the name code of the node, used for matching names */ public int getNameCode() { // overridden for attributes and namespace nodes. return tree.nameCode[nodeNr]; } /** * Get the prefix part of the name of this node. This is the name before the ":" if any. * * @return the prefix part of the name. For an unnamed node, return "". */ public String getPrefix() { int code = tree.nameCode[nodeNr]; if (code < 0) { return ""; } if (NamePool.getPrefixIndex(code) == 0) { return ""; } return tree.getNamePool().getPrefix(code); } /** * Get the URI part of the name of this node. This is the URI corresponding to the * prefix, or the URI of the default namespace if appropriate. * * @return The URI of the namespace of this node. For an unnamed node, or for * an element or attribute in the default namespace, return an empty string. */ public String getURI() { int code = tree.nameCode[nodeNr]; if (code < 0) { return ""; } return tree.getNamePool().getURI(code); } /** * Get the display name of this node (a lexical QName). For elements and attributes this is [prefix:]localname. * The original prefix is retained. For unnamed nodes, the result is an empty string. * * @return The display name of this node. * For a node with no name, return an empty string. */ public String getDisplayName() { int code = tree.nameCode[nodeNr]; if (code < 0) { return ""; } return tree.getNamePool().getDisplayName(code); } /** * Get the local part of the name of this node. * * @return The local name of this node. * For a node with no name, return "". */ public String getLocalPart() { int code = tree.nameCode[nodeNr]; if (code < 0) { return ""; } return tree.getNamePool().getLocalName(code); } /** * Return an iterator over all the nodes reached by the given axis from this node * * @param axisNumber Identifies the required axis, eg. Axis.CHILD or Axis.PARENT * @return a AxisIteratorImpl that scans the nodes reached by the axis in turn. */ public AxisIterator iterateAxis(byte axisNumber) { // fast path for child axis if (axisNumber == Axis.CHILD) { if (hasChildNodes()) { return new SiblingEnumeration(tree, this, null, true); } else { return EmptyIterator.getInstance(); } } else { return iterateAxis(axisNumber, AnyNodeTest.getInstance()); } } /** * Return an iterator over the nodes reached by the given axis from this node * * @param axisNumber Identifies the required axis, eg. Axis.CHILD or Axis.PARENT * @param nodeTest A pattern to be matched by the returned nodes. * @return a AxisIteratorImpl that scans the nodes reached by the axis in turn. */ public AxisIterator iterateAxis(byte axisNumber, NodeTest nodeTest) { int type = getNodeKind(); switch (axisNumber) { case Axis.ANCESTOR: return new AncestorEnumeration(this, nodeTest, false); case Axis.ANCESTOR_OR_SELF: return new AncestorEnumeration(this, nodeTest, true); case Axis.ATTRIBUTE: if (type != Type.ELEMENT) { return EmptyIterator.getInstance(); } if (tree.alpha[nodeNr] < 0) { return EmptyIterator.getInstance(); } return new AttributeEnumeration(tree, nodeNr, nodeTest); case Axis.CHILD: if (hasChildNodes()) { return new SiblingEnumeration(tree, this, nodeTest, true); } else { return EmptyIterator.getInstance(); } case Axis.DESCENDANT: if (type == Type.DOCUMENT && nodeTest instanceof NameTest && nodeTest.getPrimitiveType() == Type.ELEMENT) { return ((TinyDocumentImpl)this).getAllElements(nodeTest.getFingerprint()); } else if (hasChildNodes()) { return new DescendantEnumeration(tree, this, nodeTest, false); } else { return EmptyIterator.getInstance(); } case Axis.DESCENDANT_OR_SELF: if (hasChildNodes()) { return new DescendantEnumeration(tree, this, nodeTest, true); } else { return Navigator.filteredSingleton(this, nodeTest); } case Axis.FOLLOWING: if (type == Type.ATTRIBUTE || type == Type.NAMESPACE) { return new FollowingEnumeration(tree, (TinyNodeImpl)getParent(), nodeTest, true); } else if (tree.depth[nodeNr] == 0) { return EmptyIterator.getInstance(); } else { return new FollowingEnumeration(tree, this, nodeTest, false); } case Axis.FOLLOWING_SIBLING: if (type == Type.ATTRIBUTE || type == Type.NAMESPACE || tree.depth[nodeNr] == 0) { return EmptyIterator.getInstance(); } else { return new SiblingEnumeration(tree, this, nodeTest, false); } case Axis.NAMESPACE: if (type != Type.ELEMENT) { return EmptyIterator.getInstance(); } return NamespaceIterator.makeIterator(this, nodeTest); case Axis.PARENT: NodeInfo parent = getParent(); return Navigator.filteredSingleton(parent, nodeTest); case Axis.PRECEDING: if (type == Type.ATTRIBUTE || type == Type.NAMESPACE) { return new PrecedingEnumeration(tree, (TinyNodeImpl)getParent(), nodeTest, false); } else if (tree.depth[nodeNr] == 0) { return EmptyIterator.getInstance(); } else { return new PrecedingEnumeration(tree, this, nodeTest, false); } case Axis.PRECEDING_SIBLING: if (type == Type.ATTRIBUTE || type == Type.NAMESPACE || tree.depth[nodeNr] == 0) { return EmptyIterator.getInstance(); } else { return new PrecedingSiblingEnumeration(tree, this, nodeTest); } case Axis.SELF: return Navigator.filteredSingleton(this, nodeTest); case Axis.PRECEDING_OR_ANCESTOR: if (type == Type.DOCUMENT) { return EmptyIterator.getInstance(); } else if (type == Type.ATTRIBUTE || type == Type.NAMESPACE) { // See test numb32. TinyNodeImpl el = (TinyNodeImpl)getParent(); return new PrependIterator(el, new PrecedingEnumeration(tree, el, nodeTest, true)); } else { return new PrecedingEnumeration(tree, this, nodeTest, true); } default: throw new IllegalArgumentException("Unknown axis number " + axisNumber); } } /** * Find the parent node of this node. * * @return The Node object describing the containing element or root node. */ public NodeInfo getParent() { if (parent != null) { return parent; } int p = getParentNodeNr(tree, nodeNr); if (p == -1) { parent = null; } else { parent = tree.getNode(p); } return parent; } /** * Static method to get the parent of a given node, without instantiating the node as an object. * The starting node is any node other than an attribute or namespace node. * * @param tree the tree containing the starting node * @param nodeNr the node number of the starting node within the tree * @return the node number of the parent node, or -1 if there is no parent. */ static int getParentNodeNr(TinyTree tree, int nodeNr) { if (tree.depth[nodeNr] == 0) { return -1; } // follow the next-sibling pointers until we reach either a next sibling pointer that // points backwards, or a parent-pointer pseudo-node int p = tree.next[nodeNr]; while (p > nodeNr) { if (tree.nodeKind[p] == Type.PARENT_POINTER) { return tree.alpha[p]; } p = tree.next[p]; } return p; } /** * Determine whether the node has any children. * * @return true if this node has any attributes, * false otherwise. */ public boolean hasChildNodes() { // overridden in TinyParentNodeImpl return false; } /** * Get the value of a given attribute of this node * * @param fingerprint The fingerprint of the attribute name * @return the attribute value if it exists or null if not */ public String getAttributeValue(int fingerprint) { // overridden in TinyElementImpl return null; } /** * Get the root node of the tree (not necessarily a document node) * * @return the NodeInfo representing the root of this tree */ public NodeInfo getRoot() { if (tree.depth[nodeNr] == 0) { return this; } if (parent != null) { return parent.getRoot(); } return tree.getNode(tree.getRootNode(nodeNr)); } /** * Get the root (document) node * * @return the DocumentInfo representing the containing document */ public DocumentInfo getDocumentRoot() { NodeInfo root = getRoot(); if (root.getNodeKind() == Type.DOCUMENT) { return (DocumentInfo)root; } else { return null; } } /** * Get the configuration */ public Configuration getConfiguration() { return tree.getConfiguration(); } /** * Get the NamePool for the tree containing this node * * @return the NamePool */ public NamePool getNamePool() { return tree.getNamePool(); } /** * Get all namespace undeclarations and undeclarations defined on this element. * * @param buffer If this is non-null, and the result array fits in this buffer, then the result * may overwrite the contents of this array, to avoid the cost of allocating a new array on the heap. * @return An array of integers representing the namespace declarations and undeclarations present on * this element. For a node other than an element, return null. Otherwise, the returned array is a * sequence of namespace codes, whose meaning may be interpreted by reference to the name pool. The * top half word of each namespace code represents the prefix, the bottom half represents the URI. * If the bottom half is zero, then this is a namespace undeclaration rather than a declaration. * The XML namespace is never included in the list. If the supplied array is larger than required, * then the first unused entry will be set to -1. *

    *

    For a node other than an element, the method returns null.

    */ public int[] getDeclaredNamespaces(int[] buffer) { return null; } /** * Get a character string that uniquely identifies this node * * @param buffer buffer, which on return will contain * a character string that uniquely identifies this node. * */ public void generateId(FastStringBuffer buffer) { buffer.append("d"); buffer.append(Integer.toString(tree.getDocumentNumber())); buffer.append(NODE_LETTER[getNodeKind()]); buffer.append(Integer.toString(nodeNr)); } /** * Get the document number of the document containing this node * (Needed when the document isn't a real node, for sorting free-standing elements) */ public final int getDocumentNumber() { return tree.getDocumentNumber(); } /** * Test if this node is an ancestor-or-self of another * * @param d the putative descendant-or-self node * @return true if this node is an ancestor-or-self of d */ public boolean isAncestorOrSelf(TinyNodeImpl d) { // If it's a different tree, return false if (tree != d.tree) return false; int dn = d.nodeNr; // If d is an attribute, then either "this" must be the same attribute, or "this" must // be an ancestor-or-self of the parent of d. if (d instanceof TinyAttributeImpl) { if (this instanceof TinyAttributeImpl) { return nodeNr == dn; } else { dn = tree.attParent[dn]; } } // If this is an attribute, return false (we've already handled the case where it's the same attribute) if (this instanceof TinyAttributeImpl) return false; // From now on, we know that both "this" and "dn" are nodes in the primary array // If d is later in document order, return false if (nodeNr > dn) return false; // If it's the same node, return true if (nodeNr == dn) return true; // We've dealt with the "self" case: to be an ancestor, it must be an element or document node if (!(this instanceof TinyParentNodeImpl)) return false; // If this node is deeper than the target node then it can't be an ancestor if (tree.depth[nodeNr] >= tree.depth[dn]) return false; // The following code will exit as soon as we find an ancestor that has a following-sibling: // when that happens, we know it's an ancestor iff its following-sibling is beyond the node we're // looking for. If the ancestor has no following sibling, we go up a level. // The algorithm depends on the following assertion: if A is before D in document order, then // either A is an ancestor of D, or some ancestor-or-self of A has a following-sibling that // is before-or-equal to D in document order. int n = nodeNr; while (true) { int nextSib = tree.next[n]; if (nextSib > dn) { return true; } else if (nextSib < 0 || tree.depth[nextSib] == 0) { return true; } else if (nextSib < n) { n = nextSib; // continue } else { return false; } } } /** * Determine whether this node has the is-id property * @return true if the node is an ID */ public boolean isId() { return false; // overridden for element and attribute nodes } /** * Determine whether this node has the is-idref property * @return true if the node is an IDREF or IDREFS element or attribute */ public boolean isIdref() { return false; // overridden for element and attribute nodes } /** * Determine whether the node has the is-nilled property * @return true if the node has the is-nilled property */ public boolean isNilled() { return tree.isNilled(nodeNr); } /** * Get the node number of this node within the TinyTree. This method is intended for internal use. * @return the internal node number */ public int getNodeNumber() { return nodeNr; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/tinytree/TinyAttributeImpl.java0000644000175000017500000001600111117247366023551 0ustar eugeneeugenepackage net.sf.saxon.tinytree; import net.sf.saxon.event.Receiver; import net.sf.saxon.om.FastStringBuffer; import net.sf.saxon.om.NamePool; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.Type; /** * A node in the XML parse tree representing an attribute. Note that this is * generated only "on demand", when the attribute is selected by a select pattern.

    * @author Michael H. Kay */ final class TinyAttributeImpl extends TinyNodeImpl { public TinyAttributeImpl(TinyTree tree, int nodeNr) { this.tree = tree; this.nodeNr = nodeNr; } public void setSystemId(String uri) { // no action: an attribute has the same base URI as its parent } /** * Get the parent node */ public NodeInfo getParent() { return tree.getNode(tree.attParent[nodeNr]); } /** * Get the root node of the tree (not necessarily a document node) * * @return the NodeInfo representing the root of this tree */ public NodeInfo getRoot() { NodeInfo parent = getParent(); if (parent == null) { return this; // doesn't happen - parentless attributes are represented by the Orphan class } else { return parent.getRoot(); } } /** * Get the node sequence number (in document order). Sequence numbers are monotonic but not * consecutive. In this implementation, elements have a zero * least-significant word, while attributes and namespaces use the same value in the top word as * the containing element, and use the bottom word to hold * a sequence number, which numbers namespaces first and then attributes. */ protected long getSequenceNumber() { return ((TinyNodeImpl)getParent()).getSequenceNumber() + 0x8000 + (nodeNr - tree.alpha[tree.attParent[nodeNr]]); // note the 0x8000 is to leave room for namespace nodes } /** * Return the type of node. * @return Node.ATTRIBUTE */ public final int getNodeKind() { return Type.ATTRIBUTE; } /** * Return the string value of the node. * @return the attribute value */ public CharSequence getStringValueCS() { return tree.attValue[nodeNr]; } /** * Return the string value of the node. * @return the attribute value */ public String getStringValue() { return tree.attValue[nodeNr].toString(); } /** * Get the fingerprint of the node, used for matching names */ public int getFingerprint() { return tree.attCode[nodeNr] & 0xfffff; } /** * Get the name code of the node, used for finding names in the name pool */ public int getNameCode() { return tree.attCode[nodeNr]; } /** * Get the prefix part of the name of this node. This is the name before the ":" if any. * @return the prefix part of the name. For an unnamed node, return null. */ public String getPrefix() { int code = tree.attCode[nodeNr]; if (NamePool.getPrefixIndex(code) == 0) return ""; return tree.getNamePool().getPrefix(code); } /** * Get the display name of this node. For elements and attributes this is [prefix:]localname. * For unnamed nodes, it is an empty string. * @return The display name of this node. * For a node with no name, return an empty string. */ public String getDisplayName() { return tree.getNamePool().getDisplayName(tree.attCode[nodeNr]); } /** * Get the local name of this node. * @return The local name of this node. * For a node with no name, return an empty string. */ public String getLocalPart() { return tree.getNamePool().getLocalName(tree.attCode[nodeNr]); } /** * Get the URI part of the name of this node. * @return The URI of the namespace of this node. For the default namespace, return an * empty string */ public final String getURI() { return tree.getNamePool().getURI(tree.attCode[nodeNr]); } /** * Get the type annotation of this node, if any * The bit {@link NodeInfo#IS_DTD_TYPE} (1<<30) will be set in the case of an attribute node if the type annotation * is one of ID, IDREF, or IDREFS and this is derived from DTD rather than schema validation. * Returns UNTYPED_ATOMIC if there is no type annotation */ public int getTypeAnnotation() { return tree.getAttributeAnnotation(nodeNr); } /** * Generate id. Returns key of owning element with the attribute namecode as a suffix * @param buffer Buffer to contain the generated ID value */ public void generateId(FastStringBuffer buffer) { getParent().generateId(buffer); buffer.append("a"); buffer.append(Integer.toString(tree.attCode[nodeNr])); // we previously used the attribute name. But this breaks the requirement // that the result of generate-id consists entirely of alphanumeric ASCII // characters } /** * Copy this node to a given outputter */ public void copy(Receiver out, int whichNamespaces, boolean copyAnnotations, int locationId) throws XPathException { int nameCode = tree.attCode[nodeNr]; int typeCode = (copyAnnotations ? getTypeAnnotation() : -1); out.attribute(nameCode, typeCode, getStringValue(), locationId, 0); } /** * Get the line number of the node within its source document entity */ public int getLineNumber() { return getParent().getLineNumber(); } /** * Get the column number of the node within its source document entity */ public int getColumnNumber() { return getParent().getColumnNumber(); } /** * Determine whether the node has the is-nilled property * @return true if the node has the is-nilled property */ public boolean isNilled() { return false; } /** * Determine whether this node has the is-id property * * @return true if the node is an ID */ public boolean isId() { return tree.isIdAttribute(nodeNr); } /** * Determine whether this node has the is-idref property * * @return true if the node is an IDREF or IDREFS element or attribute */ public boolean isIdref() { return tree.isIdrefAttribute(nodeNr); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/tinytree/TinyTree.java0000644000175000017500000013261011033112257021653 0ustar eugeneeugenepackage net.sf.saxon.tinytree; import net.sf.saxon.Configuration; import net.sf.saxon.event.ReceiverOptions; import net.sf.saxon.om.*; import net.sf.saxon.sort.IntArraySet; import net.sf.saxon.tree.SystemIdMap; import net.sf.saxon.type.*; import net.sf.saxon.value.AtomicValue; import net.sf.saxon.value.StringValue; import net.sf.saxon.value.UntypedAtomicValue; import net.sf.saxon.value.Whitespace; import java.util.ArrayList; import java.util.Arrays; /** * A data structure to hold the contents of a tree. As the name implies, this implementation * of the data model is optimized for size, and for speed of creation: it minimizes the number * of Java objects used. * *

    It can be used to represent a tree that is rooted at a document node, or one that is rooted * at an element node.

    */ public final class TinyTree { private static final String[] EMPTY_STRING_ARRAY = new String[0]; private Configuration config; // List of top-level document nodes. private ArrayList documentList = new ArrayList(5); // The document number (really a tree number: it can identify a non-document root node protected int documentNumber; // the contents of the document protected LargeStringBuffer charBuffer; protected FastStringBuffer commentBuffer = null; // created when needed protected int numberOfNodes = 0; // excluding attributes and namespaces // The following arrays contain one entry for each node other than attribute // and namespace nodes, arranged in document order. // nodeKind indicates the kind of node, e.g. element, text, or comment public byte[] nodeKind; // depth is the depth of the node in the hierarchy, i.e. the number of ancestors protected short[] depth; // next is the node number of the next sibling // - unless it points backwards, in which case it is the node number of the parent protected int[] next; // alpha holds a value that depends on the node kind. For text nodes, it is the offset // into the text buffer. For comments and processing instructions, it is the offset into // the comment buffer. For elements, it is the index of the first attribute node, or -1 // if this element has no attributes. protected int[] alpha; // beta holds a value that depends on the node kind. For text nodes, it is the length // of the text. For comments and processing instructions, it is the length of the text. // For elements, it is the index of the first namespace node, or -1 // if this element has no namespaces. protected int[] beta; // nameCode holds the name of the node, as an identifier resolved using the name pool protected int[] nameCode; // the prior array indexes preceding-siblings; it is constructed only when required protected int[] prior = null; // the typeCode array holds type codes for element nodes; it is constructed only // if at least one element has a type other than untyped, or has an IDREF property. // The array holds the type fingerprint, with bit TYPECODE_IDREF set if the value is an IDREF protected int[] typeCodeArray = null; private static final int TYPECODE_IDREF = 1<<29; // the owner array gives fast access from a node to its parent; it is constructed // only when required // protected int[] parentIndex = null; // the following arrays have one entry for each attribute. protected int numberOfAttributes = 0; // attParent is the index of the parent element node protected int[] attParent; // attCode is the nameCode representing the attribute name protected int[] attCode; // attValue is the string value of the attribute protected CharSequence[] attValue; // attTypeCode holds type annotations. The array is created only if any nodes have a type annotation // or are marked as IDREF/IDREFS attributes. The bit TYPECODE_IDREF represents the is-idref property, // while IS_DTD_TYPE is set if the type is DTD-derived. protected int[] attTypeCode; // The following arrays have one entry for each namespace declaration protected int numberOfNamespaces = 0; // namespaceParent is the index of the element node owning the namespace declaration protected int[] namespaceParent; // namespaceCode is the namespace code used by the name pool: the top half is the prefix // code, the bottom half the URI code protected int[] namespaceCode; // an array holding the offsets of all the level-0 (root) nodes, so that the root of a given // node can be found efficiently private int[] rootIndex = new int[5]; protected int rootIndexUsed = 0; private int[] lineNumbers = null; private int[] columnNumbers = null; private SystemIdMap systemIdMap = null; // a boolean that is set to true if the document declares a namespace other than the XML namespace protected boolean usesNamespaces = false; // We maintain statistics in static data, recording how large the trees created under this Java VM // turned out to be. These figures are then used when allocating space for new trees, on the assumption // that there is likely to be some uniformity. The statistics are initialized to an arbitrary value // so that they can be used every time including the first time. The count of how many trees have been // created so far is initialized artificially to 5, to provide some smoothing if the first real tree is // atypically large or small. private static int treesCreated = 5; private static double averageNodes = 4000.0; private static double averageAttributes = 100.0; private static double averageNamespaces = 20.0; private static double averageCharacters = 4000.0; /** * Create a TinyTree. The initial size is based on the average size of * trees previously built in this session */ public TinyTree() { this((int)(averageNodes + 1), (int)(averageAttributes + 1), (int)(averageNamespaces + 1), (int)(averageCharacters + 1)); } /** * Create a tree with a specified initial size * @param nodes the expected number of (non attribute or namespace) nodes * @param attributes the expected number of attributes * @param namespaces the expected number of namespace declarations * @param characters the expected number of characters in the document (in text nodes) */ public TinyTree(int nodes, int attributes, int namespaces, int characters) { //System.err.println("TinyTree.new() (initial size " + nodes + ", treesCreated = " + treesCreated + ")"); nodeKind = new byte[nodes]; depth = new short[nodes]; next = new int[nodes]; alpha = new int[nodes]; beta = new int[nodes]; nameCode = new int[nodes]; numberOfAttributes = 0; attParent = new int[attributes]; attCode = new int[attributes]; attValue = new String[attributes]; numberOfNamespaces = 0; namespaceParent = new int[namespaces]; namespaceCode = new int[namespaces]; charBuffer = new LargeStringBuffer(characters, 64000); } /** * Set the Configuration that contains this document * @param config the Saxon configuration */ public void setConfiguration(Configuration config) { this.config = config; addNamespace(0, NamespaceConstant.XML_NAMESPACE_CODE); } /** * Get the configuration previously set using setConfiguration * @return the Saxon configuration */ public Configuration getConfiguration() { return config; } /** * Get the name pool used for the names in this document * @return the name pool */ public NamePool getNamePool() { return config.getNamePool(); } private void ensureNodeCapacity(short kind) { if (nodeKind.length < numberOfNodes+1) { //System.err.println("Number of nodes = " + numberOfNodes); int k = (kind == Type.STOPPER ? numberOfNodes+1 : numberOfNodes*2); byte[] nodeKind2 = new byte[k]; int[] next2 = new int[k]; short[] depth2 = new short[k]; int[] alpha2 = new int[k]; int[] beta2 = new int[k]; int[] nameCode2 = new int[k]; System.arraycopy(nodeKind, 0, nodeKind2, 0, numberOfNodes); System.arraycopy(next, 0, next2, 0, numberOfNodes); System.arraycopy(depth, 0, depth2, 0, numberOfNodes); System.arraycopy(alpha, 0, alpha2, 0, numberOfNodes); System.arraycopy(beta, 0, beta2, 0, numberOfNodes); System.arraycopy(nameCode, 0, nameCode2, 0, numberOfNodes); nodeKind = nodeKind2; next = next2; depth = depth2; alpha = alpha2; beta = beta2; nameCode = nameCode2; if (typeCodeArray != null) { int[] typeCodeArray2 = new int[k]; System.arraycopy(typeCodeArray, 0, typeCodeArray2, 0, numberOfNodes); typeCodeArray = typeCodeArray2; } if (lineNumbers != null) { int[] lines2 = new int[k]; System.arraycopy(lineNumbers, 0, lines2, 0, numberOfNodes); lineNumbers = lines2; int[] columns2 = new int[k]; System.arraycopy(columnNumbers, 0, columns2, 0, numberOfNodes); columnNumbers = columns2; } } } private void ensureAttributeCapacity() { if (attParent.length < numberOfAttributes+1) { int k = numberOfAttributes*2; if (k==0) { k = 10; } int[] attParent2 = new int[k]; int[] attCode2 = new int[k]; String[] attValue2 = new String[k]; System.arraycopy(attParent, 0, attParent2, 0, numberOfAttributes); System.arraycopy(attCode, 0, attCode2, 0, numberOfAttributes); System.arraycopy(attValue, 0, attValue2, 0, numberOfAttributes); attParent = attParent2; attCode = attCode2; attValue = attValue2; if (attTypeCode != null) { int[] attTypeCode2 = new int[k]; System.arraycopy(attTypeCode, 0, attTypeCode2, 0, numberOfAttributes); attTypeCode = attTypeCode2; } } } private void ensureNamespaceCapacity() { if (namespaceParent.length < numberOfNamespaces+1) { int k = numberOfNamespaces*2; int[] namespaceParent2 = new int[k]; int[] namespaceCode2 = new int[k]; System.arraycopy(namespaceParent, 0, namespaceParent2, 0, numberOfNamespaces); System.arraycopy(namespaceCode, 0, namespaceCode2, 0, numberOfNamespaces); namespaceParent = namespaceParent2; namespaceCode = namespaceCode2; } } /** * Add a document node to the tree. The data structure can contain any number of document (or element) nodes * as top-level nodes. The document node is retained in the documentList list, and its offset in that list * is held in the alpha array for the relevant node number. * @param doc the document node to be added * @return the number of the node that was added */ int addDocumentNode(TinyDocumentImpl doc) { documentList.add(doc); return addNode(Type.DOCUMENT, 0, documentList.size()-1, 0, -1); } /** * Add a node to the tree * @param kind The kind of the node. This must be a document, element, text, comment, * or processing-instruction node (not an attribute or namespace) * @param depth The depth in the tree * @param alpha Pointer to attributes or text * @param beta Pointer to namespaces or text * @param nameCode The name of the node * @return the node number of the node that was added */ int addNode(short kind, int depth, int alpha, int beta, int nameCode) { ensureNodeCapacity(kind); nodeKind[numberOfNodes] = (byte)kind; this.depth[numberOfNodes] = (short)depth; this.alpha[numberOfNodes] = alpha; this.beta[numberOfNodes] = beta; this.nameCode[numberOfNodes] = nameCode; next[numberOfNodes] = -1; // safety precaution if (typeCodeArray != null) { typeCodeArray[numberOfNodes] = StandardNames.XS_UNTYPED; } if (numberOfNodes == 0) { documentNumber = config.getDocumentNumberAllocator().allocateDocumentNumber(); } if (depth == 0 && kind != Type.STOPPER) { if (rootIndexUsed == rootIndex.length) { int[] r2 = new int[rootIndexUsed * 2]; System.arraycopy(rootIndex, 0, r2, 0, rootIndexUsed); rootIndex = r2; } rootIndex[rootIndexUsed++] = numberOfNodes; } return numberOfNodes++; } /** * Append character data to the current text node * @param chars the character data to be appended */ void appendChars(CharSequence chars) { charBuffer.append(chars); } /** * Condense the tree: release unused memory. This is done after the full tree has been built. * The method makes a pragmatic judgement as to whether it is worth reclaiming space; this is * only done when the constructed tree is very small compared with the space allocated. */ void condense() { //System.err.println("TinyTree.condense() " + this + " roots " + rootIndexUsed + " nodes " + numberOfNodes + " capacity " + nodeKind.length); // If there are already two trees in this forest, the chances are that more will be added. In this // case we don't want to condense the arrays because we will only have to expand them again, which gets // increasingly expensive as they grow larger. if (rootIndexUsed > 1) { return; } if (numberOfNodes * 3 < nodeKind.length || (nodeKind.length - numberOfNodes > 20000)) { //System.err.println("-- copying node arrays"); int k = numberOfNodes + 1; byte[] nodeKind2 = new byte[k]; int[] next2 = new int[k]; short[] depth2 = new short[k]; int[] alpha2 = new int[k]; int[] beta2 = new int[k]; int[] nameCode2 = new int[k]; System.arraycopy(nodeKind, 0, nodeKind2, 0, numberOfNodes); System.arraycopy(next, 0, next2, 0, numberOfNodes); System.arraycopy(depth, 0, depth2, 0, numberOfNodes); System.arraycopy(alpha, 0, alpha2, 0, numberOfNodes); System.arraycopy(beta, 0, beta2, 0, numberOfNodes); System.arraycopy(nameCode, 0, nameCode2, 0, numberOfNodes); if (typeCodeArray != null) { int[] type2 = new int[k]; System.arraycopy(typeCodeArray, 0, type2, 0, numberOfNodes); typeCodeArray = type2; } if (lineNumbers != null) { int[] lines2 = new int[k]; System.arraycopy(lineNumbers, 0, lines2, 0, numberOfNodes); lineNumbers = lines2; int[] columns2 = new int[k]; System.arraycopy(columnNumbers, 0, columns2, 0, numberOfNodes); columnNumbers = columns2; } nodeKind = nodeKind2; next = next2; depth = depth2; alpha = alpha2; beta = beta2; nameCode = nameCode2; } if ((numberOfAttributes * 3 < attParent.length) || (attParent.length - numberOfAttributes > 1000)) { int k = numberOfAttributes; //System.err.println("-- copying attribute arrays"); if (k==0) { attParent = IntArraySet.EMPTY_INT_ARRAY; attCode = IntArraySet.EMPTY_INT_ARRAY; attValue = EMPTY_STRING_ARRAY; attTypeCode = null; } int[] attParent2 = new int[k]; int[] attCode2 = new int[k]; String[] attValue2 = new String[k]; System.arraycopy(attParent, 0, attParent2, 0, numberOfAttributes); System.arraycopy(attCode, 0, attCode2, 0, numberOfAttributes); System.arraycopy(attValue, 0, attValue2, 0, numberOfAttributes); attParent = attParent2; attCode = attCode2; attValue = attValue2; if (attTypeCode != null) { int[] attTypeCode2 = new int[k]; System.arraycopy(attTypeCode, 0, attTypeCode2, 0, numberOfAttributes); attTypeCode = attTypeCode2; } } if (numberOfNamespaces * 3 < namespaceParent.length) { int k = numberOfNamespaces; int[] namespaceParent2 = new int[k]; int[] namespaceCode2 = new int[k]; //System.err.println("-- copying namespace arrays"); System.arraycopy(namespaceParent, 0, namespaceParent2, 0, numberOfNamespaces); System.arraycopy(namespaceCode, 0, namespaceCode2, 0, numberOfNamespaces); namespaceParent = namespaceParent2; namespaceCode = namespaceCode2; } updateStatistics(); // System.err.println("STATS: " + averageNodes + ", " + averageAttributes + ", " // + averageNamespaces + ", " + averageCharacters); // if (charBufferLength * 3 < charBuffer.length || // charBuffer.length - charBufferLength > 10000) { // char[] c2 = new char[charBufferLength]; // System.arraycopy(charBuffer, 0, c2, 0, charBufferLength); // charBuffer = c2; // } } /** * Set the type annotation of an element node * @param nodeNr the node whose type annotation is to be set * @param typeCode the type annotation */ void setElementAnnotation(int nodeNr, int typeCode) { if (typeCode != StandardNames.XS_UNTYPED) { if (typeCodeArray == null) { typeCodeArray = new int[nodeKind.length]; Arrays.fill(typeCodeArray, 0, nodeKind.length, StandardNames.XS_UNTYPED); } typeCodeArray[nodeNr] = typeCode; } } /** * Get the type annotation of a node. Applies only to document, element, text, * processing instruction, and comment nodes. * @param nodeNr the node whose type annotation is required * @return the fingerprint of the type annotation for elements and attributes, otherwise undefined. */ public int getTypeAnnotation(int nodeNr) { if (typeCodeArray == null) { return StandardNames.XS_UNTYPED; } return typeCodeArray[nodeNr] & NamePool.FP_MASK; } /** * Get the node kind of a given node, which must be a document, element, * text, comment, or processing instruction node * @param nodeNr the node number * @return the node kind */ public int getNodeKind(int nodeNr) { int kind = nodeKind[nodeNr]; return (kind == Type.WHITESPACE_TEXT ? Type.TEXT : kind); } /** * Get the nameCode for a given node, which must be a document, element, * text, comment, or processing instruction node * @param nodeNr the node number * @return the name code */ public int getNameCode(int nodeNr) { return nameCode[nodeNr]; } /** * On demand, make an index for quick access to preceding-sibling nodes */ void ensurePriorIndex() { // TODO: avoid rebuilding the whole index in the second case, i.e. with a forest if (prior==null || prior.length < numberOfNodes) { makePriorIndex(); } } private synchronized void makePriorIndex() { prior = new int[numberOfNodes]; Arrays.fill(prior, 0, numberOfNodes, -1); for (int i=0; i i) { prior[nextNode] = i; } } } /** * Add an attribute node to the tree * @param root the root of the tree to contain the attribute * @param parent the parent element of the new attribute * @param nameCode the name code of the attribute * @param typeCode the type annotation of the attribute * @param attValue the string value of the attribute * @param properties any special properties of the attribute (bit-significant) */ void addAttribute(NodeInfo root, int parent, int nameCode, int typeCode, CharSequence attValue, int properties) { ensureAttributeCapacity(); attParent[numberOfAttributes] = parent; attCode[numberOfAttributes] = nameCode; this.attValue[numberOfAttributes] = attValue; if (typeCode == -1) { // this shouldn't happen any more typeCode = StandardNames.XS_UNTYPED_ATOMIC; } if (typeCode != StandardNames.XS_UNTYPED_ATOMIC) { initializeAttributeTypeCodes(); } if (attTypeCode != null) { attTypeCode[numberOfAttributes] = typeCode; } if (alpha[parent] == -1) { alpha[parent] = numberOfAttributes; } if (root instanceof TinyDocumentImpl) { boolean isID = false; if ((properties & ReceiverOptions.IS_ID) != 0) { isID = true; } else if ((nameCode & NamePool.FP_MASK) == StandardNames.XML_ID) { isID = true; } else if (config.getTypeHierarchy().isIdCode(typeCode)) { isID = true; } if (isID) { // The attribute is marked as being an ID. But we don't trust it - it // might come from a non-validating parser. Before adding it to the index, we // check that it really is an ID. String id = Whitespace.trim(attValue); // Make an exception to our usual policy of storing the original string value. // This is because xml:id processing applies whitespace trimming at an earlier stage this.attValue[numberOfAttributes] = id; if (root.getConfiguration().getNameChecker().isValidNCName(id)) { NodeInfo e = getNode(parent); ((TinyDocumentImpl)root).registerID(e, id); } else if (attTypeCode != null) { attTypeCode[numberOfAttributes] = StandardNames.XS_UNTYPED_ATOMIC; } } if ((properties & ReceiverOptions.IS_IDREF) != 0) { initializeAttributeTypeCodes(); attTypeCode[numberOfAttributes] = typeCode | TYPECODE_IDREF; } } // Note: IDREF attributes are not indexed at this stage; that happens only if and when // the idref() function is called. // Note that an attTypes array will be created for all attributes if any ID or IDREF is reported. numberOfAttributes++; } private void initializeAttributeTypeCodes() { if (attTypeCode==null) { // this is the first typed attribute; // create an array for the types, and set all previous attributes to untyped attTypeCode = new int[attParent.length]; Arrays.fill(attTypeCode, 0, numberOfAttributes, StandardNames.XS_UNTYPED_ATOMIC); // for (int i=0; i level) { if (nodeKind[next]==Type.TEXT) { if (sb==null) { sb = new FastStringBuffer(1024); } sb.append(TinyTextImpl.getStringValue(this, next)); } else if (nodeKind[next]==Type.WHITESPACE_TEXT) { if (sb==null) { sb = new FastStringBuffer(1024); } WhitespaceTextImpl.appendStringValue(this, next, sb); } next++; } if (sb==null) { return UntypedAtomicValue.ZERO_LENGTH_UNTYPED; } else { return new UntypedAtomicValue(sb.condense()); } case Type.TEXT: return new UntypedAtomicValue(TinyTextImpl.getStringValue(this, nodeNr)); case Type.WHITESPACE_TEXT: return new UntypedAtomicValue(WhitespaceTextImpl.getStringValue(this, nodeNr)); case Type.COMMENT: case Type.PROCESSING_INSTRUCTION: int start2 = alpha[nodeNr]; int len2 = beta[nodeNr]; if (len2==0) return UntypedAtomicValue.ZERO_LENGTH_UNTYPED; char[] dest = new char[len2]; commentBuffer.getChars(start2, start2+len2, dest, 0); return new StringValue(new CharSlice(dest, 0, len2)); default: throw new IllegalStateException("Unknown node kind"); } } /** * Make a (transient) attribute node from the array of attributes * @param nr the node number of the attribute * @return an attribute node */ TinyAttributeImpl getAttributeNode(int nr) { return new TinyAttributeImpl(this, nr); } /** * Get the type annotation of an attribute node. * The bit {@link NodeInfo#IS_DTD_TYPE} (1<<30) will be set in the case of an attribute node if the type annotation * is one of ID, IDREF, or IDREFS and this is derived from DTD rather than schema validation. * @param nr the node number of the attribute * @return Type.UNTYPED_ATOMIC if there is no annotation */ int getAttributeAnnotation(int nr) { if (attTypeCode == null) { return StandardNames.XS_UNTYPED_ATOMIC; } else { return attTypeCode[nr] & (NamePool.FP_MASK | NodeInfo.IS_DTD_TYPE); } } /** * Determine whether an attribute is an IDREF/IDREFS attribute. (The represents the * is-idref property in the data model) * @param nr the node number of the attribute * @return true if this is an IDREF/IDREFS attribute */ public boolean isIdAttribute(int nr) { if (attTypeCode == null) { return false; } int tc = attTypeCode[nr]; tc &= NamePool.FP_MASK; if (tc == StandardNames.XS_UNTYPED_ATOMIC) { return false; } else if (tc == StandardNames.XS_ID) { return true; } else if (tc < 1024) { return false; } else { final SchemaType type = getConfiguration().getSchemaType(tc); final TypeHierarchy th = getConfiguration().getTypeHierarchy(); if (type.isAtomicType()) { return th.isSubType((AtomicType)type, BuiltInAtomicType.ID); } else if (type instanceof ListType) { // TODO: rules for ID's in list and union types SimpleType itemType = ((ListType)type).getItemType(); return itemType.isAtomicType() && th.isSubType((AtomicType)itemType, BuiltInAtomicType.ID); } } return false; } /** * Determine whether an attribute is an IDREF/IDREFS attribute. (The represents the * is-idref property in the data model) * @param nr the node number of the attribute * @return true if this is an IDREF/IDREFS attribute */ public boolean isIdrefAttribute(int nr) { if (attTypeCode == null) { return false; } int tc = attTypeCode[nr]; if ((attTypeCode[nr] & TYPECODE_IDREF) != 0) { return true; } tc &= NamePool.FP_MASK; if (tc == StandardNames.XS_UNTYPED_ATOMIC) { return false; } else if (tc == StandardNames.XS_IDREF) { return true; } else if (tc == StandardNames.XS_IDREFS) { return true; } else if (tc < 1024) { return false; } else { final SchemaType type = getConfiguration().getSchemaType(tc); final TypeHierarchy th = getConfiguration().getTypeHierarchy(); if (type.isAtomicType()) { return th.isSubType((AtomicType)type, BuiltInAtomicType.IDREF); } else if (type instanceof ListType) { SimpleType itemType = ((ListType)type).getItemType(); return itemType.isAtomicType() && th.isSubType((AtomicType)itemType, BuiltInAtomicType.IDREF); } } return false; } /** * Ask whether an element is an IDREF/IDREFS element. (The represents the * is-idref property in the data model) * @param nr the element node whose is-idref property is required * @return true if the node has the is-idref property */ public boolean isIdrefElement(int nr) { if (typeCodeArray == null) { return false; } int tc = typeCodeArray[nr]; return (tc & TYPECODE_IDREF) != 0 || getConfiguration().getTypeHierarchy().isIdrefsCode(tc & NamePool.FP_MASK); } /** * Set the system id of an element in the document. This identifies the external entity containing * the node - this is not necessarily the same as the base URI. * @param seq the node number * @param uri the system ID */ void setSystemId(int seq, String uri) { if (uri==null) { uri = ""; } if (systemIdMap==null) { systemIdMap = new SystemIdMap(); } systemIdMap.setSystemId(seq, uri); } /** * Get the system id of an element in the document * @param seq the node number of the element node * @return the system id (base URI) of the element */ String getSystemId(int seq) { if (systemIdMap==null) { return null; } return systemIdMap.getSystemId(seq); } /** * Get the root node for a given node * @param nodeNr the node number of the given node * @return the node number of the root of the tree containing the given node */ int getRootNode(int nodeNr) { for (int i=rootIndexUsed-1; i>=0; i--) { if (rootIndex[i] <= nodeNr) { return rootIndex[i]; } } return 0; } /** * Set line numbering on */ public void setLineNumbering() { lineNumbers = new int[nodeKind.length]; Arrays.fill(lineNumbers, -1); columnNumbers = new int[nodeKind.length]; Arrays.fill(columnNumbers, -1); } /** * Set the line number for a node. Ignored if line numbering is off. * @param sequence the node number * @param line the line number to be set for the node * @param column the column number for the node */ void setLineNumber(int sequence, int line, int column) { if (lineNumbers != null) { lineNumbers[sequence] = line; columnNumbers[sequence] = column; } } /** * Get the line number for a node. * @param sequence the node number * @return the line number of the node. Return -1 if line numbering is off. */ int getLineNumber(int sequence) { if (lineNumbers != null) { // find the nearest preceding node that has a known line number, and return it for (int i=sequence; i>=0; i--) { int c = lineNumbers[sequence]; if (c > 0) { return c; } } } return -1; } /** * Get the column number for a node. * @param sequence the node number * @return the line number of the node. Return -1 if line numbering is off. */ int getColumnNumber(int sequence) { if (columnNumbers != null) { // find the nearest preceding node that has a known column number, and return it for (int i=sequence; i>=0; i--) { int c = columnNumbers[sequence]; if (c > 0) { return c; } } } return -1; } /** * Get the document number (actually, the tree number) * @return the unique number of this TinyTree structure */ public int getDocumentNumber() { return documentNumber; } /** * Ask whether a given node is nilled * @param nodeNr the node in question * @return true if the node has the nilled property */ public boolean isNilled(int nodeNr) { return (typeCodeArray != null && (typeCodeArray[nodeNr] & NodeInfo.IS_NILLED) != 0); } /** * Produce diagnostic print of main tree arrays */ public void diagnosticDump() { NamePool pool = config.getNamePool(); System.err.println(" node type depth next alpha beta name"); for (int i=0; i>16) + n8(namespaceCode[i]&0xffff)); } } /** * Create diagnostic dump of the tree containing a particular node. * Designed to be called as an extension function for diagnostics. * @param node the node in question */ public static synchronized void diagnosticDump(NodeInfo node) { if (node instanceof TinyNodeImpl) { TinyTree tree = ((TinyNodeImpl)node).tree; System.err.println("Tree containing node " + ((TinyNodeImpl)node).nodeNr); tree.diagnosticDump(); } else { System.err.println("Node is not in a TinyTree"); } } /** * Output a number as a string of 8 characters * @param val the number * @return the string representation of the number, aligned in a fixed width field */ private String n8(int val) { String s = " " + val; return s.substring(s.length()-8); } /** * Output a statistical summary to System.err */ public void showSize() { System.err.println("Tree size: " + numberOfNodes + " nodes, " + charBuffer.length() + " characters, " + numberOfAttributes + " attributes"); } /** * Update the statistics held in static data. We don't bother to sychronize, on the basis that it doesn't * matter if the stats are wrong. */ private void updateStatistics() { int n0 = treesCreated; int n1 = treesCreated + 1; treesCreated = n1; averageNodes = ((averageNodes * n0) + numberOfNodes) / n1; if (averageNodes < 10.0) { averageNodes = 10.0; } averageAttributes = ((averageAttributes * n0) + numberOfAttributes) / n1; if (averageAttributes < 10.0) { averageAttributes = 10.0; } averageNamespaces = ((averageNamespaces * n0) + numberOfNamespaces) / n1; if (averageNamespaces < 5.0) { averageNamespaces = 5.0; } averageCharacters = ((averageCharacters * n0) + charBuffer.length()) / n1; if (averageCharacters < 100.0) { averageCharacters = 100.0; } } /** * Get the number of nodes in the tree, excluding attributes and namespace nodes * @return the number of nodes. */ public int getNumberOfNodes() { return numberOfNodes; } /** * Get the number of attributes in the tree * @return the number of attributes */ public int getNumberOfAttributes() { return numberOfAttributes; } /** * Get the number of namespace declarations in the tree * @return the number of namespace declarations */ public int getNumberOfNamespaces() { return numberOfNamespaces; } /** * Get the array holding node kind information * @return an array of bytes, byte N is the node kind of node number N */ public byte[] getNodeKindArray() { return nodeKind; } /** * Get the array holding node depth information * @return an array of shorts, byte N is the node depth of node number N */ public short[] getNodeDepthArray() { return depth; } /** * Get the array holding node name information * @return an array of integers, integer N is the name code of node number N */ public int[] getNameCodeArray() { return nameCode; } /** * Get the array holding node type information * @return an array of integers, integer N is the type code of node number N */ public int[] getTypeCodeArray() { return typeCodeArray; } /** * Get the array holding next-sibling pointers * @return an array of integers, integer N is the next-sibling pointer for node number N */ public int[] getNextPointerArray() { return next; } /** * Get the array holding alpha information * @return an array of integers, whose meaning depends on the node kind. For elements it is a pointer * to the first attribute, for text, comment, and processing instruction nodes it is a pointer to the content */ public int[] getAlphaArray() { return alpha; } /** * Get the array holding beta information * @return an array of integers, whose meaning depends on the node kind. For elements it is a pointer * to the first namespace declaration */ public int[] getBetaArray() { return beta; } /** * Get the character buffer used to hold all the text data of the document * @return the character buffer */ public CharSequence getCharacterBuffer() { //return new CharSlice(charBuffer, 0, charBufferLength); return charBuffer; } /** * Get the character buffer used to hold all the comment data of the document * @return the character buffer used for comments */ public CharSequence getCommentBuffer() { return commentBuffer; } /** * Get the array used to hold the name codes of all attributes * @return an integer array; the Nth integer holds the attribute name code of attribute N */ public int[] getAttributeNameCodeArray() { return attCode; } /** * Get the array used to hold the type codes of all attributes * @return an integer array; the Nth integer holds the attribute type code of attribute N */ public int[] getAttributeTypeCodeArray() { return attTypeCode; } /** * Get the array used to hold the parent pointers of all attributes * @return an integer array; the Nth integer holds the pointer to the parent element of attribute N */ public int[] getAttributeParentArray() { return attParent; } /** * Get the array used to hold the name codes of all attributes * @return an array of strings; the Nth string holds the string value of attribute N */ public CharSequence[] getAttributeValueArray() { return attValue; } /** * Get the array used to hold the namespace codes of namespace declarations * @return an array of integer namespace codes */ public int[] getNamespaceCodeArray() { return namespaceCode; } /** * Get the array used to hold the parent pointers of all namespace declarations * @return an integer array; the Nth integer holds the pointer to the parent element of namespace N */ public int[] getNamespaceParentArray() { return namespaceParent; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/tinytree/package.html0000644000175000017500000001054611033112257021531 0ustar eugeneeugene Package overview for net.sf.saxon.tinytree

    This package is an implementation of the Saxon internal tree structure, designed to minimize memory usage, and the costs of allocating and garbage-collecting Java objects.

    The data structure consists of a set of arrays, held in the TinyTree object. A TinyTree represents one or more root document or element nodes, together with their subtrees. If there is more than one root node, these will often be members of a sequence, but this is not essential and is never assumed. The arrays are in three groups.

    The principal group of arrays contain one entry for each node other than namespace and attribute nodes. These arrays are in document order. The following information is maintained for each node: the depth in the tree, the name code, the index of the next sibling, and two fields labelled "alpha" and "beta". The meaning of "alpha" and "beat" depends on the node type. For text nodes, comment nodes, and processing instructions these fields index into a StringBuffer holding the text. For element nodes, "alpha" is an index into the attributes table, and "beta" is an offset into the namespaces table. Either of these may be set to -1 if there are no attributes/namespaces.

    A name code is an integer value that indexes into the NamePool object: it can be used to determine the prefix, local name, or namespace URI of an element or attribute name.

    The attribute group holds the following information for each attribute node: parent element, prefix, name code, attribute type, and attribute value. Attributes for the same element are adjacent.

    The namespace group holds one entry per namespace declaration (not one per namespace node). The following information is held: a pointer to the element on which the namespace was declared, and a namespace code. A namespace code is an integer, which the NamePool can resolve into a prefix and a namespace URI: the top 16 bits identify the prefix, the bottom 16 bits the URI.

    The data structure contains no Java object references: the links between elements and attributes/namespaces are all held as integer offsets. This reduces size, and also makes the whole structure relocatable (though this capability is not currently exploited). All navigation is done by serial traversal of the arrays, using the node depth as a guide. An array of pointers to the preceding sibling is created on demand, the first time that backwards navigation is attempted. There are no parent pointers; Saxon attempts to remember the parent while navigating down the tree, and where this is not possible it locates the parent by searching through the following siblings; the last sibling points back to the parent. The absence of the other pointers is a trade-off between tree-building time and transformation time: I found that in most cases, more time was spent creating these pointers than actually using them. Occasionally, however, in trees with a very large fan-out, locating ancestors can be slow.

    When the tree is navigated, transient ("flyweight") nodes are created as Java objects. These disappear as soon as they are no longer needed. Note that to compare two nodes for identity, you can use either the isSameNode() method, or compare the results of generateId(). Comparing the Java objects using "==" is incorrect.

    The tree structure implements the DOM interface as well as the Saxon NodeInfo interface. There are limitations in the DOM support, however: especially (a) the tree is immutable, so all updating methods throw an exception; (b) namespace declarations are not exposed as attributes, and (c) only the core DOM classes are provided.

    The primary way of navigating the tree is through the XPath axes, accessible through the iterateAxis() method. The familiar DOM methods such as getNextSibling() and getFirstChild() are not provided as an intrinsic part of the NodeInfo interface: all navigation is done by iterating the axes, and each tree model provides its own implementations of the axes. However, there are helper methods in the shared Navigator class which many of these implementations choose to use.

    Michael H. Kay
    Saxonica Limited
    9 February 2005

    saxonb-9.1.0.8/bj/net/sf/saxon/jdom/0000755000175000017500000000000012216261747016345 5ustar eugeneeugenesaxonb-9.1.0.8/bj/net/sf/saxon/jdom/JDOMQuery.java0000644000175000017500000000414311033112257020754 0ustar eugeneeugenepackage net.sf.saxon.jdom; import net.sf.saxon.Query; import net.sf.saxon.trans.XPathException; import org.jdom.JDOMException; import org.jdom.input.SAXBuilder; import javax.xml.transform.sax.SAXSource; import java.io.IOException; import java.util.ArrayList; import java.util.List; /** * Variant of command line net.sf.saxon.Transform do build the source document * in JDOM and then proceed with the transformation. This class is provided largely for * testing purposes. */ public class JDOMQuery extends Query { public List preprocess(List sources) throws XPathException { try { ArrayList jdomSources = new ArrayList(sources.size()); for (int i=0; i * This class should have been named Root; it is used not only for the root of a document, * but also for the root of a result tree fragment, which is not constrained to contain a * single top-level element. * @author Michael H. Kay */ public class DocumentWrapper extends NodeWrapper implements DocumentInfo { protected Configuration config; protected String baseURI; protected int documentNumber; /** * Create a Saxon wrapper for a JDOM document * @param doc The JDOM document * @param baseURI The base URI for all the nodes in the document */ public DocumentWrapper(Document doc, String baseURI, Configuration config) { super(doc, null, 0); node = doc; nodeKind = Type.DOCUMENT; this.baseURI = baseURI; docWrapper = this; setConfiguration(config); } /** * Wrap a node in the JDOM document. * @param node The node to be wrapped. This must be a node in the same document * (the system does not check for this). * @return the wrapping NodeInfo object */ public NodeWrapper wrap(Object node) { if (node==this.node) { return this; } return makeWrapper(node, this); } /** * Set the configuration (containing the name pool used for all names in this document) */ public void setConfiguration(Configuration config) { this.config = config; documentNumber = config.getDocumentNumberAllocator().allocateDocumentNumber(); } /** * Get the configuration previously set using setConfiguration * (or the default configuraton allocated automatically) */ public Configuration getConfiguration() { return config; } /** * Get the name pool used for the names in this document */ public NamePool getNamePool() { return config.getNamePool(); } /** * Get the unique document number */ public int getDocumentNumber() { return documentNumber; } /** * Get the element with a given ID, if any * @param id the required ID value * @return null: JDOM does not provide any information about attribute types. */ public NodeInfo selectID(String id) { return null; } /** * Get the list of unparsed entities defined in this document * @return an Iterator, whose items are of type String, containing the names of all * unparsed entities defined in this document. If there are no unparsed entities or if the * information is not available then an empty iterator is returned */ public Iterator getUnparsedEntityNames() { return Collections.EMPTY_LIST.iterator(); } /** * Get the unparsed entity with a given name * @param name the name of the entity * @return null: JDOM does not provide access to unparsed entities */ public String[] getUnparsedEntity(String name) { return null; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/jdom/JDOMObjectModel.java0000644000175000017500000002627211033417647022060 0ustar eugeneeugenepackage net.sf.saxon.jdom; import net.sf.saxon.Configuration; import net.sf.saxon.event.PipelineConfiguration; import net.sf.saxon.event.Receiver; import net.sf.saxon.expr.JPConverter; import net.sf.saxon.expr.PJConverter; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.*; import net.sf.saxon.pattern.AnyNodeTest; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ItemType; import net.sf.saxon.value.SingletonNode; import net.sf.saxon.value.Value; import org.jdom.*; import javax.xml.transform.Result; import javax.xml.transform.Source; import java.io.Serializable; /** * This interface must be implemented by any third-party object model that can * be wrapped with a wrapper that implements the Saxon Object Model (the NodeInfo interface). * This implementation of the interface supports wrapping of JDOM Documents. */ public class JDOMObjectModel implements ExternalObjectModel, Serializable { public JDOMObjectModel() {} /** * Get the URI of the external object model as used in the JAXP factory interfaces for obtaining * an XPath implementation */ public String getIdentifyingURI() { return NamespaceConstant.OBJECT_MODEL_JDOM; } /** * Test whether this object model recognizes a given node as one of its own */ public boolean isRecognizedNode(Object object) { return object instanceof Document || object instanceof Element || object instanceof Attribute || object instanceof Text || object instanceof CDATA || object instanceof Comment || object instanceof ProcessingInstruction || object instanceof Namespace; } public PJConverter getPJConverter(Class targetClass) { if (isRecognizedNodeClass(targetClass)) { return new PJConverter() { public Object convert(ValueRepresentation value, Class targetClass, XPathContext context) throws XPathException { return convertXPathValueToObject(Value.asValue(value), targetClass, context); } }; } else { return null; } } public JPConverter getJPConverter(Class targetClass) { if (isRecognizedNodeClass(targetClass)) { return new JPConverter() { public ValueRepresentation convert(Object object, XPathContext context) throws XPathException { return convertObjectToXPathValue(object, context.getConfiguration()); } public ItemType getItemType() { return AnyNodeTest.getInstance(); } }; } else { return null; } } /** * Get a converter that converts a sequence of XPath nodes to this model's representation * of a node list. * @param node an example of the kind of node used in this model * @return if the model does not recognize this node as one of its own, return null. Otherwise * return a PJConverter that takes a list of XPath nodes (represented as NodeInfo objects) and * returns a collection of nodes in this object model */ public PJConverter getNodeListCreator(Object node) { return null; } /** * Test whether this object model recognizes a given class as representing a * node in that object model. This method will generally be called at compile time. * * @param nodeClass A class that possibly represents nodes * @return true if the class is used to represent nodes in this object model */ public boolean isRecognizedNodeClass(Class nodeClass) { return Document.class.isAssignableFrom(nodeClass) || Element.class.isAssignableFrom(nodeClass) || Attribute.class.isAssignableFrom(nodeClass) || Text.class.isAssignableFrom(nodeClass) || CDATA.class.isAssignableFrom(nodeClass) || Comment.class.isAssignableFrom(nodeClass) || ProcessingInstruction.class.isAssignableFrom(nodeClass) || Namespace.class.isAssignableFrom(nodeClass); } /** * Test whether this object model recognizes a given class as representing a * list of nodes in that object model. This method will generally be called at compile time. * * @param nodeClass A class that possibly represents nodes * @return true if the class is used to represent nodes in this object model */ public boolean isRecognizedNodeListClass(Class nodeClass) { return false; } /** * Test whether this object model recognizes a particular kind of JAXP Result object, * and if it does, return a Receiver that builds an instance of this data model from * a sequence of events. If the Result is not recognised, return null. */ public Receiver getDocumentBuilder(Result result) { return null; } /** * Test whether this object model recognizes a particular kind of JAXP Source object, * and if it does, send the contents of the document to a supplied Receiver, and return true. * Otherwise, return false. */ public boolean sendSource(Source source, Receiver receiver, PipelineConfiguration pipe) throws XPathException { return false; } /** * Wrap or unwrap a node using this object model to return the corresponding Saxon node. If the supplied * source does not belong to this object model, return null */ public NodeInfo unravel(Source source, Configuration config) { return null; } /** * Convert a Java object to an XPath value. If the supplied object is recognized as a representation * of a value using this object model, the object model should convert the value to an XPath value * and return this as the result. If not, it should return null. If the object is recognized but cannot * be converted, an exception should be thrown */ public ValueRepresentation convertObjectToXPathValue(Object object, Configuration config) throws XPathException { if (isRecognizedNode(object)) { if (object instanceof Document) { return wrapDocument(object, ((Document)object).getBaseURI(), config); } else { Document root = getDocumentRoot(object); DocumentInfo docInfo = wrapDocument(root, root.getBaseURI(), config); return wrapNode(docInfo, object); } } else { return null; } } /** * Convert an XPath value to an object in this object model. If the supplied value can be converted * to an object in this model, of the specified class, then the conversion should be done and the * resulting object returned. If the value cannot be converted, the method should return null. Note * that the supplied class might be a List, in which case the method should inspect the contents of the * Value to see whether they belong to this object model. * @return the object that results from conversion if conversion is possible, or null otherwise */ public Object convertXPathValueToObject(Value value, Object targetClass, XPathContext context) { Class target = (Class)targetClass; if (value instanceof SingletonNode) { NodeInfo node = ((SingletonNode)value).getNode(); if (node instanceof VirtualNode) { Object u = ((VirtualNode)node).getUnderlyingNode(); if (target.isAssignableFrom(u.getClass())) { return u; } } } return null; } /** * Wrap a document node in the external object model in a document wrapper that implements * the Saxon DocumentInfo interface * @param node a node (any node) in the third party document * @param baseURI the base URI of the node (supply "" if unknown) * @param config the Saxon configuration (which among other things provides access to the NamePool) * @return the wrapper, which must implement DocumentInfo */ public DocumentInfo wrapDocument(Object node, String baseURI, Configuration config) { Document documentNode = getDocumentRoot(node); return new DocumentWrapper(documentNode, baseURI, config); } /** * Wrap a node within the external object model in a node wrapper that implements the Saxon * VirtualNode interface (which is an extension of NodeInfo) * @param document the document wrapper, as a DocumentInfo object * @param node the node to be wrapped. This must be a node within the document wrapped by the * DocumentInfo provided in the first argument * @return the wrapper for the node, as an instance of VirtualNode */ public NodeInfo wrapNode(DocumentInfo document, Object node) { return ((DocumentWrapper)document).wrap(node); } /** * Get the document root */ private Document getDocumentRoot(Object node) { while (!(node instanceof Document)) { if (node instanceof Element) { if (((Element)node).isRootElement()) { return ((Element)node).getDocument(); } else { node = ((Element)node).getParent(); } } else if (node instanceof Text) { node = ((Text)node).getParent(); } else if (node instanceof Comment) { node = ((Comment)node).getParent(); } else if (node instanceof ProcessingInstruction) { node = ((ProcessingInstruction)node).getParent(); } else if (node instanceof Attribute) { node = ((Attribute)node).getParent(); } else if (node instanceof Document) { return (Document)node; } else if (node instanceof Namespace) { throw new UnsupportedOperationException("Cannot find parent of JDOM namespace node"); } else { throw new IllegalStateException("Unknown JDOM node type " + node.getClass()); } } return (Document)node; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): Gunther Schadow (changes to allow access to public fields; also wrapping // of extensions and mapping of null to empty sequence). // saxonb-9.1.0.8/bj/net/sf/saxon/jdom/JDOMTransform.java0000644000175000017500000000604311033112257021623 0ustar eugeneeugenepackage net.sf.saxon.jdom; import net.sf.saxon.Transform; import net.sf.saxon.trans.XPathException; import org.jdom.JDOMException; import org.jdom.input.SAXBuilder; import org.xml.sax.InputSource; import javax.xml.transform.Source; import javax.xml.transform.sax.SAXSource; import javax.xml.transform.stream.StreamSource; import java.io.IOException; import java.util.ArrayList; import java.util.List; /** * Variant of command line net.sf.saxon.Transform do build the source document * in JDOM and then proceed with the transformation. This class is provided largely for * testing purposes. */ public class JDOMTransform extends Transform { public List preprocess(List sources) throws XPathException { try { ArrayList jdomSources = new ArrayList(sources.size()); for (int i=0; i * This is the implementation of the NodeInfo interface used as a wrapper for JDOM nodes. * @author Michael H. Kay */ public class NodeWrapper implements NodeInfo, VirtualNode, SiblingCountingNode { protected Object node; // the JDOM node to which this XPath node is mapped; or a List of // adjacent text nodes protected short nodeKind; private NodeWrapper parent; // null means unknown protected DocumentWrapper docWrapper; protected int index; // -1 means unknown /** * This constructor is protected: nodes should be created using the wrap * factory method on the DocumentWrapper class * @param node The JDOM node to be wrapped * @param parent The NodeWrapper that wraps the parent of this node * @param index Position of this node among its siblings */ protected NodeWrapper(Object node, NodeWrapper parent, int index) { this.node = node; this.parent = parent; this.index = index; } /** * Factory method to wrap a JDOM node with a wrapper that implements the Saxon * NodeInfo interface. * @param node The JDOM node * @param docWrapper The wrapper for the Document containing this node * @return The new wrapper for the supplied node */ protected NodeWrapper makeWrapper(Object node, DocumentWrapper docWrapper) { return makeWrapper(node, docWrapper, null, -1); } /** * Factory method to wrap a JDOM node with a wrapper that implements the Saxon * NodeInfo interface. * @param node The JDOM node * @param docWrapper The wrapper for the Document containing this node * @param parent The wrapper for the parent of the JDOM node * @param index The position of this node relative to its siblings * @return The new wrapper for the supplied node */ protected NodeWrapper makeWrapper(Object node, DocumentWrapper docWrapper, NodeWrapper parent, int index) { NodeWrapper wrapper; if (node instanceof Document) { return docWrapper; } else if (node instanceof Element) { wrapper = new NodeWrapper(node, parent, index); wrapper.nodeKind = Type.ELEMENT; } else if (node instanceof Attribute) { wrapper = new NodeWrapper(node, parent, index); wrapper.nodeKind = Type.ATTRIBUTE; } else if (node instanceof String || node instanceof Text) { wrapper = new NodeWrapper(node, parent, index); wrapper.nodeKind = Type.TEXT; } else if (node instanceof Comment) { wrapper = new NodeWrapper(node, parent, index); wrapper.nodeKind = Type.COMMENT; } else if (node instanceof ProcessingInstruction) { wrapper = new NodeWrapper(node, parent, index); wrapper.nodeKind = Type.PROCESSING_INSTRUCTION; } else if (node instanceof Namespace) { throw new IllegalArgumentException("Cannot wrap JDOM namespace objects"); } else { throw new IllegalArgumentException("Bad node type in JDOM! " + node.getClass() + " instance " + node.toString()); } wrapper.docWrapper = docWrapper; return wrapper; } /** * Get the underlying JDOM node, to implement the VirtualNode interface */ public Object getUnderlyingNode() { if (node instanceof List) { return ((List)node).get(0); } else { return node; } } /** * Get the configuration */ public Configuration getConfiguration() { return docWrapper.getConfiguration(); } /** * Get the name pool for this node * @return the NamePool */ public NamePool getNamePool() { return docWrapper.getNamePool(); } /** * Return the type of node. * @return one of the values Node.ELEMENT, Node.TEXT, Node.ATTRIBUTE, etc. */ public int getNodeKind() { return nodeKind; } /** * Get the typed value of the item */ public SequenceIterator getTypedValue() { return SingletonIterator.makeIterator((AtomicValue)atomize()); } /** * Get the typed value. The result of this method will always be consistent with the method * {@link net.sf.saxon.om.Item#getTypedValue()}. However, this method is often more convenient and may be * more efficient, especially in the common case where the value is expected to be a singleton. * * @return the typed value. If requireSingleton is set to true, the result will always be an * AtomicValue. In other cases it may be a Value representing a sequence whose items are atomic * values. * @since 8.5 */ public Value atomize() { switch (getNodeKind()) { case Type.COMMENT: case Type.PROCESSING_INSTRUCTION: return new StringValue(getStringValueCS()); default: return new UntypedAtomicValue(getStringValueCS()); } } /** * Get the type annotation */ public int getTypeAnnotation() { if (getNodeKind() == Type.ATTRIBUTE) { return StandardNames.XS_UNTYPED_ATOMIC; } return StandardNames.XS_UNTYPED; } /** * Determine whether this is the same node as another node.
    * Note: a.isSameNode(b) if and only if generateId(a)==generateId(b) * @return true if this Node object and the supplied Node object represent the * same node in the tree. */ public boolean isSameNodeInfo(NodeInfo other) { if (!(other instanceof NodeWrapper)) { return false; } NodeWrapper ow = (NodeWrapper)other; return node.equals(ow.node); } /** * The equals() method compares nodes for identity. It is defined to give the same result * as isSameNodeInfo(). * @param other the node to be compared with this node * @return true if this NodeInfo object and the supplied NodeInfo object represent * the same node in the tree. * @since 8.7 Previously, the effect of the equals() method was not defined. Callers * should therefore be aware that third party implementations of the NodeInfo interface may * not implement the correct semantics. It is safer to use isSameNodeInfo() for this reason. * The equals() method has been defined because it is useful in contexts such as a Java Set or HashMap. */ public boolean equals(Object other) { return other instanceof NodeInfo && isSameNodeInfo((NodeInfo)other); } /** * The hashCode() method obeys the contract for hashCode(): that is, if two objects are equal * (represent the same node) then they must have the same hashCode() * @since 8.7 Previously, the effect of the equals() and hashCode() methods was not defined. Callers * should therefore be aware that third party implementations of the NodeInfo interface may * not implement the correct semantics. */ public int hashCode() { return node.hashCode(); } /** * Get the System ID for the node. * @return the System Identifier of the entity in the source document containing the node, * or null if not known. Note this is not the same as the base URI: the base URI can be * modified by xml:base, but the system ID cannot. */ public String getSystemId() { return docWrapper.baseURI; } public void setSystemId(String uri) { docWrapper.baseURI = uri; } /** * Get the Base URI for the node, that is, the URI used for resolving a relative URI contained * in the node. In the JDOM model, base URIs are held only an the document level. */ public String getBaseURI() { if (getNodeKind() == Type.NAMESPACE) { return null; } NodeInfo n = this; if (getNodeKind() != Type.ELEMENT) { n = getParent(); } // Look for an xml:base attribute while (n != null) { String xmlbase = n.getAttributeValue(StandardNames.XML_BASE); if (xmlbase != null) { return xmlbase; } n = n.getParent(); } // if not found, return the base URI of the document node return docWrapper.baseURI; } /** * Get line number * @return the line number of the node in its original source document; or -1 if not available. * Always returns -1 in this implementation. */ public int getLineNumber() { return -1; } /** * Get column number * @return the column number of the node in its original source document; or -1 if not available */ public int getColumnNumber() { return -1; } /** * Determine the relative position of this node and another node, in document order. * The other node will always be in the same document. * @param other The other node, whose position is to be compared with this node * @return -1 if this node precedes the other node, +1 if it follows the other * node, or 0 if they are the same node. (In this case, isSameNode() will always * return true, and the two nodes will produce the same result for generateId()) */ public int compareOrder(NodeInfo other) { if (other instanceof SiblingCountingNode) { return Navigator.compareOrder(this, (SiblingCountingNode)other); } else { // it must be a namespace node return -other.compareOrder(this); } } /** * Return the string value of the node. The interpretation of this depends on the type * of node. For an element it is the accumulated character content of the element, * including descendant elements. * @return the string value of the node */ public String getStringValue() { return getStringValueCS().toString(); } /** * Get the value of the item as a CharSequence. This is in some cases more efficient than * the version of the method that returns a String. */ public CharSequence getStringValueCS() { if (node instanceof List) { // This wrapper is mapped to a list of adjacent text nodes List nodes = (List)node; FastStringBuffer fsb = new FastStringBuffer(100); for (int i=0; i * Note: the result is equivalent to
    * getEnumeration(Axis.CHILD, AnyNodeTest.getInstance()).hasNext() */ public boolean hasChildNodes() { switch (nodeKind) { case Type.DOCUMENT: return true; case Type.ELEMENT: return !((Element)node).getContent().isEmpty(); default: return false; } } /** * Get a character string that uniquely identifies this node. * Note: a.isSameNode(b) if and only if generateId(a)==generateId(b) * @param buffer a Buffer to contain a string that uniquely identifies this node, across all * documents */ public void generateId(FastStringBuffer buffer) { Navigator.appendSequentialKey(this, buffer, true); //buffer.append(Navigator.getSequentialKey(this)); } /** * Get the document number of the document containing this node. For a free-standing * orphan node, just return the hashcode. */ public int getDocumentNumber() { return getDocumentRoot().getDocumentNumber(); } /** * Copy this node to a given outputter (deep copy) */ public void copy(Receiver out, int whichNamespaces, boolean copyAnnotations, int locationId) throws XPathException { Navigator.copy(this, out, docWrapper.getNamePool(), whichNamespaces, copyAnnotations, locationId); } /** * Get all namespace undeclarations and undeclarations defined on this element. * * @param buffer If this is non-null, and the result array fits in this buffer, then the result * may overwrite the contents of this array, to avoid the cost of allocating a new array on the heap. * @return An array of integers representing the namespace declarations and undeclarations present on * this element. For a node other than an element, return null. Otherwise, the returned array is a * sequence of namespace codes, whose meaning may be interpreted by reference to the name pool. The * top half word of each namespace code represents the prefix, the bottom half represents the URI. * If the bottom half is zero, then this is a namespace undeclaration rather than a declaration. * The XML namespace is never included in the list. If the supplied array is larger than required, * then the first unused entry will be set to -1. *

    *

    For a node other than an element, the method returns null.

    */ public int[] getDeclaredNamespaces(int[] buffer) { if (node instanceof Element) { Element elem = (Element)node; List addl = elem.getAdditionalNamespaces(); int size = addl.size() + 1; int[] result = (buffer == null || size > buffer.length ? new int[size] : buffer); NamePool pool = getNamePool(); Namespace ns = elem.getNamespace(); String prefix = ns.getPrefix(); String uri = ns.getURI(); result[0] = pool.allocateNamespaceCode(prefix, uri); int i = 1; if (!addl.isEmpty()) { Iterator itr = addl.iterator(); while (itr.hasNext()) { ns = (Namespace) itr.next(); result[i++] = pool.allocateNamespaceCode(ns.getPrefix(), ns.getURI()); } } if (size < result.length) { result[size] = -1; } return result; } else { return null; } } /** * Determine whether this node has the is-id property * * @return true if the node is an ID */ public boolean isId() { return false; } /** * Determine whether this node has the is-idref property * * @return true if the node is an IDREF or IDREFS element or attribute */ public boolean isIdref() { return false; } /** * Determine whether the node has the is-nilled property * * @return true if the node has the is-nilled property */ public boolean isNilled() { return false; } /////////////////////////////////////////////////////////////////////////////// // Axis enumeration classes /////////////////////////////////////////////////////////////////////////////// private final class AttributeEnumeration extends Navigator.BaseEnumeration { private Iterator atts; private int ix = 0; private NodeWrapper start; public AttributeEnumeration(NodeWrapper start) { this.start = start; atts = ((Element)start.node).getAttributes().iterator(); } public void advance() { if (atts.hasNext()) { current = makeWrapper(atts.next(), docWrapper, start, ix++); } else { current = null; } } public SequenceIterator getAnother() { return new AttributeEnumeration(start); } } // end of class AttributeEnumeration /** * The class ChildEnumeration handles not only the child axis, but also the * following-sibling and preceding-sibling axes. It can also iterate the children * of the start node in reverse order, something that is needed to support the * preceding and preceding-or-ancestor axes (the latter being used by xsl:number) */ private final class ChildEnumeration extends Navigator.BaseEnumeration { private NodeWrapper start; private NodeWrapper commonParent; private ListIterator children; private int ix = 0; private boolean downwards; // iterate children of start node (not siblings) private boolean forwards; // iterate in document order (not reverse order) public ChildEnumeration(NodeWrapper start, boolean downwards, boolean forwards) { this.start = start; this.downwards = downwards; this.forwards = forwards; if (downwards) { commonParent = start; } else { commonParent = (NodeWrapper)start.getParent(); } if (commonParent.getNodeKind()==Type.DOCUMENT) { children = ((Document)commonParent.node).getContent().listIterator(); } else { children = ((Element)commonParent.node).getContent().listIterator(); } if (downwards) { if (!forwards) { // backwards enumeration: go to the end while (children.hasNext()) { children.next(); ix++; } } } else { ix = start.getSiblingPosition(); // find the start node among the list of siblings Object n = null; if (forwards) { for (int i=0; i<=ix; i++) { n = children.next(); } if (n instanceof Text) { // move to the last of a sequence of adjacent text nodes boolean atEnd = false; while (n instanceof Text) { if (children.hasNext()) { n = children.next(); ix++; } else { atEnd = true; break; } } if (!atEnd) { children.previous(); } } else { ix++; } } else { for (int i=0; i Package overview for net.sf.saxon.jdom

    This package provides glue classes that enable Saxon to process a source document supplied as a JDOM tree (see http://www.jdom.org).

    These classes are not part of the core saxon.jar product, but are released as a separate saxon-jdom.jar.

    The package provides implementations of the Saxon DocumentInfo and NodeInfo classes that act as wrappers to the relevant JDOM classes


    Michael H. Kay
    Saxonica Limited
    9 February 2005

    saxonb-9.1.0.8/bj/net/sf/saxon/instruct/0000755000175000017500000000000012216261743017263 5ustar eugeneeugenesaxonb-9.1.0.8/bj/net/sf/saxon/instruct/AttributeCreator.java0000644000175000017500000000676511033112257023416 0ustar eugeneeugenepackage net.sf.saxon.instruct; import net.sf.saxon.type.SimpleType; import net.sf.saxon.event.ReceiverOptions; /** * Abstract class for fixed and computed attribute constructor expressions */ public abstract class AttributeCreator extends SimpleNodeConstructor { private SimpleType schemaType; private int annotation; private int validationAction; private int options; /** * Set the required schema type of the attribute * @param type the required schema type, if validation against a specific type is required */ public void setSchemaType(SimpleType type) { schemaType = type; } /** * Return the required schema type of the attribute * @return if validation against a schema type was requested, return the schema type (always a simple type). * Otherwise, if validation against a specific type was not requested, return null */ public SimpleType getSchemaType() { return schemaType; } /** * Set the validation action required * @param action the validation action required, for example strict or lax */ public void setValidationAction(int action) { validationAction = action; } /** * Get the validation action requested * @return the validation action, for example strict or lax */ public int getValidationAction() { return validationAction; } /** * Set the options to be used on the attribute event * @param options */ public void setOptions(int options) { this.options = options; } /** * Indicate that two attributes with the same name are not acceptable. * (This option is set in XQuery, but not in XSLT) */ public void setRejectDuplicates() { options |= ReceiverOptions.REJECT_DUPLICATES; } /** * Indicate that the attribute value contains no special characters that * might need escaping */ public void setNoSpecialChars() { options |= ReceiverOptions.NO_SPECIAL_CHARS; } /** * Get the options to be used on the attribute event * @return the option flags to be used */ public int getOptions() { return options; } /** * Set the type annotation fingerprint to be used on the attribute event * @param type the fingerprint of the type annotation to be used */ public void setAnnotation(int type) { annotation = type; } /** * Get the type annotation fingerprint to be used on the attribute event * @return the fingerprint of the type annotation to be used */ public int getAnnotation() { return annotation; } } // // The contents of this file are subject to the Mozilla Public License Version // 1.0 (the "License"); // you may not use this file except in compliance with the License. You may // obtain a copy of the License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations // under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael Kay, // // Portions created by (your name) are Copyright (C) (your legal entity). All // Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/instruct/ElementCreator.java0000644000175000017500000004152011033112257023030 0ustar eugeneeugenepackage net.sf.saxon.instruct; import net.sf.saxon.Controller; import net.sf.saxon.value.Cardinality; import net.sf.saxon.evpull.*; import net.sf.saxon.event.*; import net.sf.saxon.expr.*; import net.sf.saxon.om.Item; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.om.StandardNames; import net.sf.saxon.om.Validation; import net.sf.saxon.pattern.NodeKindTest; import net.sf.saxon.pattern.NodeTest; import net.sf.saxon.pull.*; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.Type; import net.sf.saxon.type.TypeHierarchy; import net.sf.saxon.type.ValidationException; /** * An instruction that creates an element node. There are two subtypes, FixedElement * for use where the name is known statically, and Element where it is computed * dynamically. To allow use in both XSLT and XQuery, the class acts both as an * Instruction and as an Expression. */ public abstract class ElementCreator extends ParentNodeConstructor { /** * The inheritNamespaces flag indicates that the namespace nodes on the element created by this instruction * are to be inherited (copied) on the children of this element. That is, if this flag is false, the child * elements must carry a namespace undeclaration for all the namespaces on the parent, unless they are * redeclared in some way. */ protected boolean inheritNamespaces = true; /** * Flag set to true if validation=preserve and no schema type supplied for validation */ protected boolean preservingTypes = true; /** * Construct an ElementCreator. Exists for the benefit of subclasses. */ public ElementCreator() { } /** * Get the item type of the value returned by this instruction * @return the item type * @param th the type hierarchy cache */ public ItemType getItemType(TypeHierarchy th) { return NodeKindTest.ELEMENT; } /** * Determine whether this elementCreator performs validation or strips type annotations * @return false if the instruction performs validation of the constructed output or if it strips * type annotations, otherwise true */ public boolean isPreservingTypes() { return preservingTypes; } /** * Determine whether the inherit namespaces flag is set * @return true if namespaces constructed on a parent element are to be inherited by its children */ public boolean isInheritNamespaces() { return inheritNamespaces; } /** * Get the static properties of this expression (other than its type). The result is * bit-signficant. These properties are used for optimizations. In general, if * property bit is set, it is true, but if it is unset, the value is unknown. * * @return a set of flags indicating static properties of this expression */ public int computeSpecialProperties() { return super.computeSpecialProperties() | StaticProperty.SINGLE_DOCUMENT_NODESET; } /** * Set the validation mode for the new element */ public void setValidationMode(int mode) { super.setValidationMode(mode); if (mode != Validation.PRESERVE) { preservingTypes = false; } } /** * Suppress validation on contained element constructors, on the grounds that the parent element * is already performing validation. The default implementation does nothing. */ public void suppressValidation(int validationMode) { if (validation == validationMode) { setValidationMode(Validation.PRESERVE); } } /** * Check statically whether the content of the element creates attributes or namespaces * after creating any child nodes * @param env the static context * @throws XPathException */ protected void checkContentSequence(StaticContext env) throws XPathException { if (content instanceof Block) { TypeHierarchy th = env.getConfiguration().getTypeHierarchy(); Expression[] components = ((Block)content).getChildren(); boolean foundChild = false; boolean foundPossibleChild = false; int childNodeKinds = (1<{@x}{@y} if (components[i] instanceof ValueOf && ((ValueOf)components[i]).select instanceof StringLiteral) { String value = (((StringLiteral)((ValueOf)components[i]).select).getStringValue()); if (value.length() == 0) { // continue; // not an error } else { foundChild = true; } } else { foundPossibleChild = true; } } else if ((possibleNodeKinds & ~childNodeKinds) == 0) { if (maybeEmpty) { foundPossibleChild = true; } else { foundChild = true; } } else if (foundChild && possibleNodeKinds == 1< */ public class NumberInstruction extends Expression { private static final int SINGLE = 0; private static final int MULTI = 1; private static final int ANY = 2; private static final int SIMPLE = 3; private int level; private Pattern count = null; private Pattern from = null; private Expression select = null; private Expression value = null; private Expression format = null; private Expression groupSize = null; private Expression groupSeparator = null; private Expression letterValue = null; private Expression ordinal = null; private Expression lang = null; private NumberFormatter formatter = null; private Numberer numberer = null; private HashMap nationalNumberers = null; private boolean hasVariablesInPatterns; private boolean backwardsCompatible; private static Numberer defaultNumberer = new Numberer_en(); /** * Construct a NumberInstruction * @param config the Saxon configuration * @param select the expression supplied in the select attribute * @param level one of "single", "level", "multi" * @param count the pattern supplied in the count attribute * @param from the pattern supplied in the from attribute * @param value the expression supplied in the value attribute * @param format the expression supplied in the format attribute * @param groupSize the expression supplied in the group-size attribute * @param groupSeparator the expression supplied in the grouping-separator attribute * @param letterValue the expression supplied in the letter-value attribute * @param ordinal the expression supplied in the ordinal attribute * @param lang the expression supplied in the lang attribute * @param formatter A NumberFormatter to be used * @param numberer A Numberer to be used for localization * @param hasVariablesInPatterns true if one or more of the patterns contains variable references * @param backwardsCompatible true if running in 1.0 compatibility mode */ public NumberInstruction(Configuration config, Expression select, int level, Pattern count, Pattern from, Expression value, Expression format, Expression groupSize, Expression groupSeparator, Expression letterValue, Expression ordinal, Expression lang, NumberFormatter formatter, Numberer numberer, boolean hasVariablesInPatterns, boolean backwardsCompatible) { this.select = select; this.level = level; this.count = count; this.from = from; this.value = value; this.format = format; this.groupSize = groupSize; this.groupSeparator = groupSeparator; this.letterValue = letterValue; this.ordinal = ordinal; this.lang = lang; this.formatter = formatter; this.numberer = numberer; this.hasVariablesInPatterns = hasVariablesInPatterns; this.backwardsCompatible = backwardsCompatible; final TypeHierarchy th = config.getTypeHierarchy(); if (this.value != null && !this.value.getItemType(th).isAtomicType()) { this.value = new Atomizer(this.value, config); } Iterator kids = iterateSubExpressions(); while (kids.hasNext()) { Expression child = (Expression)kids.next(); adoptChildExpression(child); } } public Expression simplify(ExpressionVisitor visitor) throws XPathException { select = visitor.simplify(select); value = visitor.simplify(value); format = visitor.simplify(format); groupSize = visitor.simplify(groupSize); groupSeparator = visitor.simplify(groupSeparator); letterValue = visitor.simplify(letterValue); ordinal = visitor.simplify(ordinal); lang = visitor.simplify(lang); if (count != null) { count = count.simplify(visitor); } if (from != null) { from = from.simplify(visitor); } return this; } /** * Perform static analysis of an expression and its subexpressions. * *

    This checks statically that the operands of the expression have * the correct type; if necessary it generates code to do run-time type checking or type * conversion. A static type error is reported only if execution cannot possibly succeed, that * is, if a run-time type error is inevitable. The call may return a modified form of the expression.

    * *

    This method is called after all references to functions and variables have been resolved * to the declaration of the function or variable. However, the types of such functions and * variables will only be accurately known if they have been explicitly declared.

    * * @param visitor an expression visitor * @param contextItemType the static type of "." at the point where this expression is invoked. * The parameter is set to null if it is known statically that the context item will be undefined. * If the type of the context item is not known statically, the argument is set to * {@link net.sf.saxon.type.Type#ITEM_TYPE} * @throws XPathException if an error is discovered during this phase * (typically a type error) * @return the original expression, rewritten to perform necessary * run-time type checks, and to perform other type-related * optimizations */ public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { if (select != null) { select = visitor.typeCheck(select, contextItemType); } else { if (value==null) { // we are numbering the context node XPathException err = null; if (contextItemType == null) { err = new XPathException( "xsl:number requires a select attribute, a value attribute, or a context item"); } else if (contextItemType.isAtomicType()) { err = new XPathException( "xsl:number requires the context item to be a node, but it is an atomic value"); } if (err != null) { err.setIsTypeError(true); err.setErrorCode("XTTE0990"); err.setLocator(this); throw err; } } } if (value != null) { value = visitor.typeCheck(value, contextItemType); } if (format != null) { format = visitor.typeCheck(format, contextItemType); } if (groupSize != null) { groupSize = visitor.typeCheck(groupSize, contextItemType); } if (groupSeparator != null) { groupSeparator = visitor.typeCheck(groupSeparator, contextItemType); } if (letterValue != null) { letterValue = visitor.typeCheck(letterValue, contextItemType); } if (ordinal != null) { ordinal = visitor.typeCheck(ordinal, contextItemType); } if (lang != null) { lang = visitor.typeCheck(lang, contextItemType); } if (count != null) { visitor.typeCheck(new PatternSponsor(count), contextItemType); } if (from != null) { visitor.typeCheck(new PatternSponsor(from), contextItemType); } return this; } /** * Perform optimisation of an expression and its subexpressions. *

    *

    This method is called after all references to functions and variables have been resolved * to the declaration of the function or variable, and after all type checking has been done.

    * * @param visitor an expression visitor * @param contextItemType the static type of "." at the point where this expression is invoked. * The parameter is set to null if it is known statically that the context item will be undefined. * If the type of the context item is not known statically, the argument is set to * {@link net.sf.saxon.type.Type#ITEM_TYPE} * @return the original expression, rewritten if appropriate to optimize execution * @throws XPathException if an error is discovered during this phase * (typically a type error) */ public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { if (select != null) { select = visitor.optimize(select, contextItemType); } if (value != null) { value = visitor.optimize(value, contextItemType); } if (format != null) { format = visitor.optimize(format, contextItemType); } if (groupSize != null) { groupSize = visitor.optimize(groupSize, contextItemType); } if (groupSeparator != null) { groupSeparator = visitor.optimize(groupSeparator, contextItemType); } if (letterValue != null) { letterValue = visitor.optimize(letterValue, contextItemType); } if (ordinal != null) { ordinal = visitor.optimize(ordinal, contextItemType); } if (lang != null) { lang = visitor.optimize(lang, contextItemType); } return this; } /** * Get the immediate sub-expressions of this expression. Default implementation * returns a zero-length array, appropriate for an expression that has no * sub-expressions. * @return an iterator containing the sub-expressions of this expression */ public Iterator iterateSubExpressions() { List sub = new ArrayList(9); if (select != null) { sub.add(select); } if (value != null) { sub.add(value); } if (format != null) { sub.add(format); } if (groupSize != null) { sub.add(groupSize); } if (groupSeparator != null) { sub.add(groupSeparator); } if (letterValue != null) { sub.add(letterValue); } if (ordinal != null) { sub.add(ordinal); } if (lang != null) { sub.add(lang); } if (count != null) { sub.add(new PatternSponsor(count)); } if (from != null) { sub.add(new PatternSponsor(from)); } return sub.iterator(); } /** * Copy an expression. This makes a deep copy. * * @return the copy of the original expression */ public Expression copy() { throw new UnsupportedOperationException("copy"); } /** * Replace one subexpression by a replacement subexpression * @param original the original subexpression * @param replacement the replacement subexpression * @return true if the original subexpression is found */ public boolean replaceSubExpression(Expression original, Expression replacement) { boolean found = false; if (select == original) { select = replacement; found = true; } if (value == original) { value = replacement; found = true; } if (format == original) { format = replacement; found = true; } if (groupSize == original) { groupSize = replacement; found = true; } if (groupSeparator == original) { groupSeparator = replacement; found = true; } if (letterValue == original) { letterValue = replacement; found = true; } if (ordinal == original) { ordinal = replacement; found = true; } if (lang == original) { lang = replacement; found = true; } return found; } /** * Determine the intrinsic dependencies of an expression, that is, those which are not derived * from the dependencies of its subexpressions. For example, position() has an intrinsic dependency * on the context position, while (position()+1) does not. The default implementation * of the method returns 0, indicating "no dependencies". * * @return a set of bit-significant flags identifying the "intrinsic" * dependencies. The flags are documented in class net.sf.saxon.value.StaticProperty */ public int getIntrinsicDependencies() { return (select == null ? StaticProperty.DEPENDS_ON_CONTEXT_ITEM : 0); } public ItemType getItemType(TypeHierarchy th) { return BuiltInAtomicType.STRING; } public int computeCardinality() { return StaticProperty.EXACTLY_ONE; } /** * Offer promotion for this subexpression. The offer will be accepted if the subexpression * is not dependent on the factors (e.g. the context item) identified in the PromotionOffer. * By default the offer is not accepted - this is appropriate in the case of simple expressions * such as constant values and variable references where promotion would give no performance * advantage. This method is always called at compile time. * * @param offer details of the offer, for example the offer to move * expressions that don't depend on the context to an outer level in * the containing expression * @return if the offer is not accepted, return this expression unchanged. * Otherwise return the result of rewriting the expression to promote * this subexpression * @throws net.sf.saxon.trans.XPathException * if any error is detected */ public Expression promote(PromotionOffer offer) throws XPathException { Expression exp = offer.accept(this); if (exp!=null) { return exp; } else { if (select != null) { select = doPromotion(select, offer); } if (value != null) { value = doPromotion(value, offer); } if (format != null) { format = doPromotion(format, offer); } if (groupSize != null) { groupSize = doPromotion(groupSize, offer); } if (groupSeparator != null) { groupSeparator = doPromotion(groupSeparator, offer); } if (letterValue != null) { letterValue = doPromotion(letterValue, offer); } if (ordinal != null) { ordinal = doPromotion(ordinal, offer); } if (lang != null) { lang = doPromotion(lang, offer); } if (count != null) { count.promote(offer); } if (from != null) { from.promote(offer); } return this; } } public Item evaluateItem(XPathContext context) throws XPathException { long value = -1; List vec = null; // a list whose items may be of type either Long or // BigInteger or the string to be output (e.g. "NaN") if (this.value != null) { SequenceIterator iter = this.value.iterate(context); vec = new ArrayList(4); while (true) { AtomicValue val = (AtomicValue) iter.next(); if (val == null) { break; } if (backwardsCompatible && !vec.isEmpty()) { break; } try { NumericValue num; if (val instanceof NumericValue) { num = (NumericValue) val; } else { num = NumberFn.convert(val); } if (num.isNaN()) { throw new XPathException("NaN"); // thrown to be caught } num = num.round(); if (num.compareTo(Int64Value.MAX_LONG) > 0) { vec.add(((BigIntegerValue)num.convert(BuiltInAtomicType.INTEGER, true, context).asAtomic()).asBigInteger()); } else { if (num.compareTo(Int64Value.ZERO) < 0) { throw new XPathException("The numbers to be formatted must not be negative"); // thrown to be caught } long i = ((NumericValue)num.convert(BuiltInAtomicType.INTEGER, true, context).asAtomic()).longValue(); vec.add(new Long(i)); } } catch (XPathException err) { if (backwardsCompatible) { vec.add("NaN"); } else { vec.add(val.getStringValue()); XPathException e = new XPathException("Cannot convert supplied value to an integer. " + err.getMessage()); e.setErrorCode("XTDE0980"); e.setXPathContext(context); throw e; } } } if (backwardsCompatible && vec.isEmpty()) { vec.add("NaN"); } } else { NodeInfo source; if (select != null) { source = (NodeInfo) select.evaluateItem(context); } else { Item item = context.getContextItem(); if (!(item instanceof NodeInfo)) { XPathException err = new XPathException("context item for xsl:number must be a node"); err.setErrorCode("XTTE0990"); err.setIsTypeError(true); err.setXPathContext(context); throw err; } source = (NodeInfo) item; } if (level == SIMPLE) { value = Navigator.getNumberSimple(source, context); } else if (level == SINGLE) { value = Navigator.getNumberSingle(source, count, from, context); if (value == 0) { vec = Collections.EMPTY_LIST; // an empty list } } else if (level == ANY) { value = Navigator.getNumberAny(this, source, count, from, context, hasVariablesInPatterns); if (value == 0) { vec = Collections.EMPTY_LIST; // an empty list } } else if (level == MULTI) { vec = Navigator.getNumberMulti(source, count, from, context); } } int gpsize = 0; String gpseparator = ""; String letterVal; String ordinalVal = null; if (groupSize != null) { String g = groupSize.evaluateAsString(context).toString(); try { gpsize = Integer.parseInt(g); } catch (NumberFormatException err) { XPathException e = new XPathException("grouping-size must be numeric"); e.setXPathContext(context); e.setErrorCode("XTDE0030"); throw e; } } if (groupSeparator != null) { gpseparator = groupSeparator.evaluateAsString(context).toString(); } if (ordinal != null) { ordinalVal = ordinal.evaluateAsString(context).toString(); } // fast path for the simple case if (vec == null && format == null && gpsize == 0 && lang == null) { return new StringValue("" + value); } // Use the numberer decided at compile time if possible; otherwise try to get it from // a table of numberers indexed by language; if not there, load the relevant class and // add it to the table. Numberer numb = numberer; if (numb == null) { String language = lang.evaluateAsString(context).toString(); if (nationalNumberers == null) { nationalNumberers = new HashMap(4); } numb = (Numberer)nationalNumberers.get(language); if (numb == null) { numb = makeNumberer(language, null, context); nationalNumberers.put(language, numb); } } if (letterValue == null) { letterVal = ""; } else { letterVal = letterValue.evaluateAsString(context).toString(); if (!("alphabetic".equals(letterVal) || "traditional".equals(letterVal))) { XPathException e = new XPathException("letter-value must be \"traditional\" or \"alphabetic\""); e.setXPathContext(context); e.setErrorCode("XTDE0030"); throw e; } } if (vec == null) { vec = new ArrayList(1); vec.add(new Long(value)); } NumberFormatter nf; if (formatter == null) { // format not known until run-time nf = new NumberFormatter(); nf.prepare(format.evaluateAsString(context).toString()); } else { nf = formatter; } CharSequence s = nf.format(vec, gpsize, gpseparator, letterVal, ordinalVal, numb); return new StringValue(s); } /** * Load a Numberer class for a given language and check it is OK. * @param language the language for which a Numberer is required * @param country the country for which a Numberer is required * @param context XPath dynamic evaluation context * @return a suitable numberer. If no specific numberer is available * for the language, the default (English) numberer is used. */ public static Numberer makeNumberer(String language, String country, XPathContext context) { Numberer numberer; if ("en".equals(language)) { numberer = defaultNumberer; } else { String langClassName = "net.sf.saxon.number.Numberer_"; for (int i = 0; i < language.length(); i++) { if (Character.isLetter(language.charAt(i))) { langClassName += language.charAt(i); } } try { if (context == null) { Object x = Class.forName(langClassName).newInstance(); numberer = (Numberer)x ; } else { numberer = (Numberer) (context.getConfiguration().getInstance(langClassName, null)); } } catch (XPathException err) { numberer = defaultNumberer; } catch (ClassNotFoundException err) { numberer = defaultNumberer; } catch (InstantiationException err) { numberer = defaultNumberer; } catch (IllegalAccessException err) { numberer = defaultNumberer; } } numberer.setCountry(country); return numberer; } /** * Diagnostic print of expression structure. The abstract expression tree * is written to the supplied output destination. */ public void explain(ExpressionPresenter out) { out.startElement("xslNumber"); out.emitAttribute("level", (level==ANY ? "any" : level==SINGLE ? "single" : "multi")); if (count != null) { out.emitAttribute("count", count.toString()); } if (from != null) { out.emitAttribute("from", from.toString()); } if (select != null) { out.startSubsidiaryElement("select"); select.explain(out); out.endSubsidiaryElement(); } if (value != null) { out.startSubsidiaryElement("value"); value.explain(out); out.endSubsidiaryElement(); } if (format != null) { out.startSubsidiaryElement("format"); format.explain(out); out.endSubsidiaryElement(); } out.endElement(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/instruct/ApplyImports.java0000644000175000017500000002053011033112257022560 0ustar eugeneeugenepackage net.sf.saxon.instruct; import net.sf.saxon.Controller; import net.sf.saxon.expr.*; import net.sf.saxon.om.Item; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.om.StandardNames; import net.sf.saxon.trace.ExpressionPresenter; import net.sf.saxon.trans.Mode; import net.sf.saxon.trans.Rule; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ItemType; import java.util.ArrayList; import java.util.Iterator; /** * An xsl:apply-imports element in the stylesheet */ public class ApplyImports extends Instruction { WithParam[] actualParams = null; WithParam[] tunnelParams = null; private boolean backwardsCompatible; public ApplyImports(boolean backwardsCompatible) { this.backwardsCompatible = backwardsCompatible; } /** * Set the actual parameters on the call */ public void setActualParameters( WithParam[] actualParams, WithParam[] tunnelParams ) { this.actualParams = actualParams; this.tunnelParams = tunnelParams; } /** * Get the name of this instruction for diagnostic and tracing purposes */ public int getInstructionNameCode() { return StandardNames.XSL_APPLY_IMPORTS; } /** * Simplify an expression. This performs any static optimization (by rewriting the expression * as a different expression). * * @exception net.sf.saxon.trans.XPathException if an error is discovered during expression * rewriting * @return the simplified expression * @param visitor an expression visitor */ public Expression simplify(ExpressionVisitor visitor) throws XPathException { WithParam.simplify(actualParams, visitor); WithParam.simplify(tunnelParams, visitor); return this; } public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { WithParam.typeCheck(actualParams, visitor, contextItemType); WithParam.typeCheck(tunnelParams, visitor, contextItemType); return this; } public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { WithParam.optimize(visitor, actualParams, contextItemType); WithParam.optimize(visitor, tunnelParams, contextItemType); return this; } /** * Copy an expression. This makes a deep copy. * * @return the copy of the original expression */ public Expression copy() { throw new UnsupportedOperationException("copy"); } /** * Determine whether this instruction creates new nodes. * This implementation returns true (which is almost invariably the case, so it's not worth * doing any further analysis to find out more precisely). */ public final boolean createsNewNodes() { return true; } /** * Handle promotion offers, that is, non-local tree rewrites. * @param offer The type of rewrite being offered * @throws XPathException */ protected void promoteInst(PromotionOffer offer) throws XPathException { WithParam.promoteParams(actualParams, offer); WithParam.promoteParams(tunnelParams, offer); } /** * Get all the XPath expressions associated with this instruction * (in XSLT terms, the expression present on attributes of the instruction, * as distinct from the child instructions in a sequence construction) */ public Iterator iterateSubExpressions() { ArrayList list = new ArrayList(10); WithParam.getXPathExpressions(actualParams, list); WithParam.getXPathExpressions(tunnelParams, list); return list.iterator(); } /** * Replace one subexpression by a replacement subexpression * @param original the original subexpression * @param replacement the replacement subexpression * @return true if the original subexpression is found */ public boolean replaceSubExpression(Expression original, Expression replacement) { boolean found = false; if (WithParam.replaceXPathExpression(actualParams, original, replacement)) { found = true; } if (WithParam.replaceXPathExpression(tunnelParams, original, replacement)) { found = true; } return found; } public TailCall processLeavingTail(XPathContext context) throws XPathException { Controller controller = context.getController(); // handle parameters if any ParameterSet params = assembleParams(context, actualParams); ParameterSet tunnels = assembleTunnelParams(context, tunnelParams); Rule currentTemplateRule = context.getCurrentTemplateRule(); if (currentTemplateRule==null) { XPathException e = new XPathException("There is no current template rule"); e.setXPathContext(context); e.setErrorCode("XTDE0560"); e.setLocator(this); throw e; } Template currentTemplate = (Template)currentTemplateRule.getAction(); int min = currentTemplate.getMinImportPrecedence(); int max = currentTemplate.getPrecedence()-1; Mode mode = context.getCurrentMode(); if (mode == null) { mode = controller.getRuleManager().getDefaultMode(); } if (context.getCurrentIterator()==null) { XPathException e = new XPathException("Cannot call xsl:apply-imports when there is no context item"); e.setXPathContext(context); e.setErrorCode("XTDE0565"); e.setLocator(this); throw e; } Item currentItem = context.getCurrentIterator().current(); if (!(currentItem instanceof NodeInfo)) { XPathException e = new XPathException("Cannot call xsl:apply-imports when context item is not a node"); e.setXPathContext(context); e.setErrorCode("XTDE0565"); e.setLocator(this); throw e; } NodeInfo node = (NodeInfo)currentItem; Rule rule = controller.getRuleManager().getTemplateRule(node, mode, min, max, context); if (rule==null) { // use the default action for the node ApplyTemplates.defaultAction(node, params, tunnels, context, backwardsCompatible, getLocationId()); } else { XPathContextMajor c2 = context.newContext(); Template nh = (Template)rule.getAction(); c2.setOrigin(this); c2.setLocalParameters(params); c2.setTunnelParameters(tunnels); c2.openStackFrame(nh.getStackFrameMap()); nh.apply(c2, rule); } return null; // We never treat apply-imports as a tail call, though we could } /** * Diagnostic print of expression structure. The abstract expression tree * is written to the supplied output destination. */ public void explain(ExpressionPresenter out) { out.startElement("applyImports"); if (actualParams != null && actualParams.length > 0) { out.startSubsidiaryElement("withParams"); WithParam.displayExpressions(actualParams, out); out.endSubsidiaryElement(); } if (tunnelParams != null && tunnelParams.length > 0) { out.startSubsidiaryElement("tunnelParams"); WithParam.displayExpressions(tunnelParams, out); out.endSubsidiaryElement(); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/instruct/ForEach.java0000644000175000017500000003541111033112257021430 0ustar eugeneeugenepackage net.sf.saxon.instruct; import net.sf.saxon.Controller; import net.sf.saxon.expr.*; import net.sf.saxon.om.Item; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.om.StandardNames; import net.sf.saxon.trace.ExpressionPresenter; import net.sf.saxon.trace.TraceListener; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.SchemaType; import net.sf.saxon.type.TypeHierarchy; import java.util.Iterator; /** * Handler for xsl:for-each elements in a stylesheet. */ public class ForEach extends Instruction implements ContextMappingFunction { private Expression select; private Expression action; private boolean containsTailCall; /** * Create an xsl:for-each instruction * @param select the select expression * @param action the body of the xsl:for-each loop */ public ForEach(Expression select, Expression action, boolean containsTailCall) { this.select = select; this.action = action; this.containsTailCall = containsTailCall && action instanceof TailCallReturner; adoptChildExpression(select); adoptChildExpression(action); } /** * Get the name of this instruction for diagnostic and tracing purposes * @return the code for name xsl:for-each */ public int getInstructionNameCode() { return StandardNames.XSL_FOR_EACH; } /** * Get the action expression (the content of the for-each) * @return the body of the for-each loop */ public Expression getActionExpression() { return action; } /** * Determine the data type of the items returned by this expression * @return the data type * @param th the type hierarchy cache */ public final ItemType getItemType(TypeHierarchy th) { return action.getItemType(th); } /** * Determine whether this instruction creates new nodes. * This implementation returns true if the "action" creates new nodes. * (Nodes created by the condition can't contribute to the result). */ public final boolean createsNewNodes() { int props = action.getSpecialProperties(); return ((props & StaticProperty.NON_CREATIVE) == 0); } /** * Simplify an expression. This performs any static optimization (by rewriting the expression * as a different expression). * * @exception XPathException if an error is discovered during expression * rewriting * @return the simplified expression * @param visitor the expression visitor */ public Expression simplify(ExpressionVisitor visitor) throws XPathException { select = visitor.simplify(select); action = visitor.simplify(action); return this; } public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { final TypeHierarchy th = visitor.getConfiguration().getTypeHierarchy(); select = visitor.typeCheck(select, contextItemType); adoptChildExpression(select); action = visitor.typeCheck(action, select.getItemType(th)); adoptChildExpression(action); if (Literal.isEmptySequence(select)) { return select; } if (Literal.isEmptySequence(action)) { return action; } return this; } public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { final TypeHierarchy th = visitor.getConfiguration().getTypeHierarchy(); select = visitor.optimize(select, contextItemType); adoptChildExpression(select); action = action.optimize(visitor, select.getItemType(th)); adoptChildExpression(action); if (Literal.isEmptySequence(select)) { return select; } if (Literal.isEmptySequence(action)) { return action; } // If any subexpressions within the body of the for-each are not dependent on the focus, // promote them: this causes them to be evaluated once, outside the for-each loop PromotionOffer offer = new PromotionOffer(visitor.getConfiguration().getOptimizer()); offer.action = PromotionOffer.FOCUS_INDEPENDENT; offer.promoteDocumentDependent = (select.getSpecialProperties() & StaticProperty.CONTEXT_DOCUMENT_NODESET) != 0; offer.promoteXSLTFunctions = false; offer.containingExpression = this; action = doPromotion(action, offer); if (offer.containingExpression instanceof LetExpression) { offer.containingExpression = visitor.optimize(offer.containingExpression, contextItemType); } return offer.containingExpression; } /** * Add a representation of this expression to a PathMap. The PathMap captures a map of the nodes visited * by an expression in a source tree. *

    *

    The default implementation of this method assumes that an expression does no navigation other than * the navigation done by evaluating its subexpressions, and that the subexpressions are evaluated in the * same context as the containing expression. The method must be overridden for any expression * where these assumptions do not hold. For example, implementations exist for AxisExpression, ParentExpression, * and RootExpression (because they perform navigation), and for the doc(), document(), and collection() * functions because they create a new navigation root. Implementations also exist for PathExpression and * FilterExpression because they have subexpressions that are evaluated in a different context from the * calling expression.

    * * @param pathMap the PathMap to which the expression should be added * @param pathMapNodeSet the set of nodes in the path map that are affected * @return the pathMapNode representing the focus established by this expression, in the case where this * expression is the first operand of a path expression or filter expression. For an expression that does * navigation, it represents the end of the arc in the path map that describes the navigation route. For other * expressions, it is the same as the input pathMapNode. */ public PathMap.PathMapNodeSet addToPathMap(PathMap pathMap, PathMap.PathMapNodeSet pathMapNodeSet) { PathMap.PathMapNodeSet target = select.addToPathMap(pathMap, pathMapNodeSet); return action.addToPathMap(pathMap, target); } /** * Copy an expression. This makes a deep copy. * * @return the copy of the original expression */ public Expression copy() { return new ForEach(select.copy(), action.copy(), containsTailCall); } /** * Compute the dependencies of an expression, as the union of the * dependencies of its subexpressions. (This is overridden for path expressions * and filter expressions, where the dependencies of a subexpression are not all * propogated). This method should be called only once, to compute the dependencies; * after that, getDependencies should be used. * * @return the depencies, as a bit-mask */ public int computeDependencies() { // Some of the dependencies aren't relevant. Note that the sort keys are absorbed into the select // expression. int dependencies = 0; dependencies |= select.getDependencies(); dependencies |= (action.getDependencies() & ~StaticProperty.DEPENDS_ON_FOCUS); return dependencies; } /** * Handle promotion offers, that is, non-local tree rewrites. * @param offer The type of rewrite being offered * @throws XPathException */ protected void promoteInst(PromotionOffer offer) throws XPathException { select = doPromotion(select, offer); action = doPromotion(action, offer); } /** * Get all the XPath expressions associated with this instruction * (in XSLT terms, the expression present on attributes of the instruction, * as distinct from the child instructions in a sequence construction) */ public Iterator iterateSubExpressions() { return new PairIterator(select, action); } /** * Given an expression that is an immediate child of this expression, test whether * the evaluation of the parent expression causes the child expression to be * evaluated repeatedly * @param child the immediate subexpression * @return true if the child expression is evaluated repeatedly */ public boolean hasLoopingSubexpression(Expression child) { return child == action; } /** * Replace one subexpression by a replacement subexpression * @param original the original subexpression * @param replacement the replacement subexpression * @return true if the original subexpression is found */ public boolean replaceSubExpression(Expression original, Expression replacement) { boolean found = false; if (select == original) { select = replacement; found = true; } if (action == original) { action = replacement; found = true; } return found; } /** * An implementation of Expression must provide at least one of the methods evaluateItem(), iterate(), or process(). * This method indicates which of these methods is provided. This implementation provides both iterate() and * process() methods natively. */ public int getImplementationMethod() { return ITERATE_METHOD | PROCESS_METHOD; } /** * Check that any elements and attributes constructed or returned by this expression are acceptable * in the content model of a given complex type. It's always OK to say yes, since the check will be * repeated at run-time. The process of checking element and attribute constructors against the content * model of a complex type also registers the type of content expected of those constructors, so the * static validation can continue recursively. */ public void checkPermittedContents(SchemaType parentType, StaticContext env, boolean whole) throws XPathException { action.checkPermittedContents(parentType, env, false); } public TailCall processLeavingTail(XPathContext context) throws XPathException { Controller controller = context.getController(); SequenceIterator iter = select.iterate(context); XPathContextMajor c2 = context.newContext(); c2.setOrigin(this); c2.setCurrentIterator(iter); c2.setCurrentTemplateRule(null); if (containsTailCall) { if (controller.isTracing()) { TraceListener listener = controller.getTraceListener(); Item item = iter.next(); if (item == null) { return null; } listener.startCurrentItem(item); TailCall tc = ((TailCallReturner)action).processLeavingTail(c2); listener.endCurrentItem(item); return tc; } else { Item item = iter.next(); if (item == null) { return null; } return ((TailCallReturner)action).processLeavingTail(c2); } } else { if (controller.isTracing()) { TraceListener listener = controller.getTraceListener(); while(true) { Item item = iter.next(); if (item == null) { break; } listener.startCurrentItem(item); action.process(c2); listener.endCurrentItem(item); } } else { while(true) { Item item = iter.next(); if (item == null) { break; } action.process(c2); } } } return null; } /** * Return an Iterator to iterate over the values of the sequence. * * @exception XPathException if any dynamic error occurs evaluating the * expression * @param context supplies the context for evaluation * @return a SequenceIterator that can be used to iterate over the result * of the expression */ public SequenceIterator iterate(XPathContext context) throws XPathException { SequenceIterator master = select.iterate(context); XPathContextMajor c2 = context.newContext(); c2.setOrigin(this); c2.setCurrentTemplateRule(null); c2.setCurrentIterator(master); master = new ContextMappingIterator(this, c2); return master; } /** * Map one item to a sequence. * @param context The processing context. This is supplied only for mapping constructs that * set the context node, position, and size. Otherwise it is null. * @return either (a) a SequenceIterator over the sequence of items that the supplied input * item maps to, or (b) an Item if it maps to a single item, or (c) null if it maps to an empty * sequence. */ public SequenceIterator map(XPathContext context) throws XPathException { return action.iterate(context); } /** * Diagnostic print of expression structure. The abstract expression tree * is written to the supplied output destination. */ public void explain(ExpressionPresenter out) { out.startElement("forEach"); select.explain(out); out.startSubsidiaryElement("return"); action.explain(out); out.endSubsidiaryElement(); out.endElement(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/instruct/Doctype.java0000644000175000017500000003272211033112257021532 0ustar eugeneeugenepackage net.sf.saxon.instruct; import net.sf.saxon.Controller; import net.sf.saxon.event.PipelineConfiguration; import net.sf.saxon.event.Receiver; import net.sf.saxon.event.ReceiverOptions; import net.sf.saxon.event.SequenceReceiver; import net.sf.saxon.expr.*; import net.sf.saxon.om.*; import net.sf.saxon.tinytree.TinyBuilder; import net.sf.saxon.trace.ExpressionPresenter; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ItemType; import java.util.Iterator; /** * A saxon:doctype element in the stylesheet. */ public class Doctype extends Instruction { private Expression content; public Doctype(Expression content) { this.content = content; } /** * Simplify an expression. This performs any static optimization (by rewriting the expression * as a different expression). The default implementation does nothing. * * @param visitor an expression visitor * @return the simplified expression * @throws net.sf.saxon.trans.XPathException * if an error is discovered during expression rewriting */ public Expression simplify(ExpressionVisitor visitor) throws XPathException { content = visitor.simplify(content); return this; } public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { content = visitor.typeCheck(content, contextItemType); adoptChildExpression(content); return this; } public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { content = visitor.optimize(content, contextItemType); adoptChildExpression(content); return this; } /** * Get the immediate sub-expressions of this expression. Default implementation * returns a zero-length array, appropriate for an expression that has no * sub-expressions. * * @return an iterator containing the sub-expressions of this expression */ public Iterator iterateSubExpressions() { return new MonoIterator(content); } /** * Copy an expression. This makes a deep copy. * * @return the copy of the original expression */ public Expression copy() { throw new UnsupportedOperationException("copy"); } /** * Replace one subexpression by a replacement subexpression * * @param original the original subexpression * @param replacement the replacement subexpression * @return true if the original subexpression is found */ public boolean replaceSubExpression(Expression original, Expression replacement) { boolean found = false; if (content == original) { content = replacement; found = true; } return found; } /** * Handle promotion offers, that is, non-local tree rewrites. * * @param offer The type of rewrite being offered * @throws XPathException */ protected void promoteInst(PromotionOffer offer) throws XPathException { content = doPromotion(content, offer); } /** * Determine whether this instruction creates new nodes. * This implementation returns true. */ public final boolean createsNewNodes() { return true; } /** * Get the name of this instruction for diagnostic and tracing purposes */ public int getInstructionNameCode() { return StandardNames.SAXON_DOCTYPE; } public TailCall processLeavingTail(XPathContext context) throws XPathException { Controller controller = context.getController(); XPathContext c2 = context.newMinorContext(); c2.setOrigin(this); SequenceReceiver out = c2.getReceiver(); TinyBuilder builder = new TinyBuilder(); Receiver receiver = builder; PipelineConfiguration pipe = controller.makePipelineConfiguration(); pipe.setHostLanguage(getContainer().getHostLanguage()); receiver.setPipelineConfiguration(pipe); receiver.open(); receiver.startDocument(0); c2.changeOutputDestination(null, receiver, false, getHostLanguage(), Validation.PRESERVE, null); content.process(c2); receiver.endDocument(); receiver.close(); DocumentInfo dtdRoot = (DocumentInfo)builder.getCurrentRoot(); SequenceIterator children = dtdRoot.iterateAxis(Axis.CHILD); NodeInfo docType = (NodeInfo)children.next(); if (docType == null || !("doctype".equals(docType.getLocalPart()))) { XPathException e = new XPathException("saxon:doctype instruction must contain dtd:doctype"); e.setXPathContext(context); throw e; } String name = Navigator.getAttributeValue(docType, "", "name"); String system = Navigator.getAttributeValue(docType, "", "system"); String publicid = Navigator.getAttributeValue(docType, "", "public"); if (name == null) { XPathException e = new XPathException("dtd:doctype must have a name attribute"); e.setXPathContext(context); throw e; } write(out, "'); } else if (localname.equals("attlist")) { String elname = Navigator.getAttributeValue(child, "", "element"); if (elname == null) { XPathException e = new XPathException("dtd:attlist must have an attribute named 'element'"); e.setXPathContext(context); throw e; } write(out, "\n "); } else if (localname.equals("entity")) { String entname = Navigator.getAttributeValue(child, "", "name"); String parameter = Navigator.getAttributeValue(child, "", "parameter"); String esystem = Navigator.getAttributeValue(child, "", "system"); String epublicid = Navigator.getAttributeValue(child, "", "public"); String notation = Navigator.getAttributeValue(child, "", "notation"); if (entname == null) { XPathException e = new XPathException("dtd:entity must have a name attribute"); e.setXPathContext(context); throw e; } // we could do a lot more checking now... write(out, "\n "); } else if (localname.equals("notation")) { String notname = Navigator.getAttributeValue(child, "", "name"); String nsystem = Navigator.getAttributeValue(child, "", "system"); String npublicid = Navigator.getAttributeValue(child, "", "public"); if (notname == null) { XPathException e = new XPathException("dtd:notation must have a name attribute"); e.setXPathContext(context); throw e; } if ((nsystem == null) && (npublicid == null)) { XPathException e = new XPathException("dtd:notation must have a system attribute or a public attribute"); e.setXPathContext(context); throw e; } write(out, "\n "); } else { XPathException e = new XPathException("Unrecognized element " + localname + " in DTD output"); e.setXPathContext(context); throw e; } child = (NodeInfo)children.next(); } if (openSquare) { write(out, "\n]"); } write(out, ">\n"); return null; } private void write(Receiver out, String s) throws XPathException { out.characters(s, locationId, ReceiverOptions.DISABLE_ESCAPING); } /** * Diagnostic print of expression structure. The abstract expression tree * is written to the supplied output destination. */ public void explain(ExpressionPresenter out) { out.startElement("saxonDoctype"); out.endElement(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/instruct/UseAttributeSets.java0000644000175000017500000001632511033112257023403 0ustar eugeneeugenepackage net.sf.saxon.instruct; import net.sf.saxon.expr.*; import net.sf.saxon.pattern.NodeKindTest; import net.sf.saxon.trace.ExpressionPresenter; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.TypeHierarchy; /** * This instruction corresponds to a use-attribute-sets attribute on a literal result element, xsl:element, * or xsl:copy. */ public class UseAttributeSets extends Instruction { private AttributeSet[] attributeSets; /** * Create a use-attribute-sets expression * @param sets the set of attribute sets to be expanded */ public UseAttributeSets(AttributeSet[] sets) { attributeSets = sets; } /** * Simplify an expression. This performs any static optimization (by rewriting the expression * as a different expression). The default implementation does nothing. * * @return the simplified expression * @throws net.sf.saxon.trans.XPathException * if an error is discovered during expression * rewriting * @param visitor an expression visitor */ public Expression simplify(ExpressionVisitor visitor) throws XPathException { return this; } /** * Perform optimisation of an expression and its subexpressions. *

    *

    This method is called after all references to functions and variables have been resolved * to the declaration of the function or variable, and after all type checking has been done.

    * * @param visitor an expression visitor * @param contextItemType the static type of "." at the point where this expression is invoked. * The parameter is set to null if it is known statically that the context item will be undefined. * If the type of the context item is not known statically, the argument is set to * {@link net.sf.saxon.type.Type#ITEM_TYPE} * @return the original expression, rewritten if appropriate to optimize execution * @throws XPathException if an error is discovered during this phase * (typically a type error) */ public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { return this; } /** * Copy an expression. This makes a deep copy. * * @return the copy of the original expression */ public Expression copy() { throw new UnsupportedOperationException("copy"); } /** * Perform type checking of an expression and its subexpressions. *

    *

    This checks statically that the operands of the expression have * the correct type; if necessary it generates code to do run-time type checking or type * conversion. A static type error is reported only if execution cannot possibly succeed, that * is, if a run-time type error is inevitable. The call may return a modified form of the expression.

    *

    *

    This method is called after all references to functions and variables have been resolved * to the declaration of the function or variable. However, the types of such functions and * variables may not be accurately known if they have not been explicitly declared.

    * * @param visitor an expression visitor * @param contextItemType the static type of "." at the point where this expression is invoked. * The parameter is set to null if it is known statically that the context item will be undefined. * If the type of the context item is not known statically, the argument is set to * {@link net.sf.saxon.type.Type#ITEM_TYPE} * @return the original expression, rewritten to perform necessary * run-time type checks, and to perform other type-related * optimizations * @throws XPathException if an error is discovered during this phase * (typically a type error) */ public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { return this; } /** * Get the item type of the items returned by evaluating this instruction * * @return the static item type of the instruction * @param th the type hierarchy cache */ public ItemType getItemType(TypeHierarchy th) { return NodeKindTest.ATTRIBUTE; } /** * Determine the intrinsic dependencies of an expression, that is, those which are not derived * from the dependencies of its subexpressions. For example, position() has an intrinsic dependency * on the context position, while (position()+1) does not. The default implementation * of the method returns 0, indicating "no dependencies". * * @return a set of bit-significant flags identifying the "intrinsic" * dependencies. The flags are documented in class net.sf.saxon.value.StaticProperty */ public int getIntrinsicDependencies() { int d = 0; for (int i=0; i * The xsl:value-of element takes attributes:
      *
    • a mandatory attribute select="expression". * This must be a valid String expression
    • *
    • an optional disable-output-escaping attribute, value "yes" or "no"
    • *
    • an optional separator attribute. This is handled at compile-time: if the separator attribute * is present, the select expression passed in here will be a call to the string-join() function.
    • *
    */ public final class ValueOf extends SimpleNodeConstructor { private int options; private boolean isNumberingInstruction = false; // set to true if generated by xsl:number private boolean noNodeIfEmpty; /** * Create a new ValueOf expression * @param select the select expression * @param disable true if disable-output-escaping is in force * @param noNodeIfEmpty true if the instruction is to return () if the select expression is (), * false if it is to return an empty text node */ public ValueOf(Expression select, boolean disable, boolean noNodeIfEmpty) { this.select = select; options = (disable ? ReceiverOptions.DISABLE_ESCAPING : 0); this.noNodeIfEmpty = noNodeIfEmpty; adoptChildExpression(select); // If value is fixed, test whether there are any special characters that might need to be // escaped when the time comes for serialization if (select instanceof StringLiteral) { boolean special = false; CharSequence val = ((StringLiteral)select).getStringValue(); for (int k=0; k126 || c=='<' || c=='>' || c=='&') { special = true; break; } } if (!special) { options |= ReceiverOptions.NO_SPECIAL_CHARS; } } } /** * Indicate that this is really an xsl:nunber instruction */ public void setIsNumberingInstruction() { isNumberingInstruction = true; } /** * Determine whether this is really an xsl:number instruction * @return true if this derives from xsl:number */ public boolean isNumberingInstruction() { return isNumberingInstruction; } /** * Get the name of this instruction for diagnostic and tracing purposes * @return the namecode of the instruction name */ public int getInstructionNameCode() { if (isNumberingInstruction) { return StandardNames.XSL_NUMBER; } else if (select instanceof StringLiteral) { return StandardNames.XSL_TEXT; } else { return StandardNames.XSL_VALUE_OF; } } /** * Offer promotion for subexpressions. The offer will be accepted if the subexpression * is not dependent on the factors (e.g. the context item) identified in the PromotionOffer. * By default the offer is not accepted - this is appropriate in the case of simple expressions * such as constant values and variable references where promotion would give no performance * advantage. This method is always called at compile time. * * @param offer details of the offer, for example the offer to move * expressions that don't depend on the context to an outer level in * the containing expression * @exception XPathException if any error is detected */ protected void promoteInst(PromotionOffer offer) throws XPathException { super.promoteInst(offer); } /** * Test for any special options such as disable-output-escaping * @return any special options */ public int getOptions() { return options; } /** * Test whether disable-output-escaping was requested * @return true if disable-output-escaping was requested */ public boolean isDisableOutputEscaping() { return (options & ReceiverOptions.DISABLE_ESCAPING) != 0; } public ItemType getItemType(TypeHierarchy th) { return NodeKindTest.TEXT; } public int computeCardinality() { if (noNodeIfEmpty) { return StaticProperty.ALLOWS_ZERO_OR_ONE; } else { return StaticProperty.EXACTLY_ONE; } } public void localTypeCheck(ExpressionVisitor visitor, ItemType contextItemType) { // } /** * Copy an expression. This makes a deep copy. * * @return the copy of the original expression */ public Expression copy() { ValueOf exp = new ValueOf(select.copy(), (options&ReceiverOptions.DISABLE_ESCAPING) != 0 , noNodeIfEmpty); if (isNumberingInstruction) { exp.setIsNumberingInstruction(); } return exp; } /** * Check statically that the results of the expression are capable of constructing the content * of a given schema type. * * @param parentType The schema type * @param env the static context * @param whole true if this expression is to account for the whole value of the type * @throws net.sf.saxon.trans.XPathException * if the expression doesn't match the required content type */ public void checkPermittedContents(SchemaType parentType, StaticContext env, boolean whole) throws XPathException { // if the expression is a constant value, check that it is valid for the type if (select instanceof Literal) { Value selectValue = ((Literal)select).getValue(); SimpleType stype = null; if (parentType instanceof SimpleType && whole) { stype = (SimpleType)parentType; } else if (parentType instanceof ComplexType && ((ComplexType)parentType).isSimpleContent()) { stype = ((ComplexType)parentType).getSimpleContentType(); } if (whole && stype != null && !stype.isNamespaceSensitive()) { // Can't validate namespace-sensitive content statically ValidationFailure err = stype.validateContent( selectValue.getStringValue(), null, env.getConfiguration().getNameChecker()); if (err != null) { err.setLocator(this); throw err.makeException(); } return; } if (parentType instanceof ComplexType && !((ComplexType)parentType).isSimpleContent() && !((ComplexType)parentType).isMixedContent() && !Whitespace.isWhite(selectValue.getStringValue())) { XPathException err = new XPathException("Complex type " + parentType.getDescription() + " does not allow text content " + Err.wrap(selectValue.getStringValue())); err.setLocator(this); err.setIsTypeError(true); throw err; } } } /** * Convert this value-of instruction to an expression that delivers the string-value of the resulting * text node. This will often be a call on the string-join function. * @param env the static evaluation context * @return the converted expression */ public Expression convertToStringJoin(StaticContext env) { if (select.getItemType(env.getConfiguration().getTypeHierarchy()).equals(BuiltInAtomicType.UNTYPED_ATOMIC)) { return select; } else if (select instanceof StringLiteral) { try { return new Literal(new UntypedAtomicValue(((StringLiteral)select).getValue().getStringValueCS())); } catch (XPathException err) { throw new AssertionError(err); } } else { StringFn fn = (StringFn) SystemFunction.makeSystemFunction("string", new Expression[]{select}); return new CastExpression(fn, BuiltInAtomicType.UNTYPED_ATOMIC, false); } } /** * Process this instruction, sending the resulting text node to the current output destination * @param context the dynamic evaluation context * @return Always returns null * @throws XPathException */ public TailCall processLeavingTail(XPathContext context) throws XPathException { // TODO: allow the output of value-of to be streamed to the serializer SequenceReceiver out = context.getReceiver(); Item item = select.evaluateItem(context); if (item != null) { out.characters(item.getStringValueCS(), locationId, options); } return null; } /** * Evaluate this expression, returning the resulting text node to the caller * @param context the dynamic evaluation context * @return the parentless text node that results from evaluating this instruction, or null to * represent an empty sequence * @throws XPathException */ public Item evaluateItem(XPathContext context) throws XPathException { try { CharSequence val; Item item = select.evaluateItem(context); if (item == null) { if (noNodeIfEmpty) { return null; } else { val = ""; } } else { val = item.getStringValueCS(); } Orphan o = new Orphan(context.getController().getConfiguration()); o.setNodeKind(Type.TEXT); o.setStringValue(val); return o; } catch (XPathException err) { err.maybeSetLocation(this); throw err; } } /** * Diagnostic print of expression structure. The abstract expression tree * is written to the supplied output destination. */ public void explain(ExpressionPresenter out) { out.startElement("valueOf"); getSelect().explain(out); out.endElement(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/instruct/GeneralVariable.java0000644000175000017500000003644211123214377023157 0ustar eugeneeugenepackage net.sf.saxon.instruct; import net.sf.saxon.expr.*; import net.sf.saxon.om.*; import net.sf.saxon.pattern.EmptySequenceTest; import net.sf.saxon.om.StandardNames; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.TypeHierarchy; import net.sf.saxon.value.SequenceType; import net.sf.saxon.trace.ExpressionPresenter; import java.util.Collections; import java.util.Iterator; /** * This class defines common behaviour across xsl:variable, xsl:param, and xsl:with-param; * also saxon:assign */ public abstract class GeneralVariable extends Instruction implements Binding { private static final int ASSIGNABLE = 1; private static final int REQUIRED = 4; private static final int TUNNEL = 8; private static final int IMPLICITLY_REQUIRED = 16; // a parameter that is required because the fallback // value is not a valid instance of the type. private byte properties = 0; Expression select = null; protected StructuredQName variableQName; SequenceType requiredType; protected int slotNumber; protected int referenceCount = 10; protected int evaluationMode = ExpressionTool.UNDECIDED; /** * Create a general variable */ public GeneralVariable() {} /** * Initialize the properties of the variable * @param select the expression to which the variable is bound * @param qName the name of the variable */ public void init(Expression select, StructuredQName qName) { this.select = select; variableQName = qName; adoptChildExpression(select); } /** * Set the expression to which this variable is bound * @param select the initializing expression */ public void setSelectExpression(Expression select) { this.select = select; evaluationMode = ExpressionTool.UNDECIDED; adoptChildExpression(select); } /** * Get the expression to which this variable is bound * @return the initializing expression */ public Expression getSelectExpression() { return select; } /** * Set the required type of this variable * @param required the required type */ public void setRequiredType(SequenceType required) { requiredType = required; } /** * Get the required type of this variable * @return the required type */ public SequenceType getRequiredType() { return requiredType; } /** * Indicate whether this variable is assignable using saxon:assign * @param assignable true if this variable is assignable */ public void setAssignable(boolean assignable) { if (assignable) { properties |= ASSIGNABLE; } else { properties &= ~ASSIGNABLE; } } /** * Indicate that this variable represents a required parameter * @param requiredParam true if this is a required parameter */ public void setRequiredParam(boolean requiredParam) { if (requiredParam) { properties |= REQUIRED; } else { properties &= ~REQUIRED; } } /** * Indicate that this variable represents a parameter that is implicitly required (because there is no * usable default value) * @param requiredParam true if this is an implicitly required parameter */ public void setImplicitlyRequiredParam(boolean requiredParam) { if (requiredParam) { properties |= IMPLICITLY_REQUIRED; } else { properties &= ~IMPLICITLY_REQUIRED; } } /** * Indicate whether this variable represents a tunnel parameter * @param tunnel true if this is a tunnel parameter */ public void setTunnel(boolean tunnel) { if (tunnel) { properties |= TUNNEL; } else { properties &= ~TUNNEL; } } /** * Set the nominal number of references to this variable * @param refCount the nominal number of references */ public void setReferenceCount(int refCount) { referenceCount = refCount; } /** * Get the evaluation mode of the variable * @return the evaluation mode (a constant in {@link ExpressionTool} */ public int getEvaluationMode() { if (evaluationMode == ExpressionTool.UNDECIDED && referenceCount == FilterExpression.FILTERED) { evaluationMode = ExpressionTool.MAKE_INDEXED_VARIABLE; } return evaluationMode; } /** * Test whether it is permitted to assign to the variable using the saxon:assign * extension element. This will only be true if the extra attribute saxon:assignable="yes" * is present. */ public final boolean isAssignable() { return (properties & ASSIGNABLE) != 0; } /** * Get the type of the result of this instruction. An xsl:variable instruction returns nothing, so the * type is empty. * @return the empty type. * @param th the type hierarchy cache */ public ItemType getItemType(TypeHierarchy th) { return EmptySequenceTest.getInstance(); } /** * Get the cardinality of the result of this instruction. An xsl:variable instruction returns nothing, so the * type is empty. * @return the empty cardinality. */ public int getCardinality() { return StaticProperty.EMPTY; } public boolean isGlobal() { return false; } /** * If this is a local variable held on the local stack frame, return the corresponding slot number. * In other cases, return -1. */ public int getLocalSlotNumber() { return slotNumber; } /** * Ask whether this variable represents a required parameter * @return true if this is a required parameter */ public final boolean isRequiredParam() { return (properties & REQUIRED) != 0; } /** * Ask whether this variable represents a parameter that is implicitly required, because there is no usable * default value * @return true if this variable is an implicitly required parameter */ public final boolean isImplicitlyRequiredParam() { return (properties & IMPLICITLY_REQUIRED) != 0; } /** * Ask whether this variable represents a tunnel parameter * @return true if this is a tunnel parameter */ public final boolean isTunnelParam() { return (properties & TUNNEL) != 0; } /** * Get the name of this instruction (that is xsl:variable, xsl:param etc) for diagnostics * @return the name of this instruction, as a name pool name code */ public int getInstructionNameCode() { return StandardNames.XSL_VARIABLE; } /** * Simplify this expression * @param visitor an expression * @return the simplified expression * @throws XPathException */ public Expression simplify(ExpressionVisitor visitor) throws XPathException { if (select != null) { select = visitor.simplify(select); } return this; } public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { if (select != null) { select = visitor.typeCheck(select, contextItemType); adoptChildExpression(select); } checkAgainstRequiredType(visitor); return this; } public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { if (select != null) { select = visitor.optimize(select, contextItemType); adoptChildExpression(select); if (isAssignable()) { evaluationMode = ExpressionTool.eagerEvaluationMode(select); } else if (referenceCount == FilterExpression.FILTERED) { evaluationMode = ExpressionTool.MAKE_INDEXED_VARIABLE; } else { evaluationMode = ExpressionTool.lazyEvaluationMode(select); } } return this; } /** * Copy an expression. This makes a deep copy. * * @return the copy of the original expression */ public Expression copy() { throw new UnsupportedOperationException("copy"); } /** * Check the select expression against the required type. * @param visitor an expression visitor * @throws XPathException */ private void checkAgainstRequiredType(ExpressionVisitor visitor) throws XPathException { // Note, in some cases we are doing this twice. RoleLocator role = new RoleLocator(RoleLocator.VARIABLE, variableQName, 0); //role.setSourceLocator(this); SequenceType r = requiredType; if (r != null && select != null) { // check that the expression is consistent with the required type select = TypeChecker.staticTypeCheck(select, requiredType, false, role, visitor); } } /** * Evaluate an expression as a single item. This always returns either a single Item or * null (denoting the empty sequence). No conversion is done. This method should not be * used unless the static type of the expression is a subtype of "item" or "item?": that is, * it should not be called if the expression may return a sequence. There is no guarantee that * this condition will be detected. * * @param context The context in which the expression is to be evaluated * @exception XPathException if any dynamic error occurs evaluating the * expression * @return the node or atomic value that results from evaluating the * expression; or null to indicate that the result is an empty * sequence */ public Item evaluateItem(XPathContext context) throws XPathException { process(context); return null; } /** * Return an Iterator to iterate over the values of a sequence. The value of every * expression can be regarded as a sequence, so this method is supported for all * expressions. This default implementation relies on the process() method: it * "pushes" the results of the instruction to a sequence in memory, and then * iterates over this in-memory sequence. * * In principle instructions should implement a pipelined iterate() method that * avoids the overhead of intermediate storage. * * @exception XPathException if any dynamic error occurs evaluating the * expression * @param context supplies the context for evaluation * @return a SequenceIterator that can be used to iterate over the result * of the expression */ public SequenceIterator iterate(XPathContext context) throws XPathException { evaluateItem(context); return EmptyIterator.getInstance(); } /** * Evaluate the variable. That is, * get the value of the select expression if present or the content * of the element otherwise, either as a tree or as a sequence * @param context the XPath dynamic context * @return the result of evaluating the variable */ public ValueRepresentation getSelectValue(XPathContext context) throws XPathException { if (select==null) { throw new AssertionError("*** No select expression!!"); // The value of the variable is a sequence of nodes and/or atomic values } else { // There is a select attribute: do a lazy evaluation of the expression, // which will already contain any code to force conversion to the required type. return ExpressionTool.evaluate(select, evaluationMode, context, referenceCount); } } /** * Handle promotion offers, that is, non-local tree rewrites. * @param offer The type of rewrite being offered * @throws XPathException */ protected void promoteInst(PromotionOffer offer) throws XPathException { if (select != null) { select = doPromotion(select, offer); } } /** * Get all the XPath expressions associated with this instruction * (in XSLT terms, the expression present on attributes of the instruction, * as distinct from the child instructions in a sequence construction) */ public Iterator iterateSubExpressions() { if (select != null) { return new MonoIterator(select); } else { return Collections.EMPTY_LIST.iterator(); } } /** * Replace one subexpression by a replacement subexpression * @param original the original subexpression * @param replacement the replacement subexpression * @return true if the original subexpression is found */ public boolean replaceSubExpression(Expression original, Expression replacement) { boolean found = false; if (select == original) { select = replacement; found = true; } return found; } /** * Diagnostic print of expression structure. The abstract expression tree * is written to the supplied output destination. */ public void explain(ExpressionPresenter out) { out.startElement("variable"); out.emitAttribute("name", variableQName.getDisplayName()); if (select != null) { select.explain(out); } out.endElement(); } /** * Get the slot number allocated to this variable * @return the slot number, that is the position allocated to the variable on its stack frame */ public int getSlotNumber() { return slotNumber; } /** * Set the slot number of this variable * @param s the slot number, that is, the position allocated to this variable on its stack frame */ public void setSlotNumber(int s) { slotNumber = s; } /** * Set the name of the variable * @param s the name of the variable (a QName) */ public void setVariableQName(StructuredQName s) { variableQName = s; } /** * Get the name of this variable * @return the name of this variable (a QName) */ public StructuredQName getVariableQName() { return variableQName; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/instruct/TailCallReturner.java0000644000175000017500000000336211033112257023335 0ustar eugeneeugenepackage net.sf.saxon.instruct; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.trans.XPathException; /** * This interface represents an expression that is capable of being processed leaving tail calls for the * calling instruction to deal with. */ public interface TailCallReturner { /** * ProcessLeavingTail: called to do the real work of this instruction. This method * must be implemented in each subclass. The results of the instruction are written * to the current Receiver, which can be obtained via the Controller. * @param context The dynamic context of the transformation, giving access to the current node, * the current variables, etc. * @return null if the instruction has completed execution; or a TailCall indicating * a function call or template call that is delegated to the caller, to be made after the stack has * been unwound so as to save stack space. */ public TailCall processLeavingTail(XPathContext context) throws XPathException; } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/instruct/FixedElement.java0000644000175000017500000005745711055041526022514 0ustar eugeneeugenepackage net.sf.saxon.instruct; import net.sf.saxon.Configuration; import net.sf.saxon.event.Receiver; import net.sf.saxon.expr.*; import net.sf.saxon.om.NamePool; import net.sf.saxon.om.QNameException; import net.sf.saxon.om.StandardNames; import net.sf.saxon.om.Validation; import net.sf.saxon.pattern.CombinedNodeTest; import net.sf.saxon.pattern.ContentTypeTest; import net.sf.saxon.pattern.NameTest; import net.sf.saxon.pattern.NodeKindTest; import net.sf.saxon.trace.ExpressionPresenter; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.*; import org.xml.sax.Locator; import java.util.Iterator; /** * An instruction that creates an element node whose name is known statically. * Used for literal results elements in XSLT, for direct element constructors * in XQuery, and for xsl:element in cases where the name and namespace are * known statically. */ public class FixedElement extends ElementCreator { // TODO: create a separate class for the case where schema validation is involved // TODO: if the sequence of child elements is statically known (e.g. if the content is a Block consisting // entirely of FixedElement instructions) then validate against the schema content model at compile time. private int nameCode; protected int[] namespaceCodes = null; private ItemType itemType; /** * Create an instruction that creates a new element node * @param nameCode Represents the name of the element node * @param namespaceCodes List of namespaces to be added to the element node. * May be null if none are required. * @param inheritNamespaces true if the children of this element are to inherit its namespaces * @param schemaType Type annotation for the new element node * @param validation Validation mode to be applied, for example STRICT, LAX, SKIP */ public FixedElement(int nameCode, int[] namespaceCodes, boolean inheritNamespaces, SchemaType schemaType, int validation) { this.nameCode = nameCode; this.namespaceCodes = namespaceCodes; this.inheritNamespaces = inheritNamespaces; setSchemaType(schemaType); this.validation = validation; preservingTypes = schemaType == null && validation == Validation.PRESERVE; } // public InstructionInfo getInstructionInfo() { // InstructionDetails details = (InstructionDetails)super.getInstructionInfo(); // details.setConstructType(Location.LITERAL_RESULT_ELEMENT); // details.setObjectNameCode(nameCode); // return details; // } /** * Simplify an expression. This performs any context-independent rewriting * @param visitor the expression visitor * @return the simplified expression * @throws net.sf.saxon.trans.XPathException * if an error is discovered during expression rewriting */ public Expression simplify(ExpressionVisitor visitor) throws XPathException { final Configuration config = visitor.getConfiguration(); setLazyConstruction(config.isLazyConstructionMode()); preservingTypes |= !config.isSchemaAware(Configuration.XML_SCHEMA); int val = validation; SchemaType type = getSchemaType(); itemType = computeFixedElementItemType(this, visitor.getStaticContext(), val, type, nameCode, content); return super.simplify(visitor); } public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { Expression e = super.optimize(visitor, contextItemType); if (e != this) { return e; } // Remove any unnecessary creation of namespace nodes by child literal result elements. // Specifically, if this instruction creates a namespace node, then a child literal result element // doesn't need to create the same namespace if all the following conditions are true: // (a) the child element is in the same namespace as its parent, and // (b) this element doesn't specify xsl:inherit-namespaces="no" // (c) the child element is incapable of creating attributes in a non-null namespace if (!inheritNamespaces) { return this; } if (namespaceCodes == null || namespaceCodes.length == 0) { return this; } NamePool pool = visitor.getExecutable().getConfiguration().getNamePool(); int uriCode = getURICode(pool); if (content instanceof FixedElement) { if (((FixedElement)content).getURICode(pool) == uriCode) { ((FixedElement)content).removeRedundantNamespaces(visitor, namespaceCodes); } return this; } if (content instanceof Block) { Iterator iter = content.iterateSubExpressions(); while (iter.hasNext()) { Expression exp = (Expression)iter.next(); if (exp instanceof FixedElement && ((FixedElement)exp).getURICode(pool) == uriCode) { ((FixedElement)exp).removeRedundantNamespaces(visitor, namespaceCodes); } } } return this; } /** * Remove namespaces that are not required for this element because they are output on * the parent element * @param visitor the expression visitor * @param parentNamespaces the namespaces that are output by the parent element */ private void removeRedundantNamespaces(ExpressionVisitor visitor, int[] parentNamespaces) { // It's only safe to remove any namespaces if the element is incapable of creating any attribute nodes // in a non-null namespace // This is because namespaces created on this element take precedence over namespaces created by namespace // fixup based on the prefix used in the attribute name (see atrs24) if (namespaceCodes == null || namespaceCodes.length == 0) { return; } TypeHierarchy th = visitor.getConfiguration().getTypeHierarchy(); ItemType contentType = content.getItemType(th); boolean ok = th.relationship(contentType, NodeKindTest.ATTRIBUTE) == TypeHierarchy.DISJOINT; if (!ok) { // if the content might include attributes, discount any that are known to be in the null namespace if (content instanceof Block) { ok = true; Iterator iter = content.iterateSubExpressions(); while (iter.hasNext()) { Expression exp = (Expression)iter.next(); if (exp instanceof FixedAttribute) { int attNameCode = ((FixedAttribute)exp).getAttributeNameCode(); if (NamePool.getPrefixIndex(attNameCode) != 0) { ok = false; break; } } else { ItemType childType = exp.getItemType(th); if (th.relationship(childType, NodeKindTest.ATTRIBUTE) != TypeHierarchy.DISJOINT) { ok = false; break; } } } } } if (ok) { int removed = 0; for (int i=0; i 0) { if (removed == namespaceCodes.length) { namespaceCodes = null; } else { int[] ns2 = new int[namespaceCodes.length - removed]; int j=0; for (int i=0; i 0) { out.startSubsidiaryElement("withParams"); WithParam.displayExpressions(actualParams, out); out.endSubsidiaryElement(); } if (tunnelParams != null && tunnelParams.length > 0) { out.startSubsidiaryElement("tunnelParams"); WithParam.displayExpressions(tunnelParams, out); out.endSubsidiaryElement(); } out.endElement(); } /** * A CallTemplatePackage is an object that encapsulates the name of a template to be called, * the parameters to be supplied, and the execution context. This object can be returned as a tail * call, so that the actual call is made from a lower point on the stack, allowing a tail-recursive * template to execute in a finite stack size */ public static class CallTemplatePackage implements TailCall { private Template target; private ParameterSet params; private ParameterSet tunnelParams; private Instruction instruction; private XPathContext evaluationContext; /** * Construct a CallTemplatePackage that contains information about a call. * @param template the Template to be called * @param params the parameters to be supplied to the called template * @param tunnelParams the tunnel parameter supplied to the called template * @param evaluationContext saved context information from the Controller (current mode, etc) * which must be reset to ensure that the template is called with all the context information * intact */ public CallTemplatePackage(Template template, ParameterSet params, ParameterSet tunnelParams, Instruction instruction, XPathContext evaluationContext) { target = template; this.params = params; this.tunnelParams = tunnelParams; this.instruction = instruction; this.evaluationContext = evaluationContext; } /** * Process the template call encapsulated by this package. * @return another TailCall. This will never be the original call, but it may be the next * recursive call. For example, if A calls B which calls C which calls D, then B may return * a TailCall to A representing the call from B to C; when this is processed, the result may be * a TailCall representing the call from C to D. * @throws XPathException if a dynamic error occurs */ public TailCall processLeavingTail() throws XPathException { // TODO: the idea of tail call optimization is to reuse the caller's stack frame rather than // creating a new one. We're doing this for the Java stack, but not for the context stack where // local variables are held. It should be possible to avoid creating a new context, and instead // to update the existing one in situ. XPathContextMajor c2 = evaluationContext.newContext(); c2.setOrigin(instruction); c2.setLocalParameters(params); c2.setTunnelParameters(tunnelParams); c2.openStackFrame(target.getStackFrameMap()); // System.err.println("Tail call on template"); return target.expand(c2); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/instruct/BlockIterator.java0000644000175000017500000001032711033112257022664 0ustar eugeneeugenepackage net.sf.saxon.instruct; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.om.Item; import net.sf.saxon.expr.SequenceIterable; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.trans.XPathException; /** * Iterate over the instructions in the Block, concatenating the result of each instruction * into a single combined sequence. */ public class BlockIterator implements SequenceIterator { private SequenceIterable[] children; private int i = 0; private SequenceIterator child; private XPathContext context; private Item current; private int position = 0; public BlockIterator(SequenceIterable[] children, XPathContext context) { this.children = children; this.context = context; } /** * Get the next item in the sequence.
    * * @return the next item, or null if there are no more items. * @throws net.sf.saxon.trans.XPathException * if an error occurs retrieving the next item */ public Item next() throws XPathException { if (position < 0) { return null; } while (true) { if (child == null) { child = children[i++].iterate(context); } current = child.next(); if (current != null) { position++; return current; } child = null; if (i >= children.length) { current = null; position = -1; return null; } } } /** * Get the current value in the sequence (the one returned by the * most recent call on next()). This will be null before the first * call of next(). * * @return the current item, the one most recently returned by a call on * next(); or null, if next() has not been called, or if the end * of the sequence has been reached. */ public Item current() { return current; } /** * Get the current position. This will be zero before the first call * on next(), otherwise it will be the number of times that next() has * been called. * * @return the current position, the position of the item returned by the * most recent call of next() */ public int position() { return position; } public void close() { } /** * Get another SequenceIterator that iterates over the same items as the original, * but which is repositioned at the start of the sequence. * * @return a SequenceIterator that iterates over the same items, * positioned before the first item * @throws net.sf.saxon.trans.XPathException * if any error occurs */ public SequenceIterator getAnother() throws XPathException { return new BlockIterator(children, context); } /** * Get properties of this iterator, as a bit-significant integer. * * @return the properties of this iterator. This will be some combination of * properties such as {@link SequenceIterator#GROUNDED}, {@link SequenceIterator#LAST_POSITION_FINDER}, * and {@link SequenceIterator#LOOKAHEAD}. It is always * acceptable to return the value zero, indicating that there are no known special properties. * It is acceptable for the properties of the iterator to change depending on its state. */ public int getProperties() { return 0; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/instruct/AnalyzeString.java0000644000175000017500000005007711055333001022714 0ustar eugeneeugenepackage net.sf.saxon.instruct; import net.sf.saxon.Configuration; import net.sf.saxon.Platform; import net.sf.saxon.trace.ExpressionPresenter; import net.sf.saxon.expr.*; import net.sf.saxon.om.EmptyIterator; import net.sf.saxon.om.Item; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.om.StandardNames; import net.sf.saxon.pattern.EmptySequenceTest; import net.sf.saxon.regex.RegexIterator; import net.sf.saxon.regex.RegularExpression; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.*; import net.sf.saxon.value.SequenceType; import java.util.ArrayList; import java.util.Iterator; /** * An xsl:analyze-string element in the stylesheet. New at XSLT 2.0 */ public class AnalyzeString extends Instruction { private Expression select; private Expression regex; private Expression flags; private Expression matching; private Expression nonMatching; private RegularExpression pattern; /** * Construct an AnalyzeString instruction * * @param select the expression containing the input string * @param regex the regular expression * @param flags the flags parameter * @param matching actions to be applied to a matching substring * @param nonMatching actions to be applied to a non-matching substring * @param pattern the compiled regular expression, if it was known statically */ public AnalyzeString(Expression select, Expression regex, Expression flags, Expression matching, Expression nonMatching, RegularExpression pattern) { this.select = select; this.regex = regex; this.flags = flags; this.matching = matching; this.nonMatching = nonMatching; this.pattern = pattern; Iterator kids = iterateSubExpressions(); while (kids.hasNext()) { Expression child = (Expression)kids.next(); adoptChildExpression(child); } } public int getInstructionNameCode() { return StandardNames.XSL_ANALYZE_STRING; } /** * An implementation of Expression must provide at least one of the methods evaluateItem(), iterate(), or process(). * This method indicates which of these methods is prefered. */ public int getImplementationMethod() { return Expression.PROCESS_METHOD | Expression.ITERATE_METHOD; } /** * Get the expression used to process matching substrings * @return the expression used to process matching substrings */ public Expression getMatchingExpression() { return matching; } /** * Get the expression used to process non-matching substrings * @return the expression used to process non-matching substrings */ public Expression getNonMatchingExpression() { return nonMatching; } /** * Simplify an expression. This performs any static optimization (by rewriting the expression * as a different expression). * * @return the simplified expression * @throws XPathException if an error is discovered during expression * rewriting * @param visitor an expression visitor */ public Expression simplify(ExpressionVisitor visitor) throws XPathException { select = visitor.simplify(select); regex = visitor.simplify(regex); flags = visitor.simplify(flags); matching = visitor.simplify(matching); nonMatching = visitor.simplify(nonMatching); return this; } public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { select = visitor.typeCheck(select, contextItemType); adoptChildExpression(select); regex = visitor.typeCheck(regex, contextItemType); adoptChildExpression(regex); flags = visitor.typeCheck(flags, contextItemType); adoptChildExpression(flags); if (matching != null) { matching = visitor.typeCheck(matching, BuiltInAtomicType.STRING); adoptChildExpression(matching); } if (nonMatching != null) { nonMatching = visitor.typeCheck(nonMatching, BuiltInAtomicType.STRING); adoptChildExpression(nonMatching); } // Following type checking has already been done in the case of XSLT xsl:analyze-string, but is // needed where the instruction is generated from saxon:analyze-string extension function RoleLocator role = new RoleLocator(RoleLocator.INSTRUCTION, "analyze-string/select", 0); //role.setSourceLocator(this); select = TypeChecker.staticTypeCheck(select, SequenceType.SINGLE_STRING, false, role, visitor); role = new RoleLocator(RoleLocator.INSTRUCTION, "analyze-string/regex", 0); //role.setSourceLocator(this); regex = TypeChecker.staticTypeCheck(regex, SequenceType.SINGLE_STRING, false, role, visitor); role = new RoleLocator(RoleLocator.INSTRUCTION, "analyze-string/flags", 0); //role.setSourceLocator(this); flags = TypeChecker.staticTypeCheck(flags, SequenceType.SINGLE_STRING, false, role, visitor); return this; } public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { select = visitor.optimize(select, contextItemType); adoptChildExpression(select); regex = visitor.optimize(regex, contextItemType); adoptChildExpression(regex); flags = visitor.optimize(flags, contextItemType); adoptChildExpression(flags); if (matching != null) { matching = matching.optimize(visitor, BuiltInAtomicType.STRING); adoptChildExpression(matching); } if (nonMatching != null) { nonMatching = nonMatching.optimize(visitor, BuiltInAtomicType.STRING); adoptChildExpression(nonMatching); } if (pattern == null && regex instanceof StringLiteral && flags instanceof StringLiteral) { try { final Platform platform = Configuration.getPlatform(); final CharSequence regex = ((StringLiteral)this.regex).getStringValue(); final CharSequence flagstr = ((StringLiteral)flags).getStringValue(); final int xmlVersion = visitor.getConfiguration().getXMLVersion(); pattern = platform.compileRegularExpression( regex, xmlVersion, RegularExpression.XPATH_SYNTAX, flagstr); if (pattern.matches("")) { invalidRegex("The regular expression must not be one that matches a zero-length string", "XTDE1150"); } } catch (XPathException err) { if ("FORX0001".equals(err.getErrorCodeLocalPart())) { invalidRegex("Error in regular expression flags: " + err, "XTDE1145"); } else { invalidRegex("Error in regular expression: " + err, "XTDE1140"); } } } return this; } private void invalidRegex(String message, String errorCode) throws XPathException { pattern = null; XPathException err = new XPathException(message, errorCode); err.setLocator(this); throw err; } /** * Copy an expression. This makes a deep copy. * * @return the copy of the original expression */ public Expression copy() { throw new UnsupportedOperationException("copy"); } /** * Check that any elements and attributes constructed or returned by this expression are acceptable * in the content model of a given complex type. It's always OK to say yes, since the check will be * repeated at run-time. The process of checking element and attribute constructors against the content * model of a complex type also registers the type of content expected of those constructors, so the * static validation can continue recursively. */ public void checkPermittedContents(SchemaType parentType, StaticContext env, boolean whole) throws XPathException { if (matching != null) { matching.checkPermittedContents(parentType, env, false); } if (nonMatching != null) { nonMatching.checkPermittedContents(parentType, env, false); } } /** * Get the item type of the items returned by evaluating this instruction * * @return the static item type of the instruction * @param th the type hierarchy cache */ public ItemType getItemType(TypeHierarchy th) { if (matching != null) { if (nonMatching != null) { return Type.getCommonSuperType(matching.getItemType(th), nonMatching.getItemType(th), th); } else { return matching.getItemType(th); } } else { if (nonMatching != null) { return nonMatching.getItemType(th); } else { return EmptySequenceTest.getInstance(); } } } /** * Compute the dependencies of an expression, as the union of the * dependencies of its subexpressions. (This is overridden for path expressions * and filter expressions, where the dependencies of a subexpression are not all * propogated). This method should be called only once, to compute the dependencies; * after that, getDependencies should be used. * * @return the depencies, as a bit-mask */ public int computeDependencies() { // some of the dependencies in the "action" part and in the grouping and sort keys aren't relevant, // because they don't depend on values set outside the for-each-group expression int dependencies = 0; dependencies |= select.getDependencies(); dependencies |= regex.getDependencies(); dependencies |= flags.getDependencies(); if (matching != null) { dependencies |= (matching.getDependencies() &~ (StaticProperty.DEPENDS_ON_FOCUS | StaticProperty.DEPENDS_ON_REGEX_GROUP)); } if (nonMatching != null) { dependencies |= (nonMatching.getDependencies() &~ (StaticProperty.DEPENDS_ON_FOCUS | StaticProperty.DEPENDS_ON_REGEX_GROUP)); } return dependencies; } /** * Handle promotion offers, that is, non-local tree rewrites. * * @param offer The type of rewrite being offered * @throws XPathException */ protected void promoteInst(PromotionOffer offer) throws XPathException { select = doPromotion(select, offer); regex = doPromotion(regex, offer); flags = doPromotion(flags, offer); if (matching != null) { matching = doPromotion(matching, offer); } if (nonMatching != null) { nonMatching = doPromotion(nonMatching, offer); } } /** * Get all the XPath expressions associated with this instruction * (in XSLT terms, the expression present on attributes of the instruction, * as distinct from the child instructions in a sequence construction) */ public Iterator iterateSubExpressions() { ArrayList list = new ArrayList(5); list.add(select); list.add(regex); list.add(flags); if (matching != null) { list.add(matching); } if (nonMatching != null) { list.add(nonMatching); } return list.iterator(); } /** * Given an expression that is an immediate child of this expression, test whether * the evaluation of the parent expression causes the child expression to be * evaluated repeatedly * @param child the immediate subexpression * @return true if the child expression is evaluated repeatedly */ public boolean hasLoopingSubexpression(Expression child) { return child == matching || child == nonMatching; } /** * Replace one subexpression by a replacement subexpression * @param original the original subexpression * @param replacement the replacement subexpression * @return true if the original subexpression is found */ public boolean replaceSubExpression(Expression original, Expression replacement) { boolean found = false; if (select == original) { select = replacement; found = true; } if (regex == original) { regex = replacement; found = true; } if (flags == original) { flags = replacement; found = true; } if (matching == original) { matching = replacement; found = true; } if (nonMatching == original) { nonMatching = replacement; found = true; } return found; } /** * ProcessLeavingTail: called to do the real work of this instruction. This method * must be implemented in each subclass. The results of the instruction are written * to the current Receiver, which can be obtained via the Controller. * @param context The dynamic context of the transformation, giving access to the current node, * the current variables, etc. * @return null if the instruction has completed execution; or a TailCall indicating * a function call or template call that is delegated to the caller, to be made after the stack has * been unwound so as to save stack space. */ public TailCall processLeavingTail(XPathContext context) throws XPathException { RegexIterator iter = getRegexIterator(context); XPathContextMajor c2 = context.newContext(); c2.setOrigin(this); c2.setCurrentIterator(iter); c2.setCurrentRegexIterator(iter); while (true) { Item it = iter.next(); if (it == null) { break; } if (iter.isMatching()) { if (matching != null) { matching.process(c2); } } else { if (nonMatching != null) { nonMatching.process(c2); } } } return null; } /** * Get an iterator over the substrings defined by the regular expression * * @param context the evaluation context * @return an iterator that returns matching and nonmatching substrings * @throws XPathException */ private RegexIterator getRegexIterator(XPathContext context) throws XPathException { CharSequence input = select.evaluateAsString(context); RegularExpression re = pattern; if (re == null) { CharSequence flagstr = flags.evaluateAsString(context); final Platform platform = Configuration.getPlatform(); final int xmlVersion = context.getConfiguration().getXMLVersion(); re = platform.compileRegularExpression( regex.evaluateAsString(context), xmlVersion, RegularExpression.XPATH_SYNTAX, flagstr); if (re.matches("")) { dynamicError("The regular expression must not be one that matches a zero-length string", "XTDE1150", context); } } return re.analyze(input); } /** * Return an Iterator to iterate over the values of a sequence. The value of every * expression can be regarded as a sequence, so this method is supported for all * expressions. This default implementation handles iteration for expressions that * return singleton values: for non-singleton expressions, the subclass must * provide its own implementation. * * @param context supplies the context for evaluation * @return a SequenceIterator that can be used to iterate over the result * of the expression * @throws net.sf.saxon.trans.XPathException * if any dynamic error occurs evaluating the * expression */ public SequenceIterator iterate(XPathContext context) throws XPathException { RegexIterator iter = getRegexIterator(context); XPathContextMajor c2 = context.newContext(); c2.setOrigin(this); c2.setCurrentIterator(iter); c2.setCurrentRegexIterator(iter); AnalyzeMappingFunction fn = new AnalyzeMappingFunction(iter, c2); return new ContextMappingIterator(fn, c2); } /** * Diagnostic print of expression structure. The abstract expression tree * is written to the supplied output destination. */ public void explain(ExpressionPresenter out) { out.startElement("analyzeString"); out.startSubsidiaryElement("select"); select.explain(out); out.endSubsidiaryElement(); out.startSubsidiaryElement("regex"); regex.explain(out); out.endSubsidiaryElement(); out.startSubsidiaryElement("flags"); flags.explain(out); out.endSubsidiaryElement(); if (matching != null) { out.startSubsidiaryElement("matching"); matching.explain(out); out.endSubsidiaryElement(); } if (nonMatching != null) { out.startSubsidiaryElement("nonMatching"); nonMatching.explain(out); out.endSubsidiaryElement(); } out.endElement(); } /** * Mapping function that maps the sequence of matching/non-matching strings to the * sequence delivered by applying the matching-substring and non-matching-substring * expressions respectively to each such string */ private class AnalyzeMappingFunction implements ContextMappingFunction { private RegexIterator base; private XPathContext c2; public AnalyzeMappingFunction(RegexIterator base, XPathContext c2) { this.base = base; this.c2 = c2; } /** * Map one item to a sequence. * * @param context The processing context. Some mapping functions use this because they require * context information. Some mapping functions modify the context by maintaining the context item * and position. In other cases, the context may be null. * @return either (a) a SequenceIterator over the sequence of items that the supplied input * item maps to, or (b) an Item if it maps to a single item, or (c) null if it maps to an empty * sequence. */ public SequenceIterator map(XPathContext context) throws XPathException { if (base.isMatching()) { if (matching != null) { return matching.iterate(c2); } } else { if (nonMatching != null) { return nonMatching.iterate(c2); } } return EmptyIterator.getInstance(); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/instruct/Instruction.java0000644000175000017500000003716311033112257022450 0ustar eugeneeugenepackage net.sf.saxon.instruct; import net.sf.saxon.Configuration; import net.sf.saxon.Controller; import net.sf.saxon.event.PipelineConfiguration; import net.sf.saxon.event.SequenceOutputter; import net.sf.saxon.expr.*; import net.sf.saxon.om.EmptyIterator; import net.sf.saxon.om.Item; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.om.SingletonIterator; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.Type; import net.sf.saxon.type.TypeHierarchy; import javax.xml.transform.SourceLocator; /** * Abstract superclass for all instructions in the compiled stylesheet. * This represents a compiled instruction, and as such, the minimum information is * retained from the original stylesheet.
    * Note: this class implements SourceLocator: that is, it can identify where in the stylesheet * the source instruction was located. */ public abstract class Instruction extends Expression implements SourceLocator, TailCallReturner { /** * Constructor */ public Instruction() {} /** * An implementation of Expression must provide at least one of the methods evaluateItem(), iterate(), or process(). * This method indicates which of these methods is prefered. For instructions this is the process() method. */ public int getImplementationMethod() { return Expression.PROCESS_METHOD; } /** * Get the namecode of the instruction for use in diagnostics * @return a code identifying the instruction: typically but not always * the fingerprint of a name in the XSLT namespace */ public int getInstructionNameCode() { return -1; } /** * Get the item type of the items returned by evaluating this instruction * @return the static item type of the instruction * @param th the type hierarchy cache */ public ItemType getItemType(TypeHierarchy th) { return Type.ITEM_TYPE; } /** * Get the cardinality of the sequence returned by evaluating this instruction * @return the static cardinality */ public int computeCardinality() { return StaticProperty.ALLOWS_ZERO_OR_MORE; } /** * ProcessLeavingTail: called to do the real work of this instruction. This method * must be implemented in each subclass. The results of the instruction are written * to the current Receiver, which can be obtained via the Controller. * @param context The dynamic context of the transformation, giving access to the current node, * the current variables, etc. * @return null if the instruction has completed execution; or a TailCall indicating * a function call or template call that is delegated to the caller, to be made after the stack has * been unwound so as to save stack space. */ public abstract TailCall processLeavingTail(XPathContext context) throws XPathException; /** * Process the instruction, without returning any tail calls * @param context The dynamic context, giving access to the current node, * the current variables, etc. */ public void process(XPathContext context) throws XPathException { try { TailCall tc = processLeavingTail(context); while (tc != null) { tc = tc.processLeavingTail(); } } catch (XPathException err) { err.maybeSetLocation(this); throw err; } } /** * Get a SourceLocator identifying the location of this instruction * @return the location of this instruction in the source stylesheet or query */ public SourceLocator getSourceLocator() { return this; } /** * Construct an exception with diagnostic information. Note that this method * returns the exception, it does not throw it: that is up to the caller. * @param loc the location of the error * @param error The exception containing information about the error * @param context The controller of the transformation * @return an exception based on the supplied exception, but with location information * added relating to this instruction */ protected static XPathException dynamicError(SourceLocator loc, XPathException error, XPathContext context) { if (error instanceof TerminationException) { return error; } error.maybeSetLocation(loc); error.maybeSetContext(context); return error; } /** * Assemble a ParameterSet. Method used by instructions that have xsl:with-param * children. This method is used for the non-tunnel parameters. * @param context the XPath dynamic context * @param actualParams the set of with-param parameters that specify tunnel="no" * @return a ParameterSet */ protected static ParameterSet assembleParams(XPathContext context, WithParam[] actualParams) throws XPathException { if (actualParams == null || actualParams.length == 0) { return null; } ParameterSet params = new ParameterSet(actualParams.length); for (int i=0; i *

    This method should always return a result, though it may be the best approximation * that is available at the time.

    * * @return a value such as Type.STRING, Type.BOOLEAN, Type.NUMBER, * Type.NODE, or Type.ITEM (meaning not known at compile time) * @param th the type hierarchy cache */ public ItemType getItemType(TypeHierarchy th) { return BuiltInAtomicType.STRING; } /** * Diagnostic print of expression structure. The abstract expression tree * is written to the supplied output destination. */ public void explain(ExpressionPresenter out) { out.startElement("simpleContentConstructor"); select.explain(out); separator.explain(out); out.endElement(); } /** * Get the immediate sub-expressions of this expression. Default implementation * returns a zero-length array, appropriate for an expression that has no * sub-expressions. * * @return an iterator containing the sub-expressions of this expression */ public Iterator iterateSubExpressions() { return new PairIterator(select, separator); } /** * Replace one subexpression by a replacement subexpression * @param original the original subexpression * @param replacement the replacement subexpression * @return true if the original subexpression is found */ public boolean replaceSubExpression(Expression original, Expression replacement) { boolean found = false; if (select == original) { select = replacement; found = true; } if (separator == original) { separator = replacement; found = true; } return found; } /** * Offer promotion for this subexpression. The offer will be accepted if the subexpression * is not dependent on the factors (e.g. the context item) identified in the PromotionOffer. * By default the offer is not accepted - this is appropriate in the case of simple expressions * such as constant values and variable references where promotion would give no performance * advantage. This method is always called at compile time. * * @param offer details of the offer, for example the offer to move * expressions that don't depend on the context to an outer level in * the containing expression * @return if the offer is not accepted, return this expression unchanged. * Otherwise return the result of rewriting the expression to promote * this subexpression * @throws net.sf.saxon.trans.XPathException * if any error is detected */ public Expression promote(PromotionOffer offer) throws XPathException { Expression exp = offer.accept(this); if (exp!=null) { return exp; } else { select = doPromotion(select, offer); separator = doPromotion(separator, offer); return this; } } /** * Evaluate an expression as a single item. This always returns either a single Item or * null (denoting the empty sequence). No conversion is done. This method should not be * used unless the static type of the expression is a subtype of "item" or "item?": that is, * it should not be called if the expression may return a sequence. There is no guarantee that * this condition will be detected. * * @param context The context in which the expression is to be evaluated * @return the node or atomic value that results from evaluating the * expression; or null to indicate that the result is an empty * sequence * @throws net.sf.saxon.trans.XPathException * if any dynamic error occurs evaluating the * expression */ public Item evaluateItem(XPathContext context) throws XPathException { SequenceIterator iter; if (isSingleton) { // optimize for this case Item item = select.evaluateItem(context); if (item == null || item instanceof StringValue) { return item; } else if (item instanceof AtomicValue) { return ((AtomicValue)item).convert(BuiltInAtomicType.STRING, true, context).asAtomic(); } else { iter = SingletonIterator.makeIterator(item); } } else { iter = select.iterate(context); } FastStringBuffer sb = new FastStringBuffer(1024); boolean prevText = false; boolean first = true; CharSequence sep = null; while (true) { Item item = iter.next(); if (item==null) { break; } if (item instanceof NodeInfo) { if (((NodeInfo)item).getNodeKind() == Type.TEXT) { CharSequence s = item.getStringValueCS(); if (s.length() > 0) { if (!first && !prevText) { if (sep == null) { sep = separator.evaluateItem(context).getStringValueCS(); } sb.append(sep); } first = false; sb.append(s); prevText = true; } } else { prevText = false; SequenceIterator iter2 = item.getTypedValue(); while (true) { Item item2 = iter2.next(); if (item2 == null) { break; } if (!first) { if (sep == null) { sep = separator.evaluateItem(context).getStringValueCS(); } sb.append(sep); } first = false; sb.append(item2.getStringValueCS()); } } } else { if (!first) { if (sep == null) { sep = separator.evaluateItem(context).getStringValueCS(); } sb.append(sep); } first = false; prevText = false; sb.append(item.getStringValueCS()); } } return StringValue.makeStringValue(sb.condense()); } /** * An implementation of Expression must provide at least one of the methods evaluateItem(), iterate(), or process(). * This method indicates which of these methods is prefered. */ public int getImplementationMethod() { return Expression.EVALUATE_METHOD; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/instruct/Bindery.java0000644000175000017500000003147111033112257021517 0ustar eugeneeugenepackage net.sf.saxon.instruct; import net.sf.saxon.expr.*; import net.sf.saxon.om.*; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.*; import net.sf.saxon.type.*; import net.sf.saxon.pattern.NameTest; import java.net.URI; import java.net.URISyntaxException; /** * The Bindery class holds information about variables and their values. From Saxon 8.1, it is * used only for global variables: local variables are now held in the XPathContext object. * * Variables are identified by a Binding object. Values will always be of class Value. */ public final class Bindery { private ValueRepresentation[] globals; // values of global variables and parameters private boolean[] busy; // set to true while variable is being evaluated private GlobalParameterSet globalParameters; // supplied global parameters private SlotManager globalVariableMap; // contains the mapping of variable names to slot numbers /** * Define how many slots are needed for global variables * @param map the SlotManager that keeps track of slot allocation for global variables. */ public void allocateGlobals(SlotManager map) { globalVariableMap = map; int n = map.getNumberOfVariables()+1; globals = new ValueRepresentation[n]; busy = new boolean[n]; for (int i=0; iIt is assumed that type-checking, of both the arguments and the results, * has been handled at compile time. That is, the expression supplied as the body * of the function must be wrapped in code to check or convert the result to the * required type, and calls on the function must be wrapped at compile time to check or * convert the supplied arguments. */ public abstract class Procedure implements Serializable, Container, InstructionInfo, LocationProvider { protected Expression body; private Executable executable; private String systemId; private int lineNumber; private SlotManager stackFrameMap; private int hostLanguage; public Procedure() {}; public void setBody(Expression body) { this.body = body; body.setContainer(this); } public void setHostLanguage(int language) { hostLanguage = language; } public int getHostLanguage() { return hostLanguage; } public final Expression getBody() { return body; } /** * Replace one subexpression by a replacement subexpression * @param original the original subexpression * @param replacement the replacement subexpression * @return true if the original subexpression is found */ public boolean replaceSubExpression(Expression original, Expression replacement) { boolean found = false; if (body == original) { body = replacement; found = true; } return found; } public void setStackFrameMap(SlotManager map) { stackFrameMap = map; } public SlotManager getStackFrameMap() { return stackFrameMap; } public final Executable getExecutable() { return executable; } public void setExecutable(Executable executable) { this.executable = executable; } /** * Get the LocationProvider allowing location identifiers to be resolved. */ public LocationProvider getLocationProvider() { return this; } public void setLineNumber(int lineNumber) { this.lineNumber = lineNumber; } public void setSystemId(String systemId) { this.systemId = systemId; } public int getLineNumber() { return lineNumber; } public String getSystemId() { return systemId; } public int getColumnNumber() { return -1; } public String getPublicId() { return null; } public String getSystemId(long locationId) { return systemId; } public int getLineNumber(long locationId) { return lineNumber; } public int getColumnNumber(long locationId) { return getColumnNumber(); } public Object getProperty(String name) { return null; } /** * Get an iterator over all the properties available. The values returned by the iterator * will be of type String, and each string can be supplied as input to the getProperty() * method to retrieve the value of the property. The iterator may return properties whose * value is null. */ public Iterator getProperties() { return Collections.EMPTY_LIST.iterator(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none // saxonb-9.1.0.8/bj/net/sf/saxon/instruct/DocumentInstr.java0000644000175000017500000003332511107304073022722 0ustar eugeneeugenepackage net.sf.saxon.instruct; import net.sf.saxon.Configuration; import net.sf.saxon.Controller; import net.sf.saxon.event.Builder; import net.sf.saxon.event.PipelineConfiguration; import net.sf.saxon.event.Receiver; import net.sf.saxon.event.SequenceReceiver; import net.sf.saxon.evpull.BracketedDocumentIterator; import net.sf.saxon.evpull.EventIterator; import net.sf.saxon.evpull.SingletonEventIterator; import net.sf.saxon.expr.*; import net.sf.saxon.functions.StringJoin; import net.sf.saxon.functions.SystemFunction; import net.sf.saxon.om.*; import net.sf.saxon.pattern.NodeKindTest; import net.sf.saxon.pattern.NodeTest; import net.sf.saxon.pull.UnconstructedDocument; import net.sf.saxon.trace.ExpressionPresenter; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.*; import net.sf.saxon.value.StringValue; import net.sf.saxon.value.TextFragmentValue; import net.sf.saxon.value.UntypedAtomicValue; /** * An instruction to create a document node. This corresponds to the xsl:document-node * instruction in XSLT. It is also used to support the document node constructor * expression in XQuery, and is generated implicitly within an xsl:variable * that constructs a temporary tree. * *

    Conceptually it represents an XSLT instruction xsl:document-node, * with no attributes, whose content is a complex content constructor for the * children of the document node.

    */ public class DocumentInstr extends ParentNodeConstructor { //private static final int[] treeSizeParameters = {50, 10, 5, 200}; // estimated size of a temporary tree: {nodes, attributes, namespaces, characters} private boolean textOnly; private String constantText; /** * Create a document constructor instruction * @param textOnly true if the content contains text nodes only * @param constantText if the content contains text nodes only and the text is known at compile time, * supplies the textual content * @param baseURI the base URI of the instruction */ public DocumentInstr(boolean textOnly, String constantText, String baseURI) { this.textOnly = textOnly; this.constantText = constantText; setBaseURI(baseURI); } /** * An implementation of Expression must provide at least one of the methods evaluateItem(), iterate(), or process(). * This method indicates which of these methods is prefered. For instructions this is the process() method. */ public int getImplementationMethod() { return Expression.EVALUATE_METHOD; } /** * Determine whether this is a "text only" document: essentially, an XSLT xsl:variable that contains * a single text node or xsl:value-of instruction. * @return true if this is a text-only document */ public boolean isTextOnly() { return textOnly; } /** * Simplify an expression. This performs any static optimization (by rewriting the expression * as a different expression). The default implementation does nothing. * * @return the simplified expression * @throws net.sf.saxon.trans.XPathException * if an error is discovered during expression rewriting * @param visitor an expression visitor */ public Expression simplify(ExpressionVisitor visitor) throws XPathException { setLazyConstruction(visitor.getConfiguration().isLazyConstructionMode()); return super.simplify(visitor); } /** * Check statically that the sequence of child instructions doesn't violate any obvious constraints * on the content of the node * @param env the static context * @throws XPathException */ protected void checkContentSequence(StaticContext env) throws XPathException { checkContentSequence(env, content, validation, getSchemaType()); } protected static void checkContentSequence(StaticContext env, Expression content, int validation, SchemaType type) throws XPathException { Expression[] components; if (content instanceof Block) { components = ((Block)content).getChildren(); } else { components = new Expression[] {content}; } int elementCount = 0; boolean isXSLT = content.getHostLanguage() == Configuration.XSLT; TypeHierarchy th = env.getConfiguration().getTypeHierarchy(); for (int i=0; i 1 && (validation==Validation.STRICT || validation==Validation.LAX || type!=null)) { XPathException de = new XPathException("A valid document must have only one child element"); if (isXSLT) { de.setErrorCode("XTTE1550"); } else { de.setErrorCode("XQDY0061"); } de.setLocator(components[i]); throw de; } if (validation==Validation.STRICT && components[i] instanceof FixedElement) { SchemaDeclaration decl = env.getConfiguration().getElementDeclaration( ((FixedElement)components[i]).getNameCode(null) & NamePool.FP_MASK); if (decl != null) { ((FixedElement)components[i]).getContentExpression(). checkPermittedContents(decl.getType(), env, true); } } } } } } /** * In the case of a text-only instruction (xsl:variable containing a text node or one or more xsl:value-of * instructions), return an expression that evaluates to the textual content as an instance of xs:untypedAtomic * @param env the static evaluation context * @return an expression that evaluates to the textual content */ public Expression getStringValueExpression(StaticContext env) { if (textOnly) { if (constantText != null) { return new StringLiteral(new UntypedAtomicValue(constantText)); } else if (content instanceof ValueOf) { return ((ValueOf)content).convertToStringJoin(env); } else { StringJoin fn = (StringJoin)SystemFunction.makeSystemFunction( "string-join", new Expression[]{content, new StringLiteral(StringValue.EMPTY_STRING)}); CastExpression cast = new CastExpression(fn, BuiltInAtomicType.UNTYPED_ATOMIC, false); ExpressionTool.copyLocationInfo(this, cast); return cast; } } else { throw new AssertionError("getStringValueExpression() called on non-text-only document instruction"); } } /** * Copy an expression. This makes a deep copy. * * @return the copy of the original expression */ public Expression copy() { DocumentInstr doc = new DocumentInstr(textOnly, constantText, getBaseURI()); doc.setContentExpression(content.copy()); doc.setValidationMode(getValidationMode()); doc.setSchemaType(getSchemaType()); doc.setLazyConstruction(isLazyConstruction()); return doc; } /** * Get the item type * @param th The TypeHierarchy * @return the in */ public ItemType getItemType(TypeHierarchy th) { return NodeKindTest.DOCUMENT; } public TailCall processLeavingTail(XPathContext context) throws XPathException { // TODO: we're always constructing the document in memory. Sometimes we could push it out directly. Item item = evaluateItem(context); if (item != null) { SequenceReceiver out = context.getReceiver(); out.append(item, locationId, NodeInfo.ALL_NAMESPACES); } return null; } /** * Evaluate as an expression. */ public Item evaluateItem(XPathContext context) throws XPathException { if (isLazyConstruction() && ( context.getConfiguration().areAllNodesUntyped() || (validation == Validation.PRESERVE && getSchemaType() == null))) { return new UnconstructedDocument(this, context); } else { Controller controller = context.getController(); DocumentInfo root; if (textOnly) { CharSequence textValue; if (constantText != null) { textValue = constantText; } else { FastStringBuffer sb = new FastStringBuffer(100); SequenceIterator iter = content.iterate(context); while (true) { Item item = iter.next(); if (item==null) break; sb.append(item.getStringValueCS()); } textValue = sb.condense(); } root = new TextFragmentValue(textValue, getBaseURI()); ((TextFragmentValue)root).setConfiguration(controller.getConfiguration()); } else { try { XPathContext c2 = context.newMinorContext(); c2.setOrigin(this); Builder builder = controller.makeBuilder(); //builder.setSizeParameters(treeSizeParameters); builder.setLineNumbering(controller.getConfiguration().isLineNumbering()); //receiver.setSystemId(getBaseURI()); builder.setBaseURI(getBaseURI()); builder.setTiming(false); PipelineConfiguration pipe = controller.makePipelineConfiguration(); pipe.setHostLanguage(getHostLanguage()); //pipe.setBaseURI(baseURI); builder.setPipelineConfiguration(pipe); c2.changeOutputDestination(null, builder, false, getHostLanguage(), validation, getSchemaType()); Receiver out = c2.getReceiver(); out.open(); out.startDocument(0); content.process(c2); out.endDocument(); out.close(); root = (DocumentInfo)builder.getCurrentRoot(); } catch (XPathException e) { e.maybeSetLocation(this); e.maybeSetContext(context); throw e; } } return root; } } public EventIterator iterateEvents(XPathContext context) throws XPathException { if (validation != Validation.PRESERVE) { // Schema validation can't be done in pull mode return new SingletonEventIterator(evaluateItem(context)); } return new BracketedDocumentIterator(content.iterateEvents(context)); } /** * Get the name of this instruction for diagnostic and tracing purposes * (the string "document-constructor") */ public int getInstructionNameCode() { return StandardNames.XSL_DOCUMENT; } /** * Diagnostic print of expression structure. The abstract expression tree * is written to the supplied output destination. */ public void explain(ExpressionPresenter out) { out.startElement("documentNode"); out.emitAttribute("validation", Validation.toString(validation)); if (getSchemaType() != null) { out.emitAttribute("type", getSchemaType().getDescription()); } content.explain(out); out.endElement(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/instruct/InstructionDetails.java0000644000175000017500000001324211033112257023746 0ustar eugeneeugenepackage net.sf.saxon.instruct; import net.sf.saxon.om.StructuredQName; import net.sf.saxon.trace.InstructionInfo; import net.sf.saxon.trace.Location; import java.io.Serializable; import java.util.HashMap; import java.util.Iterator; /** * Details about an instruction, used when reporting errors and when tracing */ public final class InstructionDetails implements InstructionInfo, Serializable { private int constructType = Location.UNCLASSIFIED; private String systemId = null; private int lineNumber = -1; private int columnNumber = -1; private StructuredQName objectName; private HashMap properties = new HashMap(5); public InstructionDetails() {} /** * Set the type of construct */ public void setConstructType(int type) { constructType = type; } /** * Get the construct type */ public int getConstructType() { return constructType; } /** * Set the URI of the module containing the instruction * @param systemId the module's URI */ public void setSystemId(String systemId) { this.systemId = systemId; } /** * Get the URI of the module containing the instruction * @return the module's URI */ public String getSystemId() { return systemId; } /** * Set the line number of the instruction within the module * @param lineNumber the line number */ public void setLineNumber(int lineNumber) { this.lineNumber = lineNumber; } /** * Get the line number of the instruction within its module * @return the line number */ public int getLineNumber() { return lineNumber; } /** * Set a name identifying the object of the expression, for example a function name, template name, * variable name, key name, element name, etc. This is used only where the name is known statically. */ public void setObjectName(StructuredQName qName) { objectName = qName; } /** * Get a name identifying the object of the expression, for example a function name, template name, * variable name, key name, element name, etc. This is used only where the name is known statically. */ public StructuredQName getObjectName() { if (objectName != null) { return objectName; } else { return null; } } /** * Set a named property of the instruction */ public void setProperty(String name, Object value) { properties.put(name, value); } /** * Get a named property of the instruction */ public Object getProperty(String name) { return properties.get(name); } /** * Get an iterator over all the properties available. The values returned by the iterator * will be of type String, and each string can be supplied as input to the getProperty() * method to retrieve the value of the property. */ public Iterator getProperties() { return properties.keySet().iterator(); } /** * Get the public ID of the module containing the instruction. This method * is provided to satisfy the SourceLocator interface. However, the public ID is * not maintained by Saxon, and the method always returns null * @return null */ public String getPublicId() { return null; } /** * Set the column number */ public void setColumnNumber(int column) { columnNumber = column; } /** * Get the column number identifying the position of the instruction. * @return -1 if column number is not known */ public int getColumnNumber() { return columnNumber; } /** * Get a description of the instruction */ // public String getDescription(NamePool pool) { // switch (constructType) { // case Location.INSTRUCTION: // return pool.getDisplayName(instructionNameCode); // case Location.LITERAL_RESULT_ELEMENT: // return "element constructor <" + pool.getDisplayName(objectNameCode) + ">"; // case Location.LITERAL_RESULT_ATTRIBUTE: // return "attribute constructor " + pool.getDisplayName(objectNameCode) + "=\"{...}\""; // default: // return "" + constructType; // } // } /** * Get the InstructionInfo details about the construct. This is to satisfy the InstructionInfoProvider * interface. */ public InstructionInfo getInstructionInfo() { return this; } public String getSystemId(long locationId) { return getSystemId(); } public int getLineNumber(long locationId) { return getLineNumber(); } public int getColumnNumber(long locationId) { return getColumnNumber(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/instruct/ResultDocument.java0000644000175000017500000011010511033112257023070 0ustar eugeneeugenepackage net.sf.saxon.instruct; import net.sf.saxon.Configuration; import net.sf.saxon.Controller; import net.sf.saxon.trans.Err; import net.sf.saxon.OutputURIResolver; import net.sf.saxon.event.SaxonOutputKeys; import net.sf.saxon.event.SequenceReceiver; import net.sf.saxon.event.StandardOutputResolver; import net.sf.saxon.expr.*; import net.sf.saxon.functions.EscapeURI; import net.sf.saxon.functions.Serialize; import net.sf.saxon.om.*; import net.sf.saxon.pattern.EmptySequenceTest; import net.sf.saxon.sort.IntHashMap; import net.sf.saxon.sort.IntIterator; import net.sf.saxon.trace.ExpressionPresenter; import net.sf.saxon.trans.SaxonErrorCode; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.SchemaType; import net.sf.saxon.type.Type; import net.sf.saxon.type.TypeHierarchy; import javax.xml.transform.OutputKeys; import javax.xml.transform.Result; import javax.xml.transform.TransformerException; import javax.xml.transform.dom.DOMResult; import javax.xml.transform.sax.SAXResult; import javax.xml.transform.stream.StreamResult; import java.util.ArrayList; import java.util.Iterator; import java.util.Properties; import java.util.StringTokenizer; /** * The compiled form of an xsl:result-document element in the stylesheet. *

    * The xsl:result-document element takes an attribute href="filename". The filename will * often contain parameters, e.g. {position()} to ensure that a different file is produced * for each element instance. *

    * There is a further attribute "format" which determines the format of the * output file, it identifies the name of an xsl:output element containing the output * format details. In addition, individual serialization properties may be specified as attributes. * These are attribute value templates, so they may need to be computed at run-time. */ public class ResultDocument extends Instruction { private Expression href; private Expression formatExpression; // null if format was known at compile time private Expression content; private Properties globalProperties; private Properties localProperties; private String baseURI; // needed only for saxon:next-in-chain, or with fn:put() private int validationAction; private SchemaType schemaType; private IntHashMap serializationAttributes; private NamespaceResolver nsResolver; private Expression dynamicOutputElement; // used in saxon:result-document() extension function private boolean resolveAgainstStaticBase = false; // used with fn:put() /** * Create a result-document instruction * @param globalProperties properties defined on static xsl:output * @param localProperties non-AVT properties defined on result-document element * @param href href attribute of instruction * @param formatExpression format attribute of instruction * @param baseURI base URI of the instruction * @param validationAction for example {@link Validation#STRICT} * @param schemaType schema type against which output is to be validated * @param serializationAttributes computed local properties * @param nsResolver namespace resolver */ public ResultDocument(Properties globalProperties, // properties defined on static xsl:output Properties localProperties, // non-AVT properties defined on result-document element Expression href, Expression formatExpression, // AVT defining the output format String baseURI, int validationAction, SchemaType schemaType, IntHashMap serializationAttributes, // computed local properties only NamespaceResolver nsResolver) { this.globalProperties = globalProperties; this.localProperties = localProperties; this.href = href; this.formatExpression = formatExpression; this.baseURI = baseURI; this.validationAction = validationAction; this.schemaType = schemaType; this.serializationAttributes = serializationAttributes; this.nsResolver = nsResolver; adoptChildExpression(href); for (Iterator it = serializationAttributes.valueIterator(); it.hasNext();) { adoptChildExpression((Expression) it.next()); } } /** * Set the expression that constructs the content * @param content the expression defining the content of the result document */ public void setContent(Expression content) { this.content = content; adoptChildExpression(content); } /** * Set an expression that evaluates to a run-time xsl:output element, used in the saxon:result-document() * extension function designed for use in XQuery * @param exp the expression whose result should be an xsl:output element */ public void setDynamicOutputElement(Expression exp) { dynamicOutputElement = exp; } /** * Set whether the the instruction should resolve the href relative URI against the static * base URI (rather than the dynamic base output URI) * @param staticBase set to true by fn:put(), to resolve against the static base URI of the query. * Default is false, which causes resolution against the base output URI obtained dynamically * from the Controller */ public void setUseStaticBaseUri(boolean staticBase) { resolveAgainstStaticBase = staticBase; } /** * Simplify an expression. This performs any static optimization (by rewriting the expression * as a different expression). The default implementation does nothing. * @return the simplified expression * @throws net.sf.saxon.trans.XPathException * if an error is discovered during expression rewriting * @param visitor an expression visitor */ public Expression simplify(ExpressionVisitor visitor) throws XPathException { content = visitor.simplify(content); href = visitor.simplify(href); for (IntIterator it = serializationAttributes.keyIterator(); it.hasNext();) { int key = it.next(); Expression value = (Expression)serializationAttributes.get(key); if (!(value instanceof Literal)) { value = visitor.simplify(value); serializationAttributes.put(key, value); } } return this; } public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { content = visitor.typeCheck(content, contextItemType); adoptChildExpression(content); if (href != null) { href = visitor.typeCheck(href, contextItemType); adoptChildExpression(href); } if (formatExpression != null) { formatExpression = visitor.typeCheck(formatExpression, contextItemType); adoptChildExpression(formatExpression); } for (IntIterator it = serializationAttributes.keyIterator(); it.hasNext();) { int key = it.next(); Expression value = (Expression)serializationAttributes.get(key); if (!(value instanceof Literal)) { value = visitor.typeCheck(value, contextItemType); adoptChildExpression(value); serializationAttributes.put(key, value); } } try { DocumentInstr.checkContentSequence(visitor.getStaticContext(), content, validationAction, schemaType); } catch (XPathException err) { err.maybeSetLocation(this); throw err; } return this; } public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { content = visitor.optimize(content, contextItemType); adoptChildExpression(content); if (href != null) { href = visitor.optimize(href, contextItemType); adoptChildExpression(href); } if (formatExpression != null) { formatExpression = visitor.optimize(formatExpression, contextItemType); adoptChildExpression(formatExpression); // TODO: if the formatExpression is now a constant, could get the output properties now } for (IntIterator it = serializationAttributes.keyIterator(); it.hasNext();) { int key = it.next(); Expression value = (Expression)serializationAttributes.get(key); if (!(value instanceof Literal)) { value = visitor.optimize(value, contextItemType); adoptChildExpression(value); serializationAttributes.put(key, value); } } return this; } public int getIntrinsicDependencies() { return StaticProperty.HAS_SIDE_EFFECTS; } /** * Copy an expression. This makes a deep copy. * * @return the copy of the original expression */ public Expression copy() { throw new UnsupportedOperationException("copy"); } /** * Handle promotion offers, that is, non-local tree rewrites. * @param offer The type of rewrite being offered * @throws XPathException */ protected void promoteInst(PromotionOffer offer) throws XPathException { content = doPromotion(content, offer); if (href != null) { href = doPromotion(href, offer); } for (IntIterator it = serializationAttributes.keyIterator(); it.hasNext();) { int key = it.next(); Expression value = (Expression)serializationAttributes.get(key); if (!(value instanceof Literal)) { value = doPromotion(value, offer); serializationAttributes.put(key, value); } } } /** * Get the name of this instruction for diagnostic and tracing purposes * (the string "xsl:result-document") */ public int getInstructionNameCode() { return StandardNames.XSL_RESULT_DOCUMENT; } /** * Get the item type of the items returned by evaluating this instruction * @return the static item type of the instruction. This is empty: the result-document instruction * returns nothing. * @param th the type hierarchy cache */ public ItemType getItemType(TypeHierarchy th) { return EmptySequenceTest.getInstance(); } /** * Get all the XPath expressions associated with this instruction * (in XSLT terms, the expression present on attributes of the instruction, * as distinct from the child instructions in a sequence construction) */ public Iterator iterateSubExpressions() { ArrayList list = new ArrayList(6); list.add(content); if (href != null) { list.add(href); } if (formatExpression != null) { list.add(formatExpression); } for (Iterator it = serializationAttributes.valueIterator(); it.hasNext();) { list.add(it.next()); } if (dynamicOutputElement != null) { list.add(dynamicOutputElement); } return list.iterator(); } /** * Replace one subexpression by a replacement subexpression * @param original the original subexpression * @param replacement the replacement subexpression * @return true if the original subexpression is found */ public boolean replaceSubExpression(Expression original, Expression replacement) { boolean found = false; if (content == original) { content = replacement; found = true; } if (href == original) { href = replacement; found = true; } for (IntIterator it = serializationAttributes.keyIterator(); it.hasNext();) { int k = it.next(); if (serializationAttributes.get(k) == original) { serializationAttributes.put(k, replacement); found = true; } } if (dynamicOutputElement == original) { dynamicOutputElement = replacement; found = true; } return found; } public TailCall processLeavingTail(XPathContext context) throws XPathException { final Controller controller = context.getController(); final Configuration config = controller.getConfiguration(); final NamePool namePool = config.getNamePool(); XPathContext c2 = context.newMinorContext(); c2.setOrigin(this); Result result; OutputURIResolver resolver = null; if (href == null) { result = controller.getPrincipalResult(); } else { try { String base; if (resolveAgainstStaticBase) { base = baseURI; } else { base = controller.getCookedBaseOutputURI(); } resolver = controller.getOutputURIResolver(); String hrefValue = EscapeURI.iriToUri(href.evaluateAsString(context)).toString(); try { result = resolver.resolve(hrefValue, base); } catch (Exception err) { throw new XPathException("Exception thrown by OutputURIResolver", err); } if (result == null) { resolver = StandardOutputResolver.getInstance(); result = resolver.resolve(hrefValue, base); } } catch (TransformerException e) { throw XPathException.makeXPathException(e); } } if (controller.getDocumentPool().find(result.getSystemId()) != null) { XPathException err = new XPathException("Cannot write to a URI that has already been read: " + result.getSystemId()); err.setXPathContext(context); err.setErrorCode("XTRE1500"); throw err; } if (!controller.checkUniqueOutputDestination(result.getSystemId())) { XPathException err = new XPathException("Cannot write more than one result document to the same URI: " + result.getSystemId()); err.setXPathContext(context); err.setErrorCode("XTDE1490"); throw err; } else { controller.addUnavailableOutputDestination(result.getSystemId()); controller.setThereHasBeenAnExplicitResultDocument(); } boolean timing = controller.getConfiguration().isTiming(); if (timing) { String dest = result.getSystemId(); if (dest == null) { if (result instanceof StreamResult) { dest = "anonymous output stream"; } else if (result instanceof SAXResult) { dest = "SAX2 ContentHandler"; } else if (result instanceof DOMResult) { dest = "DOM tree"; } else { dest = result.getClass().getName(); } } System.err.println("Writing to " + dest); } Properties computedGlobalProps = globalProperties; if (formatExpression != null) { // format was an AVT and now needs to be computed CharSequence format = formatExpression.evaluateAsString(context); String[] parts; try { parts = controller.getConfiguration().getNameChecker().getQNameParts(format); } catch (QNameException e) { XPathException err = new XPathException("The requested output format " + Err.wrap(format) + " is not a valid QName"); err.setErrorCode("XTDE1460"); err.setXPathContext(context); throw err; } String uri = nsResolver.getURIForPrefix(parts[0], false); if (uri == null) { XPathException err = new XPathException("The namespace prefix in the format name " + format + " is undeclared"); err.setErrorCode("XTDE1460"); err.setXPathContext(context); throw err; } StructuredQName qName = new StructuredQName(parts[0], uri, parts[1]); computedGlobalProps = getExecutable().getOutputProperties(qName); if (computedGlobalProps == null) { XPathException err = new XPathException("There is no xsl:output format named " + format); err.setErrorCode("XTDE1460"); err.setXPathContext(context); throw err; } } // Now combine the properties specified on xsl:result-document with those specified on xsl:output Properties computedLocalProps = new Properties(computedGlobalProps); // First handle the properties with fixed values on xsl:result-document final NameChecker checker = config.getNameChecker(); for (Iterator citer=localProperties.keySet().iterator(); citer.hasNext();) { String key = (String)citer.next(); String[] parts = NamePool.parseClarkName(key); try { setSerializationProperty(computedLocalProps, parts[0], parts[1], localProperties.getProperty(key), nsResolver, true, checker); } catch (XPathException e) { e.maybeSetLocation(this); throw e; } } // Now add the properties that were specified as AVTs if (serializationAttributes.size() > 0) { for (IntIterator it = serializationAttributes.keyIterator(); it.hasNext();) { int key = it.next(); Expression exp = (Expression) serializationAttributes.get(key); String value = exp.evaluateAsString(context).toString(); String lname = namePool.getLocalName(key); String uri = namePool.getURI(key); try { setSerializationProperty(computedLocalProps, uri, lname, value, nsResolver, false, checker); } catch (XPathException e) { e.maybeSetLocation(this); e.maybeSetContext(context); if (NamespaceConstant.SAXON.equals(e.getErrorCodeNamespace()) && "warning".equals(e.getErrorCodeLocalPart())) { try { context.getController().getErrorListener().warning(e); } catch (TransformerException e2) { throw XPathException.makeXPathException(e2); } } else { throw e; } } } } // Handle properties specified using a dynamic xsl:output element // (Used when the instruction is generated from a saxon:result-document extension function call) if (dynamicOutputElement != null) { Item outputArg = dynamicOutputElement.evaluateItem(context); if (!(outputArg instanceof NodeInfo && ((NodeInfo)outputArg).getNodeKind() == Type.ELEMENT && ((NodeInfo)outputArg).getFingerprint() == StandardNames.XSL_OUTPUT)) { XPathException err = new XPathException( "The third argument of saxon:result-document must be an element"); err.setLocator(this); err.setXPathContext(context); throw err; } Properties dynamicProperties = new Properties(); Serialize.processXslOutputElement((NodeInfo)outputArg, dynamicProperties, context); for (Iterator it = dynamicProperties.keySet().iterator(); it.hasNext();) { String key = (String)it.next(); StructuredQName name = StructuredQName.fromClarkName(key); String value = dynamicProperties.getProperty(key); try { setSerializationProperty( computedLocalProps, name.getNamespaceURI(), name.getLocalName(), value, nsResolver, false, checker); } catch (XPathException e) { e.maybeSetLocation(this); e.maybeSetContext(context); throw e; } } } String nextInChain = computedLocalProps.getProperty(SaxonOutputKeys.NEXT_IN_CHAIN); if (nextInChain != null) { try { result = controller.prepareNextStylesheet(nextInChain, baseURI, result); } catch (TransformerException e) { throw XPathException.makeXPathException(e); } } // TODO: cache the serializer and reuse it if the serialization properties are fixed at // compile time (that is, if serializationAttributes.isEmpty). Need to save the serializer // in a form where the final output destination can be changed. c2.changeOutputDestination(computedLocalProps, result, true, Configuration.XSLT, validationAction, schemaType); SequenceReceiver out = c2.getReceiver(); out.open(); out.startDocument(0); content.process(c2); out.endDocument(); out.close(); if (resolver != null) { try { resolver.close(result); } catch (TransformerException e) { throw XPathException.makeXPathException(e); } } return null; } /** * Validate a serialization property and add its value to a Properties collection * @param details the properties to be updated * @param uri the uri of the property name * @param lname the local part of the property name * @param value the value of the serialization property. In the case of QName-valued values, * this will use lexical QNames if prevalidated is false, Clark-format names otherwise * @param nsResolver resolver for lexical QNames; not needed if prevalidated * @param prevalidated true if values are already known to be valid and lexical QNames have been * expanded into Clark notation * @param checker the XML 1.0 or 1.1 name checker */ public static void setSerializationProperty(Properties details, String uri, String lname, String value, NamespaceResolver nsResolver, boolean prevalidated, NameChecker checker) throws XPathException { // TODO: combine this code with SaxonOutputKeys.checkOutputProperty() if (uri.length() == 0) { if (lname.equals(StandardNames.METHOD)) { if (value.equals("xml") || value.equals("html") || value.equals("text") || value.equals("xhtml") || prevalidated) { details.setProperty(OutputKeys.METHOD, value); } else { String[] parts; try { parts = checker.getQNameParts(value); String prefix = parts[0]; if (prefix.length() == 0) { XPathException err = new XPathException("method must be xml, html, xhtml, or text, or a prefixed name"); err.setErrorCode("XTSE1570"); err.setIsStaticError(true); throw err; } else { String muri = nsResolver.getURIForPrefix(prefix, false); if (muri==null) { XPathException err = new XPathException("Namespace prefix '" + prefix + "' has not been declared"); err.setErrorCode("XTSE1570"); err.setIsStaticError(true); throw err; } details.setProperty(OutputKeys.METHOD, '{' + muri + '}' + parts[1]); } } catch (QNameException e) { XPathException err = new XPathException("Invalid method name. " + e.getMessage()); err.setErrorCode("XTSE1570"); err.setIsStaticError(true); throw err; } } } else if (lname.equals(StandardNames.OUTPUT_VERSION) || lname.equals(StandardNames.VERSION)) { details.setProperty(OutputKeys.VERSION, value); } else if (lname.equals(StandardNames.BYTE_ORDER_MARK)) { if (prevalidated || value.equals("yes") || value.equals("no")) { details.setProperty(SaxonOutputKeys.BYTE_ORDER_MARK, value); } else { XPathException err = new XPathException("byte-order-mark value must be 'yes' or 'no'"); err.setErrorCode("XTDE0030"); throw err; } } else if (lname.equals(StandardNames.INDENT)) { if (prevalidated || value.equals("yes") || value.equals("no")) { details.setProperty(OutputKeys.INDENT, value); } else { XPathException err = new XPathException("indent must be 'yes' or 'no'"); err.setErrorCode("XTDE0030"); throw err; } } else if (lname.equals(StandardNames.ENCODING)) { details.setProperty(OutputKeys.ENCODING, value); } else if (lname.equals(StandardNames.MEDIA_TYPE)) { details.setProperty(OutputKeys.MEDIA_TYPE, value); } else if (lname.equals(StandardNames.DOCTYPE_SYSTEM)) { details.setProperty(OutputKeys.DOCTYPE_SYSTEM, value); } else if (lname.equals(StandardNames.DOCTYPE_PUBLIC)) { details.setProperty(OutputKeys.DOCTYPE_PUBLIC, value); } else if (lname.equals(StandardNames.OMIT_XML_DECLARATION)) { if (prevalidated || value.equals("yes") || value.equals("no")) { details.setProperty(OutputKeys.OMIT_XML_DECLARATION, value); } else { XPathException err = new XPathException("omit-xml-declaration attribute must be 'yes' or 'no'"); err.setErrorCode("XTDE0030"); throw err; } } else if (lname.equals(StandardNames.STANDALONE)) { if (prevalidated || value.equals("yes") || value.equals("no") || value.equals("omit")) { details.setProperty(OutputKeys.STANDALONE, value); } else { XPathException err = new XPathException("standalone attribute must be 'yes' or 'no' or 'omit'"); err.setErrorCode("XTDE0030"); throw err; } } else if (lname.equals(StandardNames.CDATA_SECTION_ELEMENTS)) { String existing = details.getProperty(OutputKeys.CDATA_SECTION_ELEMENTS); if (existing == null) { existing = ""; } String s = parseListOfElementNames(value, nsResolver, prevalidated, checker, "XTDE0030"); details.setProperty(OutputKeys.CDATA_SECTION_ELEMENTS, existing + s); } else if (lname.equals(StandardNames.USE_CHARACTER_MAPS)) { // The use-character-maps attribute is always turned into a Clark-format name at compile time String existing = details.getProperty(SaxonOutputKeys.USE_CHARACTER_MAPS); if (existing == null) { existing = ""; } details.setProperty(SaxonOutputKeys.USE_CHARACTER_MAPS, existing + value); } else if (lname.equals(StandardNames.UNDECLARE_PREFIXES)) { if (prevalidated || value.equals("yes") || value.equals("no")) { details.setProperty(SaxonOutputKeys.UNDECLARE_PREFIXES, value); } else { XPathException err = new XPathException("undeclare-namespaces value must be 'yes' or 'no'"); err.setErrorCode("XTDE0030"); throw err; } } else if (lname.equals(StandardNames.INCLUDE_CONTENT_TYPE)) { if (prevalidated || value.equals("yes") || value.equals("no")) { details.setProperty(SaxonOutputKeys.INCLUDE_CONTENT_TYPE, value); } else { XPathException err = new XPathException("include-content-type attribute must be 'yes' or 'no'"); err.setErrorCode("XTDE0030"); throw err; } } else if (lname.equals(StandardNames.ESCAPE_URI_ATTRIBUTES) || lname.equals("escape-uri-attibutes")) { // misspelling was in Saxon 9.0 and previous releases if (prevalidated || value.equals("yes") || value.equals("no")) { details.setProperty(SaxonOutputKeys.ESCAPE_URI_ATTRIBUTES, value); } else { XPathException err = new XPathException("escape-uri-attributes value must be 'yes' or 'no'"); err.setErrorCode("XTDE0030"); throw err; } } else if (lname.equals(StandardNames.NORMALIZATION_FORM)) { if (Name11Checker.getInstance().isValidNmtoken(value)) { // if (prevalidated || value.equals("NFC") || value.equals("NFD") || // value.equals("NFKC") || value.equals("NFKD")) { details.setProperty(SaxonOutputKeys.NORMALIZATION_FORM, value); } else if (value.equals("none")) { // do nothing } else { XPathException err = new XPathException("normalization-form must be a valid NMTOKEN"); err.setErrorCode("XTDE0030"); throw err; } } else { // Normally detected statically, but not with saxon:serialize XPathException err = new XPathException("Unknown serialization property " + lname); err.setErrorCode("XTDE0030"); throw err; } } else if (uri.equals(NamespaceConstant.SAXON)) { if (lname.equals("character-representation")) { details.setProperty(SaxonOutputKeys.CHARACTER_REPRESENTATION, value); } else if (lname.equals("indent-spaces")) { try { Integer.parseInt(value); details.setProperty(OutputKeys.INDENT, "yes"); details.setProperty(SaxonOutputKeys.INDENT_SPACES, value); } catch (NumberFormatException err) { XPathException e = new XPathException("saxon:indent-spaces must be an integer"); e.setErrorCode(NamespaceConstant.SAXON, SaxonErrorCode.SXWN9002); throw e; } } else if (lname.equals("suppress-indentation")) { String existing = details.getProperty(SaxonOutputKeys.SUPPRESS_INDENTATION); if (existing == null) { existing = ""; } String s = parseListOfElementNames(value, nsResolver, prevalidated, checker, "XTDE0030"); details.setProperty(SaxonOutputKeys.SUPPRESS_INDENTATION, existing + s); } else if (lname.equals("double-space")) { String existing = details.getProperty(SaxonOutputKeys.DOUBLE_SPACE); if (existing == null) { existing = ""; } String s = parseListOfElementNames(value, nsResolver, prevalidated, checker, "XTDE0030"); details.setProperty(SaxonOutputKeys.SUPPRESS_INDENTATION, existing + s); } else if (lname.equals("next-in-chain")) { XPathException e = new XPathException("saxon:next-in-chain value cannot be specified dynamically"); e.setErrorCode(NamespaceConstant.SAXON, SaxonErrorCode.SXWN9004); throw e; } else if (lname.equals("require-well-formed")) { if (prevalidated || value.equals("yes") || value.equals("no")) { details.setProperty(SaxonOutputKeys.REQUIRE_WELL_FORMED, value); } else { XPathException e = new XPathException("saxon:require-well-formed value must be 'yes' or 'no'"); e.setErrorCode(NamespaceConstant.SAXON, SaxonErrorCode.SXWN9003); throw e; } } } else { // deal with user-defined attributes details.setProperty('{' + uri + '}' + lname, value); } } public static String parseListOfElementNames( String value, NamespaceResolver nsResolver, boolean prevalidated, NameChecker checker, String errorCode) throws XPathException { String s = ""; StringTokenizer st = new StringTokenizer(value, " \t\n\r", false); while (st.hasMoreTokens()) { String displayname = st.nextToken(); if (prevalidated) { s += ' ' + displayname; } else { try { String[] parts = checker.getQNameParts(displayname); String muri = nsResolver.getURIForPrefix(parts[0], true); if (muri==null) { XPathException err = new XPathException("Namespace prefix '" + parts[0] + "' has not been declared"); err.setErrorCode(errorCode); throw err; } s += " {" + muri + '}' + parts[1]; } catch (QNameException err) { XPathException e = new XPathException("Invalid element name. " + err.getMessage()); e.setErrorCode(errorCode); throw e; } } } return s; } /** * Diagnostic print of expression structure. The abstract expression tree * is written to the supplied output destination. */ public void explain(ExpressionPresenter out) { out.startElement("resultDocument"); content.explain(out); out.endElement(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // saxonb-9.1.0.8/bj/net/sf/saxon/instruct/DummyNamespaceResolver.java0000644000175000017500000000520611033112257024552 0ustar eugeneeugenepackage net.sf.saxon.instruct; import net.sf.saxon.om.NamespaceConstant; import net.sf.saxon.om.NamespaceResolver; import java.io.Serializable; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /** * A dummy namespace resolver used when validating QName-valued attributes written to * the result tree. The namespace node might be created after the initial validation * of the attribute, so in the first round of validation we only check the lexical form * of the value, and we defer prefix checks until later. */ public final class DummyNamespaceResolver implements Serializable, NamespaceResolver { private static DummyNamespaceResolver theInstance = new DummyNamespaceResolver(); /** * Return the singular instance of this class * @return the singular instance */ public static DummyNamespaceResolver getInstance() { return theInstance; } private DummyNamespaceResolver() {}; /** * Get the namespace URI corresponding to a given prefix. * @param prefix the namespace prefix * @param useDefault true if the default namespace is to be used when the * prefix is "" * @return the uri for the namespace, or null if the prefix is not in scope */ public String getURIForPrefix(String prefix, boolean useDefault) { if ("".equals(prefix)) { return ""; } else if ("xml".equals(prefix)) { return NamespaceConstant.XML; } else { // this is a dummy namespace resolver, we don't actually know the URI return ""; } } /** * Get an iterator over all the prefixes declared in this namespace context. This will include * the default namespace (prefix="") and the XML namespace where appropriate */ public Iterator iteratePrefixes() { List list = new ArrayList(2); list.add(""); list.add("xml"); return list.iterator(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/instruct/TraceWrapper.java0000644000175000017500000002601511033112257022520 0ustar eugeneeugenepackage net.sf.saxon.instruct; import net.sf.saxon.Controller; import net.sf.saxon.expr.*; import net.sf.saxon.om.Item; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.trace.TraceListener; import net.sf.saxon.trace.ExpressionPresenter; import net.sf.saxon.trace.InstructionInfo; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.TypeHierarchy; import java.util.Iterator; /** * This class is a tracing wrapper around any expression: it delivers the same result as the * wrapped expression, but traces its evaluation to a TraceListener */ public class TraceWrapper extends Instruction { Expression child; // the instruction or other expression to be traced /** * Simplify an expression. This performs any static optimization (by rewriting the expression * as a different expression). The default implementation does nothing. * * @exception net.sf.saxon.trans.XPathException if an error is discovered during expression * rewriting * @return the simplified expression * @param visitor an expression visitor */ public Expression simplify(ExpressionVisitor visitor) throws XPathException { child = visitor.simplify(child); return this; } public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { child = visitor.typeCheck(child, contextItemType); adoptChildExpression(child); return this; } public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { child = visitor.optimize(child, contextItemType); adoptChildExpression(child); return this; } /** * Copy an expression. This makes a deep copy. * * @return the copy of the original expression */ public Expression copy() { throw new UnsupportedOperationException("copy"); } /** * Offer promotion for this subexpression. The offer will be accepted if the subexpression * is not dependent on the factors (e.g. the context item) identified in the PromotionOffer. * This method is always called at compile time. * * @param offer details of the offer, for example the offer to move * expressions that don't depend on the context to an outer level in * the containing expression * @return if the offer is not accepted, return this expression unchanged. * Otherwise return the result of rewriting the expression to promote * this subexpression * @throws net.sf.saxon.trans.XPathException * if any error is detected */ public Expression promote(PromotionOffer offer) throws XPathException { // Many rewrites are not attempted if tracing is activated. But those that are, for example // rewriting of calls to current(), must be carried out. Expression newChild = child.promote(offer); if (newChild != child) { child = newChild; adoptChildExpression(child); return this; } return this; } /** * Execute this instruction, with the possibility of returning tail calls if there are any. * This outputs the trace information via the registered TraceListener, * and invokes the instruction being traced. * @param context the dynamic execution context * @return either null, or a tail call that the caller must invoke on return * @throws net.sf.saxon.trans.XPathException */ public TailCall processLeavingTail(XPathContext context) throws XPathException { Controller controller = context.getController(); TraceListener listener = controller.getTraceListener(); if (controller.isTracing()) { listener.enter(getInstructionInfo(), context); } // Don't attempt tail call optimization when tracing, the results are too confusing child.process(context); if (controller.isTracing()) { listener.leave(getInstructionInfo()); } return null; } /** * Get the item type of the items returned by evaluating this instruction * @return the static item type of the instruction * @param th the type hierarchy cache */ public ItemType getItemType(TypeHierarchy th) { return child.getItemType(th); } /** * Determine the static cardinality of the expression. This establishes how many items * there will be in the result of the expression, at compile time (i.e., without * actually evaluating the result. * * @return one of the values Cardinality.ONE_OR_MORE, * Cardinality.ZERO_OR_MORE, Cardinality.EXACTLY_ONE, * Cardinality.ZERO_OR_ONE, Cardinality.EMPTY. This default * implementation returns ZERO_OR_MORE (which effectively gives no * information). */ public int getCardinality() { return child.getCardinality(); } /** * Determine which aspects of the context the expression depends on. The result is * a bitwise-or'ed value composed from constants such as {@link net.sf.saxon.expr.StaticProperty#DEPENDS_ON_CONTEXT_ITEM} and * {@link net.sf.saxon.expr.StaticProperty#DEPENDS_ON_CURRENT_ITEM}. The default implementation combines the intrinsic * dependencies of this expression with the dependencies of the subexpressions, * computed recursively. This is overridden for expressions such as FilterExpression * where a subexpression's dependencies are not necessarily inherited by the parent * expression. * * @return a set of bit-significant flags identifying the dependencies of * the expression */ public int getDependencies() { return child.getDependencies(); } /** * Determine whether this instruction creates new nodes. * * */ public final boolean createsNewNodes() { return (child.getSpecialProperties() & StaticProperty.NON_CREATIVE) == 0; } /** * Get the static properties of this expression (other than its type). The result is * bit-signficant. These properties are used for optimizations. In general, if * property bit is set, it is true, but if it is unset, the value is unknown. * * @return a set of flags indicating static properties of this expression */ public int computeDependencies() { return child.computeDependencies(); } /** * Evaluate an expression as a single item. This always returns either a single Item or * null (denoting the empty sequence). No conversion is done. This method should not be * used unless the static type of the expression is a subtype of "item" or "item?": that is, * it should not be called if the expression may return a sequence. There is no guarantee that * this condition will be detected. * * @param context The context in which the expression is to be evaluated * @exception net.sf.saxon.trans.XPathException if any dynamic error occurs evaluating the * expression * @return the node or atomic value that results from evaluating the * expression; or null to indicate that the result is an empty * sequence */ public Item evaluateItem(XPathContext context) throws XPathException { Controller controller = context.getController(); if (controller.isTracing()) { controller.getTraceListener().enter(getInstructionInfo(), context); } Item result = child.evaluateItem(context); if (controller.isTracing()) { controller.getTraceListener().leave(getInstructionInfo()); } return result; } /** * Return an Iterator to iterate over the values of a sequence. The value of every * expression can be regarded as a sequence, so this method is supported for all * expressions. This default implementation handles iteration for expressions that * return singleton values: for non-singleton expressions, the subclass must * provide its own implementation. * * @exception net.sf.saxon.trans.XPathException if any dynamic error occurs evaluating the * expression * @param context supplies the context for evaluation * @return a SequenceIterator that can be used to iterate over the result * of the expression */ public SequenceIterator iterate(XPathContext context) throws XPathException { Controller controller = context.getController(); if (controller.isTracing()) { controller.getTraceListener().enter(getInstructionInfo(), context); } SequenceIterator result = child.iterate(context); if (controller.isTracing()) { controller.getTraceListener().leave(getInstructionInfo()); } return result; } public Iterator iterateSubExpressions() { return new MonoIterator(child); } /** * Replace one subexpression by a replacement subexpression * @param original the original subexpression * @param replacement the replacement subexpression * @return true if the original subexpression is found */ public boolean replaceSubExpression(Expression original, Expression replacement) { boolean found = false; if (child == original) { child = replacement; found = true; } return found; } /** * Get the instruction details * @return the details of the child instruction (the instruction being traced) */ public InstructionInfo getInstructionInfo() { return child; } public int getInstructionNameCode() { if (child instanceof Instruction) { return ((Instruction)child).getInstructionNameCode(); } else { return -1; } } /** * Diagnostic print of expression structure. The abstract expression tree * is written to the supplied output destination. */ public void explain(ExpressionPresenter out) { child.explain(out); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/instruct/TerminationException.java0000644000175000017500000000223111033112257024263 0ustar eugeneeugenepackage net.sf.saxon.instruct; import net.sf.saxon.trans.XPathException; /** * An exception thrown by xsl:message terminate="yes". */ public class TerminationException extends XPathException { /** * Construct a TerminationException * @param message the text of the message to be output */ public TerminationException(String message) { super(message); setErrorCode("XTMM9000"); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/instruct/Block.java0000644000175000017500000005737311033112257021166 0ustar eugeneeugenepackage net.sf.saxon.instruct; import net.sf.saxon.evpull.BlockEventIterator; import net.sf.saxon.evpull.EmptyEventIterator; import net.sf.saxon.evpull.EventIterator; import net.sf.saxon.expr.*; import net.sf.saxon.om.EmptyIterator; import net.sf.saxon.om.Item; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.om.Axis; import net.sf.saxon.pattern.EmptySequenceTest; import net.sf.saxon.trace.ExpressionPresenter; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.*; import net.sf.saxon.value.AtomicValue; import net.sf.saxon.value.Cardinality; import net.sf.saxon.value.SequenceExtent; import java.util.*; /** * Implements an imaginary xsl:block instruction which simply evaluates * its contents. Used for top-level templates, xsl:otherwise, etc. */ public class Block extends Instruction { // TODO: allow the last expression in a Block to be a tail-call of a function, at least in push mode private Expression[] children; /** * Create an empty block */ public Block() { } /** * Static factory method to create a block. If one of the arguments is already a block, * the contents will be merged into a new composite block * @param e1 the first subexpression (child) of the block * @param e2 the second subexpression (child) of the block * @return a Block containing the two subexpressions, and if either of them is a block, it will * have been collapsed to create a flattened sequence */ public static Expression makeBlock(Expression e1, Expression e2) { if (e1==null || Literal.isEmptySequence(e1)) { return e2; } if (e2==null || Literal.isEmptySequence(e2)) { return e1; } if (e1 instanceof Block || e2 instanceof Block) { Iterator it1 = (e1 instanceof Block ? e1.iterateSubExpressions() : new MonoIterator(e1)); Iterator it2 = (e2 instanceof Block ? e2.iterateSubExpressions() : new MonoIterator(e2)); List list = new ArrayList(10); while (it1.hasNext()) { list.add(it1.next()); } while (it2.hasNext()) { list.add(it2.next()); } Expression[] exps = new Expression[list.size()]; exps = (Expression[])list.toArray(exps); Block b = new Block(); b.setChildren(exps); return b; } else { Expression[] exps = {e1, e2}; Block b = new Block(); b.setChildren(exps); return b; } } /** * Static factory method to create a block from a list of expressions * @param list the list of expressions making up this block. The members of the List must * be instances of Expression * @return a Block containing the two subexpressions, and if either of them is a block, it will * have been collapsed to create a flattened sequence */ public static Expression makeBlock(List list) { Expression[] exps = new Expression[list.size()]; exps = (Expression[])list.toArray(exps); Block b = new Block(); b.setChildren(exps); return b; } /** * Set the children of this instruction * @param children The instructions that are children of this instruction */ public void setChildren(Expression[] children) { if (children==null || children.length==0) { this.children = null; } else { this.children = children; for (int c=0; c 0 && isLiteralText[i] && isLiteralText[i-1]) { hasAdjacentTextNodes = true; } } if (hasAdjacentTextNodes) { List content = new ArrayList(children.length); String pendingText = null; for (int i=0; i 0 && children[0] instanceof LocalParam; } /** * Replace one subexpression by a replacement subexpression * @param original the original subexpression * @param replacement the replacement subexpression * @return true if the original subexpression is found */ public boolean replaceSubExpression(Expression original, Expression replacement) { boolean found = false; for (int c=0; cChanged in Saxon 9.0 to return a list of StructuredQName values rather than integers

    */ public List getVariableMap() { return variableMap; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/instruct/SimpleNodeConstructor.java0000644000175000017500000002226211033112257024426 0ustar eugeneeugenepackage net.sf.saxon.instruct; import net.sf.saxon.Configuration; import net.sf.saxon.expr.*; import net.sf.saxon.om.Item; import net.sf.saxon.om.Orphan; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.om.SingletonIterator; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.BuiltInAtomicType; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.TypeHierarchy; import java.util.Iterator; /** * Common superclass for XSLT instructions whose content template produces a text * value: xsl:attribute, xsl:comment, xsl:processing-instruction, xsl:namespace, * and xsl:text, and their XQuery equivalents */ public abstract class SimpleNodeConstructor extends Instruction { protected Expression select = null; /** * Default constructor used by subclasses */ public SimpleNodeConstructor() { } /** * Set the select expression: the value of this expression determines the string-value of the node * @param select the expression that computes the string value of the node * @param config the Saxon configuration (used for example to do early validation of the content * of an attribute against the schema-defined type) * @throws XPathException */ public void setSelect(Expression select, Configuration config) throws XPathException { this.select = select; adoptChildExpression(select); } /** * Get the expression that determines the string value of the constructed node * @return the select expression */ public Expression getSelect() { return select; } /** * Determine whether this instruction creates new nodes. * This implementation returns true. */ public final boolean createsNewNodes() { return true; } /** * Get the cardinality of the sequence returned by evaluating this instruction * @return the static cardinality */ public int computeCardinality() { return StaticProperty.EXACTLY_ONE; } public Expression simplify(ExpressionVisitor visitor) throws XPathException { if (select != null) { select = visitor.simplify(select); } return this; } /** * Get the static properties of this expression (other than its type). The result is * bit-signficant. These properties are used for optimizations. In general, if * property bit is set, it is true, but if it is unset, the value is unknown. * * @return a set of flags indicating static properties of this expression */ public int computeSpecialProperties() { return super.computeSpecialProperties() | StaticProperty.SINGLE_DOCUMENT_NODESET; } /** * Method to perform type-checking specific to the kind of instruction * @param visitor an expression visitor * @param contextItemType the static type of the context item * @throws XPathException */ public abstract void localTypeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException; /** * The typeCheck() method is called in XQuery, where node constructors * are implemented as Expressions. In this case the required type for the * select expression is a single string. * @param visitor an expression visitor * @return the rewritten expression * @throws XPathException if any static errors are found in this expression * or any of its children */ public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { localTypeCheck(visitor, contextItemType); if (select != null) { final TypeHierarchy th = visitor.getConfiguration().getTypeHierarchy(); select = visitor.typeCheck(select, contextItemType); if (!select.getItemType(th).isAtomicType()) { select = new Atomizer(select, visitor.getConfiguration()).simplify(visitor); } if (!th.isSubType(select.getItemType(th), BuiltInAtomicType.STRING)) { select = new AtomicSequenceConverter(select, BuiltInAtomicType.STRING); } adoptChildExpression(select); } return this; } public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { if (select != null) { select = visitor.optimize(select, contextItemType); adoptChildExpression(select); } return this; } public Iterator iterateSubExpressions() { return new MonoIterator(select); } /** * Replace one subexpression by a replacement subexpression * @param original the original subexpression * @param replacement the replacement subexpression * @return true if the original subexpression is found */ public boolean replaceSubExpression(Expression original, Expression replacement) { boolean found = false; if (select == original) { select = replacement; found = true; } return found; } /** * Expand the stylesheet elements subordinate to this one, returning the result * as a string. The expansion must not generate any element or attribute nodes. * @param context The dynamic context for the transformation * @return the value that will be used as the string value of the constructed node * @throws XPathException if any error occurs */ public CharSequence expandChildren(XPathContext context) throws XPathException { Item item = select.evaluateItem(context); if (item==null) { return ""; } else { return item.getStringValueCS(); } } /** * Evaluate as an expression. We rely on the fact that when these instructions * are generated by XQuery, there will always be a valueExpression to evaluate * the content */ public Item evaluateItem(XPathContext context) throws XPathException { String content = (select==null ? "" : select.evaluateAsString(context).toString()); content = checkContent(content, context); final TypeHierarchy th = context.getConfiguration().getTypeHierarchy(); Orphan o = new Orphan(context.getConfiguration()); o.setNodeKind((short)getItemType(th).getPrimitiveType()); o.setStringValue(content); o.setNameCode(evaluateNameCode(context)); return o; } /** * Check the content of the node, and adjust it if necessary. The checks depend on the node kind. * @param data the supplied content * @param context the dynamic context * @return the original content, unless adjustments are needed * @throws XPathException if the content is invalid */ protected String checkContent(String data, XPathContext context) throws XPathException { return data; } /** * Run-time method to compute the name of the node being constructed. This is overridden * for nodes that have a name. The default implementation returns -1, which is suitable for * unnamed nodes such as comments * @param context the XPath dynamic evaluation context * @return the name pool nameCode identifying the name of the constructed node * @throws XPathException if any failure occurs */ public int evaluateNameCode(XPathContext context) throws XPathException { return -1; } public SequenceIterator iterate(XPathContext context) throws XPathException { return SingletonIterator.makeIterator(evaluateItem(context)); } /** * Offer promotion for subexpressions. The offer will be accepted if the subexpression * is not dependent on the factors (e.g. the context item) identified in the PromotionOffer. * By default the offer is not accepted - this is appropriate in the case of simple expressions * such as constant values and variable references where promotion would give no performance * advantage. This method is always called at compile time. * * @param offer details of the offer, for example the offer to move * expressions that don't depend on the context to an outer level in * the containing expression * @exception XPathException if any error is detected */ protected void promoteInst(PromotionOffer offer) throws XPathException { if (select != null) { select = doPromotion(select, offer); } super.promoteInst(offer); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/instruct/Assign.java0000644000175000017500000001115711033112257021346 0ustar eugeneeugenepackage net.sf.saxon.instruct; import net.sf.saxon.expr.*; import net.sf.saxon.om.ValueRepresentation; import net.sf.saxon.om.StandardNames; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.Closure; import net.sf.saxon.value.SequenceExtent; import net.sf.saxon.value.SequenceType; import net.sf.saxon.value.Value; import net.sf.saxon.trace.ExpressionPresenter; /** * saxon:assign element in stylesheet. * * The saxon:assign element has mandatory attribute name and optional attribute expr. * It also allows xsl:extension-element-prefixes etc. */ public class Assign extends GeneralVariable implements BindingReference { private Binding binding; // link to the variable declaration public Assign() {} public void setStaticType(SequenceType type, Value constantValue, int properties) {} public void fixup(Binding binding) { this.binding = binding; } public int getIntrinsicDependencies() { return StaticProperty.HAS_SIDE_EFFECTS; } /** * Offer promotion for this subexpression. This needs careful handling in the * case of saxon:assign * * @param offer details of the offer, for example the offer to move * expressions that don't depend on the context to an outer level in * the containing expression * @exception net.sf.saxon.trans.XPathException if any error is detected * @return if the offer is not accepted, return this expression unchanged. * Otherwise return the result of rewriting the expression to promote * this subexpression */ public Expression promote(PromotionOffer offer) throws XPathException { switch (offer.action) { case PromotionOffer.RANGE_INDEPENDENT: case PromotionOffer.FOCUS_INDEPENDENT: case PromotionOffer.EXTRACT_GLOBAL_VARIABLES: return this; case PromotionOffer.REPLACE_CURRENT: case PromotionOffer.INLINE_VARIABLE_REFERENCES: case PromotionOffer.UNORDERED: return super.promote(offer); default: throw new UnsupportedOperationException("Unknown promotion action " + offer.action); } } /** * Get the name of this instruction for diagnostic and tracing purposes */ public int getInstructionNameCode() { return StandardNames.SAXON_ASSIGN; } public TailCall processLeavingTail(XPathContext context) throws XPathException { if (binding==null) { throw new IllegalStateException("saxon:assign binding has not been fixed up"); } ValueRepresentation value = getSelectValue(context); if (value instanceof Closure) { value = SequenceExtent.makeSequenceExtent(((Closure)value).iterate()); } if (binding instanceof GeneralVariable) { if (binding.isGlobal()) { context.getController().getBindery().assignGlobalVariable((GlobalVariable)binding, value); } else { throw new UnsupportedOperationException("Local variables are not assignable"); } } else { } return null; } /** * Evaluate the variable (method exists only to satisfy the interface) */ public ValueRepresentation evaluateVariable(XPathContext context) throws XPathException { throw new UnsupportedOperationException(); } /** * Diagnostic print of expression structure. The abstract expression tree * is written to the supplied output destination. */ public void explain(ExpressionPresenter out) { out.startElement("assign"); out.emitAttribute("name", variableQName.getDisplayName()); if (select != null) { select.explain(out); } out.endElement(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/instruct/FixedAttribute.java0000644000175000017500000003330611033112257023045 0ustar eugeneeugenepackage net.sf.saxon.instruct; import net.sf.saxon.Configuration; import net.sf.saxon.Controller; import net.sf.saxon.event.SequenceReceiver; import net.sf.saxon.expr.*; import net.sf.saxon.functions.SystemFunction; import net.sf.saxon.om.*; import net.sf.saxon.pattern.NodeKindTest; import net.sf.saxon.trace.ExpressionPresenter; import net.sf.saxon.trans.Err; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.*; import javax.xml.transform.SourceLocator; /** * An instruction derived from an xsl:attribute element in stylesheet, or from * an attribute constructor in XQuery. This version deals only with attributes * whose name is known at compile time. It is also used for attributes of * literal result elements. The value of the attribute is in general computed * at run-time. */ public final class FixedAttribute extends AttributeCreator { private int nameCode; /** * Construct an Attribute instruction * @param nameCode Represents the attribute name * @param validationAction the validation required, for example strict or lax * @param schemaType the schema type against which validation is required, null if not applicable * @param annotation Integer code identifying the type named in the type attribute * of the instruction - zero if the attribute was not present */ public FixedAttribute ( int nameCode, int validationAction, SimpleType schemaType, int annotation ) { this.nameCode = nameCode; setSchemaType(schemaType); if (annotation == -1) { setAnnotation(StandardNames.XS_UNTYPED_ATOMIC); } else { setAnnotation(annotation); } setValidationAction(validationAction); setOptions(0); } /** * Get the name of this instruction (return 'xsl:attribute') */ public int getInstructionNameCode() { return StandardNames.XSL_ATTRIBUTE; } /** * Set the expression defining the value of the attribute. If this is a constant, and if * validation against a schema type was requested, the validation is done immediately. * @param select The expression defining the content of the attribute * @param config The Saxon configuration * @throws XPathException if the expression is a constant, and validation is requested, and * the constant doesn't match the required type. */ public void setSelect(Expression select, Configuration config) throws XPathException { super.setSelect(select, config); // Attempt early validation if possible SimpleType schemaType = getSchemaType(); if (Literal.isAtomic(select) && schemaType != null && !schemaType.isNamespaceSensitive()) { CharSequence value = ((Literal)select).getValue().getStringValueCS(); ValidationFailure err = schemaType.validateContent( value, DummyNamespaceResolver.getInstance(), config.getNameChecker()); if (err != null) { XPathException se = new XPathException("Attribute value " + Err.wrap(value, Err.VALUE) + " does not the match the required type " + schemaType.getDescription() + ". " + err.getMessage()); se.setErrorCode("XTTE1540"); throw se; } } // If value is fixed, test whether there are any special characters that might need to be // escaped when the time comes for serialization if (select instanceof StringLiteral) { boolean special = false; CharSequence val = ((StringLiteral)select).getStringValue(); for (int k=0; k126 || c=='<' || c=='>' || c=='&' || c=='\"') { special = true; break; } } if (!special) { setNoSpecialChars(); } } // If attribute name is xml:id, add whitespace normalization if ((nameCode & NamePool.FP_MASK) == StandardNames.XML_ID) { select = SystemFunction.makeSystemFunction("normalize-space", new Expression[]{select}); super.setSelect(select, config); } } /** * Get the name pool name code of the attribute to be constructed * @return the attribute's name code */ public int getAttributeNameCode() { return nameCode; } public ItemType getItemType(TypeHierarchy th) { return NodeKindTest.ATTRIBUTE; } public int getCardinality() { return StaticProperty.EXACTLY_ONE; } /** * Copy an expression. This makes a deep copy. * * @return the copy of the original expression */ public Expression copy() { FixedAttribute exp = new FixedAttribute(nameCode, getValidationAction(), getSchemaType(), getAnnotation()); try { exp.setSelect(select.copy(), getExecutable().getConfiguration()); } catch (XPathException err) { throw new UnsupportedOperationException(err.getMessage()); } return exp; } public void localTypeCheck(ExpressionVisitor visitor, ItemType contextItemType) { // no action } public int evaluateNameCode(XPathContext context) { return nameCode; } /** * Check that any elements and attributes constructed or returned by this expression are acceptable * in the content model of a given complex type. It's always OK to say yes, since the check will be * repeated at run-time. The process of checking element and attribute constructors against the content * model of a complex type also registers the type of content expected of those constructors, so the * static validation can continue recursively. */ public void checkPermittedContents(SchemaType parentType, StaticContext env, boolean whole) throws XPathException { int fp = nameCode & NamePool.FP_MASK; if (fp == StandardNames.XSI_TYPE || fp == StandardNames.XSI_SCHEMA_LOCATION || fp == StandardNames.XSI_NIL || fp == StandardNames.XSI_NO_NAMESPACE_SCHEMA_LOCATION) { return; } if (parentType instanceof SimpleType) { XPathException err = new XPathException("Attribute " + env.getNamePool().getDisplayName(nameCode) + " is not permitted in the content model of the simple type " + parentType.getDescription()); err.setIsTypeError(true); err.setLocator(this); if (getHostLanguage() == Configuration.XSLT) { err.setErrorCode("XTTE1510"); } else { err.setErrorCode("XQDY0027"); } throw err; } SchemaType type; try { type = ((ComplexType)parentType).getAttributeUseType(fp); } catch (SchemaException e) { throw new XPathException(e); } if (type == null) { XPathException err = new XPathException("Attribute " + env.getNamePool().getDisplayName(nameCode) + " is not permitted in the content model of the complex type " + parentType.getDescription()); err.setIsTypeError(true); err.setLocator(this); if (getHostLanguage() == Configuration.XSLT) { err.setErrorCode("XTTE1510"); } else { err.setErrorCode("XQDY0027"); } throw err; } if (type instanceof AnyType) { return; } try { // When select is a SimpleContentConstructor, this does nothing select.checkPermittedContents(type, env, true); } catch (XPathException e) { if (e.getLocator() == null || e.getLocator() == e) { e.setLocator(this); } throw e; } } /** * Process this instruction * @param context the dynamic context of the transformation * @return a TailCall to be executed by the caller, always null for this instruction */ public TailCall processLeavingTail(XPathContext context) throws XPathException { Controller controller = context.getController(); SequenceReceiver out = context.getReceiver(); int opt = getOptions(); int ann = getAnnotation(); // we may need to change the namespace prefix if the one we chose is // already in use with a different namespace URI: this is done behind the scenes // by the Outputter CharSequence value = expandChildren(context); SimpleType schemaType = getSchemaType(); int validationAction = getValidationAction(); if (schemaType != null) { // test whether the value actually conforms to the given type ValidationFailure err = schemaType.validateContent( value, DummyNamespaceResolver.getInstance(), context.getConfiguration().getNameChecker()); if (err != null) { ValidationException verr = new ValidationException( "Attribute value " + Err.wrap(value, Err.VALUE) + " does not the match the required type " + schemaType.getDescription() + ". " + err.getMessage()); verr.setErrorCode("XTTE1540"); verr.setLocator((SourceLocator)this); throw verr; } } else if (validationAction==Validation.STRICT || validationAction==Validation.LAX) { // TODO: attempt compile-time validation where possible, as with type=x. try { ann = controller.getConfiguration().validateAttribute( nameCode, value, validationAction); } catch (ValidationException e) { XPathException err = XPathException.makeXPathException(e); //String errorCode = e.getErrorCodeLocalPart(); //if (errorCode == null) { // errorCode = (validationAction==Validation.STRICT ? "XTTE1510" : "XTTE1515"); //} err.setErrorCode(validationAction==Validation.STRICT ? "XTTE1510" : "XTTE1515"); err.setXPathContext(context); err.setLocator(this); err.setIsTypeError(true); throw err; } } try { out.attribute(nameCode, ann, value, locationId, opt); } catch (XPathException err) { throw dynamicError(this, err, context); } return null; } public Item evaluateItem(XPathContext context) throws XPathException { Orphan o = (Orphan)super.evaluateItem(context); SimpleType schemaType = getSchemaType(); int validationAction = getValidationAction(); if (schemaType != null) { ValidationFailure err = schemaType.validateContent( o.getStringValueCS(), DummyNamespaceResolver.getInstance(), context.getConfiguration().getNameChecker()); if (err != null) { throw new ValidationException("Attribute value " + Err.wrap(o.getStringValueCS(), Err.VALUE) + " does not the match the required type " + schemaType.getDescription() + ". " + err.getMessage()); } o.setTypeAnnotation(schemaType.getFingerprint()); if (schemaType.isNamespaceSensitive()) { throw new XPathException("Cannot validate a parentless attribute whose content is namespace-sensitive"); } } else if (validationAction==Validation.STRICT || validationAction==Validation.LAX) { try { int ann = context.getController().getConfiguration().validateAttribute( nameCode, o.getStringValueCS(), validationAction); o.setTypeAnnotation(ann); } catch (ValidationException e) { XPathException err = XPathException.makeXPathException(e); err.setErrorCode(e.getErrorCodeLocalPart()); err.setXPathContext(context); err.setLocator(this); err.setIsTypeError(true); throw err; } } return o; } /** * Diagnostic print of expression structure. The abstract expression tree * is written to the supplied output destination. */ public void explain(ExpressionPresenter out) { out.startElement("directAttribute"); out.emitAttribute("name", out.getNamePool().getDisplayName(nameCode)); out.emitAttribute("validation", Validation.toString(getValidationAction())); if (getSchemaType() != null) { out.emitAttribute("type", getSchemaType().getDescription()); } getSelect().explain(out); out.endElement(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/instruct/GlobalVariable.java0000644000175000017500000002541111033112257022766 0ustar eugeneeugenepackage net.sf.saxon.instruct; import net.sf.saxon.Configuration; import net.sf.saxon.Controller; import net.sf.saxon.expr.*; import net.sf.saxon.om.SingletonIterator; import net.sf.saxon.om.UnfailingIterator; import net.sf.saxon.om.ValueRepresentation; import net.sf.saxon.query.XQueryFunction; import net.sf.saxon.query.XQueryFunctionLibrary; import net.sf.saxon.trans.XPathException; import java.util.ArrayList; import java.util.List; import java.util.Stack; /** * A compiled global variable in a stylesheet or query.
    */ public class GlobalVariable extends GeneralVariable implements Container { private Executable executable; private SlotManager stackFrameMap = null; private int hostLanguage; /** * Create a global variable */ public GlobalVariable(){} /** * Get the executable containing this global variable * @return the containing executable */ public Executable getExecutable() { return executable; } /** * Set the containing executable * @param executable the executable that contains this global variable */ public void setExecutable(Executable executable) { this.executable = executable; } /** * Set the host language for this declaration * @param language the host language (for example XSLT, XQuery) */ public void setHostLanguage(int language) { hostLanguage = language; } /** * Get the host language for this declaration * @return the host language (for example XSLT, XQuery) */ public int getHostLanguage() { return hostLanguage; } /** * The expression that initializes a global variable may itself use local variables. * In this case a stack frame needs to be allocated while evaluating the global variable * @param map The stack frame map for local variables used while evaluating this global * variable. */ public void setContainsLocals(SlotManager map) { this.stackFrameMap = map; } /** * Is this a global variable? * @return true (yes, it is a global variable) */ public boolean isGlobal() { return true; } /** * Check for cycles in this variable definition * @param referees the calls leading up to this one; it's an error if this variable is on the * stack, because that means it calls itself directly or indirectly. The stack may contain * variable definitions (GlobalVariable objects) and user-defined functions (UserFunction objects). * It will never contain the same object more than once. * @param globalFunctionLibrary the library containing all global functions */ public void lookForCycles(Stack referees, XQueryFunctionLibrary globalFunctionLibrary) throws XPathException { if (referees.contains(this)) { int s = referees.indexOf(this); referees.push(this); String message = "Circular definition of global variable. $" + getVariableQName().getDisplayName(); for (int i = s; i < referees.size() - 1; i++) { if (i != s) { message += ", which"; } if (referees.get(i + 1) instanceof GlobalVariable) { GlobalVariable next = (GlobalVariable)referees.get(i + 1); message += " uses $" + next.getVariableQName().getDisplayName(); } else if (referees.get(i + 1) instanceof XQueryFunction) { XQueryFunction next = (XQueryFunction)referees.get(i + 1); message += " calls " + next.getFunctionName().getDisplayName() + "#" + next.getNumberOfArguments() + "()"; } } message += '.'; XPathException err = new XPathException(message); err.setErrorCode("XQST0054"); err.setIsStaticError(true); err.setLocator(this); throw err; } if (select != null) { referees.push(this); List list = new ArrayList(10); ExpressionTool.gatherReferencedVariables(select, list); for (int i=0; i=0; i--) { // TODO: isn't it better to turn the prefix into a code and compare the codes? if (namePool.getPrefixFromNamespaceCode(namespaceCodes[i]).equals(prefix)) { return namePool.getURIFromNamespaceCode(namespaceCodes[i]); } } if (prefix.length() == 0) { // use the "default default namespace" - namely "" return ""; } else { return null; } } /** * Get an iterator over all the prefixes declared in this namespace context. This will include * the default namespace (prefix="") and the XML namespace where appropriate */ public Iterator iteratePrefixes() { ArrayList prefixes = new ArrayList(namespaceCodes.length); for (int i=0; i * The saxon:while element has a mandatory attribute test, a boolean expression. * The content is output repeatedly so long as the test condition is true. */ public class While extends Instruction { private Expression test; private Expression action; public While(Expression test, Expression action) { this.test = test; this.action = action; adoptChildExpression(test); adoptChildExpression(action); } /** * Get the name of this instruction for diagnostic and tracing purposes * @return the string "saxon:while" */ public int getInstructionNameCode() { return StandardNames.SAXON_WHILE; } /** * Get the action expression (the content of the for-each) */ public Expression getActionExpression() { return action; } /** * Simplify an expression. This performs any static optimization (by rewriting the expression * as a different expression). * * @exception XPathException if an error is discovered during expression * rewriting * @return the simplified expression * @param visitor an expression visitor */ public Expression simplify(ExpressionVisitor visitor) throws XPathException { test = visitor.simplify(test); action = visitor.simplify(action); return this; } public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { test = visitor.typeCheck(test, contextItemType); adoptChildExpression(test); action = visitor.typeCheck(action, contextItemType); adoptChildExpression(action); return this; } public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { test = visitor.optimize(test, contextItemType); adoptChildExpression(test); action = visitor.optimize(action, contextItemType); adoptChildExpression(action); return this; } /** * Copy an expression. This makes a deep copy. * * @return the copy of the original expression */ public Expression copy() { return new While(test.copy(), action.copy()); } /** * Get the item type of the items returned by evaluating this instruction * * @return the static item type of the instruction * @param th the type hierarchy cache */ public ItemType getItemType(TypeHierarchy th) { return action.getItemType(th); } /** * Handle promotion offers, that is, non-local tree rewrites. * @param offer The type of rewrite being offered * @throws XPathException */ protected void promoteInst(PromotionOffer offer) throws XPathException { if (offer.action != PromotionOffer.EXTRACT_GLOBAL_VARIABLES) { test = doPromotion(test, offer); } action = doPromotion(action, offer); } /** * Determine whether this instruction creates new nodes. * This implementation returns true if the "action" creates new nodes. * (Nodes created by the condition can't contribute to the result). */ public final boolean createsNewNodes() { int props = action.getSpecialProperties(); return ((props & StaticProperty.NON_CREATIVE) == 0); } /** * Get all the XPath expressions associated with this instruction * (in XSLT terms, the expression present on attributes of the instruction, * as distinct from the child instructions in a sequence construction) */ public Iterator iterateSubExpressions() { return new PairIterator(test, action); } /** * Given an expression that is an immediate child of this expression, test whether * the evaluation of the parent expression causes the child expression to be * evaluated repeatedly * @param child the immediate subexpression * @return true if the child expression is evaluated repeatedly */ public boolean hasLoopingSubexpression(Expression child) { return child == action; } /** * Replace one subexpression by a replacement subexpression * @param original the original subexpression * @param replacement the replacement subexpression * @return true if the original subexpression is found */ public boolean replaceSubExpression(Expression original, Expression replacement) { boolean found = false; if (test == original) { test = replacement; found = true; } if (action == original) { action = replacement; found = true; } return found; } public TailCall processLeavingTail(XPathContext context) throws XPathException { while (test.effectiveBooleanValue(context)) { action.process(context); } return null; } /** * Diagnostic print of expression structure. The abstract expression tree * is written to the supplied output destination. */ public void explain(ExpressionPresenter out) { out.startElement("saxonWhile"); test.explain(out); out.startSubsidiaryElement("do"); action.explain(out); out.endSubsidiaryElement(); out.endElement(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/instruct/UserFunctionParameter.java0000644000175000017500000001252011033112257024402 0ustar eugeneeugenepackage net.sf.saxon.instruct; import net.sf.saxon.expr.Binding; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.ValueRepresentation; import net.sf.saxon.om.StructuredQName; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.SequenceType; import java.io.Serializable; /** * Run-time object representing a formal argument to a user-defined function */ public class UserFunctionParameter implements Binding, Serializable { private SequenceType requiredType; private StructuredQName variableQName; private int slotNumber; private int referenceCount = 999; // The initial value is deliberately set to indicate "many" so that it will be assumed a parameter // is referenced repeatedly until proved otherwise private boolean isIndexed = false; /** * Create a UserFunctionParameter */ public UserFunctionParameter(){} /** * Indicate whether the binding is local or global. A global binding is one that has a fixed * value for the life of a query or transformation; any other binding is local. * @return false (always) */ public final boolean isGlobal() { return false; } /** * Test whether it is permitted to assign to the variable using the saxon:assign * extension element. This will only be for an XSLT global variable where the extra * attribute saxon:assignable="yes" is present. * @return false (always) */ public final boolean isAssignable() { return false; } /** * Set the slot number to be used by this parameter * @param slot the slot number, that is, the position of the parameter value within the local stack frame */ public void setSlotNumber(int slot) { slotNumber = slot; } /** * If this is a local variable held on the local stack frame, return the corresponding slot number. * In other cases, return -1. * @return the slot number, indicating the position of the parameter on the local stack frame */ public int getLocalSlotNumber() { return slotNumber; } /** * Set the required type of this function parameter * @param type the declared type of the parameter */ public void setRequiredType(SequenceType type) { requiredType = type; } /** * Get the required type of this function parameter * @return the declared type of the parameter */ public SequenceType getRequiredType() { return requiredType; } /** * Set the name of this parameter * @param name the name of the parameter */ public void setVariableQName(StructuredQName name) { variableQName = name; } /** * Get the name of this parameter * @return the name of this parameter */ public StructuredQName getVariableQName() { return variableQName; } /** * Set the (nominal) number of references within the function body to this parameter, where a reference * inside a loop is counted as multiple references * @param count the nominal number of references */ public void setReferenceCount(int count) { referenceCount = count; } /** * Get the (nominal) number of references within the function body to this parameter, where a reference * inside a loop is counted as multiple references * @return the nominal number of references */ public int getReferenceCount() { return referenceCount; } /** * Indicate that this parameter requires (or does not require) support for indexing * @param indexed true if support for indexing is required. This will be set if the parameter * is used in a filter expression such as $param[@a = 17] */ public void setIndexedVariable(boolean indexed) { isIndexed = indexed; } /** * Ask whether this parameter requires support for indexing * @return true if support for indexing is required. This will be set if the parameter * is used in a filter expression such as $param[@a = 17] */ public boolean isIndexedVariable() { return isIndexed; } /** * Evaluate this function parameter * @param context the XPath dynamic context * @return the value of the parameter * @throws XPathException if an error occurs */ public ValueRepresentation evaluateVariable(XPathContext context) throws XPathException { return context.evaluateLocalVariable(slotNumber); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none //saxonb-9.1.0.8/bj/net/sf/saxon/instruct/ParameterSet.java0000644000175000017500000000710611033112257022515 0ustar eugeneeugenepackage net.sf.saxon.instruct; import net.sf.saxon.om.ValueRepresentation; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.Closure; /** * A ParameterSet is a set of parameters supplied when calling a template. * It is a collection of id-value pairs, the ids being numeric aliases for the parameter name, * unique within a stylesheet */ public class ParameterSet { private int[] keys; private ValueRepresentation[] values; private int used = 0; public static ParameterSet EMPTY_PARAMETER_SET = new ParameterSet(0); /** * Create an empty parameter set */ public ParameterSet() { this(10); } /** * Create a parameter set specifying the initial capacity */ public ParameterSet(int capacity) { keys = new int[capacity]; values = new ValueRepresentation[capacity]; } /** * Create a parameter set as a copy of an existing parameter set */ public ParameterSet(ParameterSet existing, int extra) { this(existing.used + extra); for (int i=0; i keys.length) { int newlength = (used<=5 ? 10 : used*2); int[] newkeys = new int[newlength]; ValueRepresentation[] newvalues = new ValueRepresentation[newlength]; System.arraycopy(values, 0, newvalues, 0, used); System.arraycopy(keys, 0, newkeys, 0, used); values = newvalues; keys = newkeys; } keys[used] = id; values[used++] = value; } /** * Get a parameter * * @param id The numeric parameter id, representing its name. * @return The value of the parameter, or null if not defined */ public ValueRepresentation get (int id) { for (int i=0; i */ public class WithParam extends GeneralVariable { int parameterId; public WithParam() {} /** * Allocate a number which is essentially an alias for the parameter name, * unique within a stylesheet * @param id the parameter id */ public void setParameterId(int id) { parameterId = id; } /** * Get the parameter id, which is essentially an alias for the parameter name, * unique within a stylesheet * @return the parameter id */ public int getParameterId() { return parameterId; } public int getInstructionNameCode() { return StandardNames.XSL_WITH_PARAM; } public TailCall processLeavingTail(XPathContext context) throws XPathException { // not used return null; } public static void simplify(WithParam[] params, ExpressionVisitor visitor) throws XPathException { for (int i=0; i")) >= 0) { if (isXSLT()) { data = data.substring(0, hh + 1) + ' ' + data.substring(hh + 1); } else { XPathException err = new XPathException("Invalid characters (?>) in processing instruction", this); err.setErrorCode("XQDY0026"); err.setXPathContext(context); throw dynamicError(this, err, context); //context.getController().recoverableError(err); } } data = Whitespace.removeLeadingWhitespace(data).toString(); return data; } public int evaluateNameCode(XPathContext context) throws XPathException { String expandedName = evaluateName(context); return context.getNamePool().allocate("", "", expandedName); } /** * Evaluate the name of the processing instruction. If it is invalid, report a recoverable error * and return null. * @param context * @return the name of the processing instruction (an NCName), or null, incicating an invalid name * @throws XPathException if evaluation fails, or if the recoverable error is treated as fatal */ private String evaluateName(XPathContext context) throws XPathException { String expandedName = Whitespace.trim(name.evaluateAsString(context)); checkName(expandedName, context); return expandedName; } private void checkName(String expandedName, XPathContext context) throws XPathException { if (!(context.getConfiguration().getNameChecker().isValidNCName(expandedName))) { XPathException e = new XPathException("Processing instruction name " + Err.wrap(expandedName) + " is not a valid NCName"); e.setXPathContext(context); e.setErrorCode((isXSLT() ? "XTDE0890" : "XQDY0041")); throw dynamicError(this, e, context); } if (expandedName.equalsIgnoreCase("xml")) { XPathException e = new XPathException("Processing instructions cannot be named 'xml' in any combination of upper/lower case"); e.setXPathContext(context); e.setErrorCode((isXSLT() ? "XTDE0890" : "XQDY0064")); throw dynamicError(this, e, context); } } /** * Diagnostic print of expression structure. The abstract expression tree * is written to the supplied output destination. */ public void explain(ExpressionPresenter out) { out.startElement("processingInstruction"); out.startSubsidiaryElement("name"); name.explain(out); out.endSubsidiaryElement(); out.startSubsidiaryElement("select"); getSelect().explain(out); out.endSubsidiaryElement(); out.endElement(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/instruct/Debugger.java0000644000175000017500000000167111033112257021646 0ustar eugeneeugenepackage net.sf.saxon.instruct; /** * This interface may be implemented by an external debugging tool */ public interface Debugger { /** * Create a SlotManager */ public SlotManager makeSlotManager(); } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // saxonb-9.1.0.8/bj/net/sf/saxon/instruct/ApplyTemplates.java0000644000175000017500000005355311033112257023074 0ustar eugeneeugenepackage net.sf.saxon.instruct; import net.sf.saxon.Controller; import net.sf.saxon.expr.*; import net.sf.saxon.om.*; import net.sf.saxon.trace.ExpressionPresenter; import net.sf.saxon.trace.Location; import net.sf.saxon.trace.TraceListener; import net.sf.saxon.trans.Mode; import net.sf.saxon.trans.Rule; import net.sf.saxon.trans.SaxonErrorCode; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.Type; import net.sf.saxon.value.Value; import java.util.ArrayList; import java.util.Iterator; /** * An instruction representing an xsl:apply-templates element in the stylesheet */ public class ApplyTemplates extends Instruction { private Expression select; private WithParam[] actualParams = null; private WithParam[] tunnelParams = null; private boolean useCurrentMode = false; private boolean useTailRecursion = false; private Mode mode; private boolean backwardsCompatible; private boolean implicitSelect; /** * Construct an apply-templates instructino * @param select the select expression * @param useCurrentMode true if mode="#current" was specified * @param useTailRecursion true if this instruction is the last in its template * @param mode the mode specified on apply-templates * @param backwardsCompatible true if XSLT backwards compatibility is enabled * @param implicitSelect true if the select attribute was defaulted */ public ApplyTemplates( Expression select, boolean useCurrentMode, boolean useTailRecursion, Mode mode, boolean backwardsCompatible, boolean implicitSelect) { this.select = select; this.useCurrentMode = useCurrentMode; this.useTailRecursion = useTailRecursion; this.mode = mode; this.backwardsCompatible = backwardsCompatible; this.implicitSelect = implicitSelect; adoptChildExpression(select); } /** * Set the actual parameters on the call * @param actualParams represents the contained xsl:with-param elements having tunnel="no" (the default) * @param tunnelParams represents the contained xsl:with-param elements having tunnel="yes" */ public void setActualParameters( WithParam[] actualParams, WithParam[] tunnelParams ) { this.actualParams = actualParams; this.tunnelParams = tunnelParams; } /** * Get the name of this instruction for diagnostic and tracing purposes */ public int getInstructionNameCode() { return StandardNames.XSL_APPLY_TEMPLATES; } /** * Set additional trace properties appropriate to the kind of instruction. This * implementation adds the mode attribute */ // public InstructionInfo getInstructionInfo() { // InstructionDetails details = (InstructionDetails)super.getInstructionInfo(); // details.setProperty("mode", mode); // return details; // } /** * Simplify an expression. This performs any static optimization (by rewriting the expression * as a different expression). * * @exception XPathException if an error is discovered during expression * rewriting * @return the simplified expression * @param visitor the expression visitor */ public Expression simplify(ExpressionVisitor visitor) throws XPathException { WithParam.simplify(actualParams, visitor); WithParam.simplify(tunnelParams, visitor); select = visitor.simplify(select); return this; } public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { WithParam.typeCheck(actualParams, visitor, contextItemType); WithParam.typeCheck(tunnelParams, visitor, contextItemType); try { select = visitor.typeCheck(select, contextItemType); } catch (XPathException e) { if (implicitSelect) { if ("XPTY0020".equals(e.getErrorCodeLocalPart())) { XPathException err = new XPathException("Cannot apply-templates to child nodes when the context item is an atomic value"); err.setErrorCode("XTTE0510"); err.setIsTypeError(true); throw err; } else if ("XPDY0002".equals(e.getErrorCodeLocalPart())) { XPathException err = new XPathException("Cannot apply-templates to child nodes when the context item is undefined"); err.setErrorCode("XTTE0510"); err.setIsTypeError(true); throw err; } } throw e; } adoptChildExpression(select); if (Literal.isEmptySequence(select)) { return select; } return this; } public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { WithParam.optimize(visitor, actualParams, contextItemType); WithParam.optimize(visitor, tunnelParams, contextItemType); select = visitor.typeCheck(select, contextItemType); // More info available second time around select = visitor.optimize(select, contextItemType); adoptChildExpression(select); if (Literal.isEmptySequence(select)) { return select; } return this; } /** * Copy an expression. This makes a deep copy. * * @return the copy of the original expression */ public Expression copy() { throw new UnsupportedOperationException("copy"); } /** * Determine whether this instruction creates new nodes. * This implementation returns true (which is almost invariably the case, so it's not worth * doing any further analysis to find out more precisely). */ public final boolean createsNewNodes() { return true; } public void process(XPathContext context) throws XPathException { apply(context, false); } public TailCall processLeavingTail(XPathContext context) throws XPathException { return apply(context, useTailRecursion); } private TailCall apply(XPathContext context, boolean returnTailCall) throws XPathException { Mode thisMode = mode; if (useCurrentMode) { thisMode = context.getCurrentMode(); } // handle parameters if any ParameterSet params = assembleParams(context, actualParams); ParameterSet tunnels = assembleTunnelParams(context, tunnelParams); if (returnTailCall) { XPathContextMajor c2 = context.newContext(); c2.setOrigin(this); return new ApplyTemplatesPackage( ExpressionTool.lazyEvaluate(select, context, 1), thisMode, params, tunnels, c2, getLocationId()); } // Get an iterator to iterate through the selected nodes in original order SequenceIterator iter = select.iterate(context); // Quick exit if the iterator is empty if (iter instanceof EmptyIterator) { return null; } // process the selected nodes now XPathContextMajor c2 = context.newContext(); c2.setOrigin(this); try { TailCall tc = applyTemplates(iter, thisMode, params, tunnels, c2, backwardsCompatible, getLocationId()); while (tc != null) { tc = tc.processLeavingTail(); } } catch (StackOverflowError e) { XPathException err = new XPathException("Too many nested apply-templates calls. The stylesheet may be looping."); err.setErrorCode(SaxonErrorCode.SXLM0001); err.setLocator(this); err.setXPathContext(context); throw err; } return null; } /** * Process selected nodes using the handlers registered for a particular * mode. * * @exception XPathException if any dynamic error occurs * @param iterator an Iterator over the nodes to be processed, in the * correct (sorted) order * @param mode Identifies the processing mode. It should match the * mode defined when the element handler was registered using * setHandler with a mode parameter. Set this parameter to null to * invoke the default mode. * @param parameters A ParameterSet containing the parameters to * the handler/template being invoked. Specify null if there are no * parameters. * @param tunnelParameters A ParameterSet containing the parameters to * the handler/template being invoked. Specify null if there are no * parameters. * @param context A newly-created context object (this must be freshly created by the caller, * as it will be modified by this method) * @param backwardsCompatible true if running in backwards compatibility mode * @param locationId location of this apply-templates instruction in the stylesheet * @return a TailCall returned by the last template to be invoked, or null, * indicating that there are no outstanding tail calls. */ public static TailCall applyTemplates(SequenceIterator iterator, Mode mode, ParameterSet parameters, ParameterSet tunnelParameters, XPathContextMajor context, boolean backwardsCompatible, int locationId) throws XPathException { Controller controller = context.getController(); TailCall tc = null; // Iterate over this sequence if (controller.isTracing()) { context.setCurrentIterator(iterator); context.setCurrentMode(mode); while(true) { NodeInfo node = (NodeInfo)iterator.next(); // We can assume it's a node - we did static type checking if (node == null) { break; } // process any tail calls returned from previous nodes while (tc != null) { tc = tc.processLeavingTail(); } // find the template rule for this node Rule rule = controller.getRuleManager().getTemplateRule(node, mode, context); if (rule==null) { // Use the default action for the node // No need to open a new stack frame! defaultAction(node, parameters, tunnelParameters, context, backwardsCompatible, locationId); } else { Template template = (Template)rule.getAction(); TraceListener traceListener = controller.getTraceListener(); context.setLocalParameters(parameters); context.setTunnelParameters(tunnelParameters); context.openStackFrame(template.getStackFrameMap()); traceListener.startCurrentItem(node); tc = template.applyLeavingTail(context, rule); traceListener.endCurrentItem(node); } } } else { // not tracing context.setCurrentIterator(iterator); context.setCurrentMode(mode); boolean lookahead = (iterator.getProperties() & SequenceIterator.LOOKAHEAD) != 0; Template previousTemplate = null; while(true) { // process any tail calls returned from previous nodes. We need to do this before changing // the context. If we have a LookaheadIterator, we can tell whether we're positioned at the // end without changing the current position, and we can then return the last tail call to // the caller and execute it further down the stack, reducing the risk of running out of stack // space. In other cases, we need to execute the outstanding tail calls before moving the iterator if (tc != null) { if (lookahead && !((LookaheadIterator)iterator).hasNext()) { break; } do { tc = tc.processLeavingTail(); } while (tc != null); } NodeInfo node = (NodeInfo)iterator.next(); // We can assume it's a node - we did static type checking if (node == null) { break; } // find the template rule for this node Rule rule = controller.getRuleManager().getTemplateRule(node, mode, context); if (rule==null) { // Use the default action for the node // No need to open a new stack frame! defaultAction(node, parameters, tunnelParameters, context, backwardsCompatible, locationId); } else { Template template = (Template)rule.getAction(); if (template != previousTemplate) { // Reuse the previous stackframe unless it's a different template rule previousTemplate = template; context.openStackFrame(template.getStackFrameMap()); context.setLocalParameters(parameters); context.setTunnelParameters(tunnelParameters); } //noinspection ConstantConditions tc = template.applyLeavingTail(context, rule); } } } // return the TailCall returned from the last node processed return tc; } /** * Perform the built-in template action for a given node. * * @param node the node to be processed * @param parameters the parameters supplied to apply-templates * @param tunnelParams the tunnel parameters to be passed through * @param context the dynamic evaluation context * @param backwardsCompatible true if in 1.0 mode (currently makes no difference) * @param locationId location of the instruction (apply-templates, apply-imports etc) that caused * the built-in template to be invoked * @exception XPathException if any dynamic error occurs */ public static void defaultAction(NodeInfo node, ParameterSet parameters, ParameterSet tunnelParams, XPathContext context, boolean backwardsCompatible, int locationId) throws XPathException { switch(node.getNodeKind()) { case Type.DOCUMENT: case Type.ELEMENT: SequenceIterator iter = node.iterateAxis(Axis.CHILD); XPathContextMajor c2 = context.newContext(); c2.setOriginatingConstructType(Location.BUILT_IN_TEMPLATE); TailCall tc = applyTemplates( iter, context.getCurrentMode(), parameters, tunnelParams, c2, backwardsCompatible, locationId); while (tc != null) { tc = tc.processLeavingTail(); } return; case Type.TEXT: // NOTE: I tried changing this to use the text node's copy() method, but // performance was worse case Type.ATTRIBUTE: context.getReceiver().characters(node.getStringValueCS(), locationId, 0); return; case Type.COMMENT: case Type.PROCESSING_INSTRUCTION: case Type.NAMESPACE: // no action } } /** * Get all the XPath expressions associated with this instruction * (in XSLT terms, the expression present on attributes of the instruction, * as distinct from the child instructions in a sequence construction) */ public Iterator iterateSubExpressions() { ArrayList list = new ArrayList(10); list.add(select); WithParam.getXPathExpressions(actualParams, list); WithParam.getXPathExpressions(tunnelParams, list); return list.iterator(); } /** * Given an expression that is an immediate child of this expression, test whether * the evaluation of the parent expression causes the child expression to be * evaluated repeatedly * @param child the immediate subexpression * @return true if the child expression is evaluated repeatedly */ public boolean hasLoopingSubexpression(Expression child) { return child instanceof WithParam; } /** * Replace one subexpression by a replacement subexpression * @param original the original subexpression * @param replacement the replacement subexpression * @return true if the original subexpression is found */ public boolean replaceSubExpression(Expression original, Expression replacement) { boolean found = false; if (select == original) { select = replacement; found = true; } if (WithParam.replaceXPathExpression(actualParams, original, replacement)) { found = true; } if (WithParam.replaceXPathExpression(tunnelParams, original, replacement)) { found = true; } return found; } /** * Get the select expression * @return the select expression */ public Expression getSelectExpression() { return select; } /** * Handle promotion offers, that is, non-local tree rewrites. * @param offer The type of rewrite being offered * @throws XPathException */ protected void promoteInst(PromotionOffer offer) throws XPathException { select = doPromotion(select, offer); WithParam.promoteParams(actualParams, offer); WithParam.promoteParams(tunnelParams, offer); } /** * Diagnostic print of expression structure. The abstract expression tree * is written to the supplied output destination. * @param out output destination */ public void explain(ExpressionPresenter out) { out.startElement("applyTemplates"); if (mode != null && !mode.isDefaultMode()) { out.emitAttribute("mode", mode.getModeName().getDisplayName()); } out.startSubsidiaryElement("select"); select.explain(out); out.endSubsidiaryElement(); if (actualParams != null && actualParams.length > 0) { out.startSubsidiaryElement("withParams"); WithParam.displayExpressions(actualParams, out); out.endSubsidiaryElement(); } if (tunnelParams != null && tunnelParams.length > 0) { out.startSubsidiaryElement("tunnelParams"); WithParam.displayExpressions(tunnelParams, out); out.endSubsidiaryElement(); } out.endElement(); } /** * An ApplyTemplatesPackage is an object that encapsulates the sequence of nodes to be processed, * the mode, the parameters to be supplied, and the execution context. This object can be returned as a tail * call, so that the actual call is made from a lower point on the stack, allowing a tail-recursive * template to execute in a finite stack size */ private static class ApplyTemplatesPackage implements TailCall { private ValueRepresentation selectedNodes; private Mode mode; private ParameterSet params; private ParameterSet tunnelParams; private XPathContextMajor evaluationContext; private int locationId; ApplyTemplatesPackage(ValueRepresentation selectedNodes, Mode mode, ParameterSet params, ParameterSet tunnelParams, XPathContextMajor context, int locationId ) { this.selectedNodes = selectedNodes; this.mode = mode; this.params = params; this.tunnelParams = tunnelParams; evaluationContext = context; this.locationId = locationId; } public TailCall processLeavingTail() throws XPathException { return applyTemplates( Value.getIterator(selectedNodes), mode, params, tunnelParams, evaluationContext, false, locationId); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/instruct/QuerySimpleContentConstructor.java0000644000175000017500000001260011033112257026174 0ustar eugeneeugenepackage net.sf.saxon.instruct; import net.sf.saxon.expr.Atomizer; import net.sf.saxon.expr.Expression; import net.sf.saxon.expr.StaticProperty; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.FastStringBuffer; import net.sf.saxon.om.Item; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.BuiltInAtomicType; import net.sf.saxon.value.AtomicValue; import net.sf.saxon.value.StringValue; /** * This class implements the rules for an XQuery simple content constructor, which are used in constructing * the string value of an attribute node, text node, comment node, etc, from the value of the select * expression or the contained sequence constructor. These differ slightly from the XSLT rules implemented * in the superclass - specifically, the sequence is simply atomized, whereas XSLT takes special steps to * concatenate adjacent text nodes before inserting separators. */ public class QuerySimpleContentConstructor extends SimpleContentConstructor { boolean noNodeIfEmpty; public QuerySimpleContentConstructor(Expression select, Expression separator, boolean noNodeIfEmpty) { super(select, separator); this.noNodeIfEmpty = noNodeIfEmpty; } public boolean isNoNodeWhenEmpty() { return noNodeIfEmpty; } /** * Compute the cardinality of the result of the expression. * @return the cardinality, @link {StaticProperty.EXACTLY_ONE} */ protected int computeCardinality() { if (noNodeIfEmpty) { return StaticProperty.ALLOWS_ZERO_OR_ONE; } else { return StaticProperty.EXACTLY_ONE; } } /** * Copy an expression. This makes a deep copy. * @return the copy of the original expression */ public Expression copy() { return new QuerySimpleContentConstructor(select.copy(), separator.copy(), noNodeIfEmpty); } /** * Expand the stylesheet elements subordinate to this one, returning the result * as a string. The expansion must not generate any element or attribute nodes. * @param context The dynamic context for the transformation */ public CharSequence expandChildren(XPathContext context) throws XPathException { Item item = select.evaluateItem(context); if (item==null) { return (noNodeIfEmpty ? null : ""); } else { return item.getStringValueCS(); } } /** * Evaluate an expression as a single item. This always returns either a single Item or * null (denoting the empty sequence). No conversion is done. This method should not be * used unless the static type of the expression is a subtype of "item" or "item?": that is, * it should not be called if the expression may return a sequence. There is no guarantee that * this condition will be detected. * * @param context The context in which the expression is to be evaluated * @return the node or atomic value that results from evaluating the * expression; or null to indicate that the result is an empty * sequence * @throws net.sf.saxon.trans.XPathException * if any dynamic error occurs evaluating the * expression */ public Item evaluateItem(XPathContext context) throws XPathException { if (isSingleton && isAtomic) { // optimize for this case Item item = select.evaluateItem(context); if (item == null) { if (noNodeIfEmpty) { return null; } else { return StringValue.EMPTY_STRING; } } if (item instanceof StringValue) { return item; } else { return ((AtomicValue)item).convert(BuiltInAtomicType.STRING, true, context).asAtomic(); } } SequenceIterator iter = select.iterate(context); if (!isAtomic) { iter = Atomizer.getAtomizingIterator(iter); } FastStringBuffer sb = new FastStringBuffer(1024); boolean first = true; String sep = " "; while (true) { Item item = iter.next(); if (item==null) { break; } if (!first) { sb.append(sep); } first = false; sb.append(item.getStringValueCS()); } if (first && noNodeIfEmpty) { return null; } return StringValue.makeStringValue(sb.condense()); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/instruct/AttributeSet.java0000644000175000017500000001245711033112257022545 0ustar eugeneeugenepackage net.sf.saxon.instruct; import net.sf.saxon.Configuration; import net.sf.saxon.expr.StaticProperty; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.expr.XPathContextMajor; import net.sf.saxon.om.StandardNames; import net.sf.saxon.om.StructuredQName; import net.sf.saxon.trans.XPathException; /** * The compiled form of an xsl:attribute-set element in the stylesheet. */ // Note, there is no run-time check for circularity. This is checked at compile time. public class AttributeSet extends Procedure { StructuredQName attributeSetName; private AttributeSet[] useAttributeSets; /** * Create an empty attribute set */ public AttributeSet() { setHostLanguage(Configuration.XSLT); } /** * Set the name of the attribute-set * @param attributeSetName the name of the attribute-set */ public void setName(StructuredQName attributeSetName) { this.attributeSetName = attributeSetName; } /** * Set the attribute sets used by this attribute set * @param useAttributeSets the set of attribute sets used by this attribute set */ public void setUseAttributeSets(AttributeSet[] useAttributeSets) { this.useAttributeSets = useAttributeSets; } /** * Set the stack frame map which allocates slots to variables declared in this attribute set * @param stackFrameMap the stack frame map */ public void setStackFrameMap(SlotManager stackFrameMap) { if (stackFrameMap != null && stackFrameMap.getNumberOfVariables() > 0) { super.setStackFrameMap(stackFrameMap); } } /** * Determine whether the attribute set has any dependencies on the focus * @return the dependencies */ public int getFocusDependencies() { int d = 0; if (body != null) { d |= body.getDependencies() & StaticProperty.DEPENDS_ON_FOCUS; } if (useAttributeSets != null) { for (int i=0; i * The xsl:param element in XSLT has mandatory attribute name and optional attribute select. It can also * be specified as required="yes" or required="no". In standard XQuery external variables are always required, * and no default value can be specified; but Saxon provides an extension pragma that allows a query * to specify a default. */ public final class GlobalParam extends GlobalVariable { /** * Get the name of this instruction for diagnostic and tracing purposes */ public int getInstructionNameCode() { return StandardNames.XSL_PARAM; } /** * Evaluate the variable */ public ValueRepresentation evaluateVariable(XPathContext context) throws XPathException { Controller controller = context.getController(); Bindery b = controller.getBindery(); boolean wasSupplied; try { wasSupplied = b.useGlobalParameter( getVariableQName(), getSlotNumber(), getRequiredType(), context); } catch (XPathException e) { e.setLocator(this); throw e; } ValueRepresentation val = b.getGlobalVariableValue(this); if (wasSupplied || val!=null) { return val; } else { if (isRequiredParam()) { XPathException e = new XPathException("No value supplied for required parameter $" + getVariableQName().getDisplayName()); e.setXPathContext(context); e.setLocator(getSourceLocator()); e.setErrorCode(isXSLT() ? "XTDE0050" : "XPDY0002"); throw e; } else if (isImplicitlyRequiredParam()) { XPathException e = new XPathException("A value must be supplied for parameter $" + getVariableQName().getDisplayName() + " because there is no default value for the required type"); e.setXPathContext(context); e.setLocator(getSourceLocator()); e.setErrorCode("XTDE0610"); throw e; } // This is the first reference to a global variable; try to evaluate it now. // But first set a flag to stop looping. This flag is set in the Bindery because // the VariableReference itself can be used by multiple threads simultaneously try { b.setExecuting(this, true); ValueRepresentation value = getSelectValue(context); b.defineGlobalVariable(this, value); b.setExecuting(this, false); return value; } catch (XPathException err) { b.setExecuting(this, false); if (err instanceof XPathException.Circularity) { XPathException e = new XPathException("Circular definition of parameter " + getVariableQName().getDisplayName()); e.setXPathContext(context); e.setErrorCode(isXSLT() ? "XTDE0640" : "XQST0054"); // Detect it more quickly the next time (in a pattern, the error is recoverable) select = new ErrorExpression(e); throw e; } else { throw err; } } } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/instruct/Choose.java0000644000175000017500000010552511033112257021345 0ustar eugeneeugenepackage net.sf.saxon.instruct; import net.sf.saxon.trace.ExpressionPresenter; import net.sf.saxon.expr.*; import net.sf.saxon.om.*; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.*; import net.sf.saxon.value.Cardinality; import net.sf.saxon.value.EmptySequence; import net.sf.saxon.value.SequenceType; import net.sf.saxon.value.BooleanValue; import net.sf.saxon.functions.BooleanFn; import net.sf.saxon.functions.SystemFunction; import net.sf.saxon.evpull.EventIterator; import net.sf.saxon.evpull.EmptyEventIterator; import java.util.ArrayList; import java.util.Iterator; /** * Compiled representation of an xsl:choose or xsl:if element in the stylesheet. * Also used for typeswitch in XQuery. */ public class Choose extends Instruction { // The class implements both xsl:choose and xsl:if. There is a list of boolean // expressions (conditions) and a list of corresponding actions: the conditions // are evaluated in turn, and when one is found that is true, the corresponding // action is evaluated. For xsl:if, there is always one condition and one action. // An xsl:otherwise is compiled as if it were xsl:when test="true()". If no // condition is satisfied, the instruction returns an empty sequence. private Expression[] conditions; private Expression[] actions; /** * Construct an xsl:choose instruction * @param conditions the conditions to be tested, in order * @param actions the actions to be taken when the corresponding condition is true */ public Choose(Expression[] conditions, Expression[] actions) { this.conditions = conditions; this.actions = actions; if (conditions.length != actions.length) { throw new IllegalArgumentException("Choose: unequal length arguments"); } for (int i=0; i or "when (test) then ()" if (/*Literal.isConstantBoolean(conditions[conditions.length-1], true) && */ Literal.isEmptySequence(actions[actions.length-1])) { if (conditions.length == 1) { return new Literal(EmptySequence.getInstance()); } else { Expression[] c = new Expression[conditions.length-1]; System.arraycopy(conditions, 0, c, 0, conditions.length-1); Expression[] a = new Expression[actions.length-1]; System.arraycopy(actions, 0, a, 0, actions.length-1); } } // Flatten an "else if" if (Literal.isConstantBoolean(conditions[conditions.length-1], true) && actions[actions.length-1] instanceof Choose) { Choose choose2 = (Choose)actions[actions.length-1]; int newLen = conditions.length + choose2.conditions.length - 1; Expression[] c2 = new Expression[newLen]; Expression[] a2 = new Expression[newLen]; System.arraycopy(conditions, 0, c2, 0, conditions.length - 1); System.arraycopy(actions, 0, a2, 0, actions.length - 1); System.arraycopy(choose2.conditions, 0, c2, conditions.length - 1, choose2.conditions.length); System.arraycopy(choose2.actions, 0, a2, actions.length - 1, choose2.actions.length); conditions = c2; actions = a2; } // Rewrite "if (EXP) then true() else false()" as boolean(EXP) if (conditions.length == 2 && Literal.isConstantBoolean(actions[0], true) && Literal.isConstantBoolean(actions[1], false) && Literal.isConstantBoolean(conditions[1], true)) { TypeHierarchy th = visitor.getConfiguration().getTypeHierarchy(); if (th.isSubType(conditions[0].getItemType(th), BuiltInAtomicType.BOOLEAN) && conditions[0].getCardinality() == StaticProperty.EXACTLY_ONE) { return conditions[0]; } else { return SystemFunction.makeSystemFunction("boolean", new Expression[]{conditions[0]}); } } return this; } public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { for (int i=0; i *

    The default implementation of this method assumes that an expression does no navigation other than * the navigation done by evaluating its subexpressions, and that the subexpressions are evaluated in the * same context as the containing expression. The method must be overridden for any expression * where these assumptions do not hold. For example, implementations exist for AxisExpression, ParentExpression, * and RootExpression (because they perform navigation), and for the doc(), document(), and collection() * functions because they create a new navigation root. Implementations also exist for PathExpression and * FilterExpression because they have subexpressions that are evaluated in a different context from the * calling expression.

    * * @param pathMap the PathMap to which the expression should be added * @param pathMapNodeSet the set of PathMap nodes to which the paths from this expression should be appended * @return the pathMapNode representing the focus established by this expression, in the case where this * expression is the first operand of a path expression or filter expression. For an expression that does * navigation, it represents the end of the arc in the path map that describes the navigation route. For other * expressions, it is the same as the input pathMapNode. */ public PathMap.PathMapNodeSet addToPathMap(PathMap pathMap, PathMap.PathMapNodeSet pathMapNodeSet) { // expressions used in a condition contribute paths, but these do not contribute to the result for (int i=0; i *

    The events (of class {@link net.sf.saxon.evpull.PullEvent}) are either complete * items, or one of startElement, endElement, startDocument, or endDocument, known * as semi-nodes. The stream of events may also include a nested EventIterator. * If a start-end pair exists in the sequence, then the events between * this pair represent the content of the document or element. The content sequence will * have been processed to the extent that any attribute and namespace nodes in the * content sequence will have been merged into the startElement event. Namespace fixup * will have been performed: that is, unique prefixes will have been allocated to element * and attribute nodes, and all namespaces will be declared by means of a namespace node * in the startElement event or in an outer startElement forming part of the sequence. * However, duplicate namespaces may appear in the sequence.

    *

    The content of an element or document may include adjacent or zero-length text nodes, * atomic values, and nodes represented as nodes rather than broken down into events.

    * * @param context The dynamic evaluation context * @return the result of the expression as an iterator over a sequence of PullEvent objects * @throws net.sf.saxon.trans.XPathException * if a dynamic error occurs during expression evaluation */ public EventIterator iterateEvents(XPathContext context) throws XPathException { for (int i=0; i 0) { out.startSubsidiaryElement("withParams"); WithParam.displayExpressions(actualParams, out); out.endSubsidiaryElement(); } if (tunnelParams != null && tunnelParams.length > 0) { out.startSubsidiaryElement("tunnelParams"); WithParam.displayExpressions(tunnelParams, out); out.endSubsidiaryElement(); } out.endElement(); } /** * A NextMatchPackage is an object that encapsulates the name of a template to be called, * the parameters to be supplied, and the execution context. This object can be returned as a tail * call, so that the actual call is made from a lower point on the stack, allowing a tail-recursive * template to execute in a finite stack size */ private class NextMatchPackage implements TailCall { private Rule rule; private ParameterSet params; private ParameterSet tunnelParams; private XPathContext evaluationContext; /** * Construct a NextMatchPackage that contains information about a call. * @param rule the rule identifying the Template to be called * @param params the parameters to be supplied to the called template * @param tunnelParams the tunnel parameter supplied to the called template * @param evaluationContext saved context information from the Controller (current mode, etc) * which must be reset to ensure that the template is called with all the context information * intact */ public NextMatchPackage(Rule rule, ParameterSet params, ParameterSet tunnelParams, XPathContext evaluationContext) { this.rule = rule; this.params = params; this.tunnelParams = tunnelParams; this.evaluationContext = evaluationContext; } /** * Process the template call encapsulated by this package. * @return another TailCall. This will never be the original call, but it may be the next * recursive call. For example, if A calls B which calls C which calls D, then B may return * a TailCall to A representing the call from B to C; when this is processed, the result may be * a TailCall representing the call from C to D. * @throws XPathException if a dynamic error occurs */ public TailCall processLeavingTail() throws XPathException { Template nh = (Template)rule.getAction(); XPathContextMajor c2 = evaluationContext.newContext(); c2.setOrigin(NextMatch.this); c2.setLocalParameters(params); c2.setTunnelParameters(tunnelParams); c2.openStackFrame(nh.getStackFrameMap()); // System.err.println("Tail call on template"); return nh.applyLeavingTail(c2, rule); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/instruct/ComputedAttribute.java0000644000175000017500000005610111033112257023564 0ustar eugeneeugenepackage net.sf.saxon.instruct; import net.sf.saxon.trans.Err; import net.sf.saxon.event.ReceiverOptions; import net.sf.saxon.event.SequenceReceiver; import net.sf.saxon.expr.*; import net.sf.saxon.om.*; import net.sf.saxon.pattern.NodeKindTest; import net.sf.saxon.trace.ExpressionPresenter; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.*; import net.sf.saxon.value.*; import java.util.ArrayList; import java.util.Iterator; /** * An instruction derived from an xsl:attribute element in stylesheet, or from * an attribute constructor in XQuery, in cases where the attribute name is not known * statically */ public final class ComputedAttribute extends AttributeCreator { private Expression attributeName; private Expression namespace = null; private NamespaceResolver nsContext; private boolean allowNameAsQName; /** * Construct an Attribute instruction * @param attributeName An expression to calculate the attribute name * @param namespace An expression to calculate the attribute namespace * @param nsContext a NamespaceContext object containing the static namespace context of the * stylesheet instruction * @param validationAction e.g. validation=strict, lax, strip, preserve * @param schemaType Type against which the attribute must be validated. This must not be a namespace-sensitive * type; it is the caller's responsibility to check this. * @param annotation Integer code identifying the type named in the type attribute * @param allowNameAsQName true if the attributeName expression is allowed to evaluate to a value * of type xs:QName (true in XQuery, false in XSLT) */ public ComputedAttribute (Expression attributeName, Expression namespace, NamespaceResolver nsContext, int validationAction, SimpleType schemaType, int annotation, boolean allowNameAsQName) { this.attributeName = attributeName; this.namespace = namespace; this.nsContext = nsContext; setSchemaType(schemaType); if (annotation == -1) { setAnnotation(StandardNames.XS_UNTYPED_ATOMIC); } else { setAnnotation(annotation); } setValidationAction(validationAction); setOptions(0); this.allowNameAsQName = allowNameAsQName; adoptChildExpression(attributeName); adoptChildExpression(namespace); } /** * Indicate that two attributes with the same name are not acceptable. * (This option is set in XQuery, but not in XSLT) */ public void setRejectDuplicates() { setOptions(getOptions() | ReceiverOptions.REJECT_DUPLICATES); } /** * Get the name of this instruction */ public int getInstructionNameCode() { return StandardNames.XSL_ATTRIBUTE; } /** * Get the expression used to compute the name of the attribute * @return the expression used to compute the name of the attribute */ public Expression getNameExpression() { return attributeName; } /** * Get the expression used to compute the namespace part of the name of the attribute * @return the expression used to compute the namespace part of the name of the attribute */ public Expression getNamespaceExpression() { return namespace; } /** * Get the namespace resolver used to resolve any prefix in the name of the attribute * @return the namespace resolver if one has been saved; or null otherwise */ public NamespaceResolver getNamespaceResolver() { return nsContext; } /** * Get the static type of this expression * @param th the type hierarchy cache * @return the static type of the item returned by this expression */ public ItemType getItemType(TypeHierarchy th) { return NodeKindTest.ATTRIBUTE; } /** * Get the static cardinality of this expression * @return the static cardinality (exactly one) */ public int getCardinality() { return StaticProperty.EXACTLY_ONE; } /** * Get the static properties of this expression (other than its type). The result is * bit-signficant. These properties are used for optimizations. In general, if * property bit is set, it is true, but if it is unset, the value is unknown. * * @return a set of flags indicating static properties of this expression */ public int computeSpecialProperties() { return super.computeSpecialProperties() | StaticProperty.SINGLE_DOCUMENT_NODESET; } public Expression simplify(ExpressionVisitor visitor) throws XPathException { attributeName = visitor.simplify(attributeName); namespace = visitor.simplify(namespace); return super.simplify(visitor); } public void localTypeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { StaticContext env = visitor.getStaticContext(); attributeName = visitor.typeCheck(attributeName, contextItemType); adoptChildExpression(attributeName); RoleLocator role = new RoleLocator(RoleLocator.INSTRUCTION, "attribute/name", 0); //role.setSourceLocator(this); if (allowNameAsQName) { // Can only happen in XQuery attributeName = TypeChecker.staticTypeCheck(attributeName, SequenceType.SINGLE_ATOMIC, false, role, visitor); TypeHierarchy th = visitor.getConfiguration().getTypeHierarchy(); ItemType nameItemType = attributeName.getItemType(th); boolean maybeString = th.relationship(nameItemType, BuiltInAtomicType.STRING) != TypeHierarchy.DISJOINT || th.relationship(nameItemType, BuiltInAtomicType.UNTYPED_ATOMIC) != TypeHierarchy.DISJOINT; boolean maybeQName = th.relationship(nameItemType, BuiltInAtomicType.QNAME) != TypeHierarchy.DISJOINT; if (!(maybeString || maybeQName)) { XPathException err = new XPathException( "The attribute name must be either an xs:string, an xs:QName, or untyped atomic"); err.setErrorCode("XPTY0004"); err.setIsTypeError(true); err.setLocator(this); throw err; } } else { attributeName = TypeChecker.staticTypeCheck(attributeName, SequenceType.SINGLE_STRING, false, role, visitor); } if (namespace != null) { visitor.typeCheck(namespace, contextItemType); adoptChildExpression(namespace); role = new RoleLocator(RoleLocator.INSTRUCTION, "attribute/namespace", 0); //role.setSourceLocator(this); namespace = TypeChecker.staticTypeCheck( namespace, SequenceType.SINGLE_STRING, false, role, visitor); } if (Literal.isAtomic(attributeName)) { // Check we have a valid lexical QName, whose prefix is in scope where necessary try { AtomicValue val = (AtomicValue)((Literal)attributeName).getValue(); if (val instanceof StringValue) { String[] parts = env.getConfiguration().getNameChecker().checkQNameParts(val.getStringValueCS()); if (namespace == null) { String uri = getNamespaceResolver().getURIForPrefix(parts[0], true); if (uri == null) { XPathException se = new XPathException("Prefix " + parts[0] + " has not been declared"); se.setErrorCode(isXSLT() ? "XTDE0860" : "XQDY0074"); se.setIsStaticError(true); throw se; } namespace = new StringLiteral(uri); } } } catch (XPathException e) { if (e.getErrorCodeLocalPart() == null || e.getErrorCodeLocalPart().equals("FORG0001")) { e.setErrorCode(isXSLT() ? "XTDE0850" : "XQDY0074"); } e.maybeSetLocation(this); e.setIsStaticError(true); throw e; } } // TODO: if the attribute name was a compile-time expression, we could replace this expression // by a FixedAttribute instruction (ditto for elements) } public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { attributeName = visitor.optimize(attributeName, contextItemType); return super.optimize(visitor, contextItemType); } /** * Copy an expression. This makes a deep copy. * * @return the copy of the original expression */ public Expression copy() { ComputedAttribute exp = new ComputedAttribute( attributeName == null ? null : attributeName.copy(), namespace == null ? null : namespace.copy(), nsContext, getValidationAction(), getSchemaType(), getAnnotation(), allowNameAsQName); try { exp.setSelect(select == null ? null : select.copy(), getExecutable().getConfiguration()); } catch (XPathException err) { throw new UnsupportedOperationException(err.getMessage()); } return exp; } /** * Get the subexpressions of this expression * @return an iterator over the subexpressions */ public Iterator iterateSubExpressions() { ArrayList list = new ArrayList(3); if (select != null) { list.add(select); } list.add(attributeName); if (namespace != null) { list.add(namespace); } return list.iterator(); } /** * Replace one subexpression by a replacement subexpression * @param original the original subexpression * @param replacement the replacement subexpression * @return true if the original subexpression is found */ public boolean replaceSubExpression(Expression original, Expression replacement) { boolean found = false; if (select == original) { select = replacement; found = true; } if (attributeName == original) { attributeName = replacement; found = true; } if (namespace == original) { namespace = replacement; found = true; } return found; } /** * Offer promotion for subexpressions. The offer will be accepted if the subexpression * is not dependent on the factors (e.g. the context item) identified in the PromotionOffer. * By default the offer is not accepted - this is appropriate in the case of simple expressions * such as constant values and variable references where promotion would give no performance * advantage. This method is always called at compile time. * * @param offer details of the offer, for example the offer to move * expressions that don't depend on the context to an outer level in * the containing expression * @exception XPathException if any error is detected */ protected void promoteInst(PromotionOffer offer) throws XPathException { attributeName = doPromotion(attributeName, offer); if (namespace != null) { namespace = doPromotion(namespace, offer); } super.promoteInst(offer); } /** * Check that any elements and attributes constructed or returned by this expression are acceptable * in the content model of a given complex type. It's always OK to say yes, since the check will be * repeated at run-time. The process of checking element and attribute constructors against the content * model of a complex type also registers the type of content expected of those constructors, so the * static validation can continue recursively. */ public void checkPermittedContents(SchemaType parentType, StaticContext env, boolean whole) throws XPathException { if (parentType instanceof SimpleType) { XPathException err = new XPathException("Attributes are not permitted here: the containing element is of simple type " + parentType.getDescription()); err.setIsTypeError(true); err.setLocator(this); throw err; } } /** * Process this instruction * @param context the dynamic context of the transformation * @return a TailCall to be executed by the caller, always null for this instruction */ public TailCall processLeavingTail(XPathContext context) throws XPathException { int nameCode = evaluateNameCode(context); if (nameCode == -1) { return null; } SequenceReceiver out = context.getReceiver(); int opt = getOptions(); int ann = getAnnotation(); // we may need to change the namespace prefix if the one we chose is // already in use with a different namespace URI: this is done behind the scenes // by the ComplexContentOutputter CharSequence value = expandChildren(context).toString(); SimpleType schemaType = getSchemaType(); int validationAction = getValidationAction(); if (schemaType != null) { // test whether the value actually conforms to the given type try { ValidationFailure err = schemaType.validateContent( value, DummyNamespaceResolver.getInstance(), context.getConfiguration().getNameChecker()); if (err != null) { ValidationException ve = new ValidationException( "Attribute value " + Err.wrap(value, Err.VALUE) + " does not match the required type " + schemaType.getDescription() + ". " + err.getMessage()); ve.setErrorCode("XTTE1540"); throw ve; } } catch (UnresolvedReferenceException ure) { throw new ValidationException(ure); } } else if (validationAction==Validation.STRICT || validationAction==Validation.LAX) { try { ann = context.getConfiguration().validateAttribute(nameCode, value, validationAction); } catch (ValidationException e) { XPathException err = XPathException.makeXPathException(e); String errorCode = e.getErrorCodeLocalPart(); if (errorCode == null) { errorCode = (validationAction==Validation.STRICT ? "XTTE1510" : "XTTE1515"); } err.setErrorCode(errorCode); err.setXPathContext(context); err.setLocator(this); err.setIsTypeError(true); throw err; } } if ((nameCode & NamePool.FP_MASK) == StandardNames.XML_ID) { value = Whitespace.collapseWhitespace(value); } try { out.attribute(nameCode, ann, value, locationId, opt); } catch (XPathException err) { throw dynamicError(this, err, context); } return null; } /** * Determine the name to be used for the attribute, as an integer name code * @param context Dynamic evaluation context * @return the integer name code for the attribute name * @throws XPathException */ public int evaluateNameCode(XPathContext context) throws XPathException { NamePool pool = context.getNamePool(); Item nameValue = attributeName.evaluateItem(context); String prefix = null; String localName; String uri = null; if (nameValue instanceof StringValue) { // this will always be the case in XSLT CharSequence rawName = nameValue.getStringValueCS(); if (Whitespace.containsWhitespace(rawName)) { rawName = Whitespace.trim(rawName); } try { String[] parts = context.getConfiguration().getNameChecker().getQNameParts(rawName); prefix = parts[0]; localName = parts[1]; } catch (QNameException err) { XPathException err1 = new XPathException("Invalid attribute name: " + rawName, this); err1.setErrorCode((isXSLT() ? "XTDE0850" : "XQDY0074")); err1.setXPathContext(context); throw dynamicError(this, err1, context); } if (rawName.toString().equals("xmlns")) { if (namespace==null) { XPathException err = new XPathException("Invalid attribute name: " + rawName, this); err.setErrorCode((isXSLT() ? "XTDE0855" : "XQDY0044")); err.setXPathContext(context); throw dynamicError(this, err, context); } } if (prefix.equals("xmlns")) { if (namespace==null) { XPathException err = new XPathException("Invalid attribute name: " + rawName, this); err.setErrorCode((isXSLT() ? "XTDE0860" : "XQDY0044")); err.setXPathContext(context); throw dynamicError(this, err, context); } else { // ignore the prefix "xmlns" prefix = ""; } } } else if (nameValue instanceof QNameValue && allowNameAsQName) { // this is allowed in XQuery localName = ((QNameValue)nameValue).getLocalName(); uri = ((QNameValue)nameValue).getNamespaceURI(); if (uri == null) { uri = ""; } if (localName.equals("xmlns") && uri.length()==0) { XPathException err = new XPathException("Invalid attribute name: xmlns", this); err.setErrorCode("XQDY0044"); err.setXPathContext(context); throw dynamicError(this, err, context); } if ("xmlns".equals(prefix) || uri.equals("http://www.w3.org/2000/xmlns/")) { XPathException err = new XPathException("Invalid attribute namespace: http://www.w3.org/2000/xmlns/", this); err.setErrorCode("XQDY0044"); err.setXPathContext(context); throw dynamicError(this, err, context); } if (uri.length() == 0) { prefix = ""; } else { prefix = ((QNameValue)nameValue).getPrefix(); if (prefix.length()==0) { // if (uri.equals(NamespaceConstant.XML)) { // prefix = "xml"; // } else { prefix = pool.suggestPrefixForURI(uri); if (prefix == null) { prefix = "ns0"; } // } } // If the prefix is a duplicate, a different one will be substituted } } else { XPathException err = new XPathException("Attribute name must be either a string or a QName", this); err.setErrorCode("XPTY0004"); err.setIsTypeError(true); err.setXPathContext(context); throw dynamicError(this, err, context); } if (namespace == null && uri == null) { if (prefix.length() == 0) { uri = ""; } else { uri = nsContext.getURIForPrefix(prefix, false); if (uri==null) { XPathException err = new XPathException("Undeclared prefix in attribute name: " + prefix, this); err.setErrorCode((isXSLT() ? "XTDE0860" : "XQDY0074")); err.setXPathContext(context); throw dynamicError(this, err, context); } } } else { if (uri == null) { // generate a name using the supplied namespace URI if (namespace instanceof StringLiteral) { uri = ((StringLiteral)namespace).getStringValue(); } else { uri = namespace.evaluateAsString(context).toString(); if (!AnyURIValue.isValidURI(uri)) { XPathException de = new XPathException("The value of the namespace attribute must be a valid URI"); de.setErrorCode("XTDE0865"); de.setXPathContext(context); de.setLocator(this); throw de; } } } if (uri.length() == 0) { // there is a special rule for this case in the XSLT specification; // we force the attribute to go in the null namespace prefix = ""; } else { // if a suggested prefix is given, use it; otherwise try to find a prefix // associated with this URI; if all else fails, invent one. if (prefix.length() == 0) { prefix = pool.suggestPrefixForURI(uri); if (prefix == null) { prefix = "ns0"; // this will be replaced later if it is already in use } } } } return pool.allocate(prefix, uri, localName); } /** * Diagnostic print of expression structure. The abstract expression tree * is written to the supplied output destination. */ public void explain(ExpressionPresenter out) { out.startElement("computedAttribute"); out.emitAttribute("validation", Validation.toString(getValidationAction())); if (getSchemaType() != null) { out.emitAttribute("type", getSchemaType().getDescription()); } out.startSubsidiaryElement("name"); attributeName.explain(out); out.endSubsidiaryElement(); if (namespace != null) { out.startSubsidiaryElement("namespace"); namespace.explain(out); out.endSubsidiaryElement(); } out.startSubsidiaryElement("select"); getSelect().explain(out); out.endSubsidiaryElement(); out.endElement(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/instruct/LocationMap.java0000644000175000017500000000637711033112257022340 0ustar eugeneeugenepackage net.sf.saxon.instruct; import net.sf.saxon.event.LocationProvider; import java.io.Serializable; /** * A LocationMap allocates integer codes to (systemId, lineNumber) pairs. The integer * codes are held inside an Expression object to track the location of the expression * in the source code */ public class LocationMap implements LocationProvider, Serializable { private String[] modules = new String[10]; private int numberOfModules = 0; /** * Create a location map */ public LocationMap() {} /** * Allocate a location identifier to an expression * @param module the URI (system identifier) of the module * @param lineNumber the line number of the expression within the module * @return the corresponding location identifier */ public int allocateLocationId(String module, int lineNumber) { if (module == null) { // the module has no base URI module = "*module with no systemId*"; } int mod = -1; for (int m=numberOfModules-1; m>=0; m--) { if (modules[m].equals(module)) { mod = m; break; } } if (mod == -1) { if (numberOfModules >= modules.length) { String[] m2 = new String[numberOfModules*2]; System.arraycopy(modules, 0, m2, 0, numberOfModules); modules = m2; } mod = numberOfModules; modules[numberOfModules++] = module; } if (mod >= 1024) { modules[mod] = "*unknown module*"; mod = 1023; } if (lineNumber > 999999) { lineNumber = 999999; } return (mod<<20) + lineNumber; } /** * Get the system identifier corresponding to a locationId * @param locationId the location identifier * @return the corresponding system identifier */ public String getSystemId(long locationId) { int m = ((int)locationId)>>20; if (m < 0 || m >= numberOfModules) { return null; } return modules[m]; } /** * Get the line number corresponding to a locationId * @param locationId the location identifier * @return the corresponding line number */ public int getLineNumber(long locationId) { return ((int)locationId) & 0xfffff; } public int getColumnNumber(long locationId) { return -1; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. //saxonb-9.1.0.8/bj/net/sf/saxon/instruct/LocalParam.java0000644000175000017500000001534711033112257022142 0ustar eugeneeugenepackage net.sf.saxon.instruct; import net.sf.saxon.expr.*; import net.sf.saxon.om.StandardNames; import net.sf.saxon.om.ValueRepresentation; import net.sf.saxon.trans.XPathException; import net.sf.saxon.trace.ExpressionPresenter; import java.util.Collections; import java.util.Iterator; /** * The compiled form of an xsl:param element within a template in an XSLT stylesheet. * *

    The xsl:param element in XSLT has mandatory attribute name and optional attribute select. It can also * be specified as required="yes" or required="no".

    * *

    This is used only for parameters to XSLT templates. For function calls, the caller of the function * places supplied arguments onto the callee's stackframe and the callee does not need to do anything. * Global parameters (XQuery external variables) are handled using {@link GlobalParam}. */ public final class LocalParam extends GeneralVariable { private int parameterId; private Expression conversion = null; private int conversionEvaluationMode = ExpressionTool.UNDECIDED; /** * Allocate a number which is essentially an alias for the parameter name, * unique within a stylesheet * @param id the parameter id */ public void setParameterId(int id) { parameterId = id; } /** * Get the parameter id, which is essentially an alias for the parameter name, * unique within a stylesheet * @return the parameter id */ public int getParameterId() { return parameterId; } /** * Define a conversion that is to be applied to the supplied parameter value. * @param convertor The expression to be applied. This performs type checking, * and the basic conversions implied by function calling rules, for example * numeric promotion, atomization, and conversion of untyped atomic values to * a required type. The conversion uses the actual parameter value as input, * referencing it using a VariableReference. */ public void setConversion(Expression convertor) { conversion = convertor; if (convertor != null) { conversionEvaluationMode = ExpressionTool.eagerEvaluationMode(conversion); } } /** * Get the name of this instruction for diagnostic and tracing purposes */ public int getInstructionNameCode() { return StandardNames.XSL_PARAM; } /** * Get all the XPath expressions associated with this instruction * (in XSLT terms, the expression present on attributes of the instruction, * as distinct from the child instructions in a sequence construction) */ public Iterator iterateSubExpressions() { if (select != null && conversion != null) { return new PairIterator(select, conversion); } else if (select != null) { return new MonoIterator(select); } else if (conversion != null) { return new MonoIterator(conversion); } else { return Collections.EMPTY_LIST.iterator(); } } /** * Replace one subexpression by a replacement subexpression * @param original the original subexpression * @param replacement the replacement subexpression * @return true if the original subexpression is found */ public boolean replaceSubExpression(Expression original, Expression replacement) { boolean found = false; if (select == original) { select = replacement; found = true; } if (conversion == original) { conversion = replacement; found = true; } return found; } /** * Process the local parameter declaration */ public TailCall processLeavingTail(XPathContext context) throws XPathException { boolean wasSupplied = context.useLocalParameter(getVariableQName(), this, isTunnelParam()); if (wasSupplied) { // if a parameter was supplied by the caller, we may need to convert it to the type required if (conversion != null) { context.setLocalVariable(getSlotNumber(), ExpressionTool.evaluate(conversion, conversionEvaluationMode, context, 10)); // We do an eager evaluation here for safety, because the result of the // type conversion overwrites the slot where the actual supplied parameter // is contained. } // don't evaluate the default if a value has been supplied or if it has already been // evaluated by virtue of a forwards reference } else { if (isImplicitlyRequiredParam()) { XPathException e = new XPathException("A value must be supplied for the parameter because " + "the default value is not a valid instance of the required type"); e.setXPathContext(context); e.setErrorCode("XTDE0610"); throw e; } else if (isRequiredParam()) { XPathException e = new XPathException("No value supplied for required parameter"); e.setXPathContext(context); e.setErrorCode("XTDE0700"); throw e; } context.setLocalVariable(getSlotNumber(), getSelectValue(context)); } return null; } /** * Evaluate the variable */ public ValueRepresentation evaluateVariable(XPathContext c) { return c.evaluateLocalVariable(slotNumber); } /** * Diagnostic print of expression structure. The abstract expression tree * is written to the supplied output destination. */ public void explain(ExpressionPresenter out) { out.startElement("param"); out.emitAttribute("name", variableQName.getDisplayName()); if (select != null) { select.explain(out); } out.endElement(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/instruct/Message.java0000644000175000017500000002473511033112257021514 0ustar eugeneeugenepackage net.sf.saxon.instruct; import net.sf.saxon.Configuration; import net.sf.saxon.Controller; import net.sf.saxon.event.*; import net.sf.saxon.expr.*; import net.sf.saxon.om.*; import net.sf.saxon.trace.ExpressionPresenter; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.AnyItemType; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.TypeHierarchy; import net.sf.saxon.type.Type; import javax.xml.transform.OutputKeys; import java.util.ArrayList; import java.util.Iterator; import java.util.Properties; /** * An xsl:message element in the stylesheet. */ public class Message extends Instruction { private Expression terminate; private Expression select; /** * Create an xsl:message instruction * @param select the expression that constructs the message (composite of the select attribute * and the contained sequence constructor) * @param terminate expression that calculates terminate = yes or no. */ public Message(Expression select, Expression terminate) { this.terminate = terminate; this.select = select; adoptChildExpression(terminate); adoptChildExpression(select); } /** * Simplify an expression. This performs any static optimization (by rewriting the expression * as a different expression). The default implementation does nothing. * @return the simplified expression * @throws net.sf.saxon.trans.XPathException * if an error is discovered during expression rewriting * @param visitor an expression visitor */ public Expression simplify(ExpressionVisitor visitor) throws XPathException { select = visitor.simplify(select); terminate = visitor.simplify(terminate); return this; } public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { select = visitor.typeCheck(select, contextItemType); adoptChildExpression(select); if (terminate != null) { terminate = visitor.typeCheck(terminate, contextItemType); adoptChildExpression(terminate); } return this; } public Expression optimize(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { select = visitor.optimize(select, contextItemType); adoptChildExpression(select); if (terminate != null) { terminate = visitor.optimize(terminate, contextItemType); adoptChildExpression(terminate); } return this; } /** * Copy an expression. This makes a deep copy. * * @return the copy of the original expression */ public Expression copy() { throw new UnsupportedOperationException("copy"); } /** * Get the name of this instruction for diagnostic and tracing purposes */ public int getInstructionNameCode() { return StandardNames.XSL_MESSAGE; } /** * Get the item type. To avoid spurious compile-time type errors, we falsely declare that the * instruction can return anything * @param th the type hierarchy cache * @return AnyItemType */ public ItemType getItemType(TypeHierarchy th) { return AnyItemType.getInstance(); } /** * Get the static cardinality. To avoid spurious compile-time type errors, we falsely declare that the * instruction returns zero or one items - this is always acceptable * @return zero or one */ public int getCardinality() { return StaticProperty.ALLOWS_ZERO_OR_ONE; } /** * Determine whether this instruction creates new nodes. * This implementation returns true. */ public final boolean createsNewNodes() { return true; } /** * Handle promotion offers, that is, non-local tree rewrites. * @param offer The type of rewrite being offered * @throws XPathException */ protected void promoteInst(PromotionOffer offer) throws XPathException { if (select != null) { select = doPromotion(select, offer); } if (terminate != null) { terminate = doPromotion(terminate, offer); } } /** * Get all the XPath expressions associated with this instruction * (in XSLT terms, the expression present on attributes of the instruction, * as distinct from the child instructions in a sequence construction) */ public Iterator iterateSubExpressions() { ArrayList list = new ArrayList(2); if (select != null) { list.add(select); } if (terminate != null) { list.add(terminate); } return list.iterator(); } /** * Replace one subexpression by a replacement subexpression * @param original the original subexpression * @param replacement the replacement subexpression * @return true if the original subexpression is found */ public boolean replaceSubExpression(Expression original, Expression replacement) { boolean found = false; if (select == original) { select = replacement; found = true; } if (terminate == original) { terminate = replacement; found = true; } return found; } public TailCall processLeavingTail(XPathContext context) throws XPathException { Controller controller = context.getController(); Receiver emitter = controller.getMessageEmitter(); SequenceReceiver rec = new TreeReceiver(emitter); rec = new AttributeMasker(rec); XPathContext c2 = context.newMinorContext(); c2.setOrigin(this); Properties props = new Properties(); props.setProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); c2.changeOutputDestination(props, rec, false, Configuration.XSLT, Validation.PRESERVE, null); boolean abort = false; if (terminate != null) { String term = terminate.evaluateAsString(context).toString(); if (term.equals("no")) { // no action } else if (term.equals("yes")) { abort = true; } else { XPathException e = new XPathException("The terminate attribute of xsl:message must be 'yes' or 'no'"); e.setXPathContext(context); e.setErrorCode("XTDE0030"); throw e; } } rec.startDocument(abort ? ReceiverOptions.TERMINATE : 0); if (select != null) { SequenceIterator iter = select.iterate(c2); while (true) { Item item = iter.next(); if (item == null) { break; } rec.append(item, locationId, NodeInfo.ALL_NAMESPACES); } } rec.endDocument(); if (abort) { throw new TerminationException( "Processing terminated by xsl:message at line " + getLineNumber() + " in " + ExpressionLocation.truncateURI(getSystemId())); } return null; } /** * Diagnostic print of expression structure. The abstract expression tree * is written to the supplied output destination. */ public void explain(ExpressionPresenter out) { out.startElement("xslMessage"); out.endElement(); } private static class AttributeMasker extends ProxyReceiver { private boolean contentStarted = true; public AttributeMasker(SequenceReceiver next) { setPipelineConfiguration(next.getPipelineConfiguration()); setUnderlyingReceiver(next); } public void startElement(int nameCode, int typeCode, int locationId, int properties) throws XPathException { contentStarted = false; super.startElement(nameCode, typeCode, locationId, properties); } public void startContent() throws XPathException { contentStarted = true; super.startContent(); } public void attribute(int nameCode, int typeCode, CharSequence value, int locationId, int properties) throws XPathException { if (contentStarted) { String attName = getNamePool().getDisplayName(nameCode); processingInstruction("attribute", "name=\"" + attName + "\" value=\"" + value + "\"", 0, 0); } else { super.attribute(nameCode, typeCode, value, locationId, properties); } } public void namespace(int namespaceCode, int properties) throws XPathException { if (contentStarted) { String prefix = getNamePool().getPrefixFromNamespaceCode(namespaceCode); String uri = getNamePool().getURIFromNamespaceCode(namespaceCode); processingInstruction("namespace", "prefix=\"" + prefix + "\" uri=\"" + uri + "\"", 0, 0); } else { super.namespace(namespaceCode, properties); } } public void append(Item item, int locationId, int copyNamespaces) throws XPathException { if (item instanceof NodeInfo) { int kind = ((NodeInfo)item).getNodeKind(); if (kind == Type.ATTRIBUTE || kind == Type.NAMESPACE) { ((NodeInfo)item).copy(this, NodeInfo.NO_NAMESPACES, false, 0); return; } } ((SequenceReceiver)nextReceiver).append(item, locationId, copyNamespaces); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/instruct/Comment.java0000644000175000017500000001163411033112257021524 0ustar eugeneeugenepackage net.sf.saxon.instruct; import net.sf.saxon.event.SequenceReceiver; import net.sf.saxon.expr.*; import net.sf.saxon.om.StandardNames; import net.sf.saxon.pattern.NodeKindTest; import net.sf.saxon.trace.ExpressionPresenter; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.TypeHierarchy; /** * An instruction representing an xsl:comment element in the stylesheet. */ public final class Comment extends SimpleNodeConstructor { /** * Construct the instruction */ public Comment() {} /** * Get the instruction name, for diagnostics and tracing * return the string "xsl:comment" */ public int getInstructionNameCode() { return StandardNames.XSL_COMMENT; } public ItemType getItemType(TypeHierarchy th) { return NodeKindTest.COMMENT; } public int getCardinality() { return StaticProperty.EXACTLY_ONE; } /** * Copy an expression. This makes a deep copy. * * @return the copy of the original expression */ public Expression copy() { Comment exp = new Comment(); try { exp.setSelect(select.copy(), getExecutable().getConfiguration()); } catch (XPathException err) { throw new UnsupportedOperationException(err.getMessage()); } return exp; } public void localTypeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { // Do early checking of content if known statically if (select instanceof Literal) { String s = ((Literal)select).getValue().getStringValue(); String s2 = checkContent(s, visitor.getStaticContext().makeEarlyEvaluationContext()); if (!s2.equals(s)) { setSelect(new StringLiteral(s2), visitor.getConfiguration()); } } } /** * Process this instruction, to output a Comment Node * @param context the dynamic context for this transformation * @return a TailCall representing a call delegated to the caller. Always * returns null in this implementation */ public TailCall processLeavingTail(XPathContext context) throws XPathException { String comment = expandChildren(context).toString(); comment = checkContent(comment, context); SequenceReceiver out = context.getReceiver(); out.comment(comment, locationId, 0); return null; } /** * Check the content of the node, and adjust it if necessary * * @param comment the supplied content * @param context the dynamic context * @return the original content, unless adjustments are needed * @throws XPathException if the content is invalid */ protected String checkContent(String comment, XPathContext context) throws XPathException { while(true) { int hh = comment.indexOf("--"); if (hh < 0) break; if (isXSLT()) { comment = comment.substring(0, hh+1) + ' ' + comment.substring(hh+1); } else { XPathException err = new XPathException("Invalid characters (--) in comment", this); err.setErrorCode("XQDY0072"); err.setXPathContext(context); throw dynamicError(this, err, context); } } if (comment.length()>0 && comment.charAt(comment.length()-1)=='-') { if (isXSLT()) { comment = comment + ' '; } else { XPathException err = new XPathException("Comment cannot end in '-'", this); err.setErrorCode("XQDY0072"); err.setXPathContext(context); throw dynamicError(this, err, context); } } return comment; } /** * Diagnostic print of expression structure. The abstract expression tree * is written to the supplied output destination. */ public void explain(ExpressionPresenter out) { out.startElement("comment"); getSelect().explain(out); out.endElement(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/instruct/ForEachGroup.java0000644000175000017500000007140511033112257022450 0ustar eugeneeugenepackage net.sf.saxon.instruct; import net.sf.saxon.Controller; import net.sf.saxon.trans.Err; import net.sf.saxon.expr.*; import net.sf.saxon.om.Item; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.om.StandardNames; import net.sf.saxon.pattern.PatternSponsor; import net.sf.saxon.sort.*; import net.sf.saxon.trace.ExpressionPresenter; import net.sf.saxon.trace.TraceListener; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.SchemaType; import net.sf.saxon.type.TypeHierarchy; import net.sf.saxon.value.StringValue; import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Iterator; /** * Handler for xsl:for-each-group elements in stylesheet. This is a new instruction * defined in XSLT 2.0 */ public class ForEachGroup extends Instruction implements ContextMappingFunction, SortKeyEvaluator { public static final int GROUP_BY = 0; public static final int GROUP_ADJACENT = 1; public static final int GROUP_STARTING = 2; public static final int GROUP_ENDING = 3; private Expression select; private Expression action; private byte algorithm; private Expression key; // for group-starting and group-ending, this is a PatternSponsor private Expression collationNameExpression; private String baseURI; private StringCollator collator = null; // collation used for the grouping comparisons private SortKeyDefinition[] sortKeys = null; private transient AtomicComparer[] sortComparators = null; // comparators used for sorting the groups /** * Create a for-each-group instruction * @param select the select expression (selects the population to be grouped) * @param action the body of the for-each-group (applied to each group in turn) * @param algorithm one of group-by, group-adjacent, group-starting-with, group-ending-with * @param key expression to evaluate the grouping key * @param collator user for comparing strings * @param collationNameExpression expression that yields the name of the collation to be used * @param baseURI static base URI of the expression * @param sortKeys list of xsl:sort keys for sorting the groups */ public ForEachGroup(Expression select, Expression action, byte algorithm, Expression key, StringCollator collator, Expression collationNameExpression, String baseURI, SortKeyDefinition[] sortKeys) { this.select = select; this.action = action; this.algorithm = algorithm; this.key = key; this.collator = collator; this.collationNameExpression = collationNameExpression; this.baseURI = baseURI; this.sortKeys = sortKeys; Iterator kids = iterateSubExpressions(); while (kids.hasNext()) { Expression child = (Expression)kids.next(); adoptChildExpression(child); } } /** * Get the name of this instruction for diagnostic and tracing purposes * @return the name of the instruction */ public int getInstructionNameCode() { return StandardNames.XSL_FOR_EACH_GROUP; } /** * Get the action expression (the content of the for-each-group) * @return the body of the xsl:for-each-group instruction */ public Expression getActionExpression() { return action; } /** * Get the grouping key expression expression (the group-by or group-adjacent expression, or a * PatternSponsor containing the group-starting-with or group-ending-with expression) * @return the expression used to calculate grouping keys */ public Expression getGroupingKey() { return key; } /** * Simplify an expression. This performs any static optimization (by rewriting the expression * as a different expression). * * @return the simplified expression * @throws XPathException if an error is discovered during expression * rewriting * @param visitor an expression visitor */ public Expression simplify(ExpressionVisitor visitor) throws XPathException { select = visitor.simplify(select); action = visitor.simplify(action); key = visitor.simplify(key); return this; } public Expression typeCheck(ExpressionVisitor visitor, ItemType contextItemType) throws XPathException { final TypeHierarchy th = visitor.getConfiguration().getTypeHierarchy(); select = visitor.typeCheck(select, contextItemType); ItemType selectedItemType = select.getItemType(th); action = visitor.typeCheck(action, selectedItemType); key = visitor.typeCheck(key, selectedItemType); if (Literal.isEmptySequence(select)) { return select; } if (Literal.isEmptySequence(action)) { return action; } if (sortKeys != null) { boolean allFixed = true; for (int i=0; i *

    The default implementation of this method assumes that an expression does no navigation other than * the navigation done by evaluating its subexpressions, and that the subexpressions are evaluated in the * same context as the containing expression. The method must be overridden for any expression * where these assumptions do not hold. For example, implementations exist for AxisExpression, ParentExpression, * and RootExpression (because they perform navigation), and for the doc(), document(), and collection() * functions because they create a new navigation root. Implementations also exist for PathExpression and * FilterExpression because they have subexpressions that are evaluated in a different context from the * calling expression.

    * * @param pathMap the PathMap to which the expression should be added * @param pathMapNodeSet * @return the pathMapNode representing the focus established by this expression, in the case where this * expression is the first operand of a path expression or filter expression. For an expression that does * navigation, it represents the end of the arc in the path map that describes the navigation route. For other * expressions, it is the same as the input pathMapNode. */ public PathMap.PathMapNodeSet addToPathMap(PathMap pathMap, PathMap.PathMapNodeSet pathMapNodeSet) { PathMap.PathMapNodeSet target = select.addToPathMap(pathMap, pathMapNodeSet); if (collationNameExpression != null) { collationNameExpression.addToPathMap(pathMap, pathMapNodeSet); } if (sortKeys != null) { for (int i = 0; i < sortKeys.length; i++) { sortKeys[i].getSortKey().addToPathMap(pathMap, target); Expression e = sortKeys[i].getOrder(); if (e != null) { e.addToPathMap(pathMap, pathMapNodeSet); } e = sortKeys[i].getCaseOrder(); if (e != null) { e.addToPathMap(pathMap, pathMapNodeSet); } e = sortKeys[i].getDataTypeExpression(); if (e != null) { e.addToPathMap(pathMap, pathMapNodeSet); } e = sortKeys[i].getLanguage(); if (e != null) { e.addToPathMap(pathMap, pathMapNodeSet); } e = sortKeys[i].getCollationNameExpression(); if (e != null) { e.addToPathMap(pathMap, pathMapNodeSet); } } } return action.addToPathMap(pathMap, target); } /** * Given an expression that is an immediate child of this expression, test whether * the evaluation of the parent expression causes the child expression to be * evaluated repeatedly * @param child the immediate subexpression * @return true if the child expression is evaluated repeatedly */ public boolean hasLoopingSubexpression(Expression child) { return child == action || child == key; } /** * Replace one subexpression by a replacement subexpression * @param original the original subexpression * @param replacement the replacement subexpression * @return true if the original subexpression is found */ public boolean replaceSubExpression(Expression original, Expression replacement) { boolean found = false; if (select == original) { select = replacement; found = true; } if (action == original) { action = replacement; found = true; } if (collationNameExpression == original) { collationNameExpression = replacement; found = true; } if (key == original) { key = replacement; found = true; } if (sortKeys != null) { for (int i = 0; i < sortKeys.length; i++) { if (sortKeys[i].getSortKey() == original) { sortKeys[i].setSortKey(replacement); found = true; } if (sortKeys[i].getOrder() == original) { sortKeys[i].setOrder(replacement); found = true; } if (sortKeys[i].getCaseOrder() == original) { sortKeys[i].setCaseOrder(replacement); found = true; } if (sortKeys[i].getDataTypeExpression() == original) { sortKeys[i].setDataTypeExpression(replacement); found = true; } if (sortKeys[i].getLanguage() == original) { sortKeys[i].setLanguage(replacement); found = true; } } } return found; } /** * Check that any elements and attributes constructed or returned by this expression are acceptable * in the content model of a given complex type. It's always OK to say yes, since the check will be * repeated at run-time. The process of checking element and attribute constructors against the content * model of a complex type also registers the type of content expected of those constructors, so the * static validation can continue recursively. */ public void checkPermittedContents(SchemaType parentType, StaticContext env, boolean whole) throws XPathException { action.checkPermittedContents(parentType, env, false); } public TailCall processLeavingTail(XPathContext context) throws XPathException { Controller controller = context.getController(); GroupIterator groupIterator = getGroupIterator(context); XPathContextMajor c2 = context.newContext(); c2.setOrigin(this); c2.setCurrentIterator(groupIterator); c2.setCurrentGroupIterator(groupIterator); c2.setCurrentTemplateRule(null); if (controller.isTracing()) { TraceListener listener = controller.getTraceListener(); while (true) { Item item = groupIterator.next(); if (item == null) { break; } listener.startCurrentItem(item); action.process(c2); listener.endCurrentItem(item); } } else { while (true) { Item item = groupIterator.next(); if (item == null) { break; } action.process(c2); } } return null; } /** * Get (and if necessary, create) the comparator used for comparing grouping key values * @param context XPath dynamic context * @return a StringCollator suitable for comparing the values of grouping keys * @throws XPathException */ private StringCollator getCollator(XPathContext context) throws XPathException { if (collationNameExpression != null) { StringValue collationValue = (StringValue)collationNameExpression.evaluateItem(context); String cname = collationValue.getStringValue(); URI collationURI; try { collationURI = new URI(cname); if (!collationURI.isAbsolute()) { if (baseURI == null) { XPathException err = new XPathException("Cannot resolve relative collation URI '" + cname + "': unknown or invalid base URI"); err.setErrorCode("XTDE1110"); err.setXPathContext(context); err.setLocator(this); throw err; } collationURI = new URI(baseURI).resolve(collationURI); cname = collationURI.toString(); } } catch (URISyntaxException e) { XPathException err = new XPathException("Collation name '" + cname + "' is not a valid URI"); err.setErrorCode("XTDE1110"); err.setXPathContext(context); err.setLocator(this); throw err; } return context.getCollation(cname); } else { StringCollator collator = context.getDefaultCollation(); return (collator==null ? CodepointCollator.getInstance() : collator); } } private GroupIterator getGroupIterator(XPathContext context) throws XPathException { SequenceIterator population = select.iterate(context); // get an iterator over the groups in "order of first appearance" GroupIterator groupIterator; switch (algorithm) { case GROUP_BY: { StringCollator coll = collator; if (coll==null) { // The collation is determined at run-time coll = getCollator(context); } XPathContext c2 = context.newMinorContext(); c2.setOrigin(this); c2.setCurrentIterator(population); groupIterator = new GroupByIterator(population, key, c2, coll); break; } case GROUP_ADJACENT: { StringCollator coll = collator; if (coll==null) { // The collation is determined at run-time coll = getCollator(context); } groupIterator = new GroupAdjacentIterator(population, key, context, coll); break; } case GROUP_STARTING: groupIterator = new GroupStartingIterator(population, ((PatternSponsor)key).getPattern(), context); break; case GROUP_ENDING: groupIterator = new GroupEndingIterator(population, ((PatternSponsor)key).getPattern(), context); break; default: throw new AssertionError("Unknown grouping algorithm"); } // now iterate over the leading nodes of the groups if (sortKeys != null) { AtomicComparer[] comps = sortComparators; XPathContext xpc = context.newMinorContext(); if (comps == null) { comps = new AtomicComparer[sortKeys.length]; for (int s = 0; s < sortKeys.length; s++) { comps[s] = sortKeys[s].makeComparator(xpc); } } groupIterator = new SortedGroupIterator(xpc, groupIterator, this, comps, this); } return groupIterator; } /** * Return an Iterator to iterate over the values of a sequence. The value of every * expression can be regarded as a sequence, so this method is supported for all * expressions. This default implementation relies on the process() method: it * "pushes" the results of the instruction to a sequence in memory, and then * iterates over this in-memory sequence. *

    * In principle instructions should implement a pipelined iterate() method that * avoids the overhead of intermediate storage. * * @param context supplies the context for evaluation * @return a SequenceIterator that can be used to iterate over the result * of the expression * @throws XPathException if any dynamic error occurs evaluating the * expression */ public SequenceIterator iterate(XPathContext context) throws XPathException { GroupIterator master = getGroupIterator(context); XPathContextMajor c2 = context.newContext(); c2.setOrigin(this); c2.setCurrentIterator(master); c2.setCurrentGroupIterator(master); c2.setCurrentTemplateRule(null); return new ContextMappingIterator(this, c2); } /** * Map one item to a sequence. * * @param context The processing context. This is supplied only for mapping constructs that * set the context node, position, and size. Otherwise it is null. * @return either (a) a SequenceIterator over the sequence of items that the supplied input * item maps to, or (b) an Item if it maps to a single item, or (c) null if it maps to an empty * sequence. */ public SequenceIterator map(XPathContext context) throws XPathException { return action.iterate(context); } /** * Callback for evaluating the sort keys */ public Item evaluateSortKey(int n, XPathContext c) throws XPathException { return sortKeys[n].getSortKey().evaluateItem(c); } /** * Diagnostic print of expression structure. The abstract expression tree * is written to the supplied output destination. */ public void explain(ExpressionPresenter out) { out.startElement("forEachGroup"); out.emitAttribute("algorithm", getAlgorithmName(algorithm)); out.startSubsidiaryElement("select"); select.explain(out); out.endSubsidiaryElement(); out.startSubsidiaryElement("key"); key.explain(out); out.endSubsidiaryElement(); out.startSubsidiaryElement("return"); action.explain(out); out.endSubsidiaryElement(); out.endElement(); } private String getAlgorithmName(byte algorithm) { switch (algorithm) { case GROUP_BY: return "group-by"; case GROUP_ADJACENT: return "group-adjacent"; case GROUP_STARTING: return "group-starting-with"; case GROUP_ENDING: return "group-ending-with"; default: return "** unknown algorithm **"; } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/instruct/UserFunction.java0000644000175000017500000005203611033112257022547 0ustar eugeneeugenepackage net.sf.saxon.instruct; import net.sf.saxon.Controller; import net.sf.saxon.trace.Location; import net.sf.saxon.evpull.EventIterator; import net.sf.saxon.expr.*; import net.sf.saxon.om.*; import net.sf.saxon.sort.SortExpression; import net.sf.saxon.sort.TupleSorter; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.Type; import net.sf.saxon.type.TypeHierarchy; import net.sf.saxon.value.SequenceType; import net.sf.saxon.value.Value; import java.util.HashMap; import java.util.Iterator; import java.util.Set; /** * This object represents the compiled form of a user-written function * (the source can be either an XSLT stylesheet function or an XQuery function). * *

    It is assumed that type-checking, of both the arguments and the results, * has been handled at compile time. That is, the expression supplied as the body * of the function must be wrapped in code to check or convert the result to the * required type, and calls on the function must be wrapped at compile time to check or * convert the supplied arguments. */ public class UserFunction extends Procedure { private StructuredQName functionName; private boolean memoFunction = false; private boolean tailCalls = false; // indicates that the function contains tail calls, not necessarily recursive ones. private boolean tailRecursive = false; // indicates that the function contains tail calls on itself private UserFunctionParameter[] parameterDefinitions; private SequenceType resultType; private int evaluationMode = ExpressionTool.UNDECIDED; private boolean isUpdating = false; /** * Create a user-defined function with no body (the body must be added later) */ public UserFunction() {} /** * Create a user-defined function * @param body the expression comprising the body of the function, which is evaluated to compute the result * of the function */ public UserFunction(Expression body) { setBody(body); } /** * Set the function name * @param name the function name */ public void setFunctionName(StructuredQName name) { functionName = name; } /** * Get the function name * @return the function name, as a StructuredQName */ public StructuredQName getFunctionName() { return functionName; } /** * Get a name identifying the object of the expression, for example a function name, template name, * variable name, key name, element name, etc. This is used only where the name is known statically. * */ public StructuredQName getObjectName() { return functionName; } /** * Determine the preferred evaluation mode for this function */ public void computeEvaluationMode() { if (tailRecursive || memoFunction) { // If this function contains tail calls, we evaluate it eagerly, because // the caller needs to know whether a tail call was returned or not: if we // return a Closure, the tail call escapes into the wild and can reappear anywhere... // Eager evaluation also makes sense if it's a memo function. evaluationMode = ExpressionTool.eagerEvaluationMode(getBody()); } else { evaluationMode = ExpressionTool.lazyEvaluationMode(getBody()); } } /** * Set the definitions of the declared parameters for this function * @param params an array of parameter definitions */ public void setParameterDefinitions(UserFunctionParameter[] params) { parameterDefinitions = params; } /** * Get the definitions of the declared parameters for this function * @return an array of parameter definitions */ public UserFunctionParameter[] getParameterDefinitions() { return parameterDefinitions; } /** * Set the declared result type of the function * @param resultType the declared return type */ public void setResultType(SequenceType resultType) { this.resultType = resultType; } /** * Indicate whether the function contains a tail call * @param tailCalls true if the function contains a tail call (on any function) * @param recursiveTailCalls true if the function contains a tail call (on itself) */ public void setTailRecursive(boolean tailCalls, boolean recursiveTailCalls) { this.tailCalls = tailCalls; tailRecursive = recursiveTailCalls; } /** * Determine whether the function contains tail calls (on this or other functions) * @return true if the function contains tail calls */ public boolean containsTailCalls() { return tailCalls; } /** * Determine whether the function contains a tail call, calling itself * @return true if the function contains a directly-recursive tail call */ public boolean isTailRecursive() { return tailRecursive; } /** * Set whether this is an updating function (as defined in XQuery Update) * @param isUpdating true if this is an updating function */ public void setUpdating(boolean isUpdating) { this.isUpdating = isUpdating; } /** * Ask whether this is an updating function (as defined in XQuery Update) * @return true if this is an updating function */ public boolean isUpdating() { return isUpdating; } /** * Get the type of value returned by this function * @param th the type hierarchy cache * @return the declared result type, or the inferred result type * if this is more precise */ public SequenceType getResultType(TypeHierarchy th) { if (resultType == SequenceType.ANY_SEQUENCE) { // see if we can infer a more precise result type. We don't do this if the function contains // calls on further functions, to prevent infinite regress. if (!containsUserFunctionCalls(getBody())) { resultType = SequenceType.makeSequenceType( getBody().getItemType(th), getBody().getCardinality()); } } return resultType; } /** * Determine whether a given expression contains calls on user-defined functions * @param exp the expression to be tested * @return true if the expression contains calls to user functions. */ private static boolean containsUserFunctionCalls(Expression exp) { if (exp instanceof UserFunctionCall) { return true; } Iterator i = exp.iterateSubExpressions(); while (i.hasNext()) { Expression e = (Expression)i.next(); if (containsUserFunctionCalls(e)) { return true; } } return false; } /** * Get the required types of an argument to this function * @param n identifies the argument in question, starting at 0 * @return a SequenceType object, indicating the required type of the argument */ public SequenceType getArgumentType(int n) { return parameterDefinitions[n].getRequiredType(); } /** * Get the evaluation mode. The evaluation mode will be computed if this has not already been done * @return the computed evaluation mode */ public int getEvaluationMode() { if (evaluationMode == ExpressionTool.UNDECIDED) { computeEvaluationMode(); } return evaluationMode; } /** * Get the arity of this function * @return the number of arguments */ public int getNumberOfArguments() { return parameterDefinitions.length; } /** * Mark this function as a memo function (or not) * @param isMemo true if this is a memo function */ public void setMemoFunction(boolean isMemo) { memoFunction = isMemo; } /** * Ask whether this function is a memo function * @return true if this function is marked as a memo function */ public boolean isMemoFunction() { return memoFunction; } /** * Gather the direct contributing callees of this function. A callee is a function that this one * calls. A contributing callee is a function whose output is added directly to the output of this * function without further processing (other than by attaching it to a parent element or document * node). A direct contributing callee is a function that is called directly, rather than indirectly. * @param result the list into which the callees are gathered. */ public void gatherDirectContributingCallees(Set result) { Expression body = getBody(); gatherDirectContributingCallees(body, result); } private void gatherDirectContributingCallees(Expression exp, Set result) { Iterator kids = exp.iterateSubExpressions(); while (kids.hasNext()) { Expression kid = (Expression)kids.next(); if (kid instanceof UserFunctionCall) { result.add(((UserFunctionCall)kid).getFunction()); } else if (kid instanceof Assignation) { gatherDirectContributingCallees(((Assignation)kid).getAction(), result); // } else if (kid instanceof IfExpression) { // gatherDirectContributingCallees(((IfExpression)kid).getThenExpression(), result); // gatherDirectContributingCallees(((IfExpression)kid).getElseExpression(), result); } else if (kid instanceof Choose) { Expression[] actions = ((Choose)kid).getActions(); for (int c=0; c *

    The default implementation of this method assumes that an expression does no navigation other than * the navigation done by evaluating its subexpressions, and that the subexpressions are evaluated in the * same context as the containing expression. The method must be overridden for any expression * where these assumptions do not hold. For example, implementations exist for AxisExpression, ParentExpression, * and RootExpression (because they perform navigation), and for the doc(), document(), and collection() * functions because they create a new navigation root. Implementations also exist for PathExpression and * FilterExpression because they have subexpressions that are evaluated in a different context from the * calling expression.

    * * @param pathMap the PathMap to which the expression should be added * @param pathMapNodeSet the PathMapNodeSet to which the paths embodied in this expression should be added * @return the pathMapNodeSet representing the points in the source document that are both reachable by this * expression, and that represent possible results of this expression. For an expression that does * navigation, it represents the end of the arc in the path map that describes the navigation route. For other * expressions, it is the same as the input pathMapNode. */ public PathMap.PathMapNodeSet addToPathMap(PathMap pathMap, PathMap.PathMapNodeSet pathMapNodeSet) { PathMap.PathMapNodeSet result = super.addToPathMap(pathMap, pathMapNodeSet); result.addDescendants(); return new PathMap.PathMapNodeSet(pathMap.makeNewRoot(this)); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/instruct/TraceExpression.java0000644000175000017500000001547411033112257023246 0ustar eugeneeugenepackage net.sf.saxon.instruct; import net.sf.saxon.expr.Expression; import net.sf.saxon.om.NamespaceResolver; import net.sf.saxon.om.StructuredQName; import net.sf.saxon.trace.InstructionInfo; import java.util.HashMap; import java.util.Iterator; /** * A subclass of TraceWrapper used to trace expressions in XPath and XQuery. Unlike * the TraceInstruction class, this class contains all information needed for tracing, * rather than referencing a separate InstructionDetails object. */ public class TraceExpression extends TraceWrapper implements InstructionInfo { private int lineNumber = -1; private int columnNumber = -1; private String systemId = null; //private int objectNameCode = -1; private StructuredQName objectName; private int constructType; private NamespaceResolver namespaceResolver = null; private HashMap properties = new HashMap(10); /** * Create a trace expression that traces execution of a given child expression * @param child the expression to be traced. This will be available to the TraceListener * as the value of the "expression" property of the InstructionInfo. */ public TraceExpression(Expression child) { this.child = child; adoptChildExpression(child); setProperty("expression", child); } /** * Set the line number of the expression being traced * @param line */ public void setLineNumber(int line) { lineNumber = line; } /** * Set the column number of the expression being traced * @param column */ public void setColumnNumber(int column) { columnNumber = column; } /** * Set the type of construct. This will generally be a constant * in class {@link net.sf.saxon.trace.Location} */ public void setConstructType(int type) { constructType = type; } /** * Get the construct type. This will generally be a constant * in class {@link net.sf.saxon.trace.Location} */ public int getConstructType() { return constructType; } /** * Set the namespace context for the instruction being traced. This is needed if the * tracelistener wants to evaluate XPath expressions in the context of the current instruction */ public void setNamespaceResolver(NamespaceResolver resolver) { namespaceResolver = resolver; } /** * Get the namespace resolver to supply the namespace context of the instruction * that is being traced */ public NamespaceResolver getNamespaceResolver() { return namespaceResolver; } /** * Set the URI of the module containing the instruction * @param systemId the module's URI */ public void setSystemId(String systemId) { this.systemId = systemId; } /** * Get the URI of the module containing the instruction * @return the module's URI */ public String getSystemId() { return systemId; } /** * Get the line number of the instruction within its module * @return the line number */ public int getLineNumber() { return lineNumber; } /** * Set a name identifying the object of the expression, for example a function name, template name, * variable name, key name, element name, etc. This is used only where the name is known statically. */ public void setObjectName(StructuredQName qName) { objectName = qName; } /** * Get a name identifying the object of the expression, for example a function name, template name, * variable name, key name, element name, etc. This is used only where the name is known statically. */ public StructuredQName getObjectName() { return objectName; } /** * Set a named property of the instruction/expression */ public void setProperty(String name, Object value) { properties.put(name, value); } /** * Get a named property of the instruction/expression */ public Object getProperty(String name) { return properties.get(name); } /** * Get an iterator over all the properties available. The values returned by the iterator * will be of type String, and each string can be supplied as input to the getProperty() * method to retrieve the value of the property. */ public Iterator getProperties() { return properties.keySet().iterator(); } /** * Get the column number identifying the position of the instruction. This method * is provided to satisfy the SourceLocator interface. However, the column number is * not maintained by Saxon, and the method always returns -1 * @return -1 */ public int getColumnNumber() { return columnNumber; } /** * Get the InstructionInfo details about the construct. This is to satisfy the InstructionInfoProvider * interface. */ public InstructionInfo getInstructionInfo() { return this; } /** * Get the system identifier (that is the base URI) of the static context of the expression being * traced. This returns the same result as getSystemId(), it is provided to satisfy the * {@link net.sf.saxon.event.LocationProvider} interface. * @param locationId not used * @return the URI of the module containing the expression */ public String getSystemId(long locationId) { return getSystemId(); } /** * Get the line number of the expression being * traced. This returns the same result as getLineNumber(), it is provided to satisfy the * {@link net.sf.saxon.event.LocationProvider} interface. * @param locationId not used * @return the line number of the expression within its module */ public int getLineNumber(long locationId) { return getLineNumber(); } public int getColumnNumber(long locationId) { return getColumnNumber(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/instruct/package.html0000644000175000017500000000336511033112257021542 0ustar eugeneeugene Package overview: net.sf.saxon.instruct

    This package provides classes for the compiled representation of the various elements and other instructions found in an XSLT stylesheet. The same constructs are also used for evaluating similar constructs in XQuery, in particular, expressions that construct new nodes.

    Instances of these classes are constructed when the stylesheet or query is compiled. In the case of XSLT, the objects representing the compile-time stylesheet (in package net.sf.saxon.style) can then be discarded and garbage-collected.

    The most important class is Instruction, which represents an XSLT Instruction. In most cases these instructions have a one-to-one relationship with instructions in the original source XSLT stylesheet, and the names of the subclasses (for example ApplyImports, ApplyTemplates, Choose) reflect this.

    In XSLT 1.0, XSLT instructions and XPath expressions were quite distinct, and were evaluated in different ways: XSLT instructions in "push" mode (they were described as "writing to the result tree"), and XPath expressions in "pull" mode (reading from the source tree). This distinction is no longer present in the XSLT 2.0 processing model, and the boundary between the Instruction and Expression classes is therefore a rather fuzzy one. Both instructions and expressions can now be evaluated in either push or pull mode. Flow-of-control constructs such as conditional expressions and FOR expressions are evaluated in either mode depending on their parent expression.


    Michael H. Kay
    Saxonica Limited
    9 February 2005

    saxonb-9.1.0.8/bj/net/sf/saxon/value/0000755000175000017500000000000012216261744016525 5ustar eugeneeugenesaxonb-9.1.0.8/bj/net/sf/saxon/value/GDayValue.java0000644000175000017500000001205511033112257021202 0ustar eugeneeugenepackage net.sf.saxon.value; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.FastStringBuffer; import net.sf.saxon.om.StandardNames; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.*; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Implementation of the xs:gDay data type */ public class GDayValue extends GDateValue { private static Pattern regex = Pattern.compile("---([0-9][0-9])(Z|[+-][0-9][0-9]:[0-9][0-9])?"); private GDayValue(){} public static ConversionResult makeGDayValue(CharSequence value) { Matcher m = regex.matcher(Whitespace.trimWhitespace(value)); if (!m.matches()) { return new ValidationFailure("Cannot convert '" + value + "' to a gDay"); } GDayValue g = new GDayValue(); String base = m.group(1); String tz = m.group(2); String date = "2000-01-" + base + (tz==null ? "" : tz); g.typeLabel = BuiltInAtomicType.G_DAY; return setLexicalValue(g, date); } public GDayValue(byte day, int tz) { this(day, tz, BuiltInAtomicType.G_DAY); } public GDayValue(byte day, int tz, AtomicType type) { this.year = 2000; this.month = 1; this.day = day; setTimezoneInMinutes(tz); this.typeLabel = type; } /** * Make a copy of this date, time, or dateTime value * @param typeLabel */ public AtomicValue copyAsSubType(AtomicType typeLabel) { GDayValue v = new GDayValue(day, getTimezoneInMinutes()); v.typeLabel = typeLabel; return v; } /** * Determine the primitive type of the value. This delivers the same answer as * getItemType().getPrimitiveItemType(). The primitive types are * the 19 primitive types of XML Schema, plus xs:integer, xs:dayTimeDuration and xs:yearMonthDuration, * and xs:untypedAtomic. For external objects, the result is AnyAtomicType. */ public BuiltInAtomicType getPrimitiveType() { return BuiltInAtomicType.G_DAY; } /** * Convert to target data type * @param requiredType an integer identifying the required atomic type * @param context * @return an AtomicValue, a value of the required type; or an ErrorValue */ public ConversionResult convertPrimitive(BuiltInAtomicType requiredType, boolean validate, XPathContext context) { switch(requiredType.getPrimitiveType()) { case StandardNames.XS_G_DAY: case StandardNames.XS_ANY_ATOMIC_TYPE: return this; case StandardNames.XS_STRING: return new StringValue(getStringValueCS()); case StandardNames.XS_UNTYPED_ATOMIC: return new UntypedAtomicValue(getStringValueCS()); default: ValidationFailure err = new ValidationFailure("Cannot convert gDay to " + requiredType.getDisplayName()); err.setErrorCode("XPTY0004"); return err; } } public CharSequence getStringValueCS() { FastStringBuffer sb = new FastStringBuffer(16); sb.append("---"); appendTwoDigits(sb, day); if (hasTimezone()) { appendTimezone(sb); } return sb; } /** * Add a duration to this date/time value * * @param duration the duration to be added (which might be negative) * @return a new date/time value representing the result of adding the duration. The original * object is not modified. * @throws net.sf.saxon.trans.XPathException * */ public CalendarValue add(DurationValue duration) throws XPathException { XPathException err = new XPathException("Cannot add a duration to an xs:gDay"); err.setErrorCode("XPTY0004"); throw err; } /** * Return a new date, time, or dateTime with the same normalized value, but * in a different timezone * * @param tz the new timezone, in minutes * @return the date/time in the new timezone */ public CalendarValue adjustTimezone(int tz) { DateTimeValue dt = (DateTimeValue)toDateTime().adjustTimezone(tz); return new GDayValue(dt.getDay(), dt.getTimezoneInMinutes()); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Saxonica Limited // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none //saxonb-9.1.0.8/bj/net/sf/saxon/value/QNameValue.java0000644000175000017500000002270011162742406021365 0ustar eugeneeugenepackage net.sf.saxon.value; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.functions.Component; import net.sf.saxon.om.NameChecker; import net.sf.saxon.om.NamePool; import net.sf.saxon.om.StructuredQName; import net.sf.saxon.om.StandardNames; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.*; /** * A QName value. This implements the so-called "triples proposal", in which the prefix is retained as * part of the value. The prefix is not used in any operation on a QName other than conversion of the * QName to a string. */ public class QNameValue extends QualifiedNameValue { /** * Constructor for a QName that is known to be valid. No validation takes place. * @param prefix The prefix part of the QName (not used in comparisons). Use "" to represent the * default prefix. * @param uri The namespace part of the QName. Use "" to represent the non-namespace. * @param localName The local part of the QName */ public QNameValue(String prefix, String uri, String localName) { this(prefix, uri, localName, BuiltInAtomicType.QNAME); } /** * Constructor for a QName that is known to be valid, allowing a user-defined subtype of QName * to be specified. No validation takes place. * @param prefix The prefix part of the QName (not used in comparisons). Use "" to represent the * default prefix (but null is also accepted) * @param uri The namespace part of the QName. Use null to represent the non-namespace (but "" is also * accepted). * @param localName The local part of the QName * @param type The type label, xs:QName or a subtype of xs:QName */ public QNameValue(String prefix, String uri, String localName, AtomicType type) { qName = new StructuredQName(prefix, uri, localName); if (type == null) { type = BuiltInAtomicType.QNAME; } typeLabel = type; } /** * Constructor starting from a NamePool namecode * @param namePool The name pool containing the specified name code * @param nameCode The name code identifying this name in the name pool */ public QNameValue(NamePool namePool, int nameCode) { String prefix = namePool.getPrefix(nameCode); String uri = namePool.getURI(nameCode); String localPart = namePool.getLocalName(nameCode); qName = new StructuredQName(prefix, uri, localPart); typeLabel = BuiltInAtomicType.QNAME; } /** * Constructor. This constructor validates that the local part is a valid NCName. * @param prefix The prefix part of the QName (not used in comparisons). Use "" to represent the * default prefix (but null is also accepted). * Note that the prefix is not checked for lexical correctness, because in most cases * it will already have been matched against in-scope namespaces. Where necessary the caller must * check the prefix. * @param uri The namespace part of the QName. Use null to represent the non-namespace (but "" is also * accepted). * @param localName The local part of the QName * @param type The atomic type, which must be either xs:QName, or a * user-defined type derived from xs:QName by restriction * @param checker NameChecker used to check the name against XML 1.0 or XML 1.1 rules. Supply null * if the name does not need to be checked (the caller asserts that it is known to be valid) * @throws XPathException if the local part of the name is malformed or if the name has a null * namespace with a non-empty prefix */ public QNameValue(String prefix, String uri, String localName, AtomicType type, NameChecker checker) throws XPathException { if (checker != null && !checker.isValidNCName(localName)) { XPathException err = new XPathException("Malformed local name in QName: '" + localName + '\''); err.setErrorCode("FORG0001"); throw err; } prefix = (prefix==null ? "" : prefix); uri = ("".equals(uri) ? null : uri); if (checker != null && uri == null && prefix.length() != 0) { XPathException err = new XPathException("QName has null namespace but non-empty prefix"); err.setErrorCode("FOCA0002"); throw err; } qName = new StructuredQName(prefix, uri, localName); typeLabel = type; } /** * Constructor * @param qName the name as a StructuredQName * @param typeLabel idenfies a subtype of xs:QName */ public QNameValue(StructuredQName qName, AtomicType typeLabel) { this.qName = qName; this.typeLabel = typeLabel; } /** * Convert to a StructuredQName * @return the name as a StructuredQName */ public StructuredQName toStructuredQName() { return qName; } /** * Create a copy of this atomic value, with a different type label * * @param typeLabel the type label of the new copy. The caller is responsible for checking that * the value actually conforms to this type. */ public AtomicValue copyAsSubType(AtomicType typeLabel) { return new QNameValue(qName, typeLabel); } /** * Determine the primitive type of the value. This delivers the same answer as * getItemType().getPrimitiveItemType(). The primitive types are * the 19 primitive types of XML Schema, plus xs:integer, xs:dayTimeDuration and xs:yearMonthDuration, * and xs:untypedAtomic. For external objects, the result is AnyAtomicType. */ public BuiltInAtomicType getPrimitiveType() { return BuiltInAtomicType.QNAME; } /** * Convert a QName to target data type * @param requiredType an integer identifying the required atomic type * @param context XPath dynamic context * @return an AtomicValue, a value of the required type; or an ErrorValue */ public ConversionResult convertPrimitive(BuiltInAtomicType requiredType, boolean validate, XPathContext context) { switch (requiredType.getPrimitiveType()) { case StandardNames.XS_ANY_ATOMIC_TYPE: case StandardNames.XS_QNAME: return this; case StandardNames.XS_STRING: return new StringValue(getStringValue()); case StandardNames.XS_UNTYPED_ATOMIC: return new UntypedAtomicValue(getStringValue()); default: ValidationFailure err = new ValidationFailure("Cannot convert QName to " + requiredType.getDisplayName()); err.setErrorCode("XPTY0004"); return err; } } /** * Get a component. Returns a zero-length string if the namespace-uri component is * requested and is not present. * @param part either Component.LOCALNAME or Component.NAMESPACE indicating which * component of the value is required * @return either the local name or the namespace URI, in each case as a StringValue */ public AtomicValue getComponent(int part) { if (part == Component.LOCALNAME) { return (AtomicValue)StringValue.makeRestrictedString( getLocalName(), BuiltInAtomicType.NCNAME, null); } else if (part == Component.NAMESPACE) { return new AnyURIValue(getNamespaceURI()); } else if (part == Component.PREFIX) { String prefix = getPrefix(); if (prefix.length() == 0) { return null; } else { return (AtomicValue)StringValue.makeRestrictedString( prefix, BuiltInAtomicType.NCNAME, null); } } else { throw new UnsupportedOperationException("Component of QName must be URI, Local Name, or Prefix"); } } /** * Determine if two QName values are equal. This comparison ignores the prefix part * of the value. * @throws ClassCastException if they are not comparable */ public boolean equals(Object other) { return qName.equals(((QNameValue)other).qName); } public Comparable getSchemaComparable() { return new QNameComparable(); } private class QNameComparable implements Comparable { public QNameValue getQNameValue() { return QNameValue.this; } public int compareTo(Object o) { return equals(o) ? 0 : INDETERMINATE_ORDERING; } public boolean equals(Object o) { return (o instanceof QNameComparable && qName.equals(((QNameComparable)o).getQNameValue().qName)); } public int hashCode() { return qName.hashCode(); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/value/CalendarValue.java0000644000175000017500000002572511033112257022077 0ustar eugeneeugenepackage net.sf.saxon.value; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.FastStringBuffer; import net.sf.saxon.sort.ComparisonKey; import net.sf.saxon.sort.StringCollator; import net.sf.saxon.trans.NoDynamicContextException; import net.sf.saxon.trans.XPathException; import java.math.BigDecimal; import java.util.GregorianCalendar; /** * Abstract superclass for Date, Time, and DateTime. */ public abstract class CalendarValue extends AtomicValue { // This is a reimplementation that makes no use of the Java Calendar/Date types except for computations. private int tzMinutes = NO_TIMEZONE; // timezone offset in minutes: or the special value NO_TIMEZONE public static final int NO_TIMEZONE = Integer.MIN_VALUE; /** * Determine whether this value includes a timezone * @return true if there is a timezone in the value, false if not */ public final boolean hasTimezone() { return tzMinutes != NO_TIMEZONE; } /** * Modify the timezone value held in this object. This must be done only while the value is being * constructed. * @param minutes The timezone offset from GMT in minutes, positive or negative; or the special * value NO_TIMEZONE indicating that the value is not in a timezone (this is the default if this * method is not called) */ public final void setTimezoneInMinutes(int minutes) { tzMinutes = minutes; } /** * Convert the value to a DateTime, retaining all the components that are actually present, and * substituting conventional values for components that are missing * @return the equivalent DateTimeValue */ public abstract DateTimeValue toDateTime(); /** * Get the timezone value held in this object. * @return The timezone offset from GMT in minutes, positive or negative; or the special * value NO_TIMEZONE indicating that the value is not in a timezone */ public final int getTimezoneInMinutes() { return tzMinutes; } /** * Convert the value to a string */ public final String getStringValue() { return getStringValueCS().toString(); } /** * Get a Java Calendar object that represents this date/time value. The Calendar * object will be newly created for the purpose * @return A Calendar object representing the date and time. Note that Java can only * represent the time to millisecond precision, and that it does not support the full * range of timezones required by XPath (-14:00 to +14:00) */ public abstract GregorianCalendar getCalendar(); /** * Add a duration to this date/time value * @param duration the duration to be added (which might be negative) * @return a new date/time value representing the result of adding the duration. The original * object is not modified. * @throws XPathException */ public abstract CalendarValue add(DurationValue duration) throws XPathException; /** * Determine the difference between two points in time, as a duration * @param other the other point in time * @param context the dynamic context, used to obtain timezone information. May be set to null * only if both values contain an explicit timezone, or if neither does so. * @return the duration as an xs:dayTimeDuration * @throws net.sf.saxon.trans.XPathException for example if one value is a date and the other is a time */ public DayTimeDurationValue subtract(CalendarValue other, XPathContext context) throws XPathException { DateTimeValue dt1 = toDateTime(); DateTimeValue dt2 = other.toDateTime(); if (dt1.getTimezoneInMinutes() != dt2.getTimezoneInMinutes()) { dt1 = dt1.normalize(context); dt2 = dt2.normalize(context); } BigDecimal d1 = dt1.toJulianInstant(); BigDecimal d2 = dt2.toJulianInstant(); BigDecimal difference = d1.subtract(d2); return DayTimeDurationValue.fromSeconds(difference); } /** * Return a date, time, or dateTime with the same localized value, but * without the timezone component * @return the result of removing the timezone */ public final CalendarValue removeTimezone() { CalendarValue c = (CalendarValue)copyAsSubType(typeLabel); c.tzMinutes = NO_TIMEZONE; return c; } /** * Return a new date, time, or dateTime with the same normalized value, but * in a different timezone * @param tz the new timezone offset from UTC, in minutes * @return the date/time in the new timezone */ public abstract CalendarValue adjustTimezone(int tz); /** * Return a new date, time, or dateTime with the same normalized value, but * in a different timezone, specified as a dayTimeDuration * @param tz the new timezone, in minutes * @return the date/time in the new timezone */ public final CalendarValue adjustTimezone(DayTimeDurationValue tz) throws XPathException { long microseconds = tz.getLengthInMicroseconds(); if (microseconds%60000000 != 0) { XPathException err = new XPathException("Timezone is not an integral number of minutes"); err.setErrorCode("FODT0003"); throw err; } int tzminutes = (int)(microseconds / 60000000); if (Math.abs(tzminutes) > 14*60) { XPathException err = new XPathException("Timezone out of range (-14:00 to +14:00)"); err.setErrorCode("FODT0003"); throw err; } return adjustTimezone(tzminutes); } /** * Get an object value that implements the XPath equality and ordering comparison semantics for this value. * If the ordered parameter is set to true, the result will be a Comparable and will support a compareTo() * method with the semantics of the XPath lt/gt operator, provided that the other operand is also obtained * using the getXPathComparable() method. In all cases the result will support equals() and hashCode() methods * that support the semantics of the XPath eq operator, again provided that the other operand is also obtained * using the getXPathComparable() method. A context argument is supplied for use in cases where the comparison * semantics are context-sensitive, for example where they depend on the implicit timezone or the default * collation. * * @param ordered true if an ordered comparison is required. In this case the result is null if the * type is unordered; in other cases the returned value will be a Comparable. * @param collator collation used for strings * @param context the XPath dynamic evaluation context, used in cases where the comparison is context * sensitive @return an Object whose equals() and hashCode() methods implement the XPath comparison semantics * with respect to this atomic value. If ordered is specified, the result will either be null if * no ordering is defined, or will be a Comparable */ public Object getXPathComparable(boolean ordered, StringCollator collator, XPathContext context) throws NoDynamicContextException { if (ordered && !(this instanceof Comparable)) { return null; } return (hasTimezone() ? this : adjustTimezone(context.getImplicitTimezone())); } /** * Compare this value to another value of the same type, using the supplied Configuration * to get the implicit timezone if required. * @param other the other value to be compared * @param context the XPath dynamic evaluation context * @return the comparison result * @throws NoDynamicContextException if the supplied context is an early evaluation context and the * result depends on the implicit timezone, which is not available at compile time */ public abstract int compareTo(CalendarValue other, XPathContext context) throws NoDynamicContextException; /** * Get a comparison key for this value. Two values are equal if and only if they their comparison * keys are equal * @param context XPath dynamic evaluation context, used to obtain implicit timezone * @return a comparison key * @throws NoDynamicContextException if the implicit timezone is needed and is not available */ public abstract ComparisonKey getComparisonKey(XPathContext context) throws NoDynamicContextException; /** * Add a string representation of the timezone, typically * formatted as "Z" or "+03:00" or "-10:00", to a supplied * string buffer * @param sb The StringBuffer that will be updated with the resulting string * representation */ public final void appendTimezone(FastStringBuffer sb) { if (hasTimezone()) { appendTimezone(getTimezoneInMinutes(), sb); } } /** * Format a timezone and append it to a buffer * @param tz the timezone * @param sb the buffer */ public static void appendTimezone(int tz, FastStringBuffer sb) { if (tz == 0) { sb.append("Z"); } else { sb.append(tz > 0 ? "+" : "-"); tz = Math.abs(tz); appendTwoDigits(sb, tz/60); sb.append(':'); appendTwoDigits(sb, tz%60); } } /** * Append an integer, formatted with leading zeros to a fixed size, to a string buffer * @param sb the string buffer * @param value the integer to be formatted * @param size the number of digits required (max 9) */ static void appendString(FastStringBuffer sb, int value, int size) { String s = "000000000"+value; sb.append( s.substring(s.length()-size) ); } /** * Append an integer, formatted as two digits, to a string buffer * @param sb the string buffer * @param value the integer to be formatted (must be in the range 0..99 */ static void appendTwoDigits(FastStringBuffer sb, int value) { sb.append((char)(value/10 + '0')); sb.append((char)(value%10 + '0')); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/value/DecimalValue.java0000644000175000017500000005571111033112257021722 0ustar eugeneeugenepackage net.sf.saxon.value; import net.sf.saxon.trans.Err; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.FastStringBuffer; import net.sf.saxon.om.StandardNames; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.*; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.math.BigDecimal; import java.math.BigInteger; import java.util.regex.Pattern; /** * A decimal value */ public final class DecimalValue extends NumericValue { public static final int DIVIDE_PRECISION = 18; private static boolean stripTrailingZerosMethodUnavailable = false; private static Method stripTrailingZerosMethod = null; private static boolean canSetScaleNegative = true; // until proved otherwise private static final Object[] EMPTY_OBJECT_ARRAY = {}; private BigDecimal value; public static final BigDecimal BIG_DECIMAL_ONE = BigDecimal.valueOf(1); public static final BigInteger BIG_INTEGER_TEN = BigInteger.valueOf(10); public static final BigDecimal BIG_DECIMAL_ONE_MILLION = BigDecimal.valueOf(1000000); public static final DecimalValue ZERO = new DecimalValue(BigDecimal.valueOf(0)); public static final DecimalValue ONE = new DecimalValue(BigDecimal.valueOf(1)); /** * Constructor supplying a BigDecimal * @param value the value of the DecimalValue */ public DecimalValue(BigDecimal value) { this.value = stripTrailingZeros(value); typeLabel = BuiltInAtomicType.DECIMAL; } private static final Pattern decimalPattern = Pattern.compile("(\\-|\\+)?((\\.[0-9]+)|([0-9]+(\\.[0-9]*)?))"); /** * Factory method to construct a DecimalValue from a string * @param in the value of the DecimalValue * @param validate true if validation is required; false if the caller knows that the value is valid * @return the required DecimalValue if the input is valid, or a ValidationFailure encapsulating the error * message if not. */ public static ConversionResult makeDecimalValue(CharSequence in, boolean validate) { // TODO: tune this method. Do the trimming, validation, and losing trailing zeros in a single pass. // Use the BigDecimal(integer, scale) constructor. String trimmed = Whitespace.trimWhitespace(in).toString(); try { if (validate) { if (!decimalPattern.matcher(trimmed).matches()) { ValidationFailure err = new ValidationFailure( "Cannot convert string " + Err.wrap(trimmed, Err.VALUE) + " to xs:decimal"); err.setErrorCode("FORG0001"); return err; } } BigDecimal val = new BigDecimal(trimmed); val = stripTrailingZeros(val); return new DecimalValue(val); } catch (NumberFormatException err) { ValidationFailure e = new ValidationFailure( "Cannot convert string " + Err.wrap(trimmed, Err.VALUE) + " to xs:decimal"); e.setErrorCode("FORG0001"); return e; } } /** * Test whether a string is castable to a decimal value * @param in the string to be tested * @return true if the string has the correct format for a decimal */ public static boolean castableAsDecimal(CharSequence in) { CharSequence trimmed = Whitespace.trimWhitespace(in); return decimalPattern.matcher(trimmed).matches(); } /** * Constructor supplying a double * @param in the value of the DecimalValue */ public DecimalValue(double in) throws ValidationException { try { value = stripTrailingZeros(new BigDecimal(in)); } catch (NumberFormatException err) { // Must be a special value such as NaN or infinity ValidationException e = new ValidationException( "Cannot convert double " + Err.wrap(in+"", Err.VALUE) + " to decimal"); e.setErrorCode("FOCA0002"); throw e; } typeLabel = BuiltInAtomicType.DECIMAL; } /** * Constructor supplying a long integer * @param in the value of the DecimalValue */ public DecimalValue(long in) { value = BigDecimal.valueOf(in); typeLabel = BuiltInAtomicType.DECIMAL; } /** * Create a copy of this atomic value, with a different type label * * @param typeLabel the type label of the new copy. The caller is responsible for checking that * the value actually conforms to this type. */ public AtomicValue copyAsSubType(AtomicType typeLabel) { DecimalValue v = new DecimalValue(value); v.typeLabel = typeLabel; return v; } /** * Determine the primitive type of the value. This delivers the same answer as * getItemType().getPrimitiveItemType(). The primitive types are * the 19 primitive types of XML Schema, plus xs:integer, xs:dayTimeDuration and xs:yearMonthDuration, * and xs:untypedAtomic. For external objects, the result is AnyAtomicType. */ public BuiltInAtomicType getPrimitiveType() { return BuiltInAtomicType.DECIMAL; } /** * Remove insignificant trailing zeros (the Java BigDecimal class retains trailing zeros, * but the XPath 2.0 xs:decimal type does not). The BigDecimal#stripTrailingZeros() method * was introduced in JDK 1.5: we use it if available, and simulate it if not. * @param value the supplied value * @return the value with trailing zeroes removed */ private static BigDecimal stripTrailingZeros(BigDecimal value) { if (stripTrailingZerosMethodUnavailable) { return stripTrailingZerosFallback(value); } try { if (stripTrailingZerosMethod == null) { Class[] argTypes = {}; stripTrailingZerosMethod = BigDecimal.class.getMethod("stripTrailingZeros", argTypes); } // Note, this designed to avoid repeated searching for the method to invoke. However, // we still carry the cost of a dynamic invocation using reflection. Object result = stripTrailingZerosMethod.invoke(value, EMPTY_OBJECT_ARRAY); return (BigDecimal)result; } catch (NoSuchMethodException e) { stripTrailingZerosMethodUnavailable = true; return stripTrailingZerosFallback(value); } catch (IllegalAccessException e) { stripTrailingZerosMethodUnavailable = true; return stripTrailingZerosFallback(value); } catch (InvocationTargetException e) { stripTrailingZerosMethodUnavailable = true; return stripTrailingZerosFallback(value); } } private static BigDecimal stripTrailingZerosFallback(BigDecimal value) { // The code below differs from JDK 1.5 stripTrailingZeros in that it does not remove trailing zeros // from integers, for example 1000 is not changed to 1E3. int scale = value.scale(); if (scale > 0) { BigInteger i = value.unscaledValue(); while (true) { BigInteger[] dr = i.divideAndRemainder(BIG_INTEGER_TEN); if (dr[1].equals(BigInteger.ZERO)) { i = dr[0]; scale--; if (scale==0) { break; } } else { break; } } if (scale != value.scale()) { value = new BigDecimal(i, scale); } } return value; } /** * Get the value */ public BigDecimal getDecimalValue() { return value; } /** * Get the hashCode. This must conform to the rules for other NumericValue hashcodes * @see NumericValue#hashCode */ public int hashCode() { BigDecimal round = value.setScale(0, BigDecimal.ROUND_DOWN); long value = round.longValue(); if (value > Integer.MIN_VALUE && value < Integer.MAX_VALUE) { return (int)value; } else { return new Double(getDoubleValue()).hashCode(); } } public boolean effectiveBooleanValue() { return value.signum() != 0; } /** * Convert to target data type */ public ConversionResult convertPrimitive(BuiltInAtomicType requiredType, boolean validate, XPathContext context) { switch(requiredType.getFingerprint()) { case StandardNames.XS_BOOLEAN: // 0.0 => false, anything else => true return BooleanValue.get(value.signum()!=0); case StandardNames.XS_NUMERIC: case StandardNames.XS_DECIMAL: case StandardNames.XS_ANY_ATOMIC_TYPE: return this; case StandardNames.XS_INTEGER: return BigIntegerValue.makeIntegerValue(value.toBigInteger()); case StandardNames.XS_UNSIGNED_LONG: case StandardNames.XS_UNSIGNED_INT: case StandardNames.XS_UNSIGNED_SHORT: case StandardNames.XS_UNSIGNED_BYTE: case StandardNames.XS_NON_POSITIVE_INTEGER: case StandardNames.XS_NEGATIVE_INTEGER: case StandardNames.XS_LONG: case StandardNames.XS_INT: case StandardNames.XS_SHORT: case StandardNames.XS_BYTE: case StandardNames.XS_NON_NEGATIVE_INTEGER: case StandardNames.XS_POSITIVE_INTEGER: IntegerValue iv = BigIntegerValue.makeIntegerValue(value.toBigInteger()); return iv.convertPrimitive(requiredType, validate, context); case StandardNames.XS_DOUBLE: return new DoubleValue(value.doubleValue()); case StandardNames.XS_FLOAT: return new FloatValue(value.floatValue()); case StandardNames.XS_STRING: return new StringValue(getStringValueCS()); case StandardNames.XS_UNTYPED_ATOMIC: return new UntypedAtomicValue(getStringValueCS()); default: ValidationFailure err = new ValidationFailure("Cannot convert decimal to " + requiredType.getDisplayName()); err.setErrorCode("XPTY0004"); return err; } } /** * Get the value of the item as a CharSequence. This is in some cases more efficient than * the version of the method that returns a String. */ public CharSequence getStringValueCS() { return decimalToString(value, new FastStringBuffer(20)); } /** * Get the canonical lexical representation as defined in XML Schema. This is not always the same * as the result of casting to a string according to the XPath rules. For xs:decimal, the canonical * representation always contains a decimal point. */ public CharSequence getCanonicalLexicalRepresentation() { String s = getStringValue(); if (s.indexOf('.') < 0) { s += ".0"; } return s; } /** * Get the value as a String * @return a String representation of the value */ public String getStringValue() { return decimalToString(value, new FastStringBuffer(20)).toString(); } /** * Convert a decimal value to a string, using the XPath rules for formatting * @param value the decimal value to be converted * @param fsb the FastStringBuffer to which the value is to be appended * @return the supplied FastStringBuffer, suitably populated */ public static FastStringBuffer decimalToString(BigDecimal value, FastStringBuffer fsb) { // Can't use the plain BigDecimal#toString() under JDK 1.5 because this produces values like "1E-5". // JDK 1.5 offers BigDecimal#toPlainString() which might do the job directly int scale = value.scale(); if (scale == 0) { fsb.append(value.toString()); return fsb; } else if (scale < 0) { String s = value.abs().unscaledValue().toString(); if (s.equals("0")) { fsb.append('0'); return fsb; } //FastStringBuffer sb = new FastStringBuffer(s.length() + (-scale) + 2); if (value.signum() < 0) { fsb.append('-'); } fsb.append(s); for (int i=0; i<(-scale); i++) { fsb.append('0'); } return fsb; } else { String s = value.abs().unscaledValue().toString(); if (s.equals("0")) { fsb.append('0'); return fsb; } int len = s.length(); //FastStringBuffer sb = new FastStringBuffer(len+1); if (value.signum() < 0) { fsb.append('-'); } if (scale >= len) { fsb.append("0."); for (int i=len; i *

    In the case of data types that are partially ordered, the returned Comparable extends the standard * semantics of the compareTo() method by returning the value {@link Value#INDETERMINATE_ORDERING} when there * is no defined order relationship between two given values.

    */ /** * Get an object that implements XML Schema comparison semantics */ public Comparable getSchemaComparable() { return new DecimalComparable(this); } protected static class DecimalComparable implements Comparable { protected DecimalValue value; public DecimalComparable(DecimalValue value) { this.value = value; } public BigDecimal asBigDecimal() { return value.getDecimalValue(); } public int compareTo(Object o) { if (o instanceof DecimalComparable) { return asBigDecimal().compareTo(((DecimalComparable)o).asBigDecimal()); } else if (o instanceof Int64Value.Int64Comparable) { return asBigDecimal().compareTo(BigDecimal.valueOf(((Int64Value.Int64Comparable)o).asLong())); } else if (o instanceof BigIntegerValue.BigIntegerComparable) { return value.compareTo(new BigDecimal(((BigIntegerValue.BigIntegerComparable)o).asBigInteger())); } else { return INDETERMINATE_ORDERING; } } public boolean equals(Object o) { return compareTo(o) == 0; } public int hashCode() { // Must align with hashCodes for other subtypes of xs:decimal if (value.isWholeNumber()) { try { return value.convertPrimitive(BuiltInAtomicType.INTEGER, true, null).asAtomic() .getSchemaComparable().hashCode(); } catch (ValidationException e) { return 12345678; // can't happen } } return value.hashCode(); } } /** * Convert to Java object (for passing to external functions) */ // public Object convertAtomicToJava(Class target, XPathContext context) throws XPathException { // if (target==Object.class || target.isAssignableFrom(BigDecimal.class)) { // return value; // } else if (target.isAssignableFrom(DecimalValue.class)) { // return this; // } else if (target==double.class || target==Double.class) { // return new Double(value.doubleValue()); // } else if (target==float.class || target==Float.class) { // return new Float(value.floatValue()); // } else if (target==long.class || target==Long.class) { // return new Long(value.longValue()); // } else if (target==int.class || target==Integer.class) { // return new Integer(value.intValue()); // } else if (target==short.class || target==Short.class) { // return new Short(value.shortValue()); // } else if (target==byte.class || target==Byte.class) { // return new Byte(value.byteValue()); // } else if (target==char.class || target==Character.class) { // return new Character((char)value.intValue()); // } else { // Object o = convertSequenceToJava(target, context); // if (o == null) { // throw new XPathException("Conversion of decimal to " + target.getName() + // " is not supported"); // } // return o; // } // } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file except the asStringXT() and zeros() methods (not currently used). // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/value/SequenceType.java0000644000175000017500000003223211033112257021772 0ustar eugeneeugenepackage net.sf.saxon.value; import net.sf.saxon.expr.StaticProperty; import net.sf.saxon.pattern.AnyNodeTest; import net.sf.saxon.pattern.EmptySequenceTest; import net.sf.saxon.type.AnyItemType; import net.sf.saxon.type.BuiltInAtomicType; import net.sf.saxon.type.ItemType; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.om.Item; import net.sf.saxon.trans.XPathException; import net.sf.saxon.Configuration; import java.io.Serializable; import java.util.Collections; import java.util.HashMap; import java.util.Map; /** * SequenceType: a sequence type consists of a primary type, which indicates the type of item, * and a cardinality, which indicates the number of occurrences permitted. Where the primary type * is element or attribute, there may also be a content type, indicating the required type * annotation on the element or attribute content. */ public final class SequenceType implements Serializable { private ItemType primaryType; // the primary type of the item, e.g. "element", "comment", or "integer" private int cardinality; // the required cardinality private static Map pool = Collections.synchronizedMap(new HashMap(50)); /** * A type that allows any sequence of items */ public static final SequenceType ANY_SEQUENCE = makeSequenceType(AnyItemType.getInstance(), StaticProperty.ALLOWS_ZERO_OR_MORE); /** * A type that allows exactly one item, of any kind */ public static final SequenceType SINGLE_ITEM = makeSequenceType(AnyItemType.getInstance(), StaticProperty.EXACTLY_ONE); /** * A type that allows zero or one items, of any kind */ // public static final SequenceType OPTIONAL_ITEM = // new SequenceType(Type.ITEM, Type.ITEM, StaticProperty.CARDINALITY_ALLOWS_ZERO_OR_ONE); /** * A type that allows exactly one atomic value */ public static final SequenceType SINGLE_ATOMIC = makeSequenceType(BuiltInAtomicType.ANY_ATOMIC, StaticProperty.EXACTLY_ONE); /** * A type that allows zero or one atomic values */ public static final SequenceType OPTIONAL_ATOMIC = makeSequenceType(BuiltInAtomicType.ANY_ATOMIC, StaticProperty.ALLOWS_ZERO_OR_ONE); /** * A type that allows zero or more atomic values */ public static final SequenceType ATOMIC_SEQUENCE = makeSequenceType(BuiltInAtomicType.ANY_ATOMIC, StaticProperty.ALLOWS_ZERO_OR_MORE); /** * A type that allows a single string */ public static final SequenceType SINGLE_STRING = makeSequenceType(BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE); /** * A type that allows a single optional string */ public static final SequenceType OPTIONAL_STRING = makeSequenceType(BuiltInAtomicType.STRING, StaticProperty.ALLOWS_ZERO_OR_ONE); /** * A type that allows a single boolean */ public static final SequenceType SINGLE_BOOLEAN = makeSequenceType(BuiltInAtomicType.BOOLEAN, StaticProperty.EXACTLY_ONE); /** * A type that allows a single optional integer */ public static final SequenceType OPTIONAL_BOOLEAN = makeSequenceType(BuiltInAtomicType.BOOLEAN, StaticProperty.ALLOWS_ZERO_OR_ONE); /** * A type that allows a single integer */ public static final SequenceType SINGLE_INTEGER = makeSequenceType(BuiltInAtomicType.INTEGER, StaticProperty.EXACTLY_ONE); /** * A type that allows a single optional integer */ public static final SequenceType OPTIONAL_INTEGER = makeSequenceType(BuiltInAtomicType.INTEGER, StaticProperty.ALLOWS_ZERO_OR_ONE); /** * A type that allows a single long */ public static final SequenceType SINGLE_LONG = makeSequenceType(BuiltInAtomicType.LONG, StaticProperty.EXACTLY_ONE); /** * A type that allows a single optional long */ public static final SequenceType OPTIONAL_LONG = makeSequenceType(BuiltInAtomicType.LONG, StaticProperty.ALLOWS_ZERO_OR_ONE); /** * A type that allows a single int */ public static final SequenceType SINGLE_INT = makeSequenceType(BuiltInAtomicType.INT, StaticProperty.EXACTLY_ONE); /** * A type that allows a single optional int */ public static final SequenceType OPTIONAL_INT = makeSequenceType(BuiltInAtomicType.INT, StaticProperty.ALLOWS_ZERO_OR_ONE); /** * A type that allows a single short */ public static final SequenceType SINGLE_SHORT = makeSequenceType(BuiltInAtomicType.SHORT, StaticProperty.EXACTLY_ONE); /** * A type that allows a single optional short */ public static final SequenceType OPTIONAL_SHORT = makeSequenceType(BuiltInAtomicType.SHORT, StaticProperty.ALLOWS_ZERO_OR_ONE); /** * A type that allows a single short */ public static final SequenceType SINGLE_BYTE = makeSequenceType(BuiltInAtomicType.BYTE, StaticProperty.EXACTLY_ONE); /** * A type that allows a single optional byte */ public static final SequenceType OPTIONAL_BYTE = makeSequenceType(BuiltInAtomicType.BYTE, StaticProperty.ALLOWS_ZERO_OR_ONE); /** * A type that allows a single double */ public static final SequenceType SINGLE_DOUBLE = makeSequenceType(BuiltInAtomicType.DOUBLE, StaticProperty.EXACTLY_ONE); /** * A type that allows a single optional double */ public static final SequenceType OPTIONAL_DOUBLE = makeSequenceType(BuiltInAtomicType.DOUBLE, StaticProperty.ALLOWS_ZERO_OR_ONE); /** * A type that allows a single float */ public static final SequenceType SINGLE_FLOAT = makeSequenceType(BuiltInAtomicType.FLOAT, StaticProperty.EXACTLY_ONE); /** * A type that allows a single optional float */ public static final SequenceType OPTIONAL_FLOAT = makeSequenceType(BuiltInAtomicType.FLOAT, StaticProperty.ALLOWS_ZERO_OR_ONE); /** * A type that allows a single optional decimal */ public static final SequenceType OPTIONAL_DECIMAL = makeSequenceType(BuiltInAtomicType.DECIMAL, StaticProperty.ALLOWS_ZERO_OR_ONE); /** * A type that allows a single optional anyURI */ public static final SequenceType OPTIONAL_ANY_URI = makeSequenceType(BuiltInAtomicType.ANY_URI , StaticProperty.ALLOWS_ZERO_OR_ONE); /** * A type that allows an optional numeric value */ public static final SequenceType OPTIONAL_NUMERIC = makeSequenceType(BuiltInAtomicType.NUMERIC, StaticProperty.ALLOWS_ZERO_OR_ONE); /** * A type that allows zero or one nodes */ public static final SequenceType OPTIONAL_NODE = makeSequenceType(AnyNodeTest.getInstance(), StaticProperty.ALLOWS_ZERO_OR_ONE); /** * A type that allows a single node */ public static final SequenceType SINGLE_NODE = makeSequenceType(AnyNodeTest.getInstance(), StaticProperty.EXACTLY_ONE); /** * A type that allows a sequence of zero or more nodes */ public static final SequenceType NODE_SEQUENCE = makeSequenceType(AnyNodeTest.getInstance(), StaticProperty.ALLOWS_ZERO_OR_MORE); /** * A type that allows a sequence of zero or more numeric values */ public static final SequenceType NUMERIC_SEQUENCE = makeSequenceType(BuiltInAtomicType.NUMERIC, StaticProperty.ALLOWS_ZERO_OR_MORE); /** * A type that only permits the empty sequence */ public static final SequenceType EMPTY_SEQUENCE = makeSequenceType(EmptySequenceTest.getInstance(), StaticProperty.EMPTY); /** * Construct an instance of SequenceType. This is a private constructor: all external * clients use the factory method makeSequenceType(), to allow object pooling. * * @param primaryType The item type * @param cardinality The required cardinality */ private SequenceType(ItemType primaryType, int cardinality) { this.primaryType = primaryType; if (primaryType instanceof EmptySequenceTest) { this.cardinality = StaticProperty.EMPTY; } else { this.cardinality = cardinality; } } /** * Construct an instance of SequenceType. This is a factory method: it maintains a * pool of SequenceType objects to reduce the amount of object creation. * * @param primaryType The item type * @param cardinality The required cardinality */ public static SequenceType makeSequenceType(ItemType primaryType, int cardinality) { if (!(primaryType instanceof BuiltInAtomicType)) { return new SequenceType(primaryType, cardinality); } // For each ItemType, there is an array of 8 SequenceTypes, one for each possible // cardinality (including impossible cardinalities, such as "0 or many"). The pool // is a static HashMap that obtains this array, given an ItemType. The array contains null // entries for cardinalities that have not been requested. SequenceType[] array = (SequenceType[])pool.get(primaryType); if (array == null) { array = new SequenceType[8]; pool.put(primaryType, array); } int code = StaticProperty.getCardinalityCode(cardinality); if (array[code] == null) { SequenceType s = new SequenceType(primaryType, cardinality); array[code] = s; return s; } else { return array[code]; } } /** * Get the "primary" part of this required type. E.g. for type element(*, xs:date) the "primary type" is element() * * @return The item type code of the primary type */ public ItemType getPrimaryType() { return primaryType; } /** * Get the cardinality component of this SequenceType. This is one of the constants Cardinality.EXACTLY_ONE, * Cardinality.ONE_OR_MORE, etc * * @return the required cardinality * @see net.sf.saxon.value.Cardinality */ public int getCardinality() { return cardinality; } /** * Determine whether a given value is a valid instance of this SequenceType * @param value the value to be tested * @return true if the value is a valid instance of this type */ public boolean matches(Value value, Configuration config) throws XPathException { if (!Cardinality.subsumes(cardinality, value.getCardinality())) { return false; } SequenceIterator iter = value.iterate(); while (true) { Item item = iter.next(); if (item == null) { return true; } if (!primaryType.matchesItem(item, false, config)) { return false; } } } /** * Return a string representation of this SequenceType * @return the string representation as an instance of the XPath * SequenceType construct */ public String toString() { String s = primaryType.toString(); if (cardinality == StaticProperty.ALLOWS_ONE_OR_MORE) { s = s + '+'; } else if (cardinality == StaticProperty.ALLOWS_ZERO_OR_MORE) { s = s + '*'; } else if (cardinality == StaticProperty.ALLOWS_ZERO_OR_ONE) { s = s + '?'; } return s; } /** * Returns a hash code value for the object. */ public int hashCode() { return primaryType.hashCode() ^ cardinality; } /** * Indicates whether some other object is "equal to" this one. */ public boolean equals(Object obj) { return obj instanceof SequenceType && this.primaryType.equals(((SequenceType)obj).primaryType) && this.cardinality == ((SequenceType)obj).cardinality; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/value/DateTimeValue.java0000644000175000017500000012732411133630214022057 0ustar eugeneeugenepackage net.sf.saxon.value; import net.sf.saxon.Controller; import net.sf.saxon.trans.Err; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.functions.Component; import net.sf.saxon.om.FastStringBuffer; import net.sf.saxon.om.StandardNames; import net.sf.saxon.sort.ComparisonKey; import net.sf.saxon.trans.NoDynamicContextException; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.AtomicType; import net.sf.saxon.type.BuiltInAtomicType; import net.sf.saxon.type.ConversionResult; import net.sf.saxon.type.ValidationFailure; import java.math.BigDecimal; import java.math.BigInteger; import java.util.*; /** * A value of type DateTime */ public final class DateTimeValue extends CalendarValue implements Comparable { private int year; // the year as written, +1 for BC years private byte month; // the month as written, range 1-12 private byte day; // the day as written, range 1-31 private byte hour; // the hour as written (except for midnight), range 0-23 private byte minute; // the minutes as written, range 0-59 private byte second; // the seconds as written, range 0-59 (no leap seconds) private int microsecond; /** * Private default constructor */ private DateTimeValue() { } /** * Get the dateTime value representing the nominal * date/time of this transformation run. Two calls within the same * query or transformation will always return the same answer. * * @param context the XPath dynamic context. May be null, in which case * the current date and time are taken directly from the system clock * @return the current xs:dateTime */ public static DateTimeValue getCurrentDateTime(XPathContext context) { Controller c; if (context == null || (c = context.getController()) == null) { // non-XSLT/XQuery environment // We also take this path when evaluating compile-time expressions that require an implicit timezone. return new DateTimeValue(new GregorianCalendar(), true); } else { return c.getCurrentDateTime(); } } /** * Constructor: create a dateTime value given a Java calendar object * * @param calendar holds the date and time * @param tzSpecified indicates whether the timezone is specified */ public DateTimeValue(Calendar calendar, boolean tzSpecified) { int era = calendar.get(GregorianCalendar.ERA); year = calendar.get(Calendar.YEAR); if (era == GregorianCalendar.BC) { year = 1 - year; } month = (byte)(calendar.get(Calendar.MONTH) + 1); day = (byte)(calendar.get(Calendar.DATE)); hour = (byte)(calendar.get(Calendar.HOUR_OF_DAY)); minute = (byte)(calendar.get(Calendar.MINUTE)); second = (byte)(calendar.get(Calendar.SECOND)); microsecond = calendar.get(Calendar.MILLISECOND) * 1000; if (tzSpecified) { int tz = (calendar.get(Calendar.ZONE_OFFSET) + calendar.get(Calendar.DST_OFFSET)) / 60000; setTimezoneInMinutes(tz); } typeLabel = BuiltInAtomicType.DATE_TIME; } /** * Factory method: create a dateTime value given a Java Date object. The returned dateTime * value will always have a timezone, which will always be UTC. * * @param suppliedDate holds the date and time * @return the corresponding xs:dateTime value */ public static DateTimeValue fromJavaDate(Date suppliedDate) throws XPathException { long millis = suppliedDate.getTime(); return (DateTimeValue)javaOrigin.add(DayTimeDurationValue.fromMilliseconds(millis)); } /** * Fixed date/time used by Java (and Unix) as the origin of the universe: 1970-01-01 */ public static final DateTimeValue javaOrigin = new DateTimeValue(1970, (byte)1, (byte)1, (byte)0, (byte)0, (byte)0, 0, 0); /** * Factory method: create a dateTime value given a date and a time. * * @param date the date * @param time the time * @return the dateTime with the given components. If either component is null, returns null * @throws XPathException if the timezones are both present and inconsistent */ public static DateTimeValue makeDateTimeValue(DateValue date, TimeValue time) throws XPathException { if (date == null || time == null) { return null; } DayTimeDurationValue tz1 = (DayTimeDurationValue)date.getComponent(Component.TIMEZONE); DayTimeDurationValue tz2 = (DayTimeDurationValue)time.getComponent(Component.TIMEZONE); boolean zoneSpecified = (tz1 != null || tz2 != null); if (tz1 != null && tz2 != null && !tz1.equals(tz2)) { XPathException err = new XPathException("Supplied date and time are in different timezones"); err.setErrorCode("FORG0008"); throw err; } DateTimeValue v = new DateTimeValue(); v.year = (int)((Int64Value)date.getComponent(Component.YEAR_ALLOWING_ZERO)).longValue(); v.month = (byte)((Int64Value)date.getComponent(Component.MONTH)).longValue(); v.day = (byte)((Int64Value)date.getComponent(Component.DAY)).longValue(); v.hour = (byte)((Int64Value)time.getComponent(Component.HOURS)).longValue(); v.minute = (byte)((Int64Value)time.getComponent(Component.MINUTES)).longValue(); final BigDecimal secs = ((DecimalValue)time.getComponent(Component.SECONDS)).getDecimalValue(); v.second = (byte)secs.intValue(); v.microsecond = secs.multiply(BigDecimal.valueOf(1000000)).intValue() % 1000000; if (zoneSpecified) { if (tz1 == null) { tz1 = tz2; } v.setTimezoneInMinutes((int)(tz1.getLengthInMicroseconds() / 60000000)); } v.typeLabel = BuiltInAtomicType.DATE_TIME; return v; } /** * Factory method: create a dateTime value from a supplied string, in * ISO 8601 format * * @param s a string in the lexical space of xs:dateTime * @return either a DateTimeValue representing the xs:dateTime supplied, or a ValidationFailure if * the lexical value was invalid */ public static ConversionResult makeDateTimeValue(CharSequence s) { // input must have format [-]yyyy-mm-ddThh:mm:ss[.fff*][([+|-]hh:mm | Z)] DateTimeValue dt = new DateTimeValue(); StringTokenizer tok = new StringTokenizer(Whitespace.trimWhitespace(s).toString(), "-:.+TZ", true); if (!tok.hasMoreElements()) { return badDate("too short", s); } String part = (String)tok.nextElement(); int era = +1; if ("+".equals(part)) { return badDate("Date must not start with '+' sign", s); } else if ("-".equals(part)) { era = -1; if (!tok.hasMoreElements()) { return badDate("No year after '-'", s); } part = (String)tok.nextElement(); } int value = DurationValue.simpleInteger(part); if (value < 0) { return badDate("Non-numeric year component", s); } dt.year = value * era; if (part.length() < 4) { return badDate("Year is less than four digits", s); } if (part.length() > 4 && part.charAt(0) == '0') { return badDate("When year exceeds 4 digits, leading zeroes are not allowed", s); } if (dt.year == 0) { return badDate("Year zero is not allowed", s); } if (era < 0) { dt.year++; // internal representation allows a year zero. } if (!tok.hasMoreElements()) { return badDate("Too short", s); } if (!"-".equals(tok.nextElement())) { return badDate("Wrong delimiter after year", s); } if (!tok.hasMoreElements()) { return badDate("Too short", s); } part = (String)tok.nextElement(); if (part.length() != 2) { return badDate("Month must be two digits", s); } value = DurationValue.simpleInteger(part); if (value < 0) { return badDate("Non-numeric month component", s); } dt.month = (byte)value; if (dt.month < 1 || dt.month > 12) { return badDate("Month is out of range", s); } if (!tok.hasMoreElements()) { return badDate("Too short", s); } if (!"-".equals(tok.nextElement())) { return badDate("Wrong delimiter after month", s); } if (!tok.hasMoreElements()) { return badDate("Too short", s); } part = (String)tok.nextElement(); if (part.length() != 2) { return badDate("Day must be two digits", s); } value = DurationValue.simpleInteger(part); if (value < 0) { return badDate("Non-numeric day component", s); } dt.day = (byte)value; if (dt.day < 1 || dt.day > 31) { return badDate("Day is out of range", s); } if (!tok.hasMoreElements()) { return badDate("Too short", s); } if (!"T".equals(tok.nextElement())) { return badDate("Wrong delimiter after day", s); } if (!tok.hasMoreElements()) { return badDate("Too short", s); } part = (String)tok.nextElement(); if (part.length() != 2) { return badDate("Hour must be two digits", s); } value = DurationValue.simpleInteger(part); if (value < 0) { return badDate("Non-numeric hour component", s); } dt.hour = (byte)value; if (dt.hour > 24) { return badDate("Hour is out of range", s); } if (!tok.hasMoreElements()) { return badDate("Too short", s); } if (!":".equals(tok.nextElement())) { return badDate("Wrong delimiter after hour", s); } if (!tok.hasMoreElements()) { return badDate("Too short", s); } part = (String)tok.nextElement(); if (part.length() != 2) { return badDate("Minute must be two digits", s); } value = DurationValue.simpleInteger(part); if (value < 0) { return badDate("Non-numeric minute component", s); } dt.minute = (byte)value; if (dt.minute > 59) { return badDate("Minute is out of range", s); } if (dt.hour == 24 && dt.minute != 0) { return badDate("If hour is 24, minute must be 00", s); } if (!tok.hasMoreElements()) { return badDate("Too short", s); } if (!":".equals(tok.nextElement())) { return badDate("Wrong delimiter after minute", s); } if (!tok.hasMoreElements()) { return badDate("Too short", s); } part = (String)tok.nextElement(); if (part.length() != 2) { return badDate("Second must be two digits", s); } value = DurationValue.simpleInteger(part); if (value < 0) { return badDate("Non-numeric second component", s); } dt.second = (byte)value; if (dt.second > 59) { return badDate("Second is out of range", s); } if (dt.hour == 24 && dt.second != 0) { return badDate("If hour is 24, second must be 00", s); } int tz = 0; int state = 0; while (tok.hasMoreElements()) { if (state == 9) { return badDate("Characters after the end", s); } String delim = (String)tok.nextElement(); if (".".equals(delim)) { if (state != 0) { return badDate("Decimal separator occurs twice", s); } if (!tok.hasMoreElements()) { return badDate("Decimal point must be followed by digits", s); } part = (String)tok.nextElement(); value = DurationValue.simpleInteger(part); if (value < 0) { return badDate("Non-numeric fractional seconds component", s); } double fractionalSeconds = Double.parseDouble('.' + part); dt.microsecond = (int)(Math.round(fractionalSeconds * 1000000)); if (dt.hour == 24 && dt.microsecond != 0) { return badDate("If hour is 24, fractional seconds must be 0", s); } state = 1; } else if ("Z".equals(delim)) { if (state > 1) { return badDate("Z cannot occur here", s); } tz = 0; state = 9; // we've finished dt.setTimezoneInMinutes(0); } else if ("+".equals(delim) || "-".equals(delim)) { if (state > 1) { return badDate(delim + " cannot occur here", s); } state = 2; if (!tok.hasMoreElements()) { return badDate("Missing timezone", s); } part = (String)tok.nextElement(); if (part.length() != 2) { return badDate("Timezone hour must be two digits", s); } value = DurationValue.simpleInteger(part); if (value < 0) { return badDate("Non-numeric timezone hour component", s); } tz = value; if (tz > 14) { return badDate("Timezone is out of range (-14:00 to +14:00)", s); } tz *= 60; if ("-".equals(delim)) { tz = -tz; } } else if (":".equals(delim)) { if (state != 2) { return badDate("Misplaced ':'", s); } state = 9; part = (String)tok.nextElement(); value = DurationValue.simpleInteger(part); if (value < 0) { return badDate("Non-numeric timezone minute component", s); } int tzminute = value; if (part.length() != 2) { return badDate("Timezone minute must be two digits", s); } if (tzminute > 59) { return badDate("Timezone minute is out of range", s); } if (tz < 0) { tzminute = -tzminute; } if (Math.abs(tz) == 14 * 60 && tzminute != 0) { return badDate("Timezone is out of range (-14:00 to +14:00)", s); } tz += tzminute; dt.setTimezoneInMinutes(tz); } else { return badDate("Timezone format is incorrect", s); } } if (state == 2 || state == 3) { return badDate("Timezone incomplete", s); } boolean midnight = false; if (dt.hour == 24) { dt.hour = 0; midnight = true; } // Check that this is a valid calendar date if (!DateValue.isValidDate(dt.year, dt.month, dt.day)) { return badDate("Non-existent date", s); } // Adjust midnight to 00:00:00 on the next day if (midnight) { DateValue t = DateValue.tomorrow(dt.year, dt.month, dt.day); dt.year = t.getYear(); dt.month = t.getMonth(); dt.day = t.getDay(); } dt.typeLabel = BuiltInAtomicType.DATE_TIME; return dt; } private static ValidationFailure badDate(String msg, CharSequence value) { ValidationFailure err = new ValidationFailure( "Invalid dateTime value " + Err.wrap(value, Err.VALUE) + " (" + msg + ")"); err.setErrorCode("FORG0001"); return err; } /** * Constructor: construct a DateTimeValue from its components. * This constructor performs no validation. * * @param year The year as held internally (note that the year before 1AD is 0) * @param month The month, 1-12 * @param day The day 1-31 * @param hour the hour value, 0-23 * @param minute the minutes value, 0-59 * @param second the seconds value, 0-59 * @param microsecond the number of microseconds, 0-999999 * @param tz the timezone displacement in minutes from UTC. Supply the value * {@link CalendarValue#NO_TIMEZONE} if there is no timezone component. */ public DateTimeValue(int year, byte month, byte day, byte hour, byte minute, byte second, int microsecond, int tz) { this.year = year; this.month = month; this.day = day; this.hour = hour; this.minute = minute; this.second = second; this.microsecond = microsecond; setTimezoneInMinutes(tz); typeLabel = BuiltInAtomicType.DATE_TIME; } /** * Determine the primitive type of the value. This delivers the same answer as * getItemType().getPrimitiveItemType(). The primitive types are * the 19 primitive types of XML Schema, plus xs:integer, xs:dayTimeDuration and xs:yearMonthDuration, * and xs:untypedAtomic. For external objects, the result is AnyAtomicType. */ public BuiltInAtomicType getPrimitiveType() { return BuiltInAtomicType.DATE_TIME; } /** * Get the year component, in its internal form (which allows a year zero) * * @return the year component */ public int getYear() { return year; } /** * Get the month component, 1-12 * * @return the month component */ public byte getMonth() { return month; } /** * Get the day component, 1-31 * * @return the day component */ public byte getDay() { return day; } /** * Get the hour component, 0-23 * * @return the hour component (never 24, even if the input was specified as 24:00:00) */ public byte getHour() { return hour; } /** * Get the minute component, 0-59 * * @return the minute component */ public byte getMinute() { return minute; } /** * Get the second component, 0-59 * * @return the second component */ public byte getSecond() { return second; } /** * Get the microsecond component, 0-999999 * * @return the microsecond component */ public int getMicrosecond() { return microsecond; } /** * Convert the value to a DateTime, retaining all the components that are actually present, and * substituting conventional values for components that are missing. (This method does nothing in * the case of xs:dateTime, but is there to implement a method in the {@link CalendarValue} interface). * * @return the value as an xs:dateTime */ public DateTimeValue toDateTime() { return this; } /** * Normalize the date and time to be in timezone Z. * * @param cc used to supply the implicit timezone, used when the value has * no explicit timezone * @return in general, a new DateTimeValue in timezone Z, representing the same instant in time. * Returns the original DateTimeValue if this is already in timezone Z. * @throws NoDynamicContextException if the implicit timezone is needed and is not available */ public DateTimeValue normalize(XPathContext cc) throws NoDynamicContextException { if (hasTimezone()) { return (DateTimeValue)adjustTimezone(0); } else { DateTimeValue dt = (DateTimeValue)copyAsSubType(null); dt.setTimezoneInMinutes(cc.getImplicitTimezone()); return (DateTimeValue)dt.adjustTimezone(0); } } /** * Get a comparison key for this value. Two values are equal if and only if they their comparison * keys are equal * @param context XPath dynamic context * @throws NoDynamicContextException if the implicit timezone is needed and is not available */ public ComparisonKey getComparisonKey(XPathContext context) throws NoDynamicContextException { return new ComparisonKey(StandardNames.XS_DATE_TIME, normalize(context)); } /** * Get the Julian instant: a decimal value whose integer part is the Julian day number * multiplied by the number of seconds per day, * and whose fractional part is the fraction of the second. * This method operates on the local time, ignoring the timezone. The caller should call normalize() * before calling this method to get a normalized time. * * @return the Julian instant corresponding to this xs:dateTime value */ public BigDecimal toJulianInstant() { int julianDay = DateValue.getJulianDayNumber(year, month, day); long julianSecond = julianDay * (24L * 60L * 60L); julianSecond += (((hour * 60L + minute) * 60L) + second); BigDecimal j = BigDecimal.valueOf(julianSecond); if (microsecond == 0) { return j; } else { return j.add(BigDecimal.valueOf(microsecond).divide(DecimalValue.BIG_DECIMAL_ONE_MILLION, 6, BigDecimal.ROUND_HALF_EVEN)); } } /** * Get the DateTimeValue corresponding to a given Julian instant * * @param instant the Julian instant: a decimal value whose integer part is the Julian day number * multiplied by the number of seconds per day, and whose fractional part is the fraction of the second. * @return the xs:dateTime value corresponding to the Julian instant. This will always be in timezone Z. */ public static DateTimeValue fromJulianInstant(BigDecimal instant) { BigInteger julianSecond = instant.toBigInteger(); BigDecimal microseconds = instant.subtract(new BigDecimal(julianSecond)).multiply(DecimalValue.BIG_DECIMAL_ONE_MILLION); long js = julianSecond.longValue(); long jd = js / (24L * 60L * 60L); DateValue date = DateValue.dateFromJulianDayNumber((int)jd); js = js % (24L * 60L * 60L); byte hour = (byte)(js / (60L * 60L)); js = js % (60L * 60L); byte minute = (byte)(js / (60L)); js = js % (60L); return new DateTimeValue(date.getYear(), date.getMonth(), date.getDay(), hour, minute, (byte)js, microseconds.intValue(), 0); } /** * Get a Java Calendar object representing the value of this DateTime. This will respect the timezone * if there is one, or be in GMT otherwise. * * @return a Java GregorianCalendar object representing the value of this xs:dateTime value. */ public GregorianCalendar getCalendar() { int tz = (hasTimezone() ? getTimezoneInMinutes() * 60000 : 0); TimeZone zone = new SimpleTimeZone(tz, "LLL"); GregorianCalendar calendar = new GregorianCalendar(zone); calendar.setGregorianChange(new Date(Long.MIN_VALUE)); calendar.setLenient(false); int yr = year; if (year <= 0) { yr = 1 - year; calendar.set(Calendar.ERA, GregorianCalendar.BC); } calendar.set(yr, month - 1, day, hour, minute, second); calendar.set(Calendar.MILLISECOND, microsecond / 1000); // loses precision unavoidably if (tz >= -12*60*60*1000 && tz <= +12*60*60*1000) { // XPath range is bigger than Java's // TODO: restriction may be lifted in JDK 1.5? calendar.set(Calendar.ZONE_OFFSET, tz); } calendar.set(Calendar.DST_OFFSET, 0); return calendar; } /** * Convert to target data type * * @param requiredType an integer identifying the required atomic type * @param context the XPath dynamic context * @return an AtomicValue, a value of the required type; or an ErrorValue */ public ConversionResult convertPrimitive(BuiltInAtomicType requiredType, boolean validate, XPathContext context) { switch (requiredType.getPrimitiveType()) { case StandardNames.XS_DATE_TIME: case StandardNames.XS_ANY_ATOMIC_TYPE: return this; case StandardNames.XS_DATE: return new DateValue(year, month, day, getTimezoneInMinutes()); case StandardNames.XS_TIME: return new TimeValue(hour, minute, second, microsecond, getTimezoneInMinutes()); case StandardNames.XS_G_YEAR: return new GYearValue(year, getTimezoneInMinutes()); case StandardNames.XS_G_YEAR_MONTH: return new GYearMonthValue(year, month, getTimezoneInMinutes()); case StandardNames.XS_G_MONTH: return new GMonthValue(month, getTimezoneInMinutes()); case StandardNames.XS_G_MONTH_DAY: return new GMonthDayValue(month, day, getTimezoneInMinutes()); case StandardNames.XS_G_DAY: return new GDayValue(day, getTimezoneInMinutes()); case StandardNames.XS_STRING: return new StringValue(getStringValueCS()); case StandardNames.XS_UNTYPED_ATOMIC: return new UntypedAtomicValue(getStringValueCS()); default: ValidationFailure err = new ValidationFailure("Cannot convert dateTime to " + requiredType.getDisplayName()); err.setErrorCode("XPTY0004"); return err; } } /** * Convert to string * * @return ISO 8601 representation. The value returned is the localized representation, * that is it uses the timezone contained within the value itself. */ public CharSequence getStringValueCS() { FastStringBuffer sb = new FastStringBuffer(30); int yr = year; if (year <= 0) { sb.append('-'); yr = -yr + 1; // no year zero in lexical space } appendString(sb, yr, (yr > 9999 ? (yr + "").length() : 4)); sb.append('-'); appendTwoDigits(sb, month); sb.append('-'); appendTwoDigits(sb, day); sb.append('T'); appendTwoDigits(sb, hour); sb.append(':'); appendTwoDigits(sb, minute); sb.append(':'); appendTwoDigits(sb, second); if (microsecond != 0) { sb.append('.'); int ms = microsecond; int div = 100000; while (ms > 0) { int d = ms / div; sb.append((char)(d + '0')); ms = ms % div; div /= 10; } } if (hasTimezone()) { appendTimezone(sb); } return sb; } /** * Get the canonical lexical representation as defined in XML Schema. This is not always the same * as the result of casting to a string according to the XPath rules. For an xs:dateTime it is the * date/time adjusted to UTC. * * @return the canonical lexical representation as defined in XML Schema */ public CharSequence getCanonicalLexicalRepresentation() { if (hasTimezone() && getTimezoneInMinutes() != 0) { return adjustTimezone(0).getStringValueCS(); } else { return getStringValueCS(); } } /** * Make a copy of this date, time, or dateTime value, but with a new type label * * @param typeLabel the type label to be attached to the new copy. It is the caller's responsibility * to ensure that the value actually conforms to the rules for this type. */ public AtomicValue copyAsSubType(AtomicType typeLabel) { DateTimeValue v = new DateTimeValue(year, month, day, hour, minute, second, microsecond, getTimezoneInMinutes()); v.typeLabel = typeLabel; return v; } /** * Return a new dateTime with the same normalized value, but * in a different timezone. * * @param timezone the new timezone offset, in minutes * @return the date/time in the new timezone. This will be a new DateTimeValue unless no change * was required to the original value */ public CalendarValue adjustTimezone(int timezone) { if (!hasTimezone()) { CalendarValue in = (CalendarValue)copyAsSubType(typeLabel); in.setTimezoneInMinutes(timezone); return in; } int oldtz = getTimezoneInMinutes(); if (oldtz == timezone) { return this; } int tz = timezone - oldtz; int h = hour; int mi = minute; mi += tz; if (mi < 0 || mi > 59) { h += Math.floor(mi / 60.0); mi = (mi + 60 * 24) % 60; } if (h >= 0 && h < 24) { return new DateTimeValue(year, month, day, (byte)h, (byte)mi, second, microsecond, timezone); } // Following code is designed to handle the corner case of adjusting from -14:00 to +14:00 or // vice versa, which can cause a change of two days in the date DateTimeValue dt = this; while (h < 0) { h += 24; DateValue t = DateValue.yesterday(dt.getYear(), dt.getMonth(), dt.getDay()); dt = new DateTimeValue(t.getYear(), t.getMonth(), t.getDay(), (byte)h, (byte)mi, second, microsecond, timezone); } if (h > 23) { h -= 24; DateValue t = DateValue.tomorrow(year, month, day); return new DateTimeValue(t.getYear(), t.getMonth(), t.getDay(), (byte)h, (byte)mi, second, microsecond, timezone); } return dt; } /** * Add a duration to a dateTime * * @param duration the duration to be added (may be negative) * @return the new date * @throws net.sf.saxon.trans.XPathException * if the duration is an xs:duration, as distinct from * a subclass thereof */ public CalendarValue add(DurationValue duration) throws XPathException { if (duration instanceof DayTimeDurationValue) { long microseconds = ((DayTimeDurationValue)duration).getLengthInMicroseconds(); BigDecimal seconds = BigDecimal.valueOf(microseconds).divide( DecimalValue.BIG_DECIMAL_ONE_MILLION, 6, BigDecimal.ROUND_HALF_EVEN); BigDecimal julian = toJulianInstant(); julian = julian.add(seconds); DateTimeValue dt = fromJulianInstant(julian); dt.setTimezoneInMinutes(getTimezoneInMinutes()); return dt; } else if (duration instanceof YearMonthDurationValue) { int months = ((YearMonthDurationValue)duration).getLengthInMonths(); int m = (month - 1) + months; int y = year + m / 12; m = m % 12; if (m < 0) { m += 12; y -= 1; } m++; int d = day; while (!DateValue.isValidDate(y, m, d)) { d -= 1; } return new DateTimeValue(y, (byte)m, (byte)d, hour, minute, second, microsecond, getTimezoneInMinutes()); } else { XPathException err = new XPathException("DateTime arithmetic is not supported on xs:duration, only on its subtypes"); err.setIsTypeError(true); throw err; } } /** * Determine the difference between two points in time, as a duration * * @param other the other point in time * @param context the XPath dynamic context * @return the duration as an xs:dayTimeDuration * @throws net.sf.saxon.trans.XPathException * for example if one value is a date and the other is a time */ public DayTimeDurationValue subtract(CalendarValue other, XPathContext context) throws XPathException { if (!(other instanceof DateTimeValue)) { XPathException err = new XPathException("First operand of '-' is a dateTime, but the second is not"); err.setIsTypeError(true); throw err; } return super.subtract(other, context); } /** * Convert to Java object (for passing to external functions) */ // public Object convertAtomicToJava(Class target, XPathContext context) throws XPathException { // if (target.isAssignableFrom(Date.class)) { // return getCalendar().getTime(); // } else if (target.isAssignableFrom(GregorianCalendar.class)) { // return getCalendar(); // } else if (target.isAssignableFrom(DateTimeValue.class)) { // return this; // } else if (target == Object.class) { // return getStringValue(); // } else { // Object o = super.convertSequenceToJava(target, context); // if (o == null) { // throw new XPathException("Conversion of dateTime to " + target.getName() + // " is not supported"); // } // return o; // } // } // /** * Get a component of the value. Returns null if the timezone component is * requested and is not present. */ public AtomicValue getComponent(int component) throws XPathException { switch (component) { case Component.YEAR_ALLOWING_ZERO: return Int64Value.makeIntegerValue(year); case Component.YEAR: return Int64Value.makeIntegerValue(year > 0 ? year : year - 1); case Component.MONTH: return Int64Value.makeIntegerValue(month); case Component.DAY: return Int64Value.makeIntegerValue(day); case Component.HOURS: return Int64Value.makeIntegerValue(hour); case Component.MINUTES: return Int64Value.makeIntegerValue(minute); case Component.SECONDS: BigDecimal d = BigDecimal.valueOf(microsecond); d = d.divide(DecimalValue.BIG_DECIMAL_ONE_MILLION, 6, BigDecimal.ROUND_HALF_UP); d = d.add(BigDecimal.valueOf(second)); return new DecimalValue(d); case Component.WHOLE_SECONDS: //(internal use only) return Int64Value.makeIntegerValue(second); case Component.MICROSECONDS: // internal use only return new Int64Value(microsecond); case Component.TIMEZONE: if (hasTimezone()) { return DayTimeDurationValue.fromMilliseconds(getTimezoneInMinutes() * 60 * 1000); } else { return null; } default: throw new IllegalArgumentException("Unknown component for dateTime: " + component); } } /** * Compare the value to another dateTime value, following the XPath comparison semantics * * @param other The other dateTime value * @param context XPath dynamic evaluation context * @return negative value if this one is the earler, 0 if they are chronologically equal, * positive value if this one is the later. For this purpose, dateTime values with an unknown * timezone are considered to be values in the implicit timezone (the Comparable interface requires * a total ordering). * @throws ClassCastException if the other value is not a DateTimeValue (the parameter * is declared as CalendarValue to satisfy the interface) * @throws NoDynamicContextException if the implicit timezone is needed and is not available */ public int compareTo(CalendarValue other, XPathContext context) throws NoDynamicContextException { if (!(other instanceof DateTimeValue)) { throw new ClassCastException("DateTime values are not comparable to " + other.getClass()); } DateTimeValue v2 = (DateTimeValue)other; if (getTimezoneInMinutes() == v2.getTimezoneInMinutes()) { // both values are in the same timezone (explicitly or implicitly) if (year != v2.year) { return IntegerValue.signum(year - v2.year); } if (month != v2.month) { return IntegerValue.signum(month - v2.month); } if (day != v2.day) { return IntegerValue.signum(day - v2.day); } if (hour != v2.hour) { return IntegerValue.signum(hour - v2.hour); } if (minute != v2.minute) { return IntegerValue.signum(minute - v2.minute); } if (second != v2.second) { return IntegerValue.signum(second - v2.second); } if (microsecond != v2.microsecond) { return IntegerValue.signum(microsecond - v2.microsecond); } return 0; } return normalize(context).compareTo(v2.normalize(context), context); } /** * Context-free comparison of two DateTimeValue values. For this to work, * the two values must either both have a timezone or both have none. * @param v2 the other value * @return the result of the comparison: -1 if the first is earlier, 0 if they * are equal, +1 if the first is later * @throws ClassCastException if the values are not comparable (which might be because * no timezone is available) */ public int compareTo(Object v2) { try { return compareTo((DateTimeValue)v2, null); } catch (Exception err) { throw new ClassCastException("DateTime comparison requires access to implicit timezone"); } } public Comparable getSchemaComparable() { return new DateTimeComparable(); } /** * DateTimeComparable is an object that implements the XML Schema rules for comparing date/time values */ private class DateTimeComparable implements Comparable { private DateTimeValue asDateTimeValue() { return DateTimeValue.this; } // Rules from XML Schema Part 2 public int compareTo(Object o) { if (o instanceof DateTimeComparable) { DateTimeValue dt0 = DateTimeValue.this; DateTimeValue dt1 = ((DateTimeComparable)o).asDateTimeValue(); if (dt0.hasTimezone()) { if (dt1.hasTimezone()) { dt0 = (DateTimeValue)dt0.adjustTimezone(0); dt1 = (DateTimeValue)dt1.adjustTimezone(0); return dt0.compareTo(dt1); } else { DateTimeValue dt1max = (DateTimeValue)dt1.adjustTimezone(14*60); if (dt0.compareTo(dt1max) < 0) { return -1; } DateTimeValue dt1min = (DateTimeValue)dt1.adjustTimezone(-14*60); if (dt0.compareTo(dt1min) > 0) { return +1; } return INDETERMINATE_ORDERING; } } else { if (dt1.hasTimezone()) { DateTimeValue dt0min = (DateTimeValue)dt0.adjustTimezone(-14*60); if (dt0min.compareTo(dt1) < 0) { return -1; } DateTimeValue dt0max = (DateTimeValue)dt0.adjustTimezone(14*60); if (dt0max.compareTo(dt1) > 0) { return +1; } return INDETERMINATE_ORDERING; } else { dt0 = (DateTimeValue)dt0.adjustTimezone(0); dt1 = (DateTimeValue)dt1.adjustTimezone(0); return dt0.compareTo(dt1); } } } else { return INDETERMINATE_ORDERING; } } public boolean equals(Object o) { return o instanceof DateTimeComparable && DateTimeValue.this.hasTimezone() == ((DateTimeComparable)o).asDateTimeValue().hasTimezone() && compareTo(o) == 0; } public int hashCode() { DateTimeValue dt0 = (DateTimeValue)adjustTimezone(0); return (dt0.year<<20) ^ (dt0.month<<16) ^ (dt0.day<<11) ^ (dt0.hour<<7) ^ (dt0.minute<<2) ^ (dt0.second*1000000 + dt0.microsecond); } } /** * Context-free comparison of two dateTime values * @param o the other date time value * @return true if the two values represent the same instant in time * @throws ClassCastException if one of the values has a timezone and the other does not */ public boolean equals(Object o) { //noinspection RedundantCast return compareTo((DateTimeValue)o) == 0; } /** * Hash code for context-free comparison of date time values. Note that equality testing * and therefore hashCode() works only for values with a timezone * @return a hash code */ public int hashCode() { return hashCode(year, month, day, hour, minute, second, microsecond, getTimezoneInMinutes()); } static int hashCode(int year, byte month, byte day, byte hour, byte minute, byte second, int microsecond, int tzMinutes) { int tz = -tzMinutes; int h = hour; int mi = minute; mi += tz; if (mi < 0 || mi > 59) { h += Math.floor(mi / 60.0); mi = (mi + 60 * 24) % 60; } while (h < 0) { h += 24; DateValue t = DateValue.yesterday(year, month, day); year = t.getYear(); month = t.getMonth(); day = t.getDay(); } while (h > 23) { h -= 24; DateValue t = DateValue.tomorrow(year, month, day); year = t.getYear(); month = t.getMonth(); day = t.getDay(); } return (year<<4) ^ (month<<28) ^ (day<<23) ^ (h<<18) ^ (mi<<13) ^ second ^ microsecond; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/value/AnyURIValue.java0000644000175000017500000001676211172067435021511 0ustar eugeneeugenepackage net.sf.saxon.value; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.functions.EscapeURI; import net.sf.saxon.om.StandardNames; import net.sf.saxon.sort.LRUCache; import net.sf.saxon.type.AtomicType; import net.sf.saxon.type.BuiltInAtomicType; import net.sf.saxon.type.ConversionResult; import net.sf.saxon.type.ValidationFailure; import java.net.URI; import java.net.URISyntaxException; /** * An XPath value of type xs:anyURI. * *

    This is implemented as a subtype of StringValue even though xs:anyURI is not a subtype of * xs:string in the XPath type hierarchy. This enables type promotion from URI to String to happen * automatically in most cases where it is appropriate.

    * *

    This implementation of xs:anyURI allows any string to be contained in the value space. It is possible * to validate that the string is a "valid URI" in the sense of XML Schema Part 2 (which refers to the XLink * specification and to RFC 2396); however, this validation is optional, and is not carried out by default. * In particular, there is no constraint that namespace URIs, collation URIs, and the like should be valid * URIs. However, casting from strings to xs:anyURI does invoke validation.

    */ public final class AnyURIValue extends StringValue { public static final AnyURIValue EMPTY_URI = new AnyURIValue(""); /** * To prevent repeated validation of commonly used URIs (especially namespaces) * we keep a small cache. This is especially useful in the case of URIs that are * valid only after escaping, as otherwise an exception occurs during the validation process */ private static ThreadLocal caches = new ThreadLocal(); //private static LRUCache cache = new LRUCache(20); /** * Constructor * @param value the String value. Null is taken as equivalent to "". This constructor * does not check that the value is a valid anyURI instance. */ public AnyURIValue(CharSequence value) { this.value = (value==null ? "" : Whitespace.collapseWhitespace(value).toString()); typeLabel = BuiltInAtomicType.ANY_URI; } /** * Constructor for a user-defined subtype of anyURI * @param value the String value. Null is taken as equivalent to "". * @param type a user-defined subtype of anyURI. It is the caller's responsibility * to ensure that this is actually a subtype of anyURI, and that the value conforms * to the definition of this type. */ public AnyURIValue(CharSequence value, AtomicType type) { this.value = (value==null ? "" : Whitespace.collapseWhitespace(value).toString()); typeLabel = type; } /** * Create a copy of this atomic value, with a different type label * * @param typeLabel the type label of the new copy. The caller is responsible for checking that * the value actually conforms to this type. */ public AtomicValue copyAsSubType(AtomicType typeLabel) { AnyURIValue v = new AnyURIValue(value); v.length = length; v.typeLabel = typeLabel; return v; } /** * Check whether a string consititutes a valid URI * @param value the string to be tested * @return true if the string is a valid URI */ public static boolean isValidURI(CharSequence value) { LRUCache cache = (LRUCache)caches.get(); if (cache == null) { cache = new LRUCache(10); caches.set(cache); } if (cache.get(value) != null) { return true; } String sv = Whitespace.trim(value); // Allow zero-length strings (RFC2396 is ambivalent on this point) if (sv.length() == 0) { return true; } // Allow a string if the java.net.URI class accepts it try { new URI(sv); cache.put(value, value); return true; } catch (URISyntaxException e) { // keep trying // Note: it's expensive to throw exceptions on a success path, so we keep a cache. } // Allow a string if it can be escaped into a form that java.net.URI accepts sv = EscapeURI.iriToUri(sv).toString(); try { new URI(sv); cache.put(value, value); return true; } catch (URISyntaxException e) { return false; } } public BuiltInAtomicType getPrimitiveType() { return BuiltInAtomicType.ANY_URI; } /** * Convert to target data type * @param requiredType integer code representing the item type required * @param context the XPath dynamic evaluation context * @return the result of the conversion, or an ErrorValue */ public ConversionResult convertPrimitive(BuiltInAtomicType requiredType, boolean validate, XPathContext context) { int req = requiredType.getPrimitiveType(); switch(req) { case StandardNames.XS_ANY_ATOMIC_TYPE: case StandardNames.XS_ANY_URI: return this; case StandardNames.XS_UNTYPED_ATOMIC: return new UntypedAtomicValue(value); case StandardNames.XS_STRING: return new StringValue(value); case StandardNames.XS_NORMALIZED_STRING: case StandardNames.XS_TOKEN: case StandardNames.XS_LANGUAGE: case StandardNames.XS_NAME: case StandardNames.XS_NCNAME: case StandardNames.XS_ID: case StandardNames.XS_IDREF: case StandardNames.XS_ENTITY: case StandardNames.XS_NMTOKEN: return makeRestrictedString(value, requiredType, (validate ? context.getConfiguration().getNameChecker() : null)); default: ValidationFailure err = new ValidationFailure("Cannot convert anyURI to " + requiredType.getDisplayName()); err.setErrorCode("XPTY0004"); return err; } } // public static void main(String[] args) { // ExecutorService executor = Executors.newFixedThreadPool(10); // for (int i = 0; i < 100; i++) { // executor.execute(new Runnable() { // public void run() { // for (int i=0; i<1000000; i++) { // String uri = "http://a.com/aaa" + i; // boolean b = AnyURIValue.isValidURI(uri); // if (i % 1000 == 0) { // System.err.println("Memory: " + (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory())); // } // } // } // }); // } // } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/value/DateValue.java0000644000175000017500000004752311033112257021243 0ustar eugeneeugenepackage net.sf.saxon.value; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.FastStringBuffer; import net.sf.saxon.om.StandardNames; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.*; import java.util.Calendar; import java.util.GregorianCalendar; /** * A value of type Date. Note that a Date may include a TimeZone. */ public class DateValue extends GDateValue implements Comparable { /** * Private constructor of a skeletal DateValue */ private DateValue(){} /** * Constructor given a year, month, and day. Performs no validation. * @param year The year as held internally (note that the year before 1AD is 0) * @param month The month, 1-12 * @param day The day 1-31 */ public DateValue(int year, byte month, byte day) { this.year = year; this.month = month; this.day = day; typeLabel = BuiltInAtomicType.DATE; } /** * Constructor given a year, month, and day, and timezone. Performs no validation. * @param year The year as held internally (note that the year before 1AD is 0) * @param month The month, 1-12 * @param day The day 1-31 * @param tz the timezone displacement in minutes from UTC. Supply the value * {@link CalendarValue#NO_TIMEZONE} if there is no timezone component. */ public DateValue(int year, byte month, byte day, int tz) { this.year = year; this.month = month; this.day = day; setTimezoneInMinutes(tz); typeLabel = BuiltInAtomicType.DATE; } /** * Constructor given a year, month, and day, and timezone, and an AtomicType representing * a subtype of xs:date. Performs no validation. * @param year The year as held internally (note that the year before 1AD is 0) * @param month The month, 1-12 * @param day The day 1-31 * @param tz the timezone displacement in minutes from UTC. Supply the value * {@link CalendarValue#NO_TIMEZONE} if there is no timezone component. * @param type the type. This must be a type derived from xs:date, and the value * must conform to this type. The method does not check these conditions. */ public DateValue(int year, byte month, byte day, int tz, AtomicType type) { this.year = year; this.month = month; this.day = day; setTimezoneInMinutes(tz); typeLabel = type; } /** * Constructor: create a date value from a supplied string, in * ISO 8601 format * @param s the lexical form of the date value * @throws ValidationException if the supplied string is not a valid date */ public DateValue(CharSequence s) throws ValidationException { setLexicalValue(this, s).asAtomic(); typeLabel = BuiltInAtomicType.DATE; } /** * Create a DateValue * @param calendar the absolute date/time value * @param tz The timezone offset from GMT in minutes, positive or negative; or the special * value NO_TIMEZONE indicating that the value is not in a timezone */ public DateValue(GregorianCalendar calendar, int tz) { // Note: this constructor is not used by Saxon itself, but might be used by applications int era = calendar.get(GregorianCalendar.ERA); year = calendar.get(Calendar.YEAR); if (era == GregorianCalendar.BC) { year = 1-year; } month = (byte)(calendar.get(Calendar.MONTH)+1); day = (byte)(calendar.get(Calendar.DATE)); setTimezoneInMinutes(tz); typeLabel = BuiltInAtomicType.DATE; } /** * Static factory method: construct a DateValue from a string in the lexical form * of a date, returning a ValidationFailure if the supplied string is invalid * @param in the lexical form of the date * @return either a DateValue or a ValidationFailure */ public static ConversionResult makeDateValue(CharSequence in) { DateValue d = new DateValue(); d.typeLabel = BuiltInAtomicType.DATE; return setLexicalValue(d, in); } /** * Determine the primitive type of the value. This delivers the same answer as * getItemType().getPrimitiveItemType(). The primitive types are * the 19 primitive types of XML Schema, plus xs:integer, xs:dayTimeDuration and xs:yearMonthDuration, * and xs:untypedAtomic. For external objects, the result is AnyAtomicType. */ public BuiltInAtomicType getPrimitiveType() { return BuiltInAtomicType.DATE; } /** * Get the date that immediately follows a given date * @param year the year * @param month the month (1-12) * @param day the day (1-31) * @return a new DateValue with no timezone information */ public static DateValue tomorrow(int year, byte month, byte day) { if (DateValue.isValidDate(year, month, day+1)) { return new DateValue(year, month, (byte)(day+1)); } else if (month < 12) { return new DateValue(year, (byte)(month+1), (byte)1); } else { return new DateValue(year+1, (byte)1, (byte)1); } } /** * Get the date that immediately precedes a given date * @param year the year * @param month the month (1-12) * @param day the day (1-31) * @return a new DateValue with no timezone information */ public static DateValue yesterday(int year, byte month, byte day) { if (day > 1) { return new DateValue(year, month, (byte)(day-1)); } else if (month > 1) { if (month == 3 && isLeapYear(year)) { return new DateValue(year, (byte)2, (byte)29); } else { return new DateValue(year, (byte)(month-1), daysPerMonth[month-2]); } } else { return new DateValue(year-1, (byte)12, (byte)31); } } /** * Convert to target data type * @param requiredType an integer identifying the required atomic type * @param context the XPath dynamic context * @return an AtomicValue, a value of the required type; or an ErrorValue */ public ConversionResult convertPrimitive(BuiltInAtomicType requiredType, boolean validate, XPathContext context) { switch(requiredType.getPrimitiveType()) { case StandardNames.XS_DATE: case StandardNames.XS_ANY_ATOMIC_TYPE: return this; case StandardNames.XS_DATE_TIME: return toDateTime(); case StandardNames.XS_STRING: return new StringValue(getStringValueCS()); case StandardNames.XS_UNTYPED_ATOMIC: return new UntypedAtomicValue(getStringValueCS()); case StandardNames.XS_G_YEAR: { return new GYearValue(year, getTimezoneInMinutes()); } case StandardNames.XS_G_YEAR_MONTH: { return new GYearMonthValue(year, month, getTimezoneInMinutes()); } case StandardNames.XS_G_MONTH: { return new GMonthValue(month, getTimezoneInMinutes()); } case StandardNames.XS_G_MONTH_DAY: { return new GMonthDayValue(month, day, getTimezoneInMinutes()); } case StandardNames.XS_G_DAY:{ return new GDayValue(day, getTimezoneInMinutes()); } default: ValidationFailure err = new ValidationFailure("Cannot convert date to " + requiredType.getDisplayName()); err.setErrorCode("XPTY0004"); return err; } } /** * Convert to string * @return ISO 8601 representation. */ public CharSequence getStringValueCS() { FastStringBuffer sb = new FastStringBuffer(16); int yr = year; if (year <= 0) { sb.append('-'); yr = -yr +1; // no year zero in lexical space } appendString(sb, yr, (yr>9999 ? (yr+"").length() : 4)); sb.append('-'); appendTwoDigits(sb, month); sb.append('-'); appendTwoDigits(sb, day); if (hasTimezone()) { appendTimezone(sb); } return sb; } /** * Get the canonical lexical representation as defined in XML Schema. This is not always the same * as the result of casting to a string according to the XPath rules. For xs:date, the timezone is * adjusted to be in the range +12:00 to -11:59 * * @return the canonical lexical representation if defined in XML Schema; otherwise, the result * of casting to string according to the XPath 2.0 rules */ public CharSequence getCanonicalLexicalRepresentation() { DateValue target = this; if (hasTimezone()) { if (getTimezoneInMinutes() > 12*60) { target = (DateValue)adjustTimezone(getTimezoneInMinutes() - 24*60); } else if (getTimezoneInMinutes() <= -12*60) { target = (DateValue)adjustTimezone(getTimezoneInMinutes() + 24*60); } } return target.getStringValueCS(); } /** * Make a copy of this date value, but with a new type label * @param typeLabel the new type label: must be a subtype of xs:date * @return the new xs:date value */ public AtomicValue copyAsSubType(AtomicType typeLabel) { DateValue v = new DateValue(year, month, day, getTimezoneInMinutes()); v.typeLabel = typeLabel; return v; } /** * Return a new date with the same normalized value, but * in a different timezone. This is called only for a DateValue that has an explicit timezone * @param timezone the new timezone offset, in minutes * @return the time in the new timezone. This will be a new TimeValue unless no change * was required to the original value */ public CalendarValue adjustTimezone(int timezone) { DateTimeValue dt = (DateTimeValue)toDateTime().adjustTimezone(timezone); return new DateValue(dt.getYear(), dt.getMonth(), dt.getDay(), dt.getTimezoneInMinutes()); } /** * Add a duration to a date * @param duration the duration to be added (may be negative) * @return the new date * @throws net.sf.saxon.trans.XPathException if the duration is an xs:duration, as distinct from * a subclass thereof */ public CalendarValue add(DurationValue duration) throws XPathException { if (duration instanceof DayTimeDurationValue) { long microseconds = ((DayTimeDurationValue)duration).getLengthInMicroseconds(); boolean negative = (microseconds < 0); microseconds = Math.abs(microseconds); int days = (int)Math.floor((double)microseconds / (1000000L*60L*60L*24L)); boolean partDay = (microseconds % (1000000L*60L*60L*24L)) > 0; int julian = getJulianDayNumber(year, month, day); DateValue d = dateFromJulianDayNumber(julian + (negative ? -days : days)); if (partDay) { if (negative) { d = yesterday(d.year, d.month, d.day); } } d.setTimezoneInMinutes(getTimezoneInMinutes()); return d; } else if (duration instanceof YearMonthDurationValue) { int months = ((YearMonthDurationValue)duration).getLengthInMonths(); int m = (month-1) + months; int y = year + m / 12; m = m % 12; if (m < 0) { m += 12; y -= 1; } m++; int d = day; while (!isValidDate(y, m, d)) { d -= 1; } return new DateValue(y, (byte)m, (byte)d, getTimezoneInMinutes()); } else { XPathException err = new XPathException("Date arithmetic is not supported on xs:duration, only on its subtypes"); err.setIsTypeError(true); err.setErrorCode("XPTY0004"); throw err; } } /** * Determine the difference between two points in time, as a duration * @param other the other point in time * @param context the XPath dynamic context * @return the duration as an xs:dayTimeDuration * @throws XPathException for example if one value is a date and the other is a time */ public DayTimeDurationValue subtract(CalendarValue other, XPathContext context) throws XPathException { if (!(other instanceof DateValue)) { XPathException err = new XPathException("First operand of '-' is a date, but the second is not"); err.setIsTypeError(true); err.setErrorCode("XPTY0004"); throw err; } return super.subtract(other, context); } /** * Context-free comparison of two DateValue values. For this to work, * the two values must either both have a timezone or both have none. * @param v2 the other value * @return the result of the comparison: -1 if the first is earlier, 0 if they * are equal, +1 if the first is later * @throws ClassCastException if the values are not comparable (which might be because * no timezone is available) */ public int compareTo(Object v2) { try { return compareTo((DateValue)v2, null); } catch (Exception err) { throw new ClassCastException("DateTime comparison requires access to implicit timezone"); } } /** * Calculate the Julian day number at 00:00 on a given date. This algorithm is taken from * http://vsg.cape.com/~pbaum/date/jdalg.htm and * http://vsg.cape.com/~pbaum/date/jdalg2.htm * (adjusted to handle BC dates correctly) * *

    Note that this assumes dates in the proleptic Gregorian calendar

    * * @param year the year * @param month the month (1-12) * @param day the day (1-31) * @return the Julian day number */ public static int getJulianDayNumber(int year, int month, int day) { int z = year - (month<3 ? 1 : 0); short f = monthData[month-1]; if (z >= 0) { return day + f + 365*z + z/4 - z/100 + z/400 + 1721118; } else { // for negative years, add 12000 years and then subtract the days! z += 12000; int j = day + f + 365*z + z/4 - z/100 + z/400 + 1721118; return j - (365*12000 + 12000/4 - 12000/100 + 12000/400); // number of leap years in 12000 years } } /** * Get the Gregorian date corresponding to a particular Julian day number. The algorithm * is taken from http://www.hermetic.ch/cal_stud/jdn.htm#comp * @param julianDayNumber the Julian day number * @return a DateValue with no timezone information set */ public static DateValue dateFromJulianDayNumber(int julianDayNumber) { if (julianDayNumber >= 0) { int L = julianDayNumber + 68569 + 1; // +1 adjustment for days starting at noon int n = ( 4 * L ) / 146097; L = L - ( 146097 * n + 3 ) / 4; int i = ( 4000 * ( L + 1 ) ) / 1461001; L = L - ( 1461 * i ) / 4 + 31; int j = ( 80 * L ) / 2447; int d = L - ( 2447 * j ) / 80; L = j / 11; int m = j + 2 - ( 12 * L ); int y = 100 * ( n - 49 ) + i + L; return new DateValue(y, (byte)m, (byte)d); } else { // add 12000 years and subtract them again... DateValue dt = dateFromJulianDayNumber(julianDayNumber + (365*12000 + 12000/4 - 12000/100 + 12000/400)); dt.year -= 12000; return dt; } } /** * Get the ordinal day number within the year (1 Jan = 1, 1 Feb = 32, etc) * @param year the year * @param month the month (1-12) * @param day the day (1-31) * @return the ordinal day number within the year */ public static int getDayWithinYear(int year, int month, int day) { int j = getJulianDayNumber(year, month, day); int k = getJulianDayNumber(year, 1, 1); return j - k + 1; } /** * Get the day of the week. The days of the week are numbered from * 1 (Monday) to 7 (Sunday) * @param year the year * @param month the month (1-12) * @param day the day (1-31) * @return the day of the week, 1=Monday .... 7=Sunday */ public static int getDayOfWeek(int year, int month, int day) { int d = getJulianDayNumber(year, month, day); d -= 2378500; // 1800-01-05 - any Monday would do while (d <= 0) { d += 70000000; // any sufficiently high multiple of 7 would do } return (d-1)%7 + 1; } /** * Get the ISO week number for a given date. The days of the week are numbered from * 1 (Monday) to 7 (Sunday), and week 1 in any calendar year is the week (from Monday to Sunday) * that includes the first Thursday of that year * @param year the year * @param month the month (1-12) * @param day the day (1-31) * @return the ISO week number */ public static int getWeekNumber(int year, int month, int day) { int d = getDayWithinYear(year, month, day); int firstDay = getDayOfWeek(year, 1, 1); if (firstDay > 4 && (firstDay + d) <= 8) { // days before week one are part of the last week of the previous year (52 or 53) return getWeekNumber(year-1, 12, 31); } int inc = (firstDay < 5 ? 1 : 0); // implements the First Thursday rule return ((d + firstDay - 2) / 7) + inc; } /** * Get the week number within a month. This is required for the XSLT format-date() function, * and the rules are not entirely clear. The days of the week are numbered from * 1 (Monday) to 7 (Sunday), and by analogy with the ISO week number, we consider that week 1 * in any calendar month is the week (from Monday to Sunday) that includes the first Thursday * of that month. Unlike the ISO week number, we put the previous days in week zero. * @param year the year * @param month the month (1-12) * @param day the day (1-31) * @return the week number within a month */ public static int getWeekNumberWithinMonth(int year, int month, int day) { int firstDay = getDayOfWeek(year, month, 1); int inc = (firstDay < 5 ? 1 : 0); // implements the First Thursday rule return ((day + firstDay - 2) / 7) + inc; } /** * Temporary test rig */ // public static void main(String[] args) throws Exception { // DateValue date = new DateValue(args[0]); // System.out.println(date.getStringValue()); // int jd = getJulianDayNumber(date.year, date.month, date.day); // System.out.println(jd); // System.out.println(dateFromJulianDayNumber(jd).getStringValue()); // } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/value/ShareableSequence.java0000644000175000017500000001453011033112257022740 0ustar eugeneeugenepackage net.sf.saxon.value; import net.sf.saxon.expr.ExpressionTool; import net.sf.saxon.expr.StaticProperty; import net.sf.saxon.om.Item; import net.sf.saxon.om.ListIterator; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.AnyItemType; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.Type; import net.sf.saxon.type.TypeHierarchy; import java.util.List; /** * A sequence value implemented extensionally using an extensible List whose leading part can be shared * with other sequence values. The list can be appended to by other users (at most one other user!), * but the items within the range used by this sequence value cannot be modified. */ public final class ShareableSequence extends Value { private List list; private int end; // the 0-based index of the first item that is NOT included private ItemType itemType = null; // memoized /** * Construct an sequence from an array of items. Note, the list of items is used as is, * which means the caller must not subsequently change its contents; however it is permitted * to subsequently append items to the list (indeed, that is the raison d'etre of this class) * * @param list the list of items to be included in the sequence */ public ShareableSequence(List list) { //System.err.println("** Using shareable sequence **"); this.list = list; end = list.size(); } /** * Determine whether another value can share this list. This is true provided the list has * not already been extended by another value. * @return true if another value can share this list */ public boolean isShareable() { return list.size() == end; } /** * Get the underlying list * @return the underlying list of values */ public List getList() { return list; } /** * Simplify this value * @return the simplified value */ public Value simplify() { int n = getLength(); if (n == 0) { return EmptySequence.getInstance(); } else if (n == 1) { return Value.asValue(itemAt(0)); } else { return this; } } /** * Reduce a value to its simplest form. If the value is a closure or some other form of deferred value * such as a FunctionCallPackage, then it is reduced to a SequenceExtent. If it is a SequenceExtent containing * a single item, then it is reduced to that item. One consequence that is exploited by class FilterExpression * is that if the value is a singleton numeric value, then the result will be an instance of NumericValue */ public Value reduce() { return simplify(); } /** * Get the number of items in the sequence * * @return the number of items in the sequence */ public int getLength() { return end; } /** * Determine the cardinality * * @return the cardinality of the sequence, using the constants defined in * net.sf.saxon.value.Cardinality * @see Cardinality */ public int getCardinality() { switch (end) { case 0: return StaticProperty.EMPTY; case 1: return StaticProperty.EXACTLY_ONE; default: return StaticProperty.ALLOWS_ONE_OR_MORE; } } /** * Get the (lowest common) item type * * @return integer identifying an item type to which all the items in this * sequence conform * @param th the type hierarchy cache */ public ItemType getItemType(TypeHierarchy th) { if (itemType != null) { // only calculate it the first time return itemType; } if (end==0) { itemType = AnyItemType.getInstance(); } else { itemType = Type.getItemType(itemAt(0), th); for (int i=1; i=getLength()) { return null; } else { return (Item)list.get(n); } } /** * Return an iterator over this sequence. * * @return the required SequenceIterator, positioned at the start of the * sequence */ public SequenceIterator iterate() { return new ListIterator(list, end); } /** * Get the effective boolean value */ public boolean effectiveBooleanValue() throws XPathException { int len = getLength(); if (len == 0) { return false; } else if (itemAt(0) instanceof NodeInfo) { return true; } else if (len > 1) { // this is a type error - reuse the error messages return ExpressionTool.effectiveBooleanValue(iterate()); } else { return ((AtomicValue)itemAt(0)).effectiveBooleanValue(); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/value/ObjectValue.java0000644000175000017500000002031711033112257021564 0ustar eugeneeugenepackage net.sf.saxon.value; import net.sf.saxon.Configuration; import net.sf.saxon.sort.StringCollator; import net.sf.saxon.om.StandardNames; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.*; /** * An XPath value that encapsulates a Java object. Such a value can only be obtained by * calling an extension function that returns it. */ public class ObjectValue extends AtomicValue { private Object value; /** * Default constructor for use in subclasses */ public ObjectValue() { typeLabel = BuiltInAtomicType.ANY_ATOMIC; } /** * Constructor * @param object the object to be encapsulated */ public ObjectValue(Object object) { value = object; typeLabel = BuiltInAtomicType.ANY_ATOMIC; } /** * Constructor * @param object the object to be encapsulated * @param type the type of the external object */ public ObjectValue(Object object, ExternalObjectType type) { value = object; typeLabel = type; } /** * Set the value in this object value * @param value the external value to be wrapped */ public void setValue(Object value) { this.value = value; } /** * Create a copy of this atomic value, with a different type label * * @param typeLabel the type label of the new copy. The caller is responsible for checking that * the value actually conforms to this type. */ public AtomicValue copyAsSubType(AtomicType typeLabel) { ObjectValue v = new ObjectValue(value); v.typeLabel = typeLabel; return v; } /** * Determine the primitive type of the value. This delivers the same answer as * getItemType().getPrimitiveItemType(). The primitive types are * the 19 primitive types of XML Schema, plus xs:integer, xs:dayTimeDuration and xs:yearMonthDuration, * and xs:untypedAtomic. For external objects, the result is AnyAtomicType. */ public BuiltInAtomicType getPrimitiveType() { return BuiltInAtomicType.ANY_ATOMIC; } /** * Determine the data type of the items in the expression, if possible * * @param th The TypeHierarchy. * @return for the default implementation: AnyItemType (not known) */ public ItemType getItemType(TypeHierarchy th) { if (typeLabel.equals(BuiltInAtomicType.ANY_ATOMIC)) { if (th == null) { throw new NullPointerException("No TypeHierarchy supplied"); } else { Configuration config = th.getConfiguration(); typeLabel = new ExternalObjectType(value.getClass(), config); } } return typeLabel; } /** * Display the type name for use in error messages * @return the type name */ public String displayTypeName() { return "java-type:" + value.getClass().getName(); } /** * Convert to target data type */ public ConversionResult convertPrimitive(BuiltInAtomicType requiredType, boolean validate, XPathContext context) { switch(requiredType.getPrimitiveType()) { case StandardNames.XS_ANY_ATOMIC_TYPE: case StandardNames.SAXON_JAVA_LANG_OBJECT: return this; case StandardNames.XS_BOOLEAN: return BooleanValue.get( (value != null && value.toString().length() > 0)); case StandardNames.XS_STRING: return new StringValue(getStringValue()); case StandardNames.XS_UNTYPED_ATOMIC: return new UntypedAtomicValue(getStringValue()); default: return new StringValue(getStringValue()).convertPrimitive(requiredType, validate, context); } } /** * Get the value as a String * @return a String representation of the value */ public String getStringValue() { return (value==null ? "" : value.toString()); } /** * Get the effective boolean value of the value * * @return true, unless the value is boolean false, numeric zero, or * zero-length string */ public boolean effectiveBooleanValue() throws XPathException { return value != null; } /** * Get the encapsulated object * @return the Java object that this external object wraps */ public Object getObject() { return value; } public Comparable getSchemaComparable() { throw new UnsupportedOperationException("External objects cannot be compared according to XML Schema rules"); } /** * Get an object value that implements the XPath equality and ordering comparison semantics for this value. * If the ordered parameter is set to true, the result will be a Comparable and will support a compareTo() * method with the semantics of the XPath lt/gt operator, provided that the other operand is also obtained * using the getXPathComparable() method. In all cases the result will support equals() and hashCode() methods * that support the semantics of the XPath eq operator, again provided that the other operand is also obtained * using the getXPathComparable() method. A context argument is supplied for use in cases where the comparison * semantics are context-sensitive, for example where they depend on the implicit timezone or the default * collation. * * @param ordered true if an ordered comparison is required. In this case the result is null if the * type is unordered; in other cases the returned value will be a Comparable. * @param collator *@param context the XPath dynamic evaluation context, used in cases where the comparison is context * sensitive @return an Object whose equals() and hashCode() methods implement the XPath comparison semantics * with respect to this atomic value. If ordered is specified, the result will either be null if * no ordering is defined, or will be a Comparable */ public Object getXPathComparable(boolean ordered, StringCollator collator, XPathContext context) { return (ordered ? null : this); } /** * Determine if two ObjectValues are equal * @throws ClassCastException if they are not comparable */ public boolean equals(Object other) { return value.equals(((ObjectValue)other).value); } public int hashCode() { return value.hashCode(); } /** * Convert to Java object (for passing to external functions) */ // public Object convertAtomicToJava(Class target, XPathContext context) throws XPathException { // // if (value==null) return null; // // if (target.isAssignableFrom(value.getClass())) { // return value; // } else if (target==Value.class || target==ObjectValue.class) { // return this; // } else if (target==String.class || target==CharSequence.class) { // return getStringValue(); // // } else { // Object o = convertSequenceToJava(target, context); // if (o == null) { // throw new XPathException("Conversion of external object to " + target.getName() + // " is not supported"); // } // return o; // } // } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/value/BigIntegerValue.java0000644000175000017500000005254011033112257022400 0ustar eugeneeugenepackage net.sf.saxon.value; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.expr.Calculator; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.*; import net.sf.saxon.om.StandardNames; import java.math.BigDecimal; import java.math.BigInteger; /** * An integer value: note this is a subtype of decimal in XML Schema, not a primitive type. * The abstract class IntegerValue is used to represent any xs:integer value; this implementation * is used for values that do not fit comfortably in a Java long; including the built-in subtype xs:unsignedLong */ public final class BigIntegerValue extends IntegerValue { private BigInteger value; private static final BigInteger MAX_INT = BigInteger.valueOf(Integer.MAX_VALUE); private static final BigInteger MIN_INT = BigInteger.valueOf(Integer.MIN_VALUE); public static final BigInteger MAX_LONG = BigInteger.valueOf(Long.MAX_VALUE); public static final BigInteger MIN_LONG = BigInteger.valueOf(Long.MIN_VALUE); public static final BigInteger MAX_UNSIGNED_LONG = new BigInteger("18446744073709551615"); public static final BigIntegerValue ZERO = new BigIntegerValue(BigInteger.ZERO); /** * Construct an xs:integer value from a Java BigInteger * @param value the supplied BigInteger */ public BigIntegerValue(BigInteger value) { this.value = value; typeLabel = BuiltInAtomicType.INTEGER; } /** * Construct an xs:integer value from a Java BigInteger, supplying a type label. * It is the caller's responsibility to ensure that the supplied value conforms * with the rules for the specified type. * @param value the value of the integer * @param typeLabel the type, which must represent a type derived from xs:integer */ public BigIntegerValue(BigInteger value, AtomicType typeLabel) { this.value = value; this.typeLabel = typeLabel; } /** * Construct an xs:integer value from a Java long. Note: normally, if the value fits in a long, * then an Int64Value should be used. This constructor is largely for internal use, when operations * are required that require two integers to use the same implementation class to be used. * @param value the supplied Java long */ public BigIntegerValue(long value) { this.value = BigInteger.valueOf(value); typeLabel = BuiltInAtomicType.INTEGER; } /** * Create a copy of this atomic value, with a different type label * * @param typeLabel the type label of the new copy. The caller is responsible for checking that * the value actually conforms to this type. */ public AtomicValue copyAsSubType(AtomicType typeLabel) { BigIntegerValue v = new BigIntegerValue(value); v.typeLabel = typeLabel; return v; } /** * This class allows subtypes of xs:integer to be held, as well as xs:integer values. * This method sets the required type label. Note that this method modifies the value in situ. * @param type the subtype of integer required * @return null if the operation succeeds, or a ValidationException if the value is out of range */ public ValidationFailure convertToSubType(BuiltInAtomicType type, boolean validate) { if (!validate) { typeLabel = type; return null; } if (IntegerValue.checkBigRange(value, type)) { typeLabel = type; return null; } else { ValidationFailure err = new ValidationFailure( "Integer value is out of range for subtype " + type.getDisplayName()); err.setErrorCode("FORG0001"); return err; } } /** * This class allows subtypes of xs:integer to be held, as well as xs:integer values. * This method checks that the value is valid against the rules for a given subtype. * * @param type the subtype of integer required * @return null if the operation succeeds, or a ValidationException if the value is out of range */ public ValidationFailure validateAgainstSubType(BuiltInAtomicType type) { if (IntegerValue.checkBigRange(value, type)) { typeLabel = type; return null; } else { ValidationFailure err = new ValidationFailure( "Integer value is out of range for subtype " + type.getDisplayName()); err.setErrorCode("FORG0001"); return err; } } /** * Get the hashCode. This must conform to the rules for other NumericValue hashcodes * @see NumericValue#hashCode */ public int hashCode() { if (value.compareTo(MIN_INT) >= 0 && value.compareTo(MAX_INT) <= 0) { return value.intValue(); } else { return new Double(getDoubleValue()).hashCode(); } } /** * Get the value as a long * * @return the value of the xs:integer, as a Java long */ public long longValue() { return value.longValue(); } /** * Get the value as a BigInteger * @return the value of the xs:integer as a Java BigInteger */ public BigInteger asBigInteger() { return value; } /** * Test whether the value is within the range that can be held in a 64-bit signed integer * @return true if the value is within range for a long */ public boolean isWithinLongRange() { return value.compareTo(MIN_LONG) >= 0 && value.compareTo(MAX_LONG) <= 0; } /** * Convert the value to a BigDecimal * @return the resulting BigDecimal */ public BigDecimal asDecimal() { return new BigDecimal(value); } /** * Return the effective boolean value of this integer * * @return false if the integer is zero, otherwise true */ public boolean effectiveBooleanValue() { return value.compareTo(BigInteger.ZERO) != 0; } /** * Compare the value to another numeric value * * @param other the numeric value to be compared to this value * @return -1 if this value is less than the other, 0 if they are equal, * +1 if this value is greater */ public int compareTo(Object other) { if (other instanceof BigIntegerValue) { return value.compareTo(((BigIntegerValue)other).value); } else if (other instanceof DecimalValue) { return asDecimal().compareTo(((DecimalValue)other).getDecimalValue()); } else { return super.compareTo(other); } } /** * Compare the value to a long * @param other the value to be compared with * @return -1 if this is less, 0 if this is equal, +1 if this is greater or if this is NaN */ public int compareTo(long other) { if (other == 0) { return value.signum(); } return value.compareTo((BigInteger.valueOf(other))); } /** * Convert to target data type * * @param requiredType identifies the required atomic type * @param context the XPath dynamic evaluation context * @return an AtomicValue, a value of the required type; or an ErrorValue */ public ConversionResult convertPrimitive(BuiltInAtomicType requiredType, boolean validate, XPathContext context) { switch (requiredType.getFingerprint()) { case StandardNames.XS_BOOLEAN: return BooleanValue.get(effectiveBooleanValue()); case StandardNames.XS_NUMERIC: case StandardNames.XS_INTEGER: case StandardNames.XS_ANY_ATOMIC_TYPE: return this; case StandardNames.XS_NON_POSITIVE_INTEGER: case StandardNames.XS_NEGATIVE_INTEGER: case StandardNames.XS_LONG: case StandardNames.XS_INT: case StandardNames.XS_SHORT: case StandardNames.XS_BYTE: case StandardNames.XS_NON_NEGATIVE_INTEGER: case StandardNames.XS_POSITIVE_INTEGER: case StandardNames.XS_UNSIGNED_INT: case StandardNames.XS_UNSIGNED_SHORT: case StandardNames.XS_UNSIGNED_BYTE: if (isWithinLongRange()) { Int64Value val = Int64Value.makeIntegerValue(longValue()); ValidationFailure err = val.convertToSubType(requiredType, validate); if (err == null) { return val; } else { return err; } } else { BigIntegerValue val = new BigIntegerValue(value); ValidationFailure err = val.convertToSubType(requiredType, validate); if (err == null) { return val; } else { return err; } } case StandardNames.XS_UNSIGNED_LONG: if (value.signum() < 0 || value.bitLength() > 64) { ValidationFailure err = new ValidationFailure("Integer value is out of range for type " + requiredType.getDisplayName()); err.setErrorCode("FORG0001"); return err; } else if (isWithinLongRange()) { Int64Value val = Int64Value.makeIntegerValue(longValue()); ValidationFailure err = val.convertToSubType(requiredType, validate); if (err != null) { return err; } return val; } else { BigIntegerValue nv = new BigIntegerValue(value); ValidationFailure err = nv.convertToSubType(requiredType, validate); if (err != null) { return err; } return nv; } case StandardNames.XS_DOUBLE: return new DoubleValue(value.doubleValue()); case StandardNames.XS_FLOAT: return new FloatValue(value.floatValue()); case StandardNames.XS_DECIMAL: return new DecimalValue(new BigDecimal(value)); case StandardNames.XS_STRING: return new StringValue(getStringValueCS()); case StandardNames.XS_UNTYPED_ATOMIC: return new UntypedAtomicValue(getStringValueCS()); default: ValidationFailure err = new ValidationFailure("Cannot convert integer to " + requiredType.getDisplayName()); err.setErrorCode("XPTY0004"); return err; } } /** * Get the value as a String * @return a String representation of the value */ public String getStringValue() { return value.toString(); } /** * Get the numeric value as a double * * @return A double representing this numeric value; NaN if it cannot be * converted */ public double getDoubleValue() { return value.doubleValue(); } /** * Get the numeric value converted to a decimal * * @return a decimal representing this numeric value; */ public BigDecimal getDecimalValue() { return new BigDecimal(value); } /** * Negate the value * @return the result of inverting the sign of the value */ public NumericValue negate() { return new BigIntegerValue(value.negate()); } /** * Implement the XPath floor() function * @return the integer value, unchanged */ public NumericValue floor() { return this; } /** * Implement the XPath ceiling() function * @return the integer value, unchanged */ public NumericValue ceiling() { return this; } /** * Implement the XPath round() function * @return the integer value, unchanged */ public NumericValue round() { return this; } /** * Implement the XPath round-to-half-even() function * * @param scale number of digits required after the decimal point; the * value -2 (for example) means round to a multiple of 100 * @return if the scale is >=0, return this value unchanged. Otherwise * round it to a multiple of 10**-scale */ public NumericValue roundHalfToEven(int scale) { if (scale >= 0) { return this; } else { BigInteger factor = BigInteger.valueOf(10).pow(-scale); BigInteger[] pair = value.divideAndRemainder(factor); int up = pair[1].compareTo(factor.divide(BigInteger.valueOf(2))); if (up > 0) { // remainder is > .5 pair[0] = pair[0].add(BigInteger.valueOf(1)); } else if (up == 0) { // remainder == .5 if (pair[0].mod(BigInteger.valueOf(2)).signum() != 0) { // last digit of quotient is odd: make it even pair[0] = pair[0].add(BigInteger.valueOf(1)); } } return makeIntegerValue(pair[0].multiply(factor)); } } /** * Determine whether the value is negative, zero, or positive * @return -1 if negative, 0 if zero, +1 if positive, NaN if NaN */ public double signum() { return value.signum(); } /** * Determine whether the value is a whole number, that is, whether it compares * equal to some integer * * @return always true for this implementation */ public boolean isWholeNumber() { return true; } /** * Add another integer */ public IntegerValue plus(IntegerValue other) { if (other instanceof BigIntegerValue) { return makeIntegerValue(value.add(((BigIntegerValue)other).value)); } else { //noinspection RedundantCast return makeIntegerValue(value.add(BigInteger.valueOf(((Int64Value)other).longValue()))); } } /** * Subtract another integer */ public IntegerValue minus(IntegerValue other) { if (other instanceof BigIntegerValue) { return makeIntegerValue(value.subtract(((BigIntegerValue)other).value)); } else { //noinspection RedundantCast return makeIntegerValue(value.subtract(BigInteger.valueOf(((Int64Value)other).longValue()))); } } /** * Multiply by another integer */ public IntegerValue times(IntegerValue other) { if (other instanceof BigIntegerValue) { return makeIntegerValue(value.multiply(((BigIntegerValue)other).value)); } else { //noinspection RedundantCast return makeIntegerValue(value.multiply(BigInteger.valueOf(((Int64Value)other).longValue()))); } } /** * Divide by another integer * * @throws net.sf.saxon.trans.XPathException * if the other integer is zero */ public NumericValue div(IntegerValue other) throws XPathException { BigInteger oi; if (other instanceof BigIntegerValue) { oi = ((BigIntegerValue)other).value; } else { oi = BigInteger.valueOf(other.longValue()); } DecimalValue a = new DecimalValue(new BigDecimal(value)); DecimalValue b = new DecimalValue(new BigDecimal(oi)); return (NumericValue)Calculator.DECIMAL_DECIMAL[Calculator.DIV].compute(a, b, null); } /** * Take modulo another integer * * @throws net.sf.saxon.trans.XPathException * if the other integer is zero */ public IntegerValue mod(IntegerValue other) throws XPathException { try { if (other instanceof BigIntegerValue) { return makeIntegerValue(value.remainder(((BigIntegerValue)other).value)); } else { return makeIntegerValue(value.remainder(BigInteger.valueOf(other.longValue()))); } } catch (ArithmeticException err) { XPathException e; if (BigInteger.valueOf(other.longValue()).signum() == 0) { e = new XPathException("Integer modulo zero", "FOAR0001"); } else { e = new XPathException("Integer mod operation failure", err); } throw e; } } /** * Integer divide by another integer * * @throws net.sf.saxon.trans.XPathException * if the other integer is zero */ public IntegerValue idiv(IntegerValue other) throws XPathException { BigInteger oi; if (other instanceof BigIntegerValue) { oi = ((BigIntegerValue)other).value; } else { oi = BigInteger.valueOf(other.longValue()); } try { return makeIntegerValue(value.divide(oi)); } catch (ArithmeticException err) { XPathException e; if ("/ by zero".equals(err.getMessage())) { e = new XPathException("Integer division by zero", "FOAR0001"); } else { e = new XPathException("Integer division failure", err); } throw e; } } /** * Get an object that implements XML Schema comparison semantics */ public Comparable getSchemaComparable() { return new BigIntegerComparable(this); } protected static class BigIntegerComparable implements Comparable { protected BigIntegerValue value; public BigIntegerComparable(BigIntegerValue value) { this.value = value; } public BigInteger asBigInteger() { return value.asBigInteger(); } public int compareTo(Object o) { if (o instanceof Int64Value.Int64Comparable) { return asBigInteger().compareTo(BigInteger.valueOf(((Int64Value.Int64Comparable)o).asLong())); } else if (o instanceof BigIntegerComparable) { return asBigInteger().compareTo(((BigIntegerComparable)o).asBigInteger()); } else if (o instanceof DecimalValue.DecimalComparable) { return value.getDecimalValue().compareTo(((DecimalValue.DecimalComparable)o).asBigDecimal()); } else { return INDETERMINATE_ORDERING; } } public boolean equals(Object o) { return compareTo(o) == 0; } public int hashCode() { // Must align with hashCodes for other subtypes of xs:decimal BigInteger big = value.asBigInteger(); if (big.compareTo(MAX_LONG) < 0 && big.compareTo(MIN_LONG) > 0) { Int64Value iv = new Int64Value(big.longValue()); return iv.hashCode(); } return big.hashCode(); } } /** * Reduce a value to its simplest form. */ public Value reduce() throws XPathException { if (compareTo(Long.MAX_VALUE) < 0 && compareTo(Long.MIN_VALUE) > 0) { Int64Value iv = new Int64Value(longValue()); iv.setTypeLabel(typeLabel); return iv; } return this; } /** * Convert to Java object (for passing to external functions) * * @param target The Java class to which conversion is required * @exception XPathException if conversion is not possible, or fails * @return the Java object that results from the conversion; always an * instance of the target class */ // public Object convertAtomicToJava(Class target, XPathContext context) throws XPathException { // if (isWithinLongRange()) { // Int64Value val = Int64Value.makeIntegerValue(longValue()); // return val.convertToJava(target, context); // } else if (target.isAssignableFrom(Int64Value.class)) { // return this; // } else if (target == BigInteger.class) { // return value; // } else { // return convertPrimitive(BuiltInAtomicType.DECIMAL, true, context).asAtomic().convertToJava(target, context); // } // } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file except the asStringXT() and zeros() methods (not currently used). // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/value/Base64BinaryValue.java0000644000175000017500000006006111033112257022547 0ustar eugeneeugenepackage net.sf.saxon.value; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.FastStringBuffer; import net.sf.saxon.om.StandardNames; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.*; import net.sf.saxon.sort.StringCollator; import java.io.ByteArrayOutputStream; import java.util.Arrays; /** * A value of type xs:base64Binary */ public class Base64BinaryValue extends AtomicValue { private byte[] binaryValue; /** * Constructor: create a base64Binary value from a supplied string in base64 encoding * @param s the lexical representation of the base64 binary value. There is no requirement * that whitespace should already be collapsed. */ public Base64BinaryValue(CharSequence s) throws XPathException { Base64Decoder decoder = new Base64Decoder(); try { decoder.translate(s); } catch (IllegalArgumentException e) { XPathException err = new XPathException(e.getMessage()); err.setErrorCode("FORG0001"); throw err; } binaryValue = decoder.getByteArray(); typeLabel = BuiltInAtomicType.BASE64_BINARY; } /** * Constructor: create a base64Binary value from a supplied string in base64 encoding, * with a specified type. This method throws no checked exceptions; the caller is expected * to ensure that the string is a valid Base64 lexical representation, that it conforms * to the specified type, and that the type is indeed a subtype of xs:base64Binary. * An unchecked exception such as an IllegalArgumentException may be thrown if these * conditions are not satisfied, but this is not guaranteed. * @param s the value in base64 encoding * @param type the atomic type. This must be xs:base64binary or a subtype. */ public Base64BinaryValue(CharSequence s, AtomicType type) { Base64Decoder decoder = new Base64Decoder(); decoder.translate(s); binaryValue = decoder.getByteArray(); typeLabel = type; } /** * Constructor: create a base64Binary value from a given array of bytes * @param value array of bytes holding the octet sequence */ public Base64BinaryValue(byte[] value) { binaryValue = value; typeLabel = BuiltInAtomicType.BASE64_BINARY; } /** * Create a copy of this atomic value (usually so that the type label can be changed). * The type label of the copy will be reset to the primitive type. * @param typeLabel the type label to be attached to the value, a subtype of xs:base64Binary * @return the copied value */ public AtomicValue copyAsSubType(AtomicType typeLabel) { Base64BinaryValue v = new Base64BinaryValue(binaryValue); v.typeLabel = typeLabel; return v; } /** * Get the binary value * @return the octet sequence that is the typed value */ public byte[] getBinaryValue() { return binaryValue; } public BuiltInAtomicType getPrimitiveType() { return BuiltInAtomicType.BASE64_BINARY; } /** * Convert to target data type * @param requiredType an integer identifying the required atomic type * @param context the XPath dynamic evaluation context * @return an AtomicValue, a value of the required type; or an ErrorValue */ public ConversionResult convertPrimitive(BuiltInAtomicType requiredType, boolean validate, XPathContext context) { switch (requiredType.getPrimitiveType()) { case StandardNames.XS_BASE64_BINARY: case StandardNames.XS_ANY_ATOMIC_TYPE: return this; case StandardNames.XS_STRING: return new StringValue(getStringValueCS()); case StandardNames.XS_UNTYPED_ATOMIC: return new UntypedAtomicValue(getStringValueCS()); case StandardNames.XS_HEX_BINARY: return new HexBinaryValue(binaryValue); default: ValidationFailure err = new ValidationFailure("Cannot convert base64Binary to " + requiredType.getDisplayName()); err.setErrorCode("XPTY0004"); return err; } } /** * Convert to string * @return the canonical representation. */ public String getStringValue() { Base64Encoder encoder = new Base64Encoder(); encoder.translate(binaryValue); return new String(encoder.getCharArray()); } /** * Get the number of octets in the value * @return the number of octets */ public int getLengthInOctets() { return binaryValue.length; } /** * Convert to Java object (for passing to external functions) */ // public Object convertAtomicToJava(Class target, XPathContext context) throws XPathException { // // if (target.isAssignableFrom(Base64BinaryValue.class)) { // return this; // } else if (target == Object.class) { // return getStringValue(); // } else { // Object o = super.convertSequenceToJava(target, context); // if (o == null) { // throw new XPathException("Conversion of base64Binary to " + target.getName() + // " is not supported"); // } // return o; // } // } /** * Support XML Schema comparison semantics */ public Comparable getSchemaComparable() { return new Base64BinaryComparable(); } private class Base64BinaryComparable implements Comparable { public Base64BinaryValue getBase64BinaryValue() { return Base64BinaryValue.this; } public int compareTo(Object o) { if (o instanceof Base64BinaryComparable && Arrays.equals(getBase64BinaryValue().binaryValue, ((Base64BinaryComparable)o).getBase64BinaryValue().binaryValue)) { return 0; } else { return INDETERMINATE_ORDERING; } } public boolean equals(Object o) { return compareTo(o) == 0; } public int hashCode() { return Base64BinaryValue.this.hashCode(); } } /** * Get an object value that implements the XPath equality and ordering comparison semantics for this value. * If the ordered parameter is set to true, the result will be a Comparable and will support a compareTo() * method with the semantics of the XPath lt/gt operator, provided that the other operand is also obtained * using the getXPathComparable() method. In all cases the result will support equals() and hashCode() methods * that support the semantics of the XPath eq operator, again provided that the other operand is also obtained * using the getXPathComparable() method. A context argument is supplied for use in cases where the comparison * semantics are context-sensitive, for example where they depend on the implicit timezone or the default * collation. * * @param ordered true if an ordered comparison is required. In this case the result is null if the * type is unordered; in other cases the returned value will be a Comparable. * @param collator *@param context the XPath dynamic evaluation context, used in cases where the comparison is context * sensitive @return an Object whose equals() and hashCode() methods implement the XPath comparison semantics * with respect to this atomic value. If ordered is specified, the result will either be null if * no ordering is defined, or will be a Comparable */ public Object getXPathComparable(boolean ordered, StringCollator collator, XPathContext context) { return (ordered ? null : this); } /** * Test if the two base64Binary values are equal. */ public boolean equals(Object other) { return Arrays.equals(binaryValue, ((Base64BinaryValue)other).binaryValue); } public int hashCode() { return byteArrayHashCode(binaryValue); } protected static int byteArrayHashCode(byte[] value) { long h = 0; for (int i=0; i> 32) ^ h); } /* * * The contents of this [inner class] are subject to the Netscape Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/NPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is mozilla.org code. * * The Initial Developer of the Original Code is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1999 Netscape Communications Corporation. All * Rights Reserved. * * Contributor(s): */ /** * Byte to text encoder using base 64 encoding. To create a base 64 * encoding of a byte stream call {@link #translate} for every * sequence of bytes and {@link #getCharArray} to mark closure of * the byte stream and retrieve the text presentation. * * @author Based on code from the Mozilla Directory SDK */ private static final class Base64Encoder { private FastStringBuffer out = new FastStringBuffer(256); private int buf = 0; // a 24-bit quantity private int buf_bytes = 0; // how many octets are set in it private char line[] = new char[74]; // output buffer private int line_length = 0; // output buffer fill pointer //static private final byte crlf[] = "\r\n".getBytes(); private static final char map[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', // 0-7 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', // 8-15 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', // 16-23 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', // 24-31 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', // 32-39 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', // 40-47 'w', 'x', 'y', 'z', '0', '1', '2', '3', // 48-55 '4', '5', '6', '7', '8', '9', '+', '/', // 56-63 }; private void encode_token() { int i = line_length; line[i] = map[0x3F & (buf >> 18)]; // sextet 1 (octet 1) line[i + 1] = map[0x3F & (buf >> 12)]; // sextet 2 (octet 1 and 2) line[i + 2] = map[0x3F & (buf >> 6)]; // sextet 3 (octet 2 and 3) line[i + 3] = map[0x3F & buf]; // sextet 4 (octet 3) line_length += 4; buf = 0; buf_bytes = 0; } private void encode_partial_token() { int i = line_length; line[i] = map[0x3F & (buf >> 18)]; // sextet 1 (octet 1) line[i + 1] = map[0x3F & (buf >> 12)]; // sextet 2 (octet 1 and 2) if (buf_bytes == 1) line[i + 2] = '='; else line[i + 2] = map[0x3F & (buf >> 6)]; // sextet 3 (octet 2 and 3) if (buf_bytes <= 2) line[i + 3] = '='; else line[i + 3] = map[0x3F & buf]; // sextet 4 (octet 3) line_length += 4; buf = 0; buf_bytes = 0; } private void flush_line() { out.append(line, 0, line_length); line_length = 0; } /** * Given a sequence of input bytes, produces a sequence of output bytes * using the base64 encoding. If there are bytes in `out' already, the * new bytes are appended, so the caller should do `out.setLength(0)' * first if that's desired. * @param in the octet sequence to be encoded in Base64 */ public final void translate(byte[] in) { int in_length = in.length; for (int i = 0; i < in_length; i++) { if (buf_bytes == 0) buf = (buf & 0x00FFFF) | (in[i] << 16); else if (buf_bytes == 1) buf = (buf & 0xFF00FF) | ((in[i] << 8) & 0x00FFFF); else buf = (buf & 0xFFFF00) | (in[i] & 0x0000FF); if ((++buf_bytes) == 3) { encode_token(); if (line_length >= 72) { flush_line(); } } if (i == (in_length - 1)) { if ((buf_bytes > 0) && (buf_bytes < 3)) encode_partial_token(); if (line_length > 0) flush_line(); } } for (int i = 0; i < line.length; i++) line[i] = 0; } public char[] getCharArray() { char[] ch; if (buf_bytes != 0) encode_partial_token(); flush_line(); for (int i = 0; i < line.length; i++) line[i] = 0; ch = new char[out.length()]; if (out.length() > 0) out.getChars(0, out.length(), ch, 0); return ch; } } /* * * The contents of this [inner class] are subject to the Netscape Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/NPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is mozilla.org code. * * The Initial Developer of the Original Code is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1999 Netscape Communications Corporation. All * Rights Reserved. * * Contributor(s): */ /** * Base 64 text to byte decoder. To produce the binary array from * base 64 encoding call {@link #translate} for each sequence of * characters and {@link #getByteArray} to mark closure of the * character stream and retrieve the binary contents. * * @author Based on code from the Mozilla Directory SDK */ private static final class Base64Decoder { private ByteArrayOutputStream out = new ByteArrayOutputStream(); private byte token[] = new byte[4]; // input buffer private byte bytes[] = new byte[3]; // output buffer private int token_length = 0; // input buffer length private static final byte NUL = 127; // must be out of range 0-64 private static final byte EOF = 126; // must be out of range 0-64 private static final byte SP = 125; // must be out of range 0-64 private static final byte[] map = { NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // x00 - x07 NUL, SP, SP, NUL, NUL, SP, NUL, NUL, // x08 - x0F NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // x10 - x17 NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // x18 - x1F SP, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // x20 - x2F !"#$%&' NUL, NUL, NUL, 62, NUL, NUL, NUL, 63, // 050-057 ()*+,-./ 52, 53, 54, 55, 56, 57, 58, 59, // 060-067 01234567 60, 61, NUL, NUL, NUL, EOF, NUL, NUL, // 070-077 89:;<=>? NUL, 0, 1, 2, 3, 4, 5, 6, // 100-107 @ABCDEFG 7, 8, 9, 10, 11, 12, 13, 14, // 110-117 HIJKLMNO 15, 16, 17, 18, 19, 20, 21, 22, // 120-127 PQRSTUVW 23, 24, 25, NUL, NUL, NUL, NUL, NUL, // 130-137 XYZ[\]^_ NUL, 26, 27, 28, 29, 30, 31, 32, // 140-147 `abcdefg 33, 34, 35, 36, 37, 38, 39, 40, // 150-157 hijklmno 41, 42, 43, 44, 45, 46, 47, 48, // 160-167 pqrstuvw 49, 50, 51, NUL, NUL, NUL, NUL, NUL, // 170-177 xyz{|}~ NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 200-207 NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 210-217 NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 220-227 NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 230-237 NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 240-247 NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 250-257 NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 260-267 NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 270-277 NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 300-307 NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 310-317 NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 320-327 NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 330-337 NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 340-347 NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 350-357 NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 360-367 NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, // 370-377 }; // Fast routine that assumes full 4-char tokens with no '=' in them. // private void decode_token() { int num = ((token[0] << 18) | (token[1] << 12) | (token[2] << 6) | (token[3])); bytes[0] = (byte)(0xFF & (num >> 16)); bytes[1] = (byte)(0xFF & (num >> 8)); bytes[2] = (byte)(0xFF & num); out.write(bytes, 0, 3); } // Hairier routine that deals with the final token, which can have fewer // than four characters, and that might be padded with '='. // private void decode_final_token() { byte b0 = token[0]; byte b1 = token[1]; byte b2 = token[2]; byte b3 = token[3]; int eq_count = 0; if (b0 == EOF) { b0 = 0; eq_count++; } if (b1 == EOF) { b1 = 0; eq_count++; } if (b2 == EOF) { b2 = 0; eq_count++; } if (b3 == EOF) { b3 = 0; eq_count++; } if (eq_count > 2) { throw new IllegalArgumentException("The number of '=' signs at the end of a base64 value must not exceed 2"); } if (eq_count == 2 && (b1 & 0x0F) != 0) { throw new IllegalArgumentException("In base64, if the value ends with '==' then the last character must be one of [AQgw]"); } if (eq_count == 1 && (b2 & 0x03) != 0) { throw new IllegalArgumentException("In base64, if the value ends with '=' then the last character must be one of [AEIMQUYcgkosw048]"); } int num = ((b0 << 18) | (b1 << 12) | (b2 << 6) | (b3)); // eq_count will be 0, 1, or 2. // No "=" padding means 4 bytes mapped to 3, the normal case, // not handled in this routine. // "xxx=" means 3 bytes mapped to 2. // "xx==" means 2 bytes mapped to 1. // "x===" can't happen, because "x" would then be encoding // only 6 bits, not 8, the minimum possible. out.write((byte)(num >> 16)); // byte 1, count = 0 or 1 or 2 if (eq_count <= 1) { out.write((byte)((num >> 8) & 0xFF)); // byte 2, count = 0 or 1 if (eq_count == 0) { out.write((byte)(num & 0xFF)); // byte 3, count = 0 } } } /** * Decode the base 64 string into a byte array (which can subsequently be accessed using getByteArray() * @param str the base 64 string * @throws IllegalArgumentException if the base64 string is incorrectly formatted */ public final void translate(CharSequence str) throws IllegalArgumentException { if (token == null) // already saw eof marker? return; int length = str.length(); int lengthAtEOF; int found_eq = 0; for (int i = 0; i < length; i++) { char c = str.charAt(i); if (c > 127) { throw new IllegalArgumentException("non-ASCII character in Base64 value (at offset " + i + ')'); } byte t = map[c]; if (t == NUL) { throw new IllegalArgumentException("invalid character '" + c + "' in Base64 value (at offset " + i + ')'); } if (found_eq > 0 && t != EOF && t != SP) { throw new IllegalArgumentException("In Base64, an '=' character can appear only at the end"); } if (t == EOF) { if (found_eq > 0) { found_eq++; if (found_eq > 2) { throw new IllegalArgumentException("Base64 value can contain at most two '=' characters"); } token_length = (token_length + 1) % 4; } else { found_eq = 1; lengthAtEOF = token_length; eof(); token_length = (lengthAtEOF + 1) % 4; } } else if (t != SP) { token[token_length++] = t; if (token_length == 4) { if (found_eq == 0) { decode_token(); } token_length = 0; } } } if (token_length != 0) { throw new IllegalArgumentException("Base64 input must be a multiple of four characters"); } } private void eof() { if (token != null && token_length != 0) { while (token_length < 4) { token[token_length++] = EOF; } decode_final_token(); } token_length = 0; token = new byte[4]; bytes = new byte[3]; } public byte[] getByteArray() { eof(); return out.toByteArray(); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file, with the exception of the two inner classes which // were originated by Mozilla/Netscape and reached Saxon via Castor. // // The Initial Developer of the Original Code is Michael H. Kay, Saxonica. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/value/AtomicValue.java0000644000175000017500000005113511033112257021574 0ustar eugeneeugenepackage net.sf.saxon.value; import net.sf.saxon.trans.Err; import net.sf.saxon.sort.StringCollator; import net.sf.saxon.expr.StaticContext; import net.sf.saxon.expr.StaticProperty; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.*; import net.sf.saxon.trans.XPathException; import net.sf.saxon.trans.NoDynamicContextException; import net.sf.saxon.type.*; /** * The AtomicValue class corresponds to the concept of an atomic value in the * XPath 2.0 data model. Atomic values belong to one of the 19 primitive types * defined in XML Schema; or they are of type xs:untypedAtomic; or they are * "external objects", representing a Saxon extension to the XPath 2.0 type system. *

    * The AtomicValue class contains some methods that are suitable for applications * to use, and many others that are designed for internal use by Saxon itself. * These have not been fully classified. At present, therefore, none of the methods on this * class should be considered to be part of the public Saxon API. *

    * * @author Michael H. Kay */ public abstract class AtomicValue extends Value implements Item, GroundedValue, ConversionResult { protected AtomicType typeLabel; /** * Set the type label on this atomic value. Note that this modifies the value, so it must only called * if the caller is confident that the value is not shared. In other cases, * use {@link #copyAsSubType(net.sf.saxon.type.AtomicType)} * * @param type the type label to be set */ public void setTypeLabel(AtomicType type) { typeLabel = type; } /** * Get a Comparable value that implements the XML Schema ordering comparison semantics for this value. * An implementation must be provided for all atomic types. *

    *

    In the case of data types that are partially ordered, the returned Comparable extends the standard * semantics of the compareTo() method by returning the value {@link #INDETERMINATE_ORDERING} when there * is no defined order relationship between two given values. This value is also returned when two values * of different types are compared.

    * * @return a Comparable that follows XML Schema comparison rules */ public abstract Comparable getSchemaComparable(); /** * Get an object value that implements the XPath equality and ordering comparison semantics for this value. * If the ordered parameter is set to true, the result will be a Comparable and will support a compareTo() * method with the semantics of the XPath lt/gt operator, provided that the other operand is also obtained * using the getXPathComparable() method. In all cases the result will support equals() and hashCode() methods * that support the semantics of the XPath eq operator, again provided that the other operand is also obtained * using the getXPathComparable() method. A context argument is supplied for use in cases where the comparison * semantics are context-sensitive, for example where they depend on the implicit timezone or the default * collation. * @param ordered true if an ordered comparison is required. In this case the result is null if the * type is unordered; in other cases the returned value will be a Comparable. * @param collator the collation to be used when comparing strings * @param context the XPath dynamic evaluation context, used in cases where the comparison is context * sensitive * @return an Object whose equals() and hashCode() methods implement the XPath comparison semantics * with respect to this atomic value. If ordered is specified, the result will either be null if * no ordering is defined, or will be a Comparable * @throws NoDynamicContextException if the comparison depends on dynamic context information that * is not available, for example implicit timezone */ public abstract Object getXPathComparable(boolean ordered, StringCollator collator, XPathContext context) throws NoDynamicContextException; /** * The equals() methods on atomic values is defined to follow the semantics of eq when applied * to two atomic values. When the other operand is not an atomic value, the result is undefined * (may be false, may be an exception). When the other operand is an atomic value that cannot be * compared with this one, the method must throw a ClassCastException. * *

    The hashCode() method is consistent with equals().

    * @param o the other value * @return true if the other operand is an atomic value and the two values are equal as defined * by the XPath eq operator */ public abstract boolean equals(Object o); /** * Get the value of the item as a CharSequence. This is in some cases more efficient than * the version of the method that returns a String. */ public CharSequence getStringValueCS() { return getStringValue(); } /** * Process the instruction, without returning any tail calls * * @param context The dynamic context, giving access to the current node, * the current variables, etc. */ public void process(XPathContext context) throws XPathException { context.getReceiver().append(this, 0, NodeInfo.ALL_NAMESPACES); } /** * Get the n'th item in the sequence (starting from 0). This is defined for all * Values, but its real benefits come for a sequence Value stored extensionally * (or for a MemoClosure, once all the values have been read) * * @param n position of the required item, counting from zero. * @return the n'th item in the sequence, where the first item in the sequence is * numbered zero. If n is negative or >= the length of the sequence, returns null. */ public final Item itemAt(int n) { return (n == 0 ? this : null); } /** * Determine the data type of the items in the expression, if possible * * @param th The TypeHierarchy. Can be null if the target is an AtomicValue, * except in the case where it is an external ObjectValue. * @return for the default implementation: AnyItemType (not known) */ public ItemType getItemType(TypeHierarchy th) { return typeLabel; } /** * Determine the data type of the value. This * delivers the same answer as {@link #getItemType}, except in the case of external objects * (instances of {@link ObjectValue}, where the method may deliver a less specific type. * * @return for the default implementation: AnyItemType (not known) */ public AtomicType getTypeLabel() { return typeLabel; } /** * Determine the primitive type of the value. This delivers the same answer as * getItemType().getPrimitiveItemType(). The primitive types are * the 19 primitive types of XML Schema, plus xs:integer, xs:dayTimeDuration and xs:yearMonthDuration, * and xs:untypedAtomic. For external objects, the result is xs:anyAtomicType. * * @return the primitive type */ public abstract BuiltInAtomicType getPrimitiveType(); /** * Determine the static cardinality * * @return code identifying the cardinality * @see net.sf.saxon.value.Cardinality */ public final int getCardinality() { return StaticProperty.EXACTLY_ONE; } /** * Convert the value to a given type. The result of the conversion will be an * atomic value of the required type. This method works only where the target * type is a built-in type. * * @param schemaType the required atomic type * @param context the XPath dynamic context * @return the result of the conversion, if conversion was possible. This * will always be an instance of the class corresponding to the type * of value requested * @throws XPathException if conversion is not allowed for this * required type, or if the particular value cannot be converted */ public final AtomicValue convert(AtomicType schemaType, XPathContext context) throws XPathException { // Note this method is used from XQuery compiled code return convert(schemaType, true, context).asAtomic(); } /** * Convert a value to either (a) another primitive type, or (b) another built-in type derived * from the current primitive type, with control over how validation is * handled. * * @param requiredType the required atomic type. This must either be a primitive type, or a built-in * type derived from the same primitive type as this atomic value. * @param validate true if validation is required. If set to false, the caller guarantees that * the value is valid for the target data type, and that further validation * is therefore not required. * Note that a validation failure may be reported even if validation was not requested. * @param context The conversion context to be used. This is required at present only when converting to * xs:Name or similar types: it determines the NameChecker to be used. * @return the result of the conversion, if successful. If unsuccessful, the value returned * will be a ValidationFailure. The caller must check for this condition. No exception is thrown, instead * the exception information will be encapsulated within the ValidationFailure. */ protected abstract ConversionResult convertPrimitive( BuiltInAtomicType requiredType, boolean validate, XPathContext context); /** * Convert the value to a given type. The result of the conversion will be * an atomic value of the required type. This method works where the target * type is a built-in atomic type and also where it is a user-defined atomic * type. * * @param targetType the type to which the value is to be converted * @param validate true if validation is required, false if the caller already knows that the * value is valid * @param context provides access to conversion context * @return the value after conversion if successful; or a {@link ValidationFailure} if conversion failed. The * caller must check for this condition. Validation may fail even if validation was not requested. */ public final ConversionResult convert(AtomicType targetType, boolean validate, XPathContext context) { if (targetType.isPrimitiveType()) { return convertPrimitive((BuiltInAtomicType)targetType, validate, context); } else if (targetType.isAbstract()) { return new ValidationFailure("Cannot convert to an abstract type"); } else if (targetType.isExternalType()) { return new ValidationFailure("Cannot convert to an external type"); } else { BuiltInAtomicType primitiveType = (BuiltInAtomicType)targetType.getPrimitiveItemType(); ConversionResult cr = convertPrimitive(primitiveType, validate, context); if (cr instanceof ValidationFailure) { return cr; } CharSequence lexicalValue; if (primitiveType.getFingerprint() == StandardNames.XS_STRING) { int whitespaceAction = targetType.getWhitespaceAction( context == null ? null : context.getConfiguration().getTypeHierarchy()); CharSequence cs = Whitespace.applyWhitespaceNormalization( whitespaceAction, ((StringValue)cr).getStringValueCS()); cr = new StringValue(cs); lexicalValue = cs; } else { lexicalValue = getCanonicalLexicalRepresentation(); } ValidationFailure vf = targetType.validate((AtomicValue)cr, lexicalValue, (context == null ? Name10Checker.getInstance() : context.getConfiguration().getNameChecker())); if (vf != null) { return vf; } return ((AtomicValue)cr).copyAsSubType(targetType); } } /** * Create a copy of this atomic value, with a different type label * * @param typeLabel the type label of the new copy. The caller is responsible for checking that * the value actually conforms to this type. * @return the copied value */ public abstract AtomicValue copyAsSubType(AtomicType typeLabel); /** * Test whether the value is the double/float value NaN * @return true if the value is float NaN or double NaN; otherwise false */ public boolean isNaN() { return false; } /** * Get the length of the sequence * * @return always 1 for an atomic value */ public final int getLength() { return 1; } /** * Iterate over the (single) item in the sequence * * @return a SequenceIterator that iterates over the single item in this * value */ public final SequenceIterator iterate() { return SingletonIterator.makeIterator(this); } /** * Convert the value to a string, using the serialization rules. * For atomic values this is the same as a cast; for sequence values * it gives a space-separated list. This method is refined for AtomicValues * so that it never throws an Exception. */ public abstract String getStringValue(); /** * Get the typed value of this item * * @return the typed value of the expression (which is this value) */ public final SequenceIterator getTypedValue() { return SingletonIterator.makeIterator(this); } /** * Get the effective boolean value of the value * * @return true, unless the value is boolean false, numeric zero, or * zero-length string */ public boolean effectiveBooleanValue() throws XPathException { XPathException err = new XPathException("Effective boolean value is not defined for an atomic value of type " + Type.displayTypeName(this)); err.setIsTypeError(true); err.setErrorCode("FORG0006"); throw err; // unless otherwise specified in a subclass } /** * Method to extract components of a value. Implemented by some subclasses, * but defined at this level for convenience * * @param component identifies the required component, as a constant defined in class * {@link net.sf.saxon.functions.Component}, for example {@link net.sf.saxon.functions.Component#HOURS} * @return the value of the requested component of this value */ public AtomicValue getComponent(int component) throws XPathException { throw new UnsupportedOperationException("Data type does not support component extraction"); } /** * Check statically that the results of the expression are capable of constructing the content * of a given schema type. * * @param parentType The schema type * @param env the static context * @param whole true if this atomic value accounts for the entire content of the containing node * @throws net.sf.saxon.trans.XPathException * if the expression doesn't match the required content type */ public void checkPermittedContents(SchemaType parentType, StaticContext env, boolean whole) throws XPathException { if (whole) { SimpleType stype = null; if (parentType instanceof SimpleType) { stype = (SimpleType)parentType; } else if (parentType instanceof ComplexType && ((ComplexType)parentType).isSimpleContent()) { stype = ((ComplexType)parentType).getSimpleContentType(); } if (stype != null && !stype.isNamespaceSensitive()) { // Can't validate namespace-sensitive content statically ValidationFailure err = stype.validateContent( getStringValueCS(), null, env.getConfiguration().getNameChecker()); if (err != null) { throw err.makeException(); } return; } } if (parentType instanceof ComplexType && !((ComplexType)parentType).isSimpleContent() && !((ComplexType)parentType).isMixedContent() && !Whitespace.isWhite(getStringValueCS())) { XPathException err = new XPathException("Complex type " + parentType.getDescription() + " does not allow text content " + Err.wrap(getStringValueCS())); err.setIsTypeError(true); throw err; } } /** * Calling this method on a ConversionResult returns the AtomicValue that results * from the conversion if the conversion was successful, and throws a ValidationException * explaining the conversion error otherwise. *

    *

    Use this method if you are calling a conversion method that returns a ConversionResult, * and if you want to throw an exception if the conversion fails.

    * * @return the atomic value that results from the conversion if the conversion was successful */ public AtomicValue asAtomic() { return this; } /** * Get a subsequence of the value * * @param start the index of the first item to be included in the result, counting from zero. * A negative value is taken as zero. If the value is beyond the end of the sequence, an empty * sequence is returned * @param length the number of items to be included in the result. Specify Integer.MAX_VALUE to * get the subsequence up to the end of the base sequence. If the value is negative, an empty sequence * is returned. If the value goes off the end of the sequence, the result returns items up to the end * of the sequence * @return the required subsequence. If min is */ public GroundedValue subsequence(int start, int length) { if (start <= 0 && start + length > 0) { return this; } else { return EmptySequence.getInstance(); } } /** * Get string value. In general toString() for an atomic value displays the value as it would be * written in XPath: that is, as a literal if available, or as a call on a constructor function * otherwise. */ public String toString() { return typeLabel.toString() + " (\"" + getStringValueCS() + "\")"; } /** * Convert to Java object (for passing to external functions) * * @param target the required target class * @param context the XPath dynamic evaluation context * @return the (boxed) Java object that best represents the XPath value */ // public final Object convertToJava(Class target, XPathContext context) throws XPathException { // return convertAtomicToJava(target, context); // } /** * Convert an atomic value to a Java object. Abstract method implemented by all subclasses * @param target the required target class * @param context the XPath dynamic evaluation context * @return the (boxed) Java object that best represents the XPath value */ //public abstract Object convertAtomicToJava(Class target, XPathContext context) throws XPathException; // TODO: delete this method and its implementations } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/value/Whitespace.java0000644000175000017500000002571611033112257021465 0ustar eugeneeugenepackage net.sf.saxon.value; import net.sf.saxon.om.FastStringBuffer; import net.sf.saxon.tinytree.CompressedWhitespace; /** * This class provides helper methods and constants for handling whitespace */ public class Whitespace { private Whitespace() {} /** * The values PRESERVE, REPLACE, and COLLAPSE represent the three options for whitespace * normalization. They are deliberately chosen in ascending strength order; given a number * of whitespace facets, only the strongest needs to be carried out. */ public static final int PRESERVE = 0; public static final int REPLACE = 1; public static final int COLLAPSE = 2; /** * The values NONE, IGNORABLE, and ALL identify which kinds of whitespace text node * should be stripped when building a source tree. UNSPECIFIED indicates that no * particular request has been made. XSLT indicates that whitespace should be stripped * as defined by the xsl:strip-space and xsl:preserve-space declarations in the stylesheet */ public static final int NONE = 0; public static final int IGNORABLE = 1; public static final int ALL = 2; public static final int UNSPECIFIED = 3; public static final int XSLT = 4; /** * Test whether a character is whitespace * @param ch the character (Unicode codepoint) to be tested * @return true if the character is one of tab, newline, carriage return, or space */ public static boolean isWhitespace(int ch) { switch (ch) { case 9: case 10: case 13: case 32: return true; default: return false; } } /** * Apply schema-defined whitespace normalization to a string * @param action the action to be applied: one of PRESERVE, REPLACE, or COLLAPSE * @param value the value to be normalized * @return the value after normalization */ public static CharSequence applyWhitespaceNormalization(int action, CharSequence value) { switch (action) { case PRESERVE: return value; case REPLACE: FastStringBuffer sb = new FastStringBuffer(value.length()); for (int i=0; i 32 || !C0WHITE[c]) { sb.append(c); } } return sb; } else { return value; } } /** * Remove leading whitespace characters from a string * @param value the string whose leading whitespace is to be removed * @return the string with leading whitespace removed. This may be the * original string if there was no leading whitespace */ public static CharSequence removeLeadingWhitespace(CharSequence value) { int start = -1; final int len = value.length(); for (int i=0; i 32 || !C0WHITE[c]) { start = i; break; } } if (start == 0) { return value; } else if (start < 0 || start == len - 1) { return ""; } else { return value.subSequence(start, len); } } /** * Determine if a string contains any whitespace * @param value the string to be tested * @return true if the string contains a character that is XML whitespace, that is * tab, newline, carriage return, or space */ public static boolean containsWhitespace(CharSequence value) { final int len = value.length(); for (int i=0; i 32 || !C0WHITE[c]) { return false; } } return true; } private static boolean[] C0WHITE = { false, false, false, false, false, false, false, false, // 0-7 false, true, true, false, false, true, false, false, // 8-15 false, false, false, false, false, false, false, false, // 16-23 false, false, false, false, false, false, false, false, // 24-31 true // 32 }; /** * Normalize whitespace as defined in XML Schema. Note that this is not the same * as the XPath normalize-space() function, which is supported by the * {@link #collapseWhitespace} method * @param in the string to be normalized * @return a copy of the string in which any whitespace character is replaced by * a single space character */ public static CharSequence normalizeWhitespace(CharSequence in) { FastStringBuffer sb = new FastStringBuffer(in.length()); for (int i=0; i0 && sb.charAt(nlen-1)==' ') { sb.setLength(nlen-1); } return sb; } /** * Remove leading and trailing whitespace. This has the same effect as collapseWhitespace, * but is cheaper, for use by data types that do not allow internal whitespace. * @param in the input string whose whitespace is to be removed * @return the result of removing excess whitespace */ public static CharSequence trimWhitespace(CharSequence in) { if (in.length()==0) { return in; } int first = 0; int last = in.length()-1; while (true) { final char x = in.charAt(first); if (x > 32 || !C0WHITE[x]) { break; } if (first++ >= last) { return ""; } } while (true) { final char x = in.charAt(last); if (x > 32 || !C0WHITE[x]) { break; } last--; } if (first == 0 && last == in.length()-1) { return in; } else { return in.subSequence(first, last+1); } } /** * Trim leading and trailing whitespace from a string, returning a string. * This differs from the Java trim() method in that the only characters treated as * whitespace are space, \n, \r, and \t. The String#trim() method removes all C0 * control characters (which is not the same thing under XML 1.1). * @param s the string to be trimmed. If null is supplied, null is returned. * @return the string with leading and trailing whitespace removed. */ public static String trim(CharSequence s) { if (s == null) { return null; } return trimWhitespace(s).toString(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/value/SequenceExtent.java0000644000175000017500000002756711033112257022337 0ustar eugeneeugenepackage net.sf.saxon.value; import net.sf.saxon.expr.ExpressionTool; import net.sf.saxon.expr.LastPositionFinder; import net.sf.saxon.expr.StaticProperty; import net.sf.saxon.om.*; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.AnyItemType; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.Type; import net.sf.saxon.type.TypeHierarchy; import java.util.ArrayList; import java.util.List; /** * A sequence value implemented extensionally. That is, this class represents a sequence * by allocating memory to each item in the sequence. */ public final class SequenceExtent extends Value implements GroundedValue { private Item[] value; private int start = 0; // zero-based offset of the start private int end; // the 0-based index of the first item that is NOT included // If start=0 this is the length of the sequence private ItemType itemType = null; // memoized // private static int instances = 0; /** * Construct an sequence from an array of items. Note, the array of items is used as is, * which means the caller must not subsequently change its contents. * * @param items the array of items to be included in the sequence */ public SequenceExtent(Item[] items) { value = items; end = items.length; } /** * Construct a SequenceExtent from part of an array of items * @param value The array * @param start zero-based offset of the first item in the array * that is to be included in the new SequenceExtent * @param length The number of items in the new SequenceExtent */ public SequenceExtent(Item[] value, int start, int length) { this.value = value; this.start = start; end = this.start + length; } /** * Construct a SequenceExtent as a view of another SequenceExtent * @param ext The existing SequenceExtent * @param start zero-based offset of the first item in the existing SequenceExtent * that is to be included in the new SequenceExtent * @param length The number of items in the new SequenceExtent */ public SequenceExtent(SequenceExtent ext, int start, int length) { value = ext.value; this.start = ext.start + start; end = this.start + length; } /** * Construct a SequenceExtent from a List. The members of the list must all * be Items * * @param list the list of items to be included in the sequence */ public SequenceExtent(List list) { Item[] array = new Item[list.size()]; value = (Item[])list.toArray(array); end = value.length; } /** * Construct a sequence containing all the items in a SequenceIterator. * * @exception net.sf.saxon.trans.XPathException if reading the items using the * SequenceIterator raises an error * @param iter The supplied sequence of items. This must be positioned at * the start, so that hasNext() returns true if there are any nodes in * the node-set, and next() returns the first node. */ public SequenceExtent(SequenceIterator iter) throws XPathException { if ((iter.getProperties() & SequenceIterator.LAST_POSITION_FINDER) == 0) { List list = new ArrayList(20); while (true) { Item it = iter.next(); if (it == null) { break; } list.add(it); } Item[] array = new Item[list.size()]; value = (Item[])list.toArray(array); end = value.length; } else { end = ((LastPositionFinder)iter).getLastPosition(); value = new Item[end]; int i = 0; while (true) { Item it = iter.next(); if (it == null) { break; } value[i++] = it; } } } /** * Factory method to make a Value holding the contents of any SequenceIterator * @param iter a Sequence iterator that will be consumed to deliver the items in the sequence * @return a ValueRepresentation holding the items delivered by the SequenceIterator. If the * sequence is empty the result will be an instance of {@link EmptySequence}. If it is of length * one, the result will be an {@link Item}. In all other cases, it will be an instance of * {@link SequenceExtent}. */ public static ValueRepresentation makeSequenceExtent(SequenceIterator iter) throws XPathException { if ((iter.getProperties() & SequenceIterator.GROUNDED) != 0) { return ((GroundedIterator)iter).materialize(); } Value extent = new SequenceExtent(iter); int len = extent.getLength(); if (len==0) { return EmptySequence.getInstance(); } else if (len==1) { return extent.itemAt(0); } else { return extent; } } /** * Simplify this SequenceExtent * @return a Value holding the items delivered by the SequenceIterator. If the * sequence is empty the result will be an instance of {@link EmptySequence}. If it is of length * one, the result will be an {@link AtomicValue} or a {@link SingletonNode}. * In all other cases, the {@link SequenceExtent} will be returned unchanged. */ public Value simplify() { int n = getLength(); if (n == 0) { return EmptySequence.getInstance(); } else if (n == 1) { return Value.asValue(itemAt(0)); } else { return this; } } /** * Reduce a value to its simplest form. If the value is a closure or some other form of deferred value * such as a FunctionCallPackage, then it is reduced to a SequenceExtent. If it is a SequenceExtent containing * a single item, then it is reduced to that item. One consequence that is exploited by class FilterExpression * is that if the value is a singleton numeric value, then the result will be an instance of NumericValue */ public Value reduce() { return simplify(); } /** * Get the number of items in the sequence * * @return the number of items in the sequence */ public int getLength() { return end - start; } /** * Determine the cardinality * * @return the cardinality of the sequence, using the constants defined in * net.sf.saxon.value.Cardinality * @see net.sf.saxon.value.Cardinality */ public int getCardinality() { switch (end - start) { case 0: return StaticProperty.EMPTY; case 1: return StaticProperty.EXACTLY_ONE; default: return StaticProperty.ALLOWS_ONE_OR_MORE; } } /** * Get the (lowest common) item type * * @return integer identifying an item type to which all the items in this * sequence conform * @param th the type hierarchy cache */ public ItemType getItemType(TypeHierarchy th) { if (itemType != null) { // only calculate it the first time return itemType; } if (end==start) { itemType = AnyItemType.getInstance(); } else { itemType = Type.getItemType(value[start], th); for (int i=start+1; i=getLength()) { return null; } else { return value[start+n]; } } /** * Swap two items (needed to support sorting) * * @param a the position of the first item to be swapped * @param b the position of the second item to be swapped */ public void swap(int a, int b) { Item temp = value[start+a]; value[start+a] = value[start+b]; value[start+b] = temp; } /** * Return an iterator over this sequence. * * @return the required SequenceIterator, positioned at the start of the * sequence */ public SequenceIterator iterate() { return new ArrayIterator(value, start, end); } /** * Return an enumeration of this sequence in reverse order (used for reverse axes) * * @return an AxisIterator that processes the items in reverse order */ public UnfailingIterator reverseIterate() { return new ReverseArrayIterator(value, start, end); } /** * Get the effective boolean value */ public boolean effectiveBooleanValue() throws XPathException { int len = getLength(); if (len == 0) { return false; } else if (value[start] instanceof NodeInfo) { return true; } else if (len > 1) { // this is a type error - reuse the error messages return ExpressionTool.effectiveBooleanValue(iterate()); } else { return ((AtomicValue)value[start]).effectiveBooleanValue(); } } /** * Get a subsequence of the value * * @param start the index of the first item to be included in the result, counting from zero. * A negative value is taken as zero. If the value is beyond the end of the sequence, an empty * sequence is returned * @param length the number of items to be included in the result. Specify Integer.MAX_VALUE to * get the subsequence up to the end of the base sequence. If the value is negative, an empty sequence * is returned. If the value goes off the end of the sequence, the result returns items up to the end * of the sequence * @return the required subsequence. If min is */ public GroundedValue subsequence(int start, int length) { int newStart; if (start < 0) { start = 0; } else if (start >= end) { return EmptySequence.getInstance(); } newStart = this.start + start; int newEnd; if (length == Integer.MAX_VALUE) { newEnd = end; } else if (length < 0) { return EmptySequence.getInstance(); } else { newEnd = newStart + length; if (newEnd > end) { newEnd = end; } } return new SequenceExtent(value, newStart, newEnd - newStart); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/value/GYearMonthValue.java0000644000175000017500000001267611077605201022410 0ustar eugeneeugenepackage net.sf.saxon.value; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.FastStringBuffer; import net.sf.saxon.om.StandardNames; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.*; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Implementation of the xs:gYearMonth data type */ public class GYearMonthValue extends GDateValue { private static Pattern regex = Pattern.compile("(-?[0-9]+-[0-9][0-9])(Z|[+-][0-9][0-9]:[0-9][0-9])?"); private GYearMonthValue(){} public static ConversionResult makeGYearMonthValue(CharSequence value) { Matcher m = regex.matcher(Whitespace.trimWhitespace(value)); if (!m.matches()) { return new ValidationFailure("Cannot convert '" + value + "' to a gYearMonth"); } GYearMonthValue g = new GYearMonthValue(); String base = m.group(1); String tz = m.group(2); String date = base + "-01" + (tz==null ? "" : tz); g.typeLabel = BuiltInAtomicType.G_YEAR_MONTH; return setLexicalValue(g, date); } public GYearMonthValue(int year, byte month, int tz) { this(year, month, tz, BuiltInAtomicType.G_YEAR_MONTH); } public GYearMonthValue(int year, byte month, int tz, AtomicType type) { this.year = year; this.month = month; day = 1; setTimezoneInMinutes(tz); typeLabel = type; } /** * Make a copy of this date, time, or dateTime value * @param typeLabel */ public AtomicValue copyAsSubType(AtomicType typeLabel) { GYearMonthValue v = new GYearMonthValue(year, month, getTimezoneInMinutes()); v.typeLabel = typeLabel; return v; } /** * Determine the primitive type of the value. This delivers the same answer as * getItemType().getPrimitiveItemType(). The primitive types are * the 19 primitive types of XML Schema, plus xs:integer, xs:dayTimeDuration and xs:yearMonthDuration, * and xs:untypedAtomic. For external objects, the result is AnyAtomicType. */ public BuiltInAtomicType getPrimitiveType() { return BuiltInAtomicType.G_YEAR_MONTH; } /** * Convert to target data type * @param requiredType an integer identifying the required atomic type * @param context * @return an AtomicValue, a value of the required type; or an ErrorValue */ public ConversionResult convertPrimitive(BuiltInAtomicType requiredType, boolean validate, XPathContext context) { switch(requiredType.getPrimitiveType()) { case StandardNames.XS_G_YEAR_MONTH: case StandardNames.XS_ANY_ATOMIC_TYPE: return this; case StandardNames.XS_STRING: return new StringValue(getStringValueCS()); case StandardNames.XS_UNTYPED_ATOMIC: return new UntypedAtomicValue(getStringValueCS()); default: ValidationFailure err = new ValidationFailure("Cannot convert gYearMonth to " + requiredType.getDisplayName()); err.setErrorCode("XPTY0004"); return err; } } public CharSequence getStringValueCS() { FastStringBuffer sb = new FastStringBuffer(16); int yr = year; if (year <= 0) { sb.append('-'); yr = -yr +1; // no year zero in lexical space } appendString(sb, yr, (yr>9999 ? (yr+"").length() : 4)); sb.append('-'); appendTwoDigits(sb, month); if (hasTimezone()) { appendTimezone(sb); } return sb; } /** * Add a duration to this date/time value * * @param duration the duration to be added (which might be negative) * @return a new date/time value representing the result of adding the duration. The original * object is not modified. * @throws net.sf.saxon.trans.XPathException * */ public CalendarValue add(DurationValue duration) throws XPathException { XPathException err = new XPathException("Cannot add a duration to an xs:gYearMonth"); err.setErrorCode("XPTY0004"); throw err; } /** * Return a new date, time, or dateTime with the same normalized value, but * in a different timezone * * @param tz the new timezone, in minutes * @return the date/time in the new timezone */ public CalendarValue adjustTimezone(int tz) { DateTimeValue dt = (DateTimeValue)toDateTime().adjustTimezone(tz); return new GYearMonthValue(dt.getYear(), dt.getMonth(), dt.getTimezoneInMinutes()); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Saxonica Limited // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none //saxonb-9.1.0.8/bj/net/sf/saxon/value/DoubleValue.java0000644000175000017500000004317611033112257021600 0ustar eugeneeugenepackage net.sf.saxon.value; import net.sf.saxon.trans.Err; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.FastStringBuffer; import net.sf.saxon.om.StandardNames; import net.sf.saxon.type.*; import java.math.BigDecimal; import java.math.BigInteger; /** * A numeric (double precision floating point) value */ public final class DoubleValue extends NumericValue { public static final DoubleValue ZERO = new DoubleValue(0.0); public static final DoubleValue NEGATIVE_ZERO = new DoubleValue(-0.0); public static final DoubleValue ONE = new DoubleValue(1.0); public static final DoubleValue NaN = new DoubleValue(Double.NaN); private double value; /** * Constructor supplying a string * @param val the string representation of the double value, conforming to the XML Schema lexical * representation of xs:double, with leading and trailing spaces permitted * @throws ValidationException if the string does not have the correct lexical form for a double. * Note that the error will contain no error code or context information. */ public DoubleValue(CharSequence val) throws ValidationException { try { value = Value.stringToNumber(val); } catch (NumberFormatException e) { throw new ValidationException("Cannot convert string " + Err.wrap(val, Err.VALUE) + " to a double"); } typeLabel = BuiltInAtomicType.DOUBLE; } /** * Constructor supplying a double * @param value the value of the NumericValue */ public DoubleValue(double value) { this.value = value; typeLabel = BuiltInAtomicType.DOUBLE; } /** * Constructor supplying a double and an AtomicType, for creating * a value that belongs to a user-defined subtype of xs:double. It is * the caller's responsibility to ensure that the supplied value conforms * to the supplied type. * @param value the value of the NumericValue * @param type the type of the value. This must be a subtype of xs:double, and the * value must conform to this type. The methosd does not check these conditions. */ public DoubleValue(double value, AtomicType type) { this.value = value; typeLabel = type; } /** * Create a copy of this atomic value, with a different type label * * @param typeLabel the type label of the new copy. The caller is responsible for checking that * the value actually conforms to this type. */ public AtomicValue copyAsSubType(AtomicType typeLabel) { DoubleValue v = new DoubleValue(value); v.typeLabel = typeLabel; return v; } /** * Determine the primitive type of the value. This delivers the same answer as * getItemType().getPrimitiveItemType(). The primitive types are * the 19 primitive types of XML Schema, plus xs:integer, xs:dayTimeDuration and xs:yearMonthDuration, * and xs:untypedAtomic. For external objects, the result is AnyAtomicType. */ public BuiltInAtomicType getPrimitiveType() { return BuiltInAtomicType.DOUBLE; } /** * Return this numeric value as a double * @return the value as a double */ public double getDoubleValue() { return value; } /** * Get the hashCode. This must conform to the rules for other NumericValue hashcodes * @see NumericValue#hashCode */ public int hashCode() { if (value > Integer.MIN_VALUE && value < Integer.MAX_VALUE) { return (int)value; } else { return new Double(value).hashCode(); } } /** * Test whether the value is the double/float value NaN */ public boolean isNaN() { return Double.isNaN(value); } /** * Get the effective boolean value * @return the effective boolean value (true unless the value is zero or NaN) */ public boolean effectiveBooleanValue() { return (value!=0.0 && !Double.isNaN(value)); } /** * Convert to target data type * @param requiredType an integer identifying the required atomic type * @param validate true if the supplied value must be validated, false if the caller warrants that it is * valid * @param context the XPath dynamic context * @return an AtomicValue, a value of the required type */ public ConversionResult convertPrimitive(BuiltInAtomicType requiredType, boolean validate, XPathContext context) { switch(requiredType.getFingerprint()) { case StandardNames.XS_BOOLEAN: return BooleanValue.get(effectiveBooleanValue()); case StandardNames.XS_DOUBLE: case StandardNames.XS_NUMERIC: case StandardNames.XS_ANY_ATOMIC_TYPE: return this; case StandardNames.XS_INTEGER: if (Double.isNaN(value)) { ValidationFailure err = new ValidationFailure("Cannot convert double NaN to an integer"); err.setErrorCode("FOCA0002"); return err; } if (Double.isInfinite(value)) { ValidationFailure err = new ValidationFailure("Cannot convert double INF to an integer"); err.setErrorCode("FOCA0002"); return err; } if (value > Long.MAX_VALUE || value < Long.MIN_VALUE) { return new BigIntegerValue(new BigDecimal(value).toBigInteger()); } return Int64Value.makeIntegerValue((long)value); case StandardNames.XS_UNSIGNED_LONG: case StandardNames.XS_UNSIGNED_INT: case StandardNames.XS_UNSIGNED_SHORT: case StandardNames.XS_UNSIGNED_BYTE: case StandardNames.XS_NON_POSITIVE_INTEGER: case StandardNames.XS_NEGATIVE_INTEGER: case StandardNames.XS_LONG: case StandardNames.XS_INT: case StandardNames.XS_SHORT: case StandardNames.XS_BYTE: case StandardNames.XS_NON_NEGATIVE_INTEGER: case StandardNames.XS_POSITIVE_INTEGER: ConversionResult iv = convertPrimitive(BuiltInAtomicType.INTEGER, validate, context); if (iv instanceof ValidationFailure) { return iv; } return ((IntegerValue)iv).convertPrimitive(requiredType, validate, context); case StandardNames.XS_DECIMAL: try { return new DecimalValue(value); } catch (ValidationException e) { return new ValidationFailure(e); } case StandardNames.XS_FLOAT: return new FloatValue((float)value); case StandardNames.XS_STRING: return new StringValue(getStringValueCS()); case StandardNames.XS_UNTYPED_ATOMIC: return new UntypedAtomicValue(getStringValueCS()); default: ValidationFailure err = new ValidationFailure("Cannot convert double to " + requiredType.getDisplayName()); err.setErrorCode("XPTY0004"); return err; } } static java.util.regex.Pattern nonExponentialPattern = java.util.regex.Pattern.compile( "(-?[0-9])([0-9]+?)(0*)\\.([0-9]*)"); /** * Convert the double to a string according to the XPath 2.0 rules * @return the string value */ public String getStringValue() { return doubleToString(value).toString(); //, Double.toString(value)).toString(); } /** * Convert the double to a string according to the XPath 2.0 rules * @return the string value */ public CharSequence getStringValueCS() { return doubleToString(value); //, Double.toString(value)); } /** * Get the canonical lexical representation as defined in XML Schema. This is not always the same * as the result of casting to a string according to the XPath rules. For xs:double, the canonical * representation always uses exponential notation. */ public CharSequence getCanonicalLexicalRepresentation() { FastStringBuffer fsb = new FastStringBuffer(20); return FloatingPointConverter.appendDoubleExponential(fsb, value); } /** * Internal method used for conversion of a double to a string * @param value the actual value * @return the value converted to a string, according to the XPath casting rules. */ public static CharSequence doubleToString(double value) { return FloatingPointConverter.appendDouble(new FastStringBuffer(20), value); } /** * Negate the value */ public NumericValue negate() { return new DoubleValue(-value); } /** * Implement the XPath floor() function */ public NumericValue floor() { return new DoubleValue(Math.floor(value)); } /** * Implement the XPath ceiling() function */ public NumericValue ceiling() { return new DoubleValue(Math.ceil(value)); } /** * Implement the XPath round() function */ public NumericValue round() { if (Double.isNaN(value)) { return this; } if (Double.isInfinite(value)) { return this; } if (value == 0.0) { return this; // handles the negative zero case } if (value >= -0.5 && value < 0.0) { return new DoubleValue(-0.0); } if (value > Long.MIN_VALUE && value < Long.MAX_VALUE) { return new DoubleValue(Math.round(value)); } // A double holds fewer significant digits than a long. Therefore, // if the double is outside the range of a long, it cannot have // any signficant digits after the decimal point. So in this // case, we return the original value unchanged return this; } /** * Implement the XPath round-to-half-even() function */ public NumericValue roundHalfToEven(int scale) { if (Double.isNaN(value)) return this; if (Double.isInfinite(value)) return this; if (value==0.0) return this; // handles the negative zero case // Convert to a scaled integer, by multiplying by 10^scale double factor = Math.pow(10, scale+1); double d = Math.abs(value * factor); if (Double.isInfinite(d)) { // double arithmetic has overflowed - do it in decimal BigDecimal dec = new BigDecimal(value); dec = dec.setScale(scale, BigDecimal.ROUND_HALF_EVEN); return new DoubleValue(dec.doubleValue()); } // Now apply any rounding needed, using the "round half to even" rule double rem = d % 10; if (rem > 5) { d += (10-rem); } else if (rem < 5){ d -= rem; } else { // round half to even - check the last bit if ((d % 20) == 15) { d +=5 ; } else { d -=5; } } // Now convert back to the original magnitude d /= factor; if (value < 0) { d = 0.0 -d; } return new DoubleValue(d); } /** * Determine whether the value is negative, zero, or positive * @return -1 if negative, 0 if zero (including negative zero), +1 if positive, NaN if NaN */ public double signum() { if (Double.isNaN(value)) { return value; } if (value > 0) return 1; if (value == 0) return 0; return -1; } /** * Determine whether the value is a whole number, that is, whether it compares * equal to some integer */ public boolean isWholeNumber() { return value == Math.floor(value) && !Double.isInfinite(value); } /** * Compare the value to a long. * @param other the value to be compared with * @return -1 if this is less, 0 if this is equal, +1 if this is greater or if this is NaN */ public int compareTo(long other) { double otherDouble = (double)other; if (value == otherDouble) return 0; if (value < otherDouble) return -1; return +1; } /** * Get an object that implements XML Schema comparison semantics */ public Comparable getSchemaComparable() { return new Double(value); } /** * Convert to Java object (for passing to external functions) */ // public Object convertAtomicToJava(Class target, XPathContext context) throws XPathException { // if (target==Object.class) { // return new Double(value); // } else if (target.isAssignableFrom(DoubleValue.class)) { // return this; // } else if (target==double.class || target==Double.class) { // return new Double(value); // } else if (target==float.class ||target==Float.class ) { // return new Float(value); // } else if (target==long.class || target==Long.class) { // return new Long((long)value); // } else if (target==int.class || target==Integer.class) { // return new Integer((int)value); // } else if (target==short.class || target==Short.class) { // return new Short((short)value); // } else if (target==byte.class || target==Byte.class) { // return new Byte((byte)value); // } else if (target==char.class || target==Character.class) { // return new Character((char)value); // } else { // Object o = convertSequenceToJava(target, context); // if (o == null) { // XPathException err = new XPathException("Conversion of double to " + target.getName() + // " is not supported"); // err.setXPathContext(context); // err.setErrorCode(SaxonErrorCode.SXJE0002); // } // return o; // } // } /** * Diagnostic method: print the sign, exponent, and significand * @param d the double to be diagnosed */ public static void printInternalForm(double d) { System.err.println("==== Double " + d + " ===="); long bits = Double.doubleToLongBits(d); System.err.println("Internal form: " + Long.toHexString(bits)); if (bits == 0x7ff0000000000000L) { System.err.println("+Infinity"); } else if (bits == 0xfff0000000000000L) { System.err.println("-Infinity"); } else if (bits == 0x7ff8000000000000L) { System.err.println("NaN"); } else { int s = ((bits >> 63) == 0) ? 1 : -1; int e = (int)((bits >> 52) & 0x7ffL); long m = (e == 0) ? (bits & 0xfffffffffffffL) << 1 : (bits & 0xfffffffffffffL) | 0x10000000000000L; int exponent = e-1075; System.err.println("Sign: " + s); System.err.println("Exponent: " + exponent); System.err.println("Significand: " + m); BigDecimal dec = BigDecimal.valueOf(m); if (exponent > 0) { dec = dec.multiply(new BigDecimal(BigInteger.valueOf(2).pow(exponent))); } else { // Next line is sometimes failing, e.g. on -3.62e-5. Not investigated. dec = dec.divide(new BigDecimal(BigInteger.valueOf(2).pow(-exponent)), BigDecimal.ROUND_HALF_EVEN); } System.err.println("Exact value: " + (s>0?"":"-") + dec); } } // public static void main(String[] args) { // System.err.println("-3.62E-5"); // printInternalForm(-3.62E-5); // } // System.err.println("(next below)"); // printInternalForm(Double.longBitsToDouble(Double.doubleToLongBits(1.1e0)-1)); // System.err.println("(next above)"); // printInternalForm(Double.longBitsToDouble(Double.doubleToLongBits(1.1e0)+1)); // System.err.println("== 2.2 =="); // printInternalForm(2.2e0); // System.err.println("(next below)"); // printInternalForm(Double.longBitsToDouble(Double.doubleToLongBits(2.2e0)-1)); // System.err.println("(next above)"); // printInternalForm(Double.longBitsToDouble(Double.doubleToLongBits(2.2e0)+1)); // // System.err.println("== 3.3 =="); // printInternalForm(3.3e0); // System.err.println("(next below)"); // printInternalForm(Double.longBitsToDouble(Double.doubleToLongBits(3.3e0)-1)); // System.err.println("(next above)"); // printInternalForm(Double.longBitsToDouble(Double.doubleToLongBits(3.3e0)+1)); // // // System.err.println("== 1.1 + 2.2 =="); // printInternalForm(1.1e0 + 2.2e0); // } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file except the asStringXT() and zeros() methods (not currently used). // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/value/YearMonthDurationValue.java0000644000175000017500000002561211033112257023775 0ustar eugeneeugenepackage net.sf.saxon.value; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.FastStringBuffer; import net.sf.saxon.sort.StringCollator; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.AtomicType; import net.sf.saxon.type.BuiltInAtomicType; import net.sf.saxon.type.ConversionResult; import java.math.BigDecimal; import java.util.StringTokenizer; /** * A value of type xs:yearMonthDuration */ public final class YearMonthDurationValue extends DurationValue implements Comparable { /** * Private constructor for internal use */ private YearMonthDurationValue() { typeLabel = BuiltInAtomicType.YEAR_MONTH_DURATION; } /** * Static factory: create a duration value from a supplied string, in * ISO 8601 format [+|-]PnYnM * * @param s a string in the lexical space of xs:yearMonthDuration. * @return either a YearMonthDurationValue, or a ValidationFailure if the string was * not in the lexical space of xs:yearMonthDuration. */ public static ConversionResult makeYearMonthDurationValue(CharSequence s) { int years = 0, months = 0; boolean negative = false; int components = 0; StringTokenizer tok = new StringTokenizer(Whitespace.trimWhitespace(s).toString(), "-+PYM", true); if (!tok.hasMoreElements()) { return badDuration("empty string", s); } String part = (String)tok.nextElement(); if ("+".equals(part)) { return badDuration("+ sign not allowed in a duration", s); } else if ("-".equals(part)) { negative = true; part = (String)tok.nextElement(); } if (!"P".equals(part)) { return badDuration("missing 'P'", s); } int state = 0; while (tok.hasMoreElements()) { part = (String)tok.nextElement(); int value = simpleInteger(part); if (value < 0) { return badDuration("non-numeric component", s); } if (!tok.hasMoreElements()) { return badDuration("missing unit letter at end", s); } char delim = ((String)tok.nextElement()).charAt(0); switch (delim) { case'Y': if (state > 0) { return badDuration("Y is out of sequence", s); } years = value; components++; state = 1; break; case'M': if (state == 0 || state == 1) { months = value; components++; state = 2; break; } else { return badDuration("M is out of sequence", s); } default: return badDuration("misplaced " + delim, s); } } if (components == 0) { return badDuration("duration specifies no components", s); } if ((long)years + ((long)months) * 12 > Integer.MAX_VALUE) { return badDuration("duration exceeds limits", s); } return YearMonthDurationValue.fromMonths((years*12 + months) * (negative ? -1 : +1)); } /** * Create a copy of this atomic value, with a different type label * * @param typeLabel the type label of the new copy. The caller is responsible for checking that * the value actually conforms to this type. */ public AtomicValue copyAsSubType(AtomicType typeLabel) { YearMonthDurationValue v = YearMonthDurationValue.fromMonths(getLengthInMonths()); v.typeLabel = typeLabel; return v; } /** * Determine the primitive type of the value. This delivers the same answer as * getItemType().getPrimitiveItemType(). The primitive types are * the 19 primitive types of XML Schema, plus xs:integer, xs:dayTimeDuration and xs:yearMonthDuration, * and xs:untypedAtomic. For external objects, the result is AnyAtomicType. */ public BuiltInAtomicType getPrimitiveType() { return BuiltInAtomicType.YEAR_MONTH_DURATION; } /** * Convert to string * * @return ISO 8601 representation. */ public CharSequence getStringValueCS() { // The canonical representation has months in the range 0-11 int y = getYears(); int m = getMonths(); FastStringBuffer sb = new FastStringBuffer(32); if (negative) { sb.append('-'); } sb.append('P'); if (y != 0) { sb.append(y + "Y"); } if (m != 0 || y == 0) { sb.append(m + "M"); } return sb; } /** * Get the number of months in the duration * * @return the number of months in the duration */ public int getLengthInMonths() { return (months) * (negative ? -1 : +1); } /** * Construct a duration value as a number of months. * * @param months the number of months (may be negative) * @return the corresponding xs:yearMonthDuration value */ public static YearMonthDurationValue fromMonths(int months) { YearMonthDurationValue mdv = new YearMonthDurationValue(); mdv.negative = (months < 0); mdv.months = (months < 0 ? -months : months); mdv.seconds = 0; mdv.microseconds = 0; return mdv; } /** * Multiply duration by a number. Also used when dividing a duration by a number */ public DurationValue multiply(double n) throws XPathException { if (Double.isNaN(n)) { XPathException err = new XPathException("Cannot multiply/divide a duration by NaN"); err.setErrorCode("FOCA0005"); throw err; } double m = (double)getLengthInMonths(); double product = n * m; if (Double.isInfinite(product) || product > Integer.MAX_VALUE || product < Integer.MIN_VALUE) { XPathException err = new XPathException("Overflow when multiplying/dividing a duration by a number"); err.setErrorCode("FODT0002"); throw err; } return fromMonths((int)Math.round(product)); } /** * Find the ratio between two durations * * @param other the dividend * @return the ratio, as a decimal * @throws XPathException */ public DecimalValue divide(DurationValue other) throws XPathException { if (other instanceof YearMonthDurationValue) { BigDecimal v1 = BigDecimal.valueOf(getLengthInMonths()); BigDecimal v2 = BigDecimal.valueOf(((YearMonthDurationValue)other).getLengthInMonths()); if (v2.signum() == 0) { XPathException err = new XPathException("Divide by zero (durations)"); err.setErrorCode("FOAR0001"); throw err; } return new DecimalValue(v1.divide(v2, 20, BigDecimal.ROUND_HALF_EVEN)); } else { XPathException err = new XPathException("Cannot divide two durations of different type"); err.setErrorCode("XPTY0004"); throw err; } } /** * Add two year-month-durations */ public DurationValue add(DurationValue other) throws XPathException { if (other instanceof YearMonthDurationValue) { return fromMonths(getLengthInMonths() + ((YearMonthDurationValue)other).getLengthInMonths()); } else { XPathException err = new XPathException("Cannot add two durations of different type"); err.setErrorCode("XPTY0004"); throw err; } } /** * Subtract two year-month-durations */ public DurationValue subtract(DurationValue other) throws XPathException { if (other instanceof YearMonthDurationValue) { return fromMonths(getLengthInMonths() - ((YearMonthDurationValue)other).getLengthInMonths()); } else { XPathException err = new XPathException("Cannot subtract two durations of different type"); err.setErrorCode("XPTY0004"); throw err; } } /** * Negate a duration (same as subtracting from zero, but it preserves the type of the original duration) */ public DurationValue negate() { return fromMonths(-getLengthInMonths()); } /** * Compare the value to another duration value * * @param other The other dateTime value * @return negative value if this one is the earler, 0 if they are chronologically equal, * positive value if this one is the later. For this purpose, dateTime values with an unknown * timezone are considered to be UTC values (the Comparable interface requires * a total ordering). * @throws ClassCastException if the other value is not a DateTimeValue (the parameter * is declared as Object to satisfy the Comparable interface) */ public int compareTo(Object other) { if (other instanceof YearMonthDurationValue) { return getLengthInMonths() - ((YearMonthDurationValue)other).getLengthInMonths(); } else { throw new ClassCastException("Cannot compare a yearMonthDuration to an object of class " + other.getClass()); } } /** * Get a Comparable value that implements the XPath ordering comparison semantics for this value. * Returns null if the value is not comparable according to XPath rules. The default implementation * returns the value itself. This is modified for types such as * xs:duration which allow ordering comparisons in XML Schema, but not in XPath. * @param ordered * @param collator * @param context */ public Object getXPathComparable(boolean ordered, StringCollator collator, XPathContext context) { return this; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/value/Cardinality.java0000644000175000017500000001673611033112257021636 0ustar eugeneeugenepackage net.sf.saxon.value; import net.sf.saxon.expr.*; /** * This class contains static methods to manipulate the cardinality * property of a type. * Cardinality of expressions is denoted by one of the values ONE_OR_MORE, ZERO_OR_MORE, * ZERO_OR_ONE, EXACTLY_ONE, or EMPTY. These are combinations of the three bit-significant * values ALLOWS_ZERO, ALLOWS_ONE, and ALLOWS_MANY. */ public final class Cardinality { /** * Private constructor: no instances allowed */ private Cardinality() {} /** * Determine whether multiple occurrences are allowed * @param cardinality the cardinality of a sequence * @return true if the cardinality allows the sequence to contain more than one item */ public static boolean allowsMany(int cardinality) { return (cardinality & StaticProperty.ALLOWS_MANY) != 0; } /** * Determine whether multiple occurrences are not only allowed, but likely. * This returns false for an expression that is the atomization of a singleton * node, since in that case it's quite unusual for the typed value to be a * non-singleton sequence. * @param expression an expression * @return true if multiple occurrences are not only allowed, but likely. Return * false if multiple occurrences are unlikely, even though they might be allowed. * This is typically the case for the atomized sequence that is obtained by atomizing * a singleton node. */ public static boolean expectsMany(Expression expression) { if (expression instanceof VariableReference) { Binding b = ((VariableReference)expression).getBinding(); if (b instanceof LetExpression) { return expectsMany(((LetExpression)b).getSequence()); } } if (expression instanceof LazyExpression) { return expectsMany(((LazyExpression)expression).getBaseExpression()); } if (expression instanceof Atomizer) { return expectsMany(((Atomizer)expression).getBaseExpression()); } if (expression instanceof FilterExpression) { return expectsMany(((FilterExpression)expression).getBaseExpression()); } return allowsMany(expression.getCardinality()); } /** * Determine whether empty sequence is allowed * @param cardinality the cardinality of a sequence * @return true if the cardinality allows the sequence to be empty */ public static boolean allowsZero(int cardinality) { return (cardinality & StaticProperty.ALLOWS_ZERO) != 0; } /** * Form the union of two cardinalities. The cardinality of the expression "if (c) then e1 else e2" * is the union of the cardinalities of e1 and e2. * @param c1 a cardinality * @param c2 another cardinality * @return the cardinality that allows both c1 and c2 */ public static int union(int c1, int c2) { int r = c1 | c2; // eliminate disallowed options if (r == (StaticProperty.ALLOWS_MANY | StaticProperty.ALLOWS_ZERO )) r = StaticProperty.ALLOWS_ZERO_OR_MORE; return r; } /** * Add two cardinalities * @param c1 the first cardinality * @param c2 the second cardinality * @return the cardinality of a sequence formed by concatenating the sequences whose cardinalities * are c1 and c2 */ public static int sum(int c1, int c2) { if (c1==StaticProperty.EMPTY) { return c2; } if (c2==StaticProperty.EMPTY) { return c1; } boolean allowsZero = Cardinality.allowsZero(c1) && Cardinality.allowsZero(c2); return StaticProperty.ALLOWS_ONE_OR_MORE | (allowsZero ? StaticProperty.ALLOWS_ZERO : 0); } /** * Test if one cardinality subsumes another. Cardinality c1 subsumes c2 if every option permitted * by c2 is also permitted by c1. * @param c1 a cardinality * @param c2 another cardinality * @return true if if every option permitted * by c2 is also permitted by c1. */ public static boolean subsumes(int c1, int c2) { return (c1|c2)==c1; } /** * Multiply two cardinalities * @param c1 the first cardinality * @param c2 the second cardinality * @return the product of the cardinalities, that is, the cardinality of the sequence * "for $x in S1 return S2", where c1 is the cardinality of S1 and c2 is the cardinality of S2 */ public static int multiply(int c1, int c2) { if (c1==StaticProperty.EMPTY || c2==StaticProperty.EMPTY) { return StaticProperty.EMPTY; } if (c2==StaticProperty.EXACTLY_ONE) { return c1; } if (c1==StaticProperty.EXACTLY_ONE) { return c2; } if (c1==StaticProperty.ALLOWS_ZERO_OR_ONE && c2==StaticProperty.ALLOWS_ZERO_OR_ONE) { return StaticProperty.ALLOWS_ZERO_OR_ONE; } if (c1==StaticProperty.ALLOWS_ONE_OR_MORE && c2==StaticProperty.ALLOWS_ONE_OR_MORE) { return StaticProperty.ALLOWS_ONE_OR_MORE; } return StaticProperty.ALLOWS_ZERO_OR_MORE; } /** * Display the cardinality as a string * @param cardinality the cardinality value to be displayed * @return the representation as a string, for example "zero or one", "zero or more" * */ public static String toString(int cardinality) { switch (cardinality) { case StaticProperty.ALLOWS_ZERO_OR_ONE: return "zero or one"; case StaticProperty.EXACTLY_ONE: return "exactly one"; case StaticProperty.ALLOWS_ZERO_OR_MORE: return "zero or more"; case StaticProperty.ALLOWS_ONE_OR_MORE: return "one or more"; case StaticProperty.EMPTY: return "exactly zero"; case StaticProperty.ALLOWS_MANY: return "more than one"; default: return "code " + cardinality; } } /** * Get the occurence indicator representing the cardinality * @param cardinality the cardinality value * @return the occurrence indicator, for example "*", "+", "?", "". */ public static String getOccurrenceIndicator(int cardinality) { switch (cardinality) { case StaticProperty.ALLOWS_ZERO_OR_ONE: return "?"; case StaticProperty.EXACTLY_ONE: return ""; case StaticProperty.ALLOWS_ZERO_OR_MORE: return "*"; case StaticProperty.ALLOWS_ONE_OR_MORE: return "+"; case StaticProperty.EMPTY: return "\u00B0"; default: throw new AssertionError("unknown cardinality value"); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/value/GMonthDayValue.java0000644000175000017500000001242611033112257022212 0ustar eugeneeugenepackage net.sf.saxon.value; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.FastStringBuffer; import net.sf.saxon.om.StandardNames; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.*; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Implementation of the xs:gYear data type */ public class GMonthDayValue extends GDateValue { private static Pattern regex = Pattern.compile("--([0-9][0-9]-[0-9][0-9])(Z|[+-][0-9][0-9]:[0-9][0-9])?"); private GMonthDayValue(){} public static ConversionResult makeGMonthDayValue(CharSequence value) { Matcher m = regex.matcher(Whitespace.trimWhitespace(value)); if (!m.matches()) { return new ValidationFailure("Cannot convert '" + value + "' to a gMonthDay"); } GMonthDayValue g = new GMonthDayValue(); String base = m.group(1); String tz = m.group(2); String date = "2000-" + base + (tz==null ? "" : tz); g.typeLabel = BuiltInAtomicType.G_MONTH_DAY; return setLexicalValue(g, date); } public GMonthDayValue(byte month, byte day, int tz) { this(month, day, tz, BuiltInAtomicType.G_MONTH_DAY); } public GMonthDayValue(byte month, byte day, int tz, AtomicType type) { this.year = 2000; this.month = month; this.day = day; setTimezoneInMinutes(tz); this.typeLabel = type; } /** * Make a copy of this date, time, or dateTime value * @param typeLabel */ public AtomicValue copyAsSubType(AtomicType typeLabel) { GMonthDayValue v = new GMonthDayValue(month, day, getTimezoneInMinutes()); v.typeLabel = typeLabel; return v; } /** * Determine the primitive type of the value. This delivers the same answer as * getItemType().getPrimitiveItemType(). The primitive types are * the 19 primitive types of XML Schema, plus xs:integer, xs:dayTimeDuration and xs:yearMonthDuration, * and xs:untypedAtomic. For external objects, the result is AnyAtomicType. */ public BuiltInAtomicType getPrimitiveType() { return BuiltInAtomicType.G_MONTH_DAY; } /** * Convert to target data type * @param requiredType an integer identifying the required atomic type * @param context * @return an AtomicValue, a value of the required type; or an ErrorValue */ public ConversionResult convertPrimitive(BuiltInAtomicType requiredType, boolean validate, XPathContext context) { switch(requiredType.getPrimitiveType()) { case StandardNames.XS_G_MONTH_DAY: case StandardNames.XS_ANY_ATOMIC_TYPE: return this; case StandardNames.XS_STRING: return new StringValue(getStringValueCS()); case StandardNames.XS_UNTYPED_ATOMIC: return new UntypedAtomicValue(getStringValueCS()); default: ValidationFailure err = new ValidationFailure("Cannot convert gMonthDay to " + requiredType.getDisplayName()); err.setErrorCode("XPTY0004"); return err; } } public CharSequence getStringValueCS() { FastStringBuffer sb = new FastStringBuffer(16); sb.append("--"); appendTwoDigits(sb, month); sb.append('-'); appendTwoDigits(sb, day); if (hasTimezone()) { appendTimezone(sb); } return sb; } /** * Add a duration to this date/time value * * @param duration the duration to be added (which might be negative) * @return a new date/time value representing the result of adding the duration. The original * object is not modified. * @throws net.sf.saxon.trans.XPathException * */ public CalendarValue add(DurationValue duration) throws XPathException { XPathException err = new XPathException("Cannot add a duration to an xs:gMonthDay"); err.setErrorCode("XPTY0004"); throw err; } /** * Return a new date, time, or dateTime with the same normalized value, but * in a different timezone * * @param tz the new timezone, in minutes * @return the date/time in the new timezone */ public CalendarValue adjustTimezone(int tz) { DateTimeValue dt = (DateTimeValue)toDateTime().adjustTimezone(tz); return new GMonthDayValue(dt.getMonth(), dt.getDay(), dt.getTimezoneInMinutes()); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Saxonica Limited // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none //saxonb-9.1.0.8/bj/net/sf/saxon/value/MemoClosure.java0000644000175000017500000003660311044033432021617 0ustar eugeneeugenepackage net.sf.saxon.value; import net.sf.saxon.Controller; import net.sf.saxon.event.SequenceOutputter; import net.sf.saxon.event.SequenceReceiver; import net.sf.saxon.event.TeeOutputter; import net.sf.saxon.expr.LastPositionFinder; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.*; import net.sf.saxon.trans.XPathException; import java.util.List; /** * A MemoClosure represents a value that has not yet been evaluated: the value is represented * by an expression, together with saved values of all the context variables that the * expression depends on. *

    *

    The MemoClosure is designed for use when the value is only read several times. The * value is saved on the first evaluation and remembered for later use.

    *

    *

    The MemoClosure maintains a reservoir containing those items in the value that have * already been read. When a new iterator is requested to read the value, this iterator * first examines and returns any items already placed in the reservoir by previous * users of the MemoClosure. When the reservoir is exhausted, it then uses an underlying * Input Iterator to read further values of the underlying expression. If the value is * not read to completion (for example, if the first user did exists($expr), then the * Input Iterator is left positioned where this user abandoned it. The next user will read * any values left in the reservoir by the first user, and then pick up iterating the * base expression where the first user left off. Eventually, all the values of the * expression will find their way into the reservoir, and future users simply iterate * over the reservoir contents. Alternatively, of course, the values may be left unread.

    *

    *

    Delayed evaluation is used only for expressions with a static type that allows * more than one item, so the evaluateItem() method will not normally be used, but it is * supported for completeness.

    *

    *

    The expression may depend on local variables and on the context item; these values * are held in the saved XPathContext object that is kept as part of the Closure, and they * will always be read from that object. The expression may also depend on global variables; * these are unchanging, so they can be read from the Bindery in the normal way. Expressions * that depend on other contextual information, for example the values of position(), last(), * current(), current-group(), should not be evaluated using this mechanism: they should * always be evaluated eagerly. This means that the Closure does not need to keep a copy * of these context variables.

    */ public class MemoClosure extends Closure { private Item[] reservoir = null; private int used; protected int state; // State in which no items have yet been read private static final int UNREAD = 0; // State in which zero or more items are in the reservoir and it is not known // whether more items exist private static final int MAYBE_MORE = 1; // State in which all the items are in the reservoir private static final int ALL_READ = 3; // State in which we are getting the base iterator. If the closure is called in this state, // it indicates a recursive entry, which is only possible on an error path private static final int BUSY = 4; // State in which we know that the value is an empty sequence protected static final int EMPTY = 5; /** * Constructor should not be called directly, instances should be made using the make() method. */ public MemoClosure() { //System.err.println("Creating MemoClosure"); } /** * Evaluate the expression in a given context to return an iterator over a sequence * */ public SequenceIterator iterate() throws XPathException { switch (state) { case UNREAD: state = BUSY; inputIterator = expression.iterate(savedXPathContext); if (inputIterator instanceof EmptyIterator) { state = EMPTY; return inputIterator; } // TODO: following optimization looks OK, but it throws func20 into an infinite loop // if (inputIterator instanceof GroundedIterator) { // state = UNREAD; // return inputIterator.getAnother(); // } reservoir = new Item[50]; used = 0; state = MAYBE_MORE; return new ProgressiveIterator(); case MAYBE_MORE: return new ProgressiveIterator(); case ALL_READ: switch (used) { case 0: state = EMPTY; return EmptyIterator.getInstance(); case 1: return SingletonIterator.makeIterator(reservoir[0]); default: return new ArrayIterator(reservoir, 0, used); } case BUSY: // recursive entry: can happen if there is a circularity involving variable and function definitions // Can also happen if variable evaluation is attempted in a debugger, hence the cautious message XPathException de = new XPathException("Attempt to access a variable while it is being evaluated"); de.setErrorCode("XTDE0640"); //de.setXPathContext(context); throw de; case EMPTY: return EmptyIterator.getInstance(); default: throw new IllegalStateException("Unknown iterator state"); } } /** * Process the expression by writing the value to the current Receiver * * @param context The dynamic context, giving access to the current node, * the current variables, etc. */ public void process(XPathContext context) throws XPathException { // To evaluate the closure in push mode, we need to use the original context of the // expression for everything except the current output destination, which is taken from the // context supplied at evaluation time if (state == EMPTY) { return; // we know there is nothing to do } else if (state == BUSY) { // recursive entry: can happen if there is a circularity involving variable and function definitions XPathException de = new XPathException("Attempt to access a variable while it is being evaluated"); de.setErrorCode("XTDE0640"); de.setXPathContext(context); throw de; } if (reservoir != null) { SequenceIterator iter = iterate(); SequenceReceiver out = context.getReceiver(); while (true) { Item it = iter.next(); if (it==null) break; out.append(it, 0, NodeInfo.ALL_NAMESPACES); } } else { state = BUSY; Controller controller = context.getController(); XPathContext c2 = savedXPathContext.newMinorContext(); //c2.setOrigin(this); // Fork the output: one copy goes to a SequenceOutputter which remembers the contents for // use next time the variable is referenced; another copy goes to the current output destination. SequenceOutputter seq = controller.allocateSequenceOutputter(20); seq.setPipelineConfiguration(controller.makePipelineConfiguration()); seq.open(); TeeOutputter tee = new TeeOutputter(context.getReceiver(), seq); tee.setPipelineConfiguration(controller.makePipelineConfiguration()); c2.setTemporaryReceiver(tee); expression.process(c2); seq.close(); List list = seq.getList(); if (list.isEmpty()) { state = EMPTY; } else { reservoir = new Item[list.size()]; reservoir = (Item[])list.toArray(reservoir); used = list.size(); state = ALL_READ; } // give unwanted stuff to the garbage collector savedXPathContext = null; seq.reset(); } } /** * Get the n'th item in the sequence (starting from 0). This is defined for all * SequenceValues, but its real benefits come for a SequenceValue stored extensionally */ public Item itemAt(int n) throws XPathException { if (n < 0) { return null; } if (reservoir != null && n < used) { return reservoir[n]; } if (state == ALL_READ || state == EMPTY) { return null; } if (state == UNREAD) { return super.itemAt(n); // this will read from the start of the sequence } // We have read some items from the input sequence but not enough. Read as many more as are needed. int diff = n - used + 1; while (diff-- > 0) { Item i = inputIterator.next(); if (i == null) { state = ALL_READ; condense(); return itemAt(n); } append(i); state = MAYBE_MORE; } //noinspection ConstantConditions return reservoir[n]; } /** * Get the length of the sequence */ public int getLength() throws XPathException { if (state == ALL_READ) { return used; } else if (state == EMPTY) { return 0; } else { return super.getLength(); } } /** * Append an item to the reservoir * @param item the item to be added */ private void append(Item item) { if (used >= reservoir.length) { Item[] r2 = new Item[used*2]; System.arraycopy(reservoir, 0, r2, 0, used); reservoir = r2; } reservoir[used++] = item; } /** * Release unused space in the reservoir (provided the amount of unused space is worth reclaiming) */ private void condense() { if (reservoir.length - used > 30) { Item[] r2 = new Item[used]; System.arraycopy(reservoir, 0, r2, 0, used); reservoir = r2; } // give unwanted stuff to the garbage collector savedXPathContext = null; // inputIterator = null; // expression = null; } /** * Determine whether the contents of the MemoClosure have been fully read * @return true if the contents have been fully read */ public boolean isFullyRead() { return state==EMPTY || state==ALL_READ; } /** * Return a value containing all the items in the sequence returned by this * SequenceIterator * * @return the corresponding value */ public Value materialize() throws XPathException { if (state == ALL_READ) { return new SequenceExtent(reservoir, 0, used); } else if (state == EMPTY) { return EmptySequence.getInstance(); } return new SequenceExtent(iterate()); } /** * A ProgressiveIterator starts by reading any items already held in the reservoir; * when the reservoir is exhausted, it reads further items from the inputIterator, * copying them into the reservoir as they are read. */ public final class ProgressiveIterator implements SequenceIterator, LastPositionFinder, GroundedIterator { int position = -1; // zero-based position in the reservoir of the // item most recently read /** * Create a ProgressiveIterator */ public ProgressiveIterator() { } public Item next() throws XPathException { if (position == -2) { // means we've already returned null once, keep doing so if called again. return null; } if (++position < used) { return reservoir[position]; } else if (state == ALL_READ) { // indicates another client has filled the reservoir position = -2; return null; } else { Item i = inputIterator.next(); if (i == null) { state = ALL_READ; condense(); //position--; // leave position at last item position = -2; return null; } position = used; append(i); state = MAYBE_MORE; return i; } } public Item current() { if (position < 0) { return null; } return reservoir[position]; } public int position() { return position + 1; // return one-based position } public void close() { } public SequenceIterator getAnother() { return new ProgressiveIterator(); } /** * Get the last position (that is, the number of items in the sequence) */ public int getLastPosition() throws XPathException { if (state == ALL_READ) { return used; } else if (state == EMPTY) { return 0; } else { // save the current position int savePos = position; // fill the reservoir while (true) { Item item = next(); if (item == null) { break; } } // reset the current position position = savePos; // return the total number of items return used; } } /** * Return a value containing all the items in the sequence returned by this * SequenceIterator * * @return the corresponding value */ public GroundedValue materialize() throws XPathException { if (state == ALL_READ) { return new SequenceExtent(reservoir); } else if (state == EMPTY) { return EmptySequence.getInstance(); } return new SequenceExtent(iterate()); } /** * Get properties of this iterator, as a bit-significant integer. * * @return the properties of this iterator. This will be some combination of * properties such as {@link #GROUNDED} and {@link #LAST_POSITION_FINDER}. It is always * acceptable to return the value zero, indicating that there are no known special properties. */ public int getProperties() { if (state == EMPTY || state == ALL_READ) { return GROUNDED | LAST_POSITION_FINDER; } else { return 0; } } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/value/StringValue.java0000644000175000017500000007756311033112257021643 0ustar eugeneeugenepackage net.sf.saxon.value; import net.sf.saxon.trans.Err; import net.sf.saxon.charcode.UTF16; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.*; import net.sf.saxon.sort.StringCollator; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.*; /** * An atomic value of type xs:string */ public class StringValue extends AtomicValue { public static final StringValue EMPTY_STRING = new StringValue(""); public static final StringValue SINGLE_SPACE = new StringValue(" "); public static final StringValue TRUE = new StringValue("true"); public static final StringValue FALSE = new StringValue("false"); // We hold the value as a CharSequence (it may be a StringBuffer rather than a string) // But the first time this is converted to a string, we keep it as a string protected CharSequence value; // may be zero-length, will never be null protected int length = -1; // the length in XML characters - not necessarily the same as the Java length /** * Protected constructor for use by subtypes */ protected StringValue() { value = ""; typeLabel = BuiltInAtomicType.STRING; } /** * Constructor. Note that although a StringValue may wrap any kind of CharSequence * (usually a String, but it can also be, for example, a StringBuffer), the caller * is responsible for ensuring that the value is immutable. * @param value the String value. Null is taken as equivalent to "". */ public StringValue(CharSequence value) { this.value = (value == null ? "" : value); typeLabel = BuiltInAtomicType.STRING; } /** * Create a copy of this atomic value, with a different type label * * @param typeLabel the type label of the new copy. The caller is responsible for checking that * the value actually conforms to this type. */ public AtomicValue copyAsSubType(AtomicType typeLabel) { StringValue v = new StringValue(value); v.length = length; v.typeLabel = typeLabel; return v; } /** * Determine the primitive type of the value. This delivers the same answer as * getItemType().getPrimitiveItemType(). The primitive types are * the 19 primitive types of XML Schema, plus xs:integer, xs:dayTimeDuration and xs:yearMonthDuration, * and xs:untypedAtomic. For external objects, the result is AnyAtomicType. */ public BuiltInAtomicType getPrimitiveType() { return BuiltInAtomicType.STRING; } /** * Factory method. Unlike the constructor, this avoids creating a new StringValue in the case * of a zero-length string (and potentially other strings, in future) * @param value the String value. Null is taken as equivalent to "". * @return the corresponding StringValue */ public static StringValue makeStringValue(CharSequence value) { if (value == null || value.length() == 0) { return StringValue.EMPTY_STRING; } else { return new StringValue(value); } } /** * Get the string value as a String */ public final String getStringValue() { return (String) (value = value.toString()); } /** * Get the value of the item as a CharSequence. This is in some cases more efficient than * the version of the method that returns a String. */ public final CharSequence getStringValueCS() { return value; } /** * Set the value of the item as a CharSequence. *

    For system use only. In principle, a StringValue is immutable. However, in special circumstances, * if it is newly constructed, the content can be changed to reflect the effect of the whiteSpace facet.

    * @param value the value of the string */ public final void setStringValueCS(CharSequence value) { this.value = value; } /** * Convert a value to another primitive data type, with control over how validation is * handled. * @param requiredType type code of the required atomic type * @param validate true if validation is required. If set to false, the caller guarantees that * the value is valid for the target data type, and that further validation is therefore not required. * Note that a validation failure may be reported even if validation was not requested. * @param context XPath dynamic context. Used only where the target type is one such as * NCName whose definition is context-sensitive * @return the result of the conversion, if successful. If unsuccessful, the value returned * will be a ValidationErrorValue. The caller must check for this condition. No exception is thrown, instead * the exception will be encapsulated within the ErrorValue. */ public ConversionResult convertPrimitive(BuiltInAtomicType requiredType, boolean validate, XPathContext context) { int req = requiredType.getFingerprint(); if (req == StandardNames.XS_STRING || req == StandardNames.XS_ANY_ATOMIC_TYPE) { return this; } return convertStringToBuiltInType(value, requiredType, (validate ? context.getConfiguration().getNameChecker() : null)); } /** * Convert a string value to another built-in data type, with control over how validation is * handled. * @param value the value to be converted * @param requiredType the required atomic type * @param checker if validation is required, a NameChecker. If set to null, the caller guarantees that * the value is valid for the target data type, and that further validation is therefore not required. * Note that a validation failure may be reported even if validation was not requested. * @return the result of the conversion, if successful. If unsuccessful, the value returned * will be a {@link ValidationFailure}. The caller must check for this condition. No exception is thrown, instead * the exception will be encapsulated within the ValidationFailure. */ public static ConversionResult convertStringToBuiltInType(CharSequence value, BuiltInAtomicType requiredType, NameChecker checker) { try { switch (requiredType.getFingerprint()) { case StandardNames.XS_BOOLEAN: { return BooleanValue.fromString(value); } case StandardNames.XS_NUMERIC: case StandardNames.XS_DOUBLE: return new DoubleValue(value); case StandardNames.XS_INTEGER: return Int64Value.stringToInteger(value); case StandardNames.XS_UNSIGNED_LONG: case StandardNames.XS_UNSIGNED_INT: case StandardNames.XS_UNSIGNED_SHORT: case StandardNames.XS_UNSIGNED_BYTE: case StandardNames.XS_NON_POSITIVE_INTEGER: case StandardNames.XS_NEGATIVE_INTEGER: case StandardNames.XS_LONG: case StandardNames.XS_INT: case StandardNames.XS_SHORT: case StandardNames.XS_BYTE: case StandardNames.XS_NON_NEGATIVE_INTEGER: case StandardNames.XS_POSITIVE_INTEGER: ConversionResult iv = IntegerValue.stringToInteger(value); if (iv instanceof ValidationFailure) { // indicates that the conversion failed return iv; } IntegerValue nv = (IntegerValue)((IntegerValue)iv).copyAsSubType(requiredType); ValidationFailure err = nv.convertToSubType(requiredType, checker != null); //noinspection RedundantCast return (err == null ? (ConversionResult)nv : (ConversionResult)err); case StandardNames.XS_DECIMAL: return DecimalValue.makeDecimalValue(value, checker != null); case StandardNames.XS_FLOAT: return new FloatValue(value); case StandardNames.XS_DATE: return DateValue.makeDateValue(value); case StandardNames.XS_DATE_TIME: return DateTimeValue.makeDateTimeValue(value); case StandardNames.XS_TIME: return TimeValue.makeTimeValue(value); case StandardNames.XS_G_YEAR: return GYearValue.makeGYearValue(value); case StandardNames.XS_G_YEAR_MONTH: return GYearMonthValue.makeGYearMonthValue(value); case StandardNames.XS_G_MONTH: return GMonthValue.makeGMonthValue(value); case StandardNames.XS_G_MONTH_DAY: return GMonthDayValue.makeGMonthDayValue(value); case StandardNames.XS_G_DAY: return GDayValue.makeGDayValue(value); case StandardNames.XS_DURATION: return DurationValue.makeDuration(value); case StandardNames.XS_YEAR_MONTH_DURATION: return YearMonthDurationValue.makeYearMonthDurationValue(value); case StandardNames.XS_DAY_TIME_DURATION: return DayTimeDurationValue.makeDayTimeDurationValue(value); case StandardNames.XS_UNTYPED_ATOMIC: case StandardNames.XS_ANY_SIMPLE_TYPE: return new UntypedAtomicValue(value); case StandardNames.XS_STRING: case StandardNames.XS_ANY_ATOMIC_TYPE: return makeStringValue(value); case StandardNames.XS_NORMALIZED_STRING: case StandardNames.XS_TOKEN: case StandardNames.XS_LANGUAGE: case StandardNames.XS_NAME: case StandardNames.XS_NCNAME: case StandardNames.XS_ID: case StandardNames.XS_IDREF: case StandardNames.XS_ENTITY: case StandardNames.XS_NMTOKEN: return makeRestrictedString(value, requiredType, checker); case StandardNames.XS_ANY_URI: if (AnyURIValue.isValidURI(value)) { return new AnyURIValue(value); } else { ValidationFailure ve = new ValidationFailure("Invalid URI: " + value.toString()); ve.setErrorCode("FORG0001"); return ve; } case StandardNames.XS_HEX_BINARY: return new HexBinaryValue(value); case StandardNames.XS_BASE64_BINARY: return new Base64BinaryValue(value); default: ValidationFailure ve = new ValidationFailure("Cannot convert string to type " + Err.wrap(requiredType.getDisplayName())); ve.setErrorCode("XPTY0004"); return ve; } } catch (ValidationException err) { ValidationFailure vf = new ValidationFailure(err.getMessage()); vf.setErrorCode(err.getErrorCodeLocalPart()); if (vf.getErrorCode() == null) { vf.setErrorCode("FORG0001"); } return vf; } catch (XPathException err) { if (err.getErrorCodeLocalPart() == null) { err.setErrorCode("FORG0001"); } ValidationFailure ve = new ValidationFailure(err.getMessage()); if (err.getErrorCodeLocalPart() == null) { ve.setErrorCode("FORG0001"); } else { ve.setErrorCode(err.getErrorCodeLocalPart()); } return ve; } } /** * Convert the value to a given type. The result of the conversion will be * an atomic value of the required type. This method works where the target * type is a built-in atomic type and also where it is a user-defined atomic * type. It does not handle namespace-sensitive types (QName, NOTATION, and derivatives). * @param value the value to be converted * @param targetType the type to which the value is to be converted * @param checker a NameChecker if validation is required, null if the caller already knows that the * value is valid. Note that a non-null NameChecker acts as a signal that validation is * required, even when the value to be checked is not a name. * @return the value after conversion if successful; or a {@link ValidationFailure} if conversion failed. The * caller must check for this condition. Validation may fail even if validation was not requested. */ public static ConversionResult convertStringToAtomicType( CharSequence value, AtomicType targetType, NameChecker checker) { if (targetType instanceof BuiltInAtomicType) { return convertStringToBuiltInType(value, (BuiltInAtomicType)targetType, checker); } else { BuiltInAtomicType primitiveType = (BuiltInAtomicType)targetType.getPrimitiveItemType(); if (primitiveType.getFingerprint() == StandardNames.XS_STRING) { int whitespaceAction = targetType.getWhitespaceAction(null); value = Whitespace.applyWhitespaceNormalization(whitespaceAction, value); } ConversionResult result = convertStringToBuiltInType(value, primitiveType, checker); if (result instanceof ValidationFailure) { // conversion has failed return result; } ValidationFailure vf = targetType.validate((AtomicValue)result, value, checker); if (vf != null) { return vf; } return ((AtomicValue)result).copyAsSubType(targetType); } } /** * Get the length of this string, as defined in XPath. This is not the same as the Java length, * as a Unicode surrogate pair counts as a single character * @return the length of the string in Unicode code points */ public int getStringLength() { // memo function; only compute it the first time if (length == -1) { length = getStringLength(value); } return length; } /** * Get the length of a string, as defined in XPath. This is not the same as the Java length, * as a Unicode surrogate pair counts as a single character. * @param s The string whose length is required * @return the length of the string in Unicode code points */ public static int getStringLength(CharSequence s) { int n = 0; for (int i = 0; i < s.length(); i++) { int c = (int) s.charAt(i); if (c < 55296 || c > 56319) n++; // don't count high surrogates, i.e. D800 to DBFF } return n; } /** * Determine whether the string is a zero-length string. This may * be more efficient than testing whether the length is equal to zero * @return true if the string is zero length */ public boolean isZeroLength() { return value.length() == 0; } /** * Determine whether the string contains surrogate pairs * @return true if the string contains any non-BMP characters */ public boolean containsSurrogatePairs() { if (length == -1) { getStringLength(); } return (length != value.length()); } /** * Iterate over a string, returning a sequence of integers representing the Unicode code-point values * @return an iterator over the characters (Unicode code points) in the string */ public UnfailingIterator iterateCharacters() { return new CharacterIterator(); } /** * Expand a string containing surrogate pairs into an array of 32-bit characters * @return an array of integers representing the Unicode code points */ public int[] expand() { int[] array = new int[getStringLength()]; int o = 0; int len = value.length(); for (int i = 0; i < len; i++) { int charval; int c = value.charAt(i); if (c >= 55296 && c <= 56319) { // we'll trust the data to be sound charval = ((c - 55296) * 1024) + ((int) value.charAt(i + 1) - 56320) + 65536; i++; } else { charval = c; } array[o++] = charval; } return array; } /** * Expand a string containing surrogate pairs into an array of 32-bit characters * @param s the string to be expanded * @return an array of integers representing the Unicode code points */ public static int[] expand(CharSequence s) { int[] array = new int[getStringLength(s)]; int o = 0; for (int i = 0; i < s.length(); i++) { int charval; int c = s.charAt(i); if (c >= 55296 && c <= 56319) { // we'll trust the data to be sound charval = ((c - 55296) * 1024) + ((int) s.charAt(i + 1) - 56320) + 65536; i++; } else { charval = c; } array[o++] = charval; } return array; } /** * Contract an array of integers containing Unicode codepoints into a Java string * @param codes an array of integers representing the Unicode code points * @param used the number of items in the array that are actually used * @return the constructed string */ public static CharSequence contract(int[] codes, int used) { FastStringBuffer sb = new FastStringBuffer(codes.length); for (int i=0; i 0; } /** * Convert to Java object (for passing to external functions) */ // public Object convertAtomicToJava(Class target, XPathContext context) throws XPathException { // if (target == Object.class) { // return getStringValue(); // } else if (target.isAssignableFrom(StringValue.class)) { // return this; // } else if (target == String.class || target == CharSequence.class) { // return getStringValue(); // } else if (target == char.class || target == Character.class) { // if (value.length() == 1) { // return new Character(value.charAt(0)); // } else { // XPathException de = new XPathException("Cannot convert xs:string to Java char unless length is 1"); // de.setXPathContext(context); // de.setErrorCode(SaxonErrorCode.SXJE0005); // throw de; // } // } else { // Object o = super.convertSequenceToJava(target, context); // if (o == null) { // XPathException err = new XPathException("Conversion of xs:string to " + target.getName() + " is not supported"); // err.setXPathContext(context); // err.setErrorCode(SaxonErrorCode.SXJE0006); // throw err; // } // return o; // } // } // public String toString() { return "\"" + value + '\"'; } /** * Factory method to create a string value belonging to a built-in type derived from string * @param value the String value. Null is taken as equivalent to "". * @param typeLabel the required type, must be a built in type derived from xs:string * @param checker a NameChecker if validation is required, * null if the caller already knows that the value is valid * @return either the required StringValue if the value is valid, or a ValidationFailure encapsulating * the error message if not. */ public static ConversionResult makeRestrictedString( CharSequence value, BuiltInAtomicType typeLabel, NameChecker checker) { StringValue rsv = new StringValue(); int type = typeLabel.getFingerprint(); rsv.setTypeLabel(typeLabel); if (value == null) { rsv.value = ""; } else if (type == StandardNames.XS_NORMALIZED_STRING) { rsv.value = Whitespace.normalizeWhitespace(value); } else if (type == StandardNames.XS_TOKEN) { rsv.value = Whitespace.collapseWhitespace(value); } else { rsv.value = Whitespace.trimWhitespace(value); if (checker != null) { ValidationFailure err = validate(typeLabel, rsv.value, checker); if (err == null) { return rsv; } else { return err; } } else { return rsv; } } return rsv; } /** * Validate that the string conforms to the rules for a built-in subtype of xs:string * @param typeLabel the built-in atomic type against which the string should be validated * @param val the string to be validated * @param checker object that checks names against the XML 1.0 or XML 1.1 rules as appropriate * @return null if the value is OK, otherwise a ValidationException containing details of the failure */ public static ValidationFailure validate(BuiltInAtomicType typeLabel, CharSequence val, NameChecker checker) { switch (typeLabel.getFingerprint()) { case StandardNames.XS_TOKEN: return null; case StandardNames.XS_NORMALIZED_STRING: return null; case StandardNames.XS_LANGUAGE: String regex = "[a-zA-Z]{1,8}(-[a-zA-Z0-9]{1,8})*"; // See erratum E2-25 to XML Schema Part 2. Was: // "(([a-z]|[A-Z])([a-z]|[A-Z])|" // ISO639Code // + "([iI]-([a-z]|[A-Z])+)|" // IanaCode // + "([xX]-([a-z]|[A-Z])+))" // UserCode // + "(-([a-z]|[A-Z])+)*"; // Subcode if (!java.util.regex.Pattern.matches(regex, val.toString())) { ValidationFailure err = new ValidationFailure("The value '" + val + "' is not a valid xs:language"); err.setErrorCode("FORG0001"); return err; } return null; case StandardNames.XS_NAME: // replace any colons by underscores and then test if it's a valid NCName FastStringBuffer buff = new FastStringBuffer(val.length()); buff.append(val); for (int i = 0; i < buff.length(); i++) { if (buff.charAt(i) == ':') { buff.setCharAt(i, '_'); } } if (!checker.isValidNCName(buff)) { ValidationFailure err = new ValidationFailure("The value '" + val + "' is not a valid Name"); err.setErrorCode("FORG0001"); return err; } return null; case StandardNames.XS_NCNAME: case StandardNames.XS_ID: case StandardNames.XS_IDREF: case StandardNames.XS_ENTITY: if (!checker.isValidNCName(val)) { ValidationFailure err = new ValidationFailure("The value '" + val + "' is not a valid NCName"); err.setErrorCode("FORG0001"); return err; } return null; case StandardNames.XS_NMTOKEN: if (!checker.isValidNmtoken(val)) { ValidationFailure err = new ValidationFailure("The value '" + val + "' is not a valid NMTOKEN"); err.setErrorCode("FORG0001"); return err; } return null; default: throw new IllegalArgumentException("Unknown string value type " + typeLabel.getFingerprint()); } } /** * Get a Comparable value that implements the XML Schema comparison semantics for this value. * Returns null if the value is not comparable according to XML Schema rules. This implementation * returns the underlying Java string, which works because strings will only be compared for * equality, not for ordering, and the equality rules for strings in XML schema are the same as in Java. */ public Comparable getSchemaComparable() { return value.toString(); } /** * Produce a diagnostic representation of the contents of the string * @param s the string * @return a string in which non-Ascii-printable characters are replaced by \ uXXXX escapes */ public static String diagnosticDisplay(String s) { FastStringBuffer fsb = new FastStringBuffer(s.length()); for (int i = 0, len = s.length(); i < len; i++) { char c = s.charAt(i); if (c >= 0x20 && c <= 0x7e) { fsb.append(c); } else { fsb.append("\\u"); for (int shift = 12; shift >= 0; shift -= 4) { fsb.append("0123456789ABCDEF".charAt((c >> shift) & 0xF)); } } } return fsb.toString(); } /** * CharacterIterator is used to iterate over the characters in a string, * returning them as integers representing the Unicode code-point. */ public final class CharacterIterator implements UnfailingIterator { int inpos = 0; // 0-based index of the current Java char int outpos = 0; // 1-based value of position() function int current = -1; // Unicode codepoint most recently returned /** * Create an iterator over a string */ public CharacterIterator() { } public Item next() { if (inpos < value.length()) { int c = value.charAt(inpos++); if (c >= 55296 && c <= 56319) { // we'll trust the data to be sound current = ((c - 55296) * 1024) + ((int) value.charAt(inpos++) - 56320) + 65536; } else { current = c; } outpos++; return new Int64Value(current); } else { outpos = -1; return null; } } public Item current() { if (outpos < 1) { return null; } return new Int64Value(current); } public int position() { return outpos; } public void close() { } public SequenceIterator getAnother() { return new CharacterIterator(); } /** * Get properties of this iterator, as a bit-significant integer. * * @return the properties of this iterator. This will be some combination of * properties such as {@link #GROUNDED} and {@link #LAST_POSITION_FINDER}. It is always * acceptable to return the value zero, indicating that there are no known special properties. */ public int getProperties() { return 0; } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/value/DurationValue.java0000644000175000017500000007640111033112257022150 0ustar eugeneeugenepackage net.sf.saxon.value; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.functions.Component; import net.sf.saxon.om.FastStringBuffer; import net.sf.saxon.om.StandardNames; import net.sf.saxon.sort.StringCollator; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.AtomicType; import net.sf.saxon.type.BuiltInAtomicType; import net.sf.saxon.type.ConversionResult; import net.sf.saxon.type.ValidationFailure; import java.util.StringTokenizer; /** * A value of type xs:duration */ public class DurationValue extends AtomicValue { protected boolean negative = false; protected int months = 0; protected long seconds = 0; protected int microseconds = 0; /** * Private constructor for internal use */ protected DurationValue() { } /** * Constructor for xs:duration taking the components of the duration. There is no requirement * that the values are normalized, for example it is acceptable to specify months=18. The values of * the individual components must all be non-negative. * * @param positive true if the duration is positive, false if negative. For a negative duration * the components are all supplied as positive integers (or zero). * @param years the number of years * @param months the number of months * @param days the number of days * @param hours the number of hours * @param minutes the number of minutes * @param seconds the number of seconds * @param microseconds the number of microseconds * @throws IllegalArgumentException if the size of the duration exceeds implementation-defined * limits: specifically, if the total number of months exceeds 2^31, or if the total number * of seconds exceeds 2^63. */ public DurationValue(boolean positive, int years, int months, int days, int hours, int minutes, long seconds, int microseconds) throws IllegalArgumentException { this(positive, years, months, days, hours, minutes, seconds, microseconds, BuiltInAtomicType.DURATION); } /** * Constructor for xs:duration taking the components of the duration, plus a user-specified * type which must be a subtype of xs:duration. There is no requirement * that the values are normalized, for example it is acceptable to specify months=18. The values of * the individual components must all be non-negative. * * @param positive true if the duration is positive, false if negative. For a negative duration * the components are all supplied as positive integers (or zero). * @param years the number of years * @param months the number of months * @param days the number of days * @param hours the number of hours * @param minutes the number of minutes * @param seconds the number of seconds (long to allow copying) * @param microseconds the number of microseconds * @param type the user-defined subtype of xs:duration. Note that this constructor cannot * be used to create an instance of xs:dayTimeDuration or xs:yearMonthDuration. * @throws IllegalArgumentException if the size of the duration exceeds implementation-defined * limits: specifically, if the total number of months exceeds 2^31, or if the total number * of seconds exceeds 2^63. */ public DurationValue(boolean positive, int years, int months, int days, int hours, int minutes, long seconds, int microseconds, AtomicType type) { negative = !positive; if (years < 0 || months < 0 || days < 0 || hours < 0 || minutes < 0 || seconds < 0 || microseconds < 0) { throw new IllegalArgumentException("Negative component value"); } if (((double)years)*12 + (double)months > Integer.MAX_VALUE) { throw new IllegalArgumentException("Duration months limit exceeded"); } if (((double)days)*(24*60*60) + ((double)hours)*(60*60) + ((double)minutes)*60 + (double)seconds > Long.MAX_VALUE) { throw new IllegalArgumentException("Duration seconds limit exceeded"); } this.months = years*12 + months; long h = days * 24 + hours ; long m = h * 60 + minutes; this.seconds = m * 60 + seconds; this.microseconds = microseconds; normalizeZeroDuration(); typeLabel = type; } /** * Ensure that a zero duration is considered positive */ protected void normalizeZeroDuration() { if (months == 0 && seconds == 0L && microseconds == 0) { negative = false; } } /** * Static factory method: create a duration value from a supplied string, in * ISO 8601 format [-]PnYnMnDTnHnMnS * * @param s a string in the lexical space of xs:duration * @return the constructed xs:duration value, or a {@link ValidationFailure} if the * supplied string is lexically invalid. */ public static ConversionResult makeDuration(CharSequence s) { int years = 0, months = 0, days = 0, hours = 0, minutes = 0, seconds = 0, microseconds = 0; boolean negative = false; StringTokenizer tok = new StringTokenizer(Whitespace.trimWhitespace(s).toString(), "-+.PYMDTHS", true); int components = 0; if (!tok.hasMoreElements()) { return badDuration("empty string", s); } String part = (String)tok.nextElement(); if ("+".equals(part)) { return badDuration("+ sign not allowed in a duration", s); } else if ("-".equals(part)) { negative = true; part = (String)tok.nextElement(); } if (!"P".equals(part)) { return badDuration("missing 'P'", s); } int state = 0; while (tok.hasMoreElements()) { part = (String)tok.nextElement(); if ("T".equals(part)) { state = 4; if (!tok.hasMoreElements()) { return badDuration("T must be followed by time components", s); } part = (String)tok.nextElement(); } int value = simpleInteger(part); if (value < 0) { if (part.length() > 8) { return badDuration("component invalid or too large", s); } else { return badDuration("non-numeric component", s); } } if (!tok.hasMoreElements()) { return badDuration("missing unit letter at end", s); } char delim = ((String)tok.nextElement()).charAt(0); switch (delim) { case'Y': if (state > 0) { return badDuration("Y is out of sequence", s); } years = value; state = 1; components++; break; case'M': if (state == 4 || state == 5) { minutes = value; state = 6; components++; break; } else if (state == 0 || state == 1) { months = value; state = 2; components++; break; } else { return badDuration("M is out of sequence", s); } case'D': if (state > 2) { return badDuration("D is out of sequence", s); } days = value; state = 3; components++; break; case'H': if (state != 4) { return badDuration("H is out of sequence", s); } hours = value; state = 5; components++; break; case'.': if (state < 4 || state > 6) { return badDuration("misplaced decimal point", s); } seconds = value; state = 7; break; case'S': if (state < 4 || state > 7) { return badDuration("S is out of sequence", s); } if (state == 7) { while (part.length() < 6) { part += "0"; } if (part.length() > 6) { part = part.substring(0, 6); } value = simpleInteger(part); if (value < 0) { return badDuration("non-numeric fractional seconds", s); } microseconds = value; } else { seconds = value; } state = 8; components++; break; default: return badDuration("misplaced " + delim, s); } } if (components == 0) { return badDuration("Duration specifies no components", s); } try { return new DurationValue( !negative, years, months, days, hours, minutes, seconds, microseconds, BuiltInAtomicType.DURATION); } catch (IllegalArgumentException err) { // catch values that exceed limits return new ValidationFailure(err.getMessage()); } } protected static ValidationFailure badDuration(String msg, CharSequence s) { ValidationFailure err = new ValidationFailure("Invalid duration value '" + s + "' (" + msg + ')'); err.setErrorCode("FORG0001"); return err; } /** * Parse a simple unsigned integer * * @param s the string containing the sequence of digits. No sign or whitespace is allowed. * @return the integer. Return -1 if the string is not a sequence of digits or exceeds 2^31 */ protected static int simpleInteger(String s) { long result = 0; int len = s.length(); if (len == 0) { return -1; } for (int i = 0; i < len; i++) { char c = s.charAt(i); if (c >= '0' && c <= '9') { result = result * 10 + (c - '0'); if (result > Integer.MAX_VALUE) { return -1; } } else { return -1; } } return (int)result; } /** * Create a copy of this atomic value, with a different type label * * @param typeLabel the type label of the new copy. The caller is responsible for checking that * the value actually conforms to this type. */ public AtomicValue copyAsSubType(AtomicType typeLabel) { return new DurationValue(!negative, 0, months, 0, 0, 0, seconds, microseconds, typeLabel); } /** * Determine the primitive type of the value. This delivers the same answer as * getItemType().getPrimitiveItemType(). The primitive types are * the 19 primitive types of XML Schema, plus xs:integer, xs:dayTimeDuration and xs:yearMonthDuration, * and xs:untypedAtomic. For external objects, the result is AnyAtomicType. */ public BuiltInAtomicType getPrimitiveType() { return BuiltInAtomicType.DURATION; } /** * Convert to target data type * * @param requiredType an integer identifying the required atomic type * @param validate if set to false, the caller asserts that the value is known to be valid * @param context the XPath dynamic context * @return an AtomicValue, a value of the required type; or a {@link ValidationFailure} if * the value cannot be converted. */ public ConversionResult convertPrimitive(BuiltInAtomicType requiredType, boolean validate, XPathContext context) { //System.err.println("Convert duration " + getClass() + " to " + Type.getTypeName(requiredType)); switch (requiredType.getPrimitiveType()) { case StandardNames.XS_DURATION: case StandardNames.XS_ANY_ATOMIC_TYPE: return this; case StandardNames.XS_STRING: return new StringValue(getStringValueCS()); case StandardNames.XS_UNTYPED_ATOMIC: return new UntypedAtomicValue(getStringValueCS()); case StandardNames.XS_YEAR_MONTH_DURATION: return YearMonthDurationValue.fromMonths(months * (negative ? -1 : +1)); case StandardNames.XS_DAY_TIME_DURATION: return new DayTimeDurationValue((negative ? -1 : +1), 0, 0, 0, seconds, microseconds); default: ValidationFailure err = new ValidationFailure("Cannot convert duration to " + requiredType.getDisplayName()); err.setErrorCode("XPTY0004"); return err; } } /** * Normalize the duration, so that months<12, hours<24, minutes<60, seconds<60. * Since durations are now always normalized, this method has become a no-op, but is retained * for backwards compatibility * @deprecated since 9.0 - the method does nothing * * @return the duration unchanged */ public DurationValue normalizeDuration() { return this; } /** * Return the signum of the value * * @return -1 if the duration is negative, zero if it is zero-length, +1 if it is positive */ public int signum() { if (negative) { return -1; } if (months == 0 && seconds == 0L && microseconds == 0) { return 0; } return +1; } /** * Get the year component * * @return the number of years in the normalized duration; always positive */ public int getYears() { return months / 12; } /** * Get the months component * * @return the number of months in the normalized duration; always positive */ public int getMonths() { return months % 12; } /** * Get the days component * * @return the number of days in the normalized duration; always positive */ public int getDays() { // System.err.println("seconds = " + seconds); // System.err.println("minutes = " + seconds / 60L); // System.err.println("hours = " + seconds / (60L*60L)); // System.err.println("days = " + seconds / (24L*60L*60L)); // System.err.println("days (int) = " + (int)(seconds / (24L*60L*60L))); return (int)(seconds / (24L*60L*60L)); } /** * Get the hours component * * @return the number of hours in the normalized duration; always positive */ public int getHours() { return (int)(seconds % (24L*60L*60L) / (60L*60L)); } /** * Get the minutes component * * @return the number of minutes in the normalized duration; always positive */ public int getMinutes() { return (int)(seconds % (60L*60L) / 60L); } /** * Get the seconds component * * @return the number of whole seconds in the normalized duration; always positive */ public int getSeconds() { return (int)(seconds % 60L); } /** * Get the microseconds component * * @return the number of microseconds in the normalized duration; always positive */ public int getMicroseconds() { return microseconds; } /** * Convert the value to a string, using the serialization rules. * For atomic values this is the same as a cast; for sequence values * it gives a space-separated list. This method is refined for AtomicValues * so that it never throws an Exception. */ public String getStringValue() { return getStringValueCS().toString(); } /** * Convert to string * * @return ISO 8601 representation. */ public CharSequence getStringValueCS() { // Note, Schema does not define a canonical representation. We omit all zero components, unless // the duration is zero-length, in which case we output PT0S. if (months == 0 && seconds == 0L && microseconds == 0) { return "PT0S"; } FastStringBuffer sb = new FastStringBuffer(32); if (negative) { sb.append('-'); } int years = getYears(); int months = getMonths(); int days = getDays(); int hours = getHours(); int minutes = getMinutes(); int seconds = getSeconds(); sb.append("P"); if (years != 0) { sb.append(years + "Y"); } if (months != 0) { sb.append(months + "M"); } if (days != 0) { sb.append(days + "D"); } if (hours != 0 || minutes != 0 || seconds != 0 || microseconds != 0) { sb.append("T"); } if (hours != 0) { sb.append(hours + "H"); } if (minutes != 0) { sb.append(minutes + "M"); } if (seconds != 0 || microseconds != 0) { if (seconds != 0 && microseconds == 0) { sb.append(seconds + "S"); } else { long ms = (seconds * 1000000) + microseconds; String mss = ms + ""; if (seconds == 0) { mss = "0000000" + mss; mss = mss.substring(mss.length() - 7); } sb.append(mss.substring(0, mss.length() - 6)); sb.append('.'); int lastSigDigit = mss.length() - 1; while (mss.charAt(lastSigDigit) == '0') { lastSigDigit--; } sb.append(mss.substring(mss.length() - 6, lastSigDigit + 1)); sb.append('S'); } } return sb; } /** * Get length of duration in seconds, assuming an average length of month. (Note, this defines a total * ordering on durations which is different from the partial order defined in XML Schema; XPath 2.0 * currently avoids defining an ordering at all. But the ordering here is consistent with the ordering * of the two duration subtypes in XPath 2.0.) * * @return the duration in seconds, as a double */ public double getLengthInSeconds() { double a = months * (365.242199 / 12.0) * 24 * 60 * 60 + seconds + ((double)microseconds / 1000000); return (negative ? -a : a); } /** * Convert to Java object (for passing to external functions) */ // public Object convertAtomicToJava(Class target, XPathContext context) throws XPathException { // if (target.isAssignableFrom(DurationValue.class)) { // return this; // } else if (target == Object.class) { // return getStringValue(); // } else { // Object o = super.convertSequenceToJava(target, context); // if (o == null) { // XPathException err = new XPathException("Conversion of xs:duration to " + target.getName() + // " is not supported"); // err.setXPathContext(context); // err.setErrorCode(SaxonErrorCode.SXJE0003); // } // return o; // } // } /** * Get a component of the normalized value */ public AtomicValue getComponent(int component) throws XPathException { switch (component) { case Component.YEAR: return Int64Value.makeIntegerValue((negative ? -getYears() : getYears())); case Component.MONTH: return Int64Value.makeIntegerValue((negative ? -getMonths() : getMonths())); case Component.DAY: return Int64Value.makeIntegerValue((negative ? -getDays() : getDays())); case Component.HOURS: return Int64Value.makeIntegerValue((negative ? -getHours() : getHours())); case Component.MINUTES: return Int64Value.makeIntegerValue((negative ? -getMinutes() : getMinutes())); case Component.SECONDS: FastStringBuffer sb = new FastStringBuffer(16); String ms = ("000000" + microseconds); ms = ms.substring(ms.length() - 6); sb.append((negative ? "-" : "") + getSeconds() + '.' + ms); return (AtomicValue)DecimalValue.makeDecimalValue(sb, false); case Component.WHOLE_SECONDS: return Int64Value.makeIntegerValue((negative ? -seconds : seconds)); case Component.MICROSECONDS: return new Int64Value((negative ? -microseconds : microseconds)); default: throw new IllegalArgumentException("Unknown component for duration: " + component); } } /** * Get an object value that implements the XPath equality and ordering comparison semantics for this value. * If the ordered parameter is set to true, the result will be a Comparable and will support a compareTo() * method with the semantics of the XPath lt/gt operator, provided that the other operand is also obtained * using the getXPathComparable() method. In all cases the result will support equals() and hashCode() methods * that support the semantics of the XPath eq operator, again provided that the other operand is also obtained * using the getXPathComparable() method. A context argument is supplied for use in cases where the comparison * semantics are context-sensitive, for example where they depend on the implicit timezone or the default * collation. * * @param ordered true if an ordered comparison is required. In this case the result is null if the * type is unordered; in other cases the returned value will be a Comparable. * @param collator collation used for comparing string values * @param context the XPath dynamic evaluation context, used in cases where the comparison is context * sensitive @return an Object whose equals() and hashCode() methods implement the XPath comparison semantics * with respect to this atomic value. If ordered is specified, the result will either be null if * no ordering is defined, or will be a Comparable */ public Object getXPathComparable(boolean ordered, StringCollator collator, XPathContext context) { return (ordered ? null : this); } /** * Test if the two durations are of equal length. * * @throws ClassCastException if the other value is not an xs:duration or subtype thereof */ public boolean equals(Object other) { DurationValue d1 = this; DurationValue d2 = (DurationValue)other; return d1.negative == d2.negative && d1.months == d2.months && d1.seconds == d2.seconds && d1.microseconds == d2.microseconds; } public int hashCode() { return new Double(getLengthInSeconds()).hashCode(); } /** * Add two durations * * @param other the duration to be added to this one * @return the sum of the two durations */ public DurationValue add(DurationValue other) throws XPathException { XPathException err = new XPathException("Only subtypes of xs:duration can be added"); err.setErrorCode("XPTY0004"); err.setIsTypeError(true); throw err; } /** * Subtract two durations * * @param other the duration to be subtracted from this one * @return the difference of the two durations */ public DurationValue subtract(DurationValue other) throws XPathException { XPathException err = new XPathException("Only subtypes of xs:duration can be subtracted"); err.setErrorCode("XPTY0004"); err.setIsTypeError(true); throw err; } /** * Negate a duration (same as subtracting from zero, but it preserves the type of the original duration) * * @return the original duration with its sign reversed, retaining its type */ public DurationValue negate() { return new DurationValue(negative, 0, months, 0, 0, 0, seconds, microseconds, typeLabel); } /** * Multiply a duration by a number * * @param factor the number to multiply by * @return the result of the multiplication */ public DurationValue multiply(double factor) throws XPathException { XPathException err = new XPathException("Only subtypes of xs:duration can be multiplied by a number"); err.setErrorCode("XPTY0004"); err.setIsTypeError(true); throw err; } /** * Divide a duration by a another duration * * @param other the duration to divide by * @return the result of the division */ public DecimalValue divide(DurationValue other) throws XPathException { XPathException err = new XPathException("Only subtypes of xs:duration can be divided by another duration"); err.setErrorCode("XPTY0004"); err.setIsTypeError(true); throw err; } /** * Get a Comparable value that implements the XML Schema ordering comparison semantics for this value. * This implementation handles the ordering rules for durations in XML Schema. * It is overridden for the two subtypes DayTimeDuration and YearMonthDuration. * * @return a suitable Comparable */ public Comparable getSchemaComparable() { return getSchemaComparable(this); } /** * Get a Comparable value that implements the XML Schema ordering comparison semantics for this value. * This implementation handles the ordering rules for durations in XML Schema. * * @param value the duration for which a comparison key is required * @return a suitable Comparable */ public static Comparable getSchemaComparable(DurationValue value) { int m = value.months; double s = value.seconds + ((double)value.microseconds / 1000000); if (value.negative) { s = -s; m = -m; } return new DurationComparable(m, s); } /** * DurationValueOrderingKey is a Comparable value that acts as a surrogate for a Duration, * having ordering rules that implement the XML Schema specification. */ private static class DurationComparable implements Comparable { private int months; private double seconds; public DurationComparable(int m, double s) { months = m; seconds = s; } /** * Compare two durations according to the XML Schema rules. * * @param o the other duration * @return -1 if this duration is smaller; 0 if they are equal; +1 if this duration is greater; * {@link AtomicValue#INDETERMINATE_ORDERING} if there is no defined order */ public int compareTo(Object o) { DurationComparable other; if (o instanceof DurationComparable) { other = (DurationComparable)o; } else if (o instanceof YearMonthDurationValue) { other = (DurationComparable)getSchemaComparable((YearMonthDurationValue)o); } else if (o instanceof DayTimeDurationValue) { other = (DurationComparable)getSchemaComparable((DayTimeDurationValue)o); } else { return INDETERMINATE_ORDERING; } if (months == other.months) { return Double.compare(seconds, other.seconds); } else if (seconds == other.seconds) { return (months == other.months ? 0 : (months < other.months ? -1 : +1)); } else { double oneDay = 24e0 * 60e0 * 60e0; double min0 = monthsToDaysMinimum(months) * oneDay + seconds; double max0 = monthsToDaysMaximum(months) * oneDay + seconds; double min1 = monthsToDaysMinimum(other.months) * oneDay + other.seconds; double max1 = monthsToDaysMaximum(other.months) * oneDay + other.seconds; if (max0 < min1) { return -1; } else if (min0 > max1) { return +1; } else { return INDETERMINATE_ORDERING; } } } public boolean equals(Object o) { return compareTo(o) == 0; } public int hashCode() { return months ^ (int)seconds; } private int monthsToDaysMinimum(int months) { if (months < 0) { return -monthsToDaysMaximum(-months); } if (months < 12) { int[] shortest = {0, 28, 59, 89, 120, 150, 181, 212, 242, 273, 303, 334}; return shortest[months]; } else { int years = months / 12; int remainingMonths = months % 12; // the -1 is to allow for the fact that we might miss a leap day if we time the start badly int yearDays = years * 365 + (years % 4) - (years % 100) + (years % 400) - 1; return yearDays + monthsToDaysMinimum(remainingMonths); } } private int monthsToDaysMaximum(int months) { if (months < 0) { return -monthsToDaysMinimum(-months); } if (months < 12) { int[] longest = {0, 31, 62, 92, 123, 153, 184, 215, 245, 276, 306, 337}; return longest[months]; } else { int years = months / 12; int remainingMonths = months % 12; // the +1 is to allow for the fact that we might miss a leap day if we time the start badly int yearDays = years * 365 + (years % 4) - (years % 100) + (years % 400) + 1; return yearDays + monthsToDaysMaximum(remainingMonths); } } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/value/TextFragmentValue.java0000644000175000017500000010015511033112257022765 0ustar eugeneeugenepackage net.sf.saxon.value; import net.sf.saxon.Configuration; import net.sf.saxon.event.Receiver; import net.sf.saxon.om.*; import net.sf.saxon.pattern.NodeTest; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.Type; import javax.xml.transform.SourceLocator; import java.util.Iterator; import java.util.Collections; /** * This class represents a temporary tree whose root document node owns a single text node.
    */ public final class TextFragmentValue implements DocumentInfo, FingerprintedNode, SourceLocator { private CharSequence text; private String baseURI; private TextFragmentTextNode textNode = null; // created on demand private Configuration config; private int documentNumber; /** * Constructor: create a result tree fragment containing a single text node * @param value a String containing the value * @param baseURI the base URI of the document node */ public TextFragmentValue(CharSequence value, String baseURI) { this.text = value; this.baseURI = baseURI; } /** * Set the configuration (containing the name pool used for all names in this document) */ public void setConfiguration(Configuration config) { this.config = config; documentNumber = -1; // the document number is allocated lazily because it can cause // contention on the NamePool and is often not needed. } /** * Get the configuration previously set using setConfiguration * (or the default configuraton allocated automatically) */ public Configuration getConfiguration() { return config; } /** * Get the name pool used for the names in this document */ public NamePool getNamePool() { return config.getNamePool(); } /** * Get the unique document number */ public int getDocumentNumber() { if (documentNumber == -1) { documentNumber = config.getDocumentNumberAllocator().allocateDocumentNumber(); // technically this isn't thread-safe; however, TextFragmentValues are invariably used within // a single thread } return documentNumber; } /** * Return the type of node. * @return Type.DOCUMENT (always) */ public final int getNodeKind() { return Type.DOCUMENT; } /** * Get the String Value */ public String getStringValue() { return text.toString(); } /** * Get the value of the item as a CharSequence. This is in some cases more efficient than * the version of the method that returns a String. */ public CharSequence getStringValueCS() { return text; } /** * Determine whether this is the same node as another node * @return true if this Node object and the supplied Node object represent the * same node in the tree. */ public boolean isSameNodeInfo(NodeInfo other) { return this==other; } /** * Get a character string that uniquely identifies this node * @param buffer the buffer to contain the generated ID */ public void generateId(FastStringBuffer buffer) { buffer.append("tt"); buffer.append(Integer.toString(getDocumentNumber())); } /** * Set the system ID (that is, the document URI property) for the document node. * @throws UnsupportedOperationException (always). This kind of tree does not have a document URI. */ public void setSystemId(String systemId) { throw new UnsupportedOperationException("A temporary tree does not have a document URI"); } /** * Get the system ID (the document URI) of the document node. */ public String getSystemId() { return null; } /** * Get the base URI for the document node. */ public String getBaseURI() { return baseURI; } /** * Determine the relative position of this node and another node, in document order. * The other node will always be in the same document. * @param other The other node, whose position is to be compared with this node * @return -1 if this node precedes the other node, +1 if it follows the other * node, or 0 if they are the same node. (In this case, isSameNode() will always * return true, and the two nodes will produce the same result for generateId()) */ public int compareOrder(NodeInfo other) { if (this==other) return 0; return -1; } /** * Get the name code of the node, used for displaying names */ public int getNameCode() { return -1; } /** * Get the fingerprint of the node, used for matching names */ public int getFingerprint() { return -1; } /** * Get the prefix part of the name of this node. This is the name before the ":" if any. * @return the prefix part of the name. For an unnamed node, return "". */ public String getPrefix() { return ""; } /** * Get the URI part of the name of this node. This is the URI corresponding to the * prefix, or the URI of the default namespace if appropriate. * @return The URI of the namespace of this node. For an unnamed node, or for * an element or attribute in the default namespace, return an empty string. */ public String getURI() { return ""; } /** * Get the display name of this node. For elements and attributes this is [prefix:]localname. * For unnamed nodes, it is an empty string. * @return The display name of this node. * For a node with no name, return an empty string. */ public String getDisplayName() { return ""; } /** * Get the local name of this node. * @return The local name of this node. * For a node with no name, return "". */ public String getLocalPart() { return ""; } /** * Determine whether the node has any children. * @return true if this node has any attributes, * false otherwise. */ public boolean hasChildNodes() { return !("".equals(text)); } /** * Get line number * * @return the line number of the node in its original source document; or * -1 if not available */ public int getLineNumber() { return -1; } /** * Get the type annotation of this node, if any. * Returns -1 for kinds of nodes that have no annotation, and for elements annotated as * untyped, and attributes annotated as untypedAtomic. * * @return the type annotation of the node. * @see net.sf.saxon.type.Type */ public int getTypeAnnotation() { return -1; } /** * Get all namespace undeclarations and undeclarations defined on this element. * * @param buffer If this is non-null, and the result array fits in this buffer, then the result * may overwrite the contents of this array, to avoid the cost of allocating a new array on the heap. * @return An array of integers representing the namespace declarations and undeclarations present on * this element. For a node other than an element, return null. Otherwise, the returned array is a * sequence of namespace codes, whose meaning may be interpreted by reference to the name pool. The * top half word of each namespace code represents the prefix, the bottom half represents the URI. * If the bottom half is zero, then this is a namespace undeclaration rather than a declaration. * The XML namespace is never included in the list. If the supplied array is larger than required, * then the first unused entry will be set to -1. *

    *

    For a node other than an element, the method returns null.

    */ public int[] getDeclaredNamespaces(int[] buffer) { return null; } /** * Get the typed value of the item * * @return the typed value of the item. In general this will be a sequence */ public SequenceIterator getTypedValue() { return SingletonIterator.makeIterator(new UntypedAtomicValue(text)); } /** * Get the typed value. The result of this method will always be consistent with the method * {@link net.sf.saxon.om.Item#getTypedValue()}. However, this method is often more convenient and may be * more efficient, especially in the common case where the value is expected to be a singleton. * * @return the typed value. If requireSingleton is set to true, the result will always be an * AtomicValue. In other cases it may be a Value representing a sequence whose items are atomic * values. * @since 8.5 */ public Value atomize() { return new UntypedAtomicValue(text); } /** * Return the public identifier for the current document event. *

    *

    The return value is the public identifier of the document * entity or of the external parsed entity in which the markup that * triggered the event appears.

    * * @return A string containing the public identifier, or * null if none is available. * @see #getSystemId */ public String getPublicId() { return null; } /** * Return the character position where the current document event ends. *

    *

    Warning: The return value from the method * is intended only as an approximation for the sake of error * reporting; it is not intended to provide sufficient information * to edit the character content of the original XML document.

    *

    *

    The return value is an approximation of the column number * in the document entity or external parsed entity where the * markup that triggered the event appears.

    * * @return The column number, or -1 if none is available. * @see #getLineNumber */ public int getColumnNumber() { return -1; } /** * Get the value of a given attribute of this node * @param fingerprint The fingerprint of the attribute name * @return the attribute value if it exists or null if not */ public String getAttributeValue(int fingerprint) { return null; } /** * Return an iteration over the nodes reached by the given axis from this node * @param axisNumber The axis to be iterated over * @return a AxisIterator that scans the nodes reached by the axis in turn. * @see net.sf.saxon.om.Axis */ public AxisIterator iterateAxis(byte axisNumber) { switch (axisNumber) { case Axis.ANCESTOR: case Axis.ATTRIBUTE: case Axis.FOLLOWING: case Axis.FOLLOWING_SIBLING: case Axis.NAMESPACE: case Axis.PARENT: case Axis.PRECEDING: case Axis.PRECEDING_SIBLING: case Axis.PRECEDING_OR_ANCESTOR: return EmptyIterator.getInstance(); case Axis.SELF: case Axis.ANCESTOR_OR_SELF: return SingleNodeIterator.makeIterator(this); case Axis.CHILD: case Axis.DESCENDANT: return SingleNodeIterator.makeIterator(getTextNode()); case Axis.DESCENDANT_OR_SELF: NodeInfo[] nodes = {this, getTextNode()}; return new NodeArrayIterator(nodes); default: throw new IllegalArgumentException("Unknown axis number " + axisNumber); } } /** * Return an enumeration over the nodes reached by the given axis from this node * @param axisNumber The axis to be iterated over * @param nodeTest A pattern to be matched by the returned nodes * @return a AxisIterator that scans the nodes reached by the axis in turn. * @see net.sf.saxon.om.Axis */ public AxisIterator iterateAxis(byte axisNumber, NodeTest nodeTest) { switch (axisNumber) { case Axis.ANCESTOR: case Axis.ATTRIBUTE: case Axis.FOLLOWING: case Axis.FOLLOWING_SIBLING: case Axis.NAMESPACE: case Axis.PARENT: case Axis.PRECEDING: case Axis.PRECEDING_SIBLING: case Axis.PRECEDING_OR_ANCESTOR: return EmptyIterator.getInstance(); case Axis.SELF: case Axis.ANCESTOR_OR_SELF: return Navigator.filteredSingleton(this, nodeTest); case Axis.CHILD: case Axis.DESCENDANT: return Navigator.filteredSingleton(getTextNode(), nodeTest); case Axis.DESCENDANT_OR_SELF: boolean b1 = nodeTest.matches(this); NodeInfo textNode2 = getTextNode(); boolean b2 = nodeTest.matches(textNode2); if (b1) { if (b2) { NodeInfo[] pair = {this, textNode2}; return new NodeArrayIterator(pair); } else { return SingleNodeIterator.makeIterator(this); } } else { if (b2) { return SingleNodeIterator.makeIterator(textNode2); } else { return EmptyIterator.getInstance(); } } default: throw new IllegalArgumentException("Unknown axis number " + axisNumber); } } /** * Find the parent node of this node. * @return The Node object describing the containing element or root node. */ public NodeInfo getParent() { return null; } /** * Get the root node * @return the NodeInfo representing the root of this tree */ public NodeInfo getRoot() { return this; } /** * Get the root (document) node * @return the DocumentInfo representing the containing document */ public DocumentInfo getDocumentRoot() { return this; } /** * Copy the result tree fragment value to a given Outputter */ public void copy(Receiver out, int whichNamespaces, boolean copyAnnotations, int locationId) throws XPathException { out.characters(text, 0, 0); } /** * Get the element with a given ID. * @param id The unique ID of the required element * @return null (this kind of tree contains no elements) */ public NodeInfo selectID(String id) { return null; } /** * Get the list of unparsed entities defined in this document * @return an Iterator, whose items are of type String, containing the names of all * unparsed entities defined in this document. If there are no unparsed entities or if the * information is not available then an empty iterator is returned */ public Iterator getUnparsedEntityNames() { return Collections.EMPTY_LIST.iterator(); } /** * Get the unparsed entity with a given name * @param name the name of the entity * @return the URI and public ID of the entity if there is one, or null if not */ public String[] getUnparsedEntity(String name) { return null; } /** * Determine whether this node has the is-id property * * @return true if the node is an ID */ public boolean isId() { return false; } /** * Determine whether this node has the is-idref property * * @return true if the node is an IDREF or IDREFS element or attribute */ public boolean isIdref() { return false; } /** * Determine whether the node has the is-nilled property * * @return true if the node has the is-nilled property */ public boolean isNilled() { return false; } /** * Make an instance of the text node */ private TextFragmentTextNode getTextNode() { if (textNode==null) { textNode = new TextFragmentTextNode(); } return textNode; } /** * Inner class representing the text node; this is created on demand */ private class TextFragmentTextNode implements NodeInfo, FingerprintedNode, SourceLocator { /** * Set the system ID for the entity containing the node. */ public void setSystemId(String systemId) {} /** * Get the configuration */ public Configuration getConfiguration() { return config; } /** * Get the name pool for this node * @return the NamePool */ public NamePool getNamePool() { return config.getNamePool(); } /** * Return the type of node. * @return Type.TEXT (always) */ public final int getNodeKind() { return Type.TEXT; } /** * Get the String Value */ public String getStringValue() { return text.toString(); } /** * Get the value of the item as a CharSequence. This is in some cases more efficient than * the version of the method that returns a String. */ public CharSequence getStringValueCS() { return text; } /** * Determine whether this is the same node as another node * @return true if this Node object and the supplied Node object represent the * same node in the tree. */ public boolean isSameNodeInfo(NodeInfo other) { return this==other; } /** * Get a character string that uniquely identifies this node */ public void generateId(FastStringBuffer buffer) { buffer.append("tt"); buffer.append(Integer.toString(getDocumentNumber())); buffer.append("t1"); } /** * Get the system ID for the entity containing the node. */ public String getSystemId() { return null; } /** * Get the base URI for the node. Default implementation for child nodes gets * the base URI of the parent node. */ public String getBaseURI() { return baseURI; } /** * Determine the relative position of this node and another node, in document order. * The other node will always be in the same document. * @param other The other node, whose position is to be compared with this node * @return -1 if this node precedes the other node, +1 if it follows the other * node, or 0 if they are the same node. (In this case, isSameNode() will always * return true, and the two nodes will produce the same result for generateId()) */ public int compareOrder(NodeInfo other) { if (this==other) return 0; return +1; } /** * Get the name code of the node, used for displaying names */ public int getNameCode() { return -1; } /** * Get the fingerprint of the node, used for matching names */ public int getFingerprint() { return -1; } /** * Get the prefix part of the name of this node. This is the name before the ":" if any. * @return the prefix part of the name. For an unnamed node, return "". */ public String getPrefix() { return ""; } /** * Get the URI part of the name of this node. This is the URI corresponding to the * prefix, or the URI of the default namespace if appropriate. * @return The URI of the namespace of this node. For an unnamed node, or for * an element or attribute in the default namespace, return an empty string. */ public String getURI() { return ""; } /** * Get the display name of this node. For elements and attributes this is [prefix:]localname. * For unnamed nodes, it is an empty string. * @return The display name of this node. * For a node with no name, return an empty string. */ public String getDisplayName() { return ""; } /** * Get the local name of this node. * @return The local name of this node. * For a node with no name, return "". */ public String getLocalPart() { return ""; } /** * Determine whether the node has any children. * @return true if this node has any attributes, * false otherwise. */ public boolean hasChildNodes() { return false; } /** * Get the value of a given attribute of this node * @param fingerprint The fingerprint of the attribute name * @return the attribute value if it exists or null if not */ public String getAttributeValue(int fingerprint) { return null; } /** * Get line number * * @return the line number of the node in its original source document; or * -1 if not available */ public int getLineNumber() { return -1; } /** * Get the type annotation of this node, if any. *

    The result is undefined for nodes other than elements and attributes.

    * * @return the type annotation of the node. * @see net.sf.saxon.type.Type */ public int getTypeAnnotation() { return -1; } /** * Get the document number of the document containing this node. For a free-standing * orphan node, just return the hashcode. */ public int getDocumentNumber() { return getDocumentRoot().getDocumentNumber(); } /** * Get all namespace undeclarations and undeclarations defined on this element. * * @param buffer If this is non-null, and the result array fits in this buffer, then the result * may overwrite the contents of this array, to avoid the cost of allocating a new array on the heap. * @return An array of integers representing the namespace declarations and undeclarations present on * this element. For a node other than an element, return null. Otherwise, the returned array is a * sequence of namespace codes, whose meaning may be interpreted by reference to the name pool. The * top half word of each namespace code represents the prefix, the bottom half represents the URI. * If the bottom half is zero, then this is a namespace undeclaration rather than a declaration. * The XML namespace is never included in the list. If the supplied array is larger than required, * then the first unused entry will be set to -1. *

    *

    For a node other than an element, the method returns null.

    */ public int[] getDeclaredNamespaces(int[] buffer) { return null; } /** * Get the typed value of the item * * @return the typed value of the item. In general this will be a sequence * @throws net.sf.saxon.trans.XPathException * where no typed value is available, e.g. for * an element with complex content */ public SequenceIterator getTypedValue() throws XPathException { return SingletonIterator.makeIterator(new UntypedAtomicValue(text)); } /** * Get the typed value. The result of this method will always be consistent with the method * {@link net.sf.saxon.om.Item#getTypedValue()}. However, this method is often more convenient and may be * more efficient, especially in the common case where the value is expected to be a singleton. * * @return the typed value. If requireSingleton is set to true, the result will always be an * AtomicValue. In other cases it may be a Value representing a sequence whose items are atomic * values. * @since 8.5 */ public Value atomize() throws XPathException { return new UntypedAtomicValue(text); } /** * Return the public identifier for the current document event. *

    *

    The return value is the public identifier of the document * entity or of the external parsed entity in which the markup that * triggered the event appears.

    * * @return A string containing the public identifier, or * null if none is available. * @see #getSystemId */ public String getPublicId() { return null; } /** * Return the character position where the current document event ends. *

    *

    Warning: The return value from the method * is intended only as an approximation for the sake of error * reporting; it is not intended to provide sufficient information * to edit the character content of the original XML document.

    *

    *

    The return value is an approximation of the column number * in the document entity or external parsed entity where the * markup that triggered the event appears.

    * * @return The column number, or -1 if none is available. * @see #getLineNumber */ public int getColumnNumber() { return -1; } /** * Return an enumeration over the nodes reached by the given axis from this node * @param axisNumber the axis to be iterated over * @return a AxisIterator that scans the nodes reached by the axis in turn. */ public AxisIterator iterateAxis(byte axisNumber) { switch (axisNumber) { case Axis.ANCESTOR: case Axis.PARENT: case Axis.PRECEDING_OR_ANCESTOR: return SingleNodeIterator.makeIterator(TextFragmentValue.this); case Axis.ANCESTOR_OR_SELF: NodeInfo[] nodes = {this, TextFragmentValue.this}; return new NodeArrayIterator(nodes); case Axis.ATTRIBUTE: case Axis.CHILD: case Axis.DESCENDANT: case Axis.FOLLOWING: case Axis.FOLLOWING_SIBLING: case Axis.NAMESPACE: case Axis.PRECEDING: case Axis.PRECEDING_SIBLING: return EmptyIterator.getInstance(); case Axis.SELF: case Axis.DESCENDANT_OR_SELF: return SingleNodeIterator.makeIterator(this); default: throw new IllegalArgumentException("Unknown axis number " + axisNumber); } } /** * Return an enumeration over the nodes reached by the given axis from this node * @param axisNumber the axis to be iterated over * @param nodeTest A pattern to be matched by the returned nodes * @return a AxisIterator that scans the nodes reached by the axis in turn. */ public AxisIterator iterateAxis( byte axisNumber, NodeTest nodeTest) { switch (axisNumber) { case Axis.ANCESTOR: case Axis.PARENT: case Axis.PRECEDING_OR_ANCESTOR: return Navigator.filteredSingleton(TextFragmentValue.this, nodeTest); case Axis.ANCESTOR_OR_SELF: boolean matchesDoc = nodeTest.matches(TextFragmentValue.this); boolean matchesText = nodeTest.matches(this); if (matchesDoc && matchesText) { NodeInfo[] nodes = {this, TextFragmentValue.this}; return new NodeArrayIterator(nodes); } else if (matchesDoc && !matchesText) { return SingleNodeIterator.makeIterator(TextFragmentValue.this); } else if (matchesText && !matchesDoc) { return SingleNodeIterator.makeIterator(this); } else { return EmptyIterator.getInstance(); } case Axis.ATTRIBUTE: case Axis.CHILD: case Axis.DESCENDANT: case Axis.FOLLOWING: case Axis.FOLLOWING_SIBLING: case Axis.NAMESPACE: case Axis.PRECEDING: case Axis.PRECEDING_SIBLING: return EmptyIterator.getInstance(); case Axis.SELF: case Axis.DESCENDANT_OR_SELF: return Navigator.filteredSingleton(this, nodeTest); default: throw new IllegalArgumentException("Unknown axis number " + axisNumber); } } /** * Find the parent node of this node. * @return The Node object describing the containing element or root node. */ public NodeInfo getParent() { return TextFragmentValue.this; } /** * Get the root node * @return the NodeInfo representing the root of this tree */ public NodeInfo getRoot() { return TextFragmentValue.this; } /** * Get the root (document) node * @return the DocumentInfo representing the containing document */ public DocumentInfo getDocumentRoot() { return TextFragmentValue.this; } /** * Copy the node to a given Outputter */ public void copy(Receiver out, int namespaces, boolean copyAnnotations, int locationId) throws XPathException { out.characters(text, 0, 0); } /** * Determine whether this node has the is-id property * * @return true if the node is an ID */ public boolean isId() { return false; } /** * Determine whether this node has the is-idref property * * @return true if the node is an IDREF or IDREFS element or attribute */ public boolean isIdref() { return false; } /** * Determine whether the node has the is-nilled property * * @return true if the node has the is-nilled property */ public boolean isNilled() { return false; } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/value/UntypedAtomicValue.java0000644000175000017500000002540411033112257023145 0ustar eugeneeugenepackage net.sf.saxon.value; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.StandardNames; import net.sf.saxon.sort.CodepointCollator; import net.sf.saxon.sort.StringCollator; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.*; /** * An Untyped Atomic value. This inherits from StringValue for implementation convenience, even * though an untypedAtomic value is not a String in the data model type hierarchy. */ public class UntypedAtomicValue extends StringValue { public static final UntypedAtomicValue ZERO_LENGTH_UNTYPED = new UntypedAtomicValue(""); // If the value is used once as a number, it's likely that it will be used // repeatedly as a number, so we cache the result of conversion DoubleValue doubleValue = null; /** * Constructor * @param value the String value. Null is taken as equivalent to "". */ public UntypedAtomicValue(CharSequence value) { this.value = (value==null ? "" : value); typeLabel = BuiltInAtomicType.UNTYPED_ATOMIC; } /** * Create a copy of this atomic value, with a different type label * * @param typeLabel the type label of the new copy. The caller is responsible for checking that * the value actually conforms to this type. */ public AtomicValue copyAsSubType(AtomicType typeLabel) { UntypedAtomicValue v = new UntypedAtomicValue(value); v.length = length; v.doubleValue = doubleValue; v.typeLabel = typeLabel; return v; } /** * Determine the primitive type of the value. This delivers the same answer as * getItemType().getPrimitiveItemType(). The primitive types are * the 19 primitive types of XML Schema, plus xs:integer, xs:dayTimeDuration and xs:yearMonthDuration, * and xs:untypedAtomic. For external objects, the result is AnyAtomicType. */ public BuiltInAtomicType getPrimitiveType() { return BuiltInAtomicType.UNTYPED_ATOMIC; } /** * Convert to target data type */ public ConversionResult convertPrimitive(BuiltInAtomicType requiredType, boolean validate, XPathContext context) { int req = requiredType.getFingerprint(); if (req== StandardNames.XS_STRING) { if (value.length() == 0) { // this case is common! return StringValue.EMPTY_STRING; } else { return new StringValue(value); } } else if (req== StandardNames.XS_UNTYPED_ATOMIC) { return this; } else if (req== StandardNames.XS_DOUBLE || req== StandardNames.XS_NUMERIC) { // for conversion to double (common in 1.0 mode), cache the result try { return toDouble(); } catch (ValidationException e) { return new ValidationFailure(e); } } else { return super.convertPrimitive(requiredType, validate, context); } } /** * Convert the value to a double, returning a DoubleValue */ private AtomicValue toDouble() throws ValidationException { if (doubleValue == null) { doubleValue = new DoubleValue(value); } return doubleValue; } /** * Compare an untypedAtomic value with another value, using a given collator to perform * any string comparisons. This works by converting the untypedAtomic value to the type * of the other operand, which is the correct behavior for operators like "=" and "!=", * but not for "eq" and "ne": in the latter case, the untypedAtomic value is converted * to a string and this method is therefore not used. * @return -1 if the this value is less than the other, 0 if they are equal, +1 if this * value is greater. * @throws ClassCastException if the value cannot be cast to the type of the other operand */ public int compareTo(AtomicValue other, StringCollator collator, XPathContext context) { if (other instanceof NumericValue) { if (doubleValue == null) { try { doubleValue = (DoubleValue)convertPrimitive(BuiltInAtomicType.DOUBLE, true, context).asAtomic(); } catch (XPathException err) { throw new ClassCastException("Cannot convert untyped value " + '\"' + getStringValueCS() + "\" to a double"); } } return doubleValue.compareTo(other); } else if (other instanceof StringValue) { if (collator instanceof CodepointCollator) { // This optimization avoids creating String objects for the purpose of the comparison return ((CodepointCollator)collator).compareCS(getStringValueCS(), other.getStringValueCS()); } else { return collator.compareStrings(getStringValue(), other.getStringValue()); } } else { final TypeHierarchy th = context.getConfiguration().getTypeHierarchy(); ConversionResult result = convert((AtomicType)other.getItemType(th), true, context); if (result instanceof ValidationFailure) { throw new ClassCastException("Cannot convert untyped atomic value '" + getStringValue() + "' to type " + other.getItemType(th)); } return ((Comparable)((AtomicValue)result)).compareTo(other); } } /** * Convert to Java object (for passing to external functions) */ // public Object convertAtomicToJava(Class target, XPathContext context) throws XPathException { // if (target == Object.class) { // return getStringValue(); // } else if (target.isAssignableFrom(StringValue.class)) { // return this; // } else if (target == String.class || target == CharSequence.class) { // return getStringValue(); // } else if (target == boolean.class) { // BooleanValue bval = (BooleanValue)convertPrimitive(BuiltInAtomicType.BOOLEAN, true, context).asAtomic(); // return Boolean.valueOf(bval.getBooleanValue()); // } else if (target == Boolean.class) { // BooleanValue bval = (BooleanValue)convertPrimitive(BuiltInAtomicType.BOOLEAN, true, context).asAtomic(); // return Boolean.valueOf(bval.getBooleanValue()); // } else if (target == double.class) { // DoubleValue dval = (DoubleValue)convertPrimitive(BuiltInAtomicType.DOUBLE, true, context).asAtomic(); // return new Double(dval.getDoubleValue()); // } else if (target == Double.class) { // DoubleValue dval = (DoubleValue)convertPrimitive(BuiltInAtomicType.DOUBLE, true, context).asAtomic(); // return new Double(dval.getDoubleValue()); // } else if (target == float.class) { // DoubleValue dval = (DoubleValue)convertPrimitive(BuiltInAtomicType.DOUBLE, true, context).asAtomic(); // return new Float(dval.getDoubleValue()); // } else if (target == Float.class) { // DoubleValue dval = (DoubleValue)convertPrimitive(BuiltInAtomicType.DOUBLE, true, context).asAtomic(); // return new Float(dval.getDoubleValue()); // } else if (target == long.class) { // Int64Value dval = (Int64Value)convertPrimitive(BuiltInAtomicType.INTEGER, true, context).asAtomic(); // return new Long(dval.longValue()); // } else if (target == Long.class) { // Int64Value dval = (Int64Value)convertPrimitive(BuiltInAtomicType.INTEGER, true, context).asAtomic(); // return new Long(dval.longValue()); // } else if (target == int.class) { // Int64Value dval = (Int64Value)convertPrimitive(BuiltInAtomicType.INTEGER, true, context).asAtomic(); // return new Integer((int) dval.longValue()); // } else if (target == Integer.class) { // Int64Value dval = (Int64Value)convertPrimitive(BuiltInAtomicType.INTEGER, true, context).asAtomic(); // return new Integer((int) dval.longValue()); // } else if (target == short.class) { // Int64Value dval = (Int64Value)convertPrimitive(BuiltInAtomicType.INTEGER, true, context).asAtomic(); // return new Short((short) dval.longValue()); // } else if (target == Short.class) { // Int64Value dval = (Int64Value)convertPrimitive(BuiltInAtomicType.INTEGER, true, context).asAtomic(); // return new Short((short) dval.longValue()); // } else if (target == byte.class) { // Int64Value dval = (Int64Value)convertPrimitive(BuiltInAtomicType.INTEGER, true, context).asAtomic(); // return new Byte((byte) dval.longValue()); // } else if (target == Byte.class) { // Int64Value dval = (Int64Value)convertPrimitive(BuiltInAtomicType.INTEGER, true, context).asAtomic(); // return new Byte((byte) dval.longValue()); // } else if (target == char.class || target == Character.class) { // if (value.length() == 1) { // return new Character(value.charAt(0)); // } else { // XPathException de = new XPathException("Cannot convert xs:string to Java char unless length is 1"); // de.setXPathContext(context); // de.setErrorCode(SaxonErrorCode.SXJE0005); // throw de; // } // } else { // Object o = super.convertSequenceToJava(target, context); // if (o == null) { // XPathException err = new XPathException("Conversion of xs:untypedAtomic to " + target.getName() + " is not supported"); // err.setXPathContext(context); // err.setErrorCode(SaxonErrorCode.SXJE0006); // throw err; // } // return o; // } // } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/value/GMonthValue.java0000644000175000017500000001235211033112257021552 0ustar eugeneeugenepackage net.sf.saxon.value; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.FastStringBuffer; import net.sf.saxon.om.StandardNames; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.*; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Implementation of the xs:gMonth data type */ public class GMonthValue extends GDateValue { private static Pattern regex = Pattern.compile("--([0-9][0-9])(--)?(Z|[+-][0-9][0-9]:[0-9][0-9])?"); // this tolerates the bogus format --MM-- which was wrongly permitted by the original schema spec private GMonthValue(){} public static ConversionResult makeGMonthValue(CharSequence value) { GMonthValue g = new GMonthValue(); Matcher m = regex.matcher(Whitespace.trimWhitespace(value)); if (!m.matches()) { return new ValidationFailure("Cannot convert '" + value + "' to a gMonth"); } String base = m.group(1); String tz = m.group(3); String date = "2000-" + base + "-01" + (tz==null ? "" : tz); g.typeLabel = BuiltInAtomicType.G_MONTH; return setLexicalValue(g, date); } public GMonthValue(byte month, int tz) { this(month, tz, BuiltInAtomicType.G_MONTH); } public GMonthValue(byte month, int tz, AtomicType type) { this.year = 2000; this.month = month; this.day = 1; setTimezoneInMinutes(tz); this.typeLabel = type; } /** * Make a copy of this date, time, or dateTime value * @param typeLabel */ public AtomicValue copyAsSubType(AtomicType typeLabel) { GMonthValue v = new GMonthValue(month, getTimezoneInMinutes()); v.typeLabel = typeLabel; return v; } /** * Determine the primitive type of the value. This delivers the same answer as * getItemType().getPrimitiveItemType(). The primitive types are * the 19 primitive types of XML Schema, plus xs:integer, xs:dayTimeDuration and xs:yearMonthDuration, * and xs:untypedAtomic. For external objects, the result is AnyAtomicType. */ public BuiltInAtomicType getPrimitiveType() { return BuiltInAtomicType.G_MONTH; } /** * Convert to target data type * @param requiredType an integer identifying the required atomic type * @param context * @return an AtomicValue, a value of the required type; or an ErrorValue */ public ConversionResult convertPrimitive(BuiltInAtomicType requiredType, boolean validate, XPathContext context) { switch(requiredType.getPrimitiveType()) { case StandardNames.XS_G_MONTH: case StandardNames.XS_ANY_ATOMIC_TYPE: return this; case StandardNames.XS_STRING: return new StringValue(getStringValueCS()); case StandardNames.XS_UNTYPED_ATOMIC: return new UntypedAtomicValue(getStringValueCS()); default: ValidationFailure err = new ValidationFailure("Cannot convert gMonth to " + requiredType.getDisplayName()); err.setErrorCode("XPTY0004"); return err; } } public CharSequence getStringValueCS() { FastStringBuffer sb = new FastStringBuffer(16); sb.append("--"); appendTwoDigits(sb, month); if (hasTimezone()) { appendTimezone(sb); } return sb; } /** * Add a duration to this date/time value * * @param duration the duration to be added (which might be negative) * @return a new date/time value representing the result of adding the duration. The original * object is not modified. * @throws net.sf.saxon.trans.XPathException * */ public CalendarValue add(DurationValue duration) throws XPathException { XPathException err = new XPathException("Cannot add a duration to an xs:gMonth"); err.setErrorCode("XPTY0004"); throw err; } /** * Return a new date, time, or dateTime with the same normalized value, but * in a different timezone * * @param tz the new timezone, in minutes * @return the date/time in the new timezone */ public CalendarValue adjustTimezone(int tz) { DateTimeValue dt = (DateTimeValue)toDateTime().adjustTimezone(tz); return new GMonthValue(dt.getMonth(), dt.getTimezoneInMinutes()); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Saxonica Limited // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none //saxonb-9.1.0.8/bj/net/sf/saxon/value/HexBinaryValue.java0000644000175000017500000002532011033112257022246 0ustar eugeneeugenepackage net.sf.saxon.value; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.FastStringBuffer; import net.sf.saxon.om.StandardNames; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.AtomicType; import net.sf.saxon.type.BuiltInAtomicType; import net.sf.saxon.type.ConversionResult; import net.sf.saxon.type.ValidationFailure; import net.sf.saxon.sort.StringCollator; import java.util.Arrays; /** * A value of type xs:hexBinary */ public class HexBinaryValue extends AtomicValue { private byte[] binaryValue; /** * Constructor: create a hexBinary value from a supplied string, in which * each octet is represented by a pair of values from 0-9, a-f, A-F * * @param in character representation of the hexBinary value */ public HexBinaryValue(CharSequence in) throws XPathException { CharSequence s = Whitespace.trimWhitespace(in); if ((s.length() & 1) != 0) { XPathException err = new XPathException("A hexBinary value must contain an even number of characters"); err.setErrorCode("FORG0001"); throw err; } binaryValue = new byte[s.length() / 2]; for (int i = 0; i < binaryValue.length; i++) { binaryValue[i] = (byte)((fromHex(s.charAt(2 * i)) << 4) + (fromHex(s.charAt(2 * i + 1)))); } typeLabel = BuiltInAtomicType.HEX_BINARY; } /** * Constructor: create a HexBinary value from a supplied string in hexBinary encoding, * with a specified type. This method throws no checked exceptions; the caller is expected * to ensure that the string is a valid Base64 lexical representation, that it conforms * to the specified type, and that the type is indeed a subtype of xs:base64Binary. * An unchecked exception such as an IllegalArgumentException may be thrown if these * conditions are not satisfied, but this is not guaranteed. * * @param s the value in hexBinary encoding, with no leading or trailing whitespace * @param type the atomic type. This must be xs:base64binary or a subtype. */ public HexBinaryValue(CharSequence s, AtomicType type) { if ((s.length() & 1) != 0) { throw new IllegalArgumentException( "A hexBinary value must contain an even number of characters"); } binaryValue = new byte[s.length() / 2]; try { for (int i = 0; i < binaryValue.length; i++) { binaryValue[i] = (byte)((fromHex(s.charAt(2 * i)) << 4) + (fromHex(s.charAt(2 * i + 1)))); } } catch (XPathException e) { throw new IllegalArgumentException(e.getMessage()); } typeLabel = type; } /** * Constructor: create a hexBinary value from a given array of bytes * * @param value the value as an array of bytes */ public HexBinaryValue(byte[] value) { binaryValue = value; typeLabel = BuiltInAtomicType.HEX_BINARY; } /** * Create a primitive copy of this atomic value (usually so that the type label can be changed). * * @param typeLabel the target type (a derived type from hexBinary) */ public AtomicValue copyAsSubType(AtomicType typeLabel) { HexBinaryValue v = new HexBinaryValue(binaryValue); v.typeLabel = typeLabel; return v; } /** * Determine the primitive type of the value. This delivers the same answer as * getItemType().getPrimitiveItemType(). The primitive types are * the 19 primitive types of XML Schema, plus xs:integer, xs:dayTimeDuration and xs:yearMonthDuration, * and xs:untypedAtomic. For external objects, the result is AnyAtomicType. */ public BuiltInAtomicType getPrimitiveType() { return BuiltInAtomicType.HEX_BINARY; } /** * Get the binary value * * @return the binary value, as a byte array */ public byte[] getBinaryValue() { return binaryValue; } /** * Decode a single hex digit * * @param c the hex digit * @return the numeric value of the hex digit * @throws XPathException if it isn't a hex digit */ private int fromHex(char c) throws XPathException { int d = "0123456789ABCDEFabcdef".indexOf(c); if (d > 15) { d = d - 6; } if (d < 0) { XPathException err = new XPathException("Invalid hexadecimal digit"); err.setErrorCode("FORG0001"); throw err; } return d; } /** * Convert to target data type * * @param requiredType an integer identifying the required atomic type * @param context XPath dynamic evaluation context * @return an AtomicValue, a value of the required type; or an ErrorValue */ public ConversionResult convertPrimitive(BuiltInAtomicType requiredType, boolean validate, XPathContext context) { switch (requiredType.getPrimitiveType()) { case StandardNames.XS_HEX_BINARY: case StandardNames.XS_ANY_ATOMIC_TYPE: return this; case StandardNames.XS_STRING: return new StringValue(getStringValueCS()); case StandardNames.XS_UNTYPED_ATOMIC: return new UntypedAtomicValue(getStringValueCS()); case StandardNames.XS_BASE64_BINARY: return new Base64BinaryValue(binaryValue); default: ValidationFailure err = new ValidationFailure("Cannot convert hexBinarry to " + requiredType.getDisplayName()); err.setErrorCode("XPTY0004"); return err; } } /** * Convert to string * * @return the canonical representation. */ public String getStringValue() { String digits = "0123456789ABCDEF"; FastStringBuffer sb = new FastStringBuffer(binaryValue.length * 2); for (int i = 0; i < binaryValue.length; i++) { sb.append(digits.charAt((binaryValue[i] >> 4) & 0xf)); sb.append(digits.charAt(binaryValue[i] & 0xf)); } return sb.toString(); } /** * Get the number of octets in the value * * @return the number of octets (bytes) in the value */ public int getLengthInOctets() { return binaryValue.length; } /** * Convert to Java object (for passing to external functions) */ // public Object convertAtomicToJava(Class target, XPathContext context) throws XPathException { // // if (target.isAssignableFrom(HexBinaryValue.class)) { // return this; // } else if (target == Object.class) { // return getStringValue(); // } else { // Object o = super.convertSequenceToJava(target, context); // if (o == null) { // throw new XPathException("Conversion of hexBinary to " + target.getName() + // " is not supported"); // } // return o; // } // } /** * Support XML Schema comparison semantics */ public Comparable getSchemaComparable() { return new HexBinaryComparable(); } private class HexBinaryComparable implements Comparable { public HexBinaryValue getHexBinaryValue() { return HexBinaryValue.this; } public int compareTo(Object o) { if (o instanceof HexBinaryComparable && Arrays.equals(getHexBinaryValue().binaryValue, ((HexBinaryComparable)o).getHexBinaryValue().binaryValue)) { return 0; } else { return INDETERMINATE_ORDERING; } } public boolean equals(Object o) { return compareTo(o) == 0; } public int hashCode() { return HexBinaryValue.this.hashCode(); } } /** * Get an object value that implements the XPath equality and ordering comparison semantics for this value. * If the ordered parameter is set to true, the result will be a Comparable and will support a compareTo() * method with the semantics of the XPath lt/gt operator, provided that the other operand is also obtained * using the getXPathComparable() method. In all cases the result will support equals() and hashCode() methods * that support the semantics of the XPath eq operator, again provided that the other operand is also obtained * using the getXPathComparable() method. A context argument is supplied for use in cases where the comparison * semantics are context-sensitive, for example where they depend on the implicit timezone or the default * collation. * * @param ordered true if an ordered comparison is required. In this case the result is null if the * type is unordered; in other cases the returned value will be a Comparable. * @param collator *@param context the XPath dynamic evaluation context, used in cases where the comparison is context * sensitive @return an Object whose equals() and hashCode() methods implement the XPath comparison semantics * with respect to this atomic value. If ordered is specified, the result will either be null if * no ordering is defined, or will be a Comparable */ public Object getXPathComparable(boolean ordered, StringCollator collator, XPathContext context) { return (ordered ? null : this); } /** * Test if the two hexBinary or Base64Binaryvalues are equal. */ public boolean equals(Object other) { return Arrays.equals(binaryValue, ((HexBinaryValue)other).binaryValue); } public int hashCode() { return Base64BinaryValue.byteArrayHashCode(binaryValue); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay, Saxonica. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/value/NumericValue.java0000644000175000017500000002472011033112257021762 0ustar eugeneeugenepackage net.sf.saxon.value; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.*; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.sort.StringCollator; import java.math.BigDecimal; /** * NumericValue is an abstract superclass for IntegerValue, DecimalValue, * FloatValue, and DoubleValue */ public abstract class NumericValue extends AtomicValue implements Comparable { /** * Get a numeric value by parsing a string; the type of numeric value depends * on the lexical form of the string, following the rules for XPath numeric * literals. * @param in the input string * @return a NumericValue representing the value of the string. Returns Double.NaN if the * value cannot be parsed as a string. */ public static NumericValue parseNumber(String in) { if (in.indexOf('e') >= 0 || in.indexOf('E') >= 0) { try { return new DoubleValue(Double.parseDouble(in)); } catch (NumberFormatException e) { return DoubleValue.NaN; } } else if (in.indexOf('.') >= 0) { ConversionResult v = DecimalValue.makeDecimalValue(in, true); if (v instanceof ValidationFailure) { return DoubleValue.NaN; } else { return (NumericValue)v; } } else { ConversionResult v = Int64Value.stringToInteger(in); if (v instanceof ValidationFailure) { return DoubleValue.NaN; } else { return (NumericValue)v; } } } /** * Get the numeric value as a double * * @return A double representing this numeric value; NaN if it cannot be * converted */ public double getDoubleValue() { try { return ((DoubleValue)convertPrimitive(BuiltInAtomicType.DOUBLE, true, null).asAtomic()).getDoubleValue(); } catch (XPathException err) { return Double.NaN; } } /** * Get the numeric value converted to a float * @return a float representing this numeric value; NaN if it cannot be converted */ public float getFloatValue() { try { return ((FloatValue)convertPrimitive(BuiltInAtomicType.FLOAT, true, null).asAtomic()).getFloatValue(); } catch (XPathException err) { return Float.NaN; } } /** * Get the numeric value converted to a decimal * @return a decimal representing this numeric value; * @throws XPathException if the value cannot be converted, for example if it is NaN or infinite */ public BigDecimal getDecimalValue() throws XPathException { return ((DecimalValue)convertPrimitive(BuiltInAtomicType.DECIMAL, true, null).asAtomic()).getDecimalValue(); } /** * Test whether a value is an integer (an instance of a subtype of xs:integer) * @param value the value being tested * @return true if the value is an instance of xs:integer or a type derived therefrom */ public static boolean isInteger(AtomicValue value) { return (value instanceof IntegerValue); } /** * Return the numeric value as a Java long. * * @exception net.sf.saxon.trans.XPathException if the value cannot be converted * @return the numeric value as a Java long. This performs truncation * towards zero. */ public long longValue() throws XPathException { return ((Int64Value)convertPrimitive(BuiltInAtomicType.INTEGER, true, null).asAtomic()).longValue(); } /** * Change the sign of the number * * @return a value, of the same type as the original, with its sign * inverted */ public abstract NumericValue negate(); /** * Implement the XPath floor() function * * @return a value, of the same type as that supplied, rounded towards * minus infinity */ public abstract NumericValue floor(); /** * Implement the XPath ceiling() function * * @return a value, of the same type as that supplied, rounded towards * plus infinity */ public abstract NumericValue ceiling(); /** * Implement the XPath round() function * * @return a value, of the same type as that supplied, rounded towards the * nearest whole number (0.5 rounded up) */ public abstract NumericValue round(); /** * Implement the XPath 2.0 round-half-to-even() function * * @param scale the decimal position for rounding: e.g. 2 rounds to a * multiple of 0.01, while -2 rounds to a multiple of 100 * @return a value, of the same type as the original, rounded towards the * nearest multiple of 10**(-scale), with rounding towards the nearest * even number if two values are equally near */ public abstract NumericValue roundHalfToEven(int scale); /** * Determine whether the value is negative, zero, or positive * @return -1 if negative, 0 if zero (including negative zero), +1 if positive, NaN if NaN */ public abstract double signum(); /** * Determine whether the value is a whole number, that is, whether it compares * equal to some integer * * @return true if the value is a whole number */ public abstract boolean isWholeNumber(); /** * Get a Comparable value that implements the XPath ordering comparison semantics for this value. * Returns null if the value is not comparable according to XPath rules. The default implementation * returns null. This is overridden for types that allow ordered comparisons in XPath: numeric, boolean, * string, date, time, dateTime, yearMonthDuration, dayTimeDuration, and anyURI. * @param ordered * @param collator * @param context */ public Object getXPathComparable(boolean ordered, StringCollator collator, XPathContext context) { return this; } /** * Compare the value to another numeric value * * @exception ClassCastException if the other value is not a NumericValue * (the parameter is declared as Object to satisfy the Comparable * interface) * @param other The other numeric value * @return -1 if this one is the lower, 0 if they are numerically equal, * +1 if this one is the higher, or if either value is NaN. Where NaN values are * involved, they should be handled by the caller before invoking this method. */ // This is the default implementation. Subclasses of number avoid the conversion to double // when comparing with another number of the same type. public int compareTo(Object other) { double a = getDoubleValue(); double b = ((NumericValue)other).getDoubleValue(); if (a == b) return 0; if (a < b) return -1; return +1; } /** * Compare the value to a long * @param other the value to be compared with * @return -1 if this is less, 0 if this is equal, +1 if this is greater or if this is NaN */ public abstract int compareTo(long other); /** * The equals() function compares numeric equality among integers, decimals, floats, doubles, and * their subtypes * * @param other the value to be compared with this one * @return true if the two values are numerically equal */ public final boolean equals(Object other) { return compareTo(other) == 0; } /** * Identify lowest common supertype of two numeric values for promotion purposes * * @param v1 the item type of the first operand * @param v2 the item type of the second operand * @param typeHierarchy the type hierarchy cache * @return the item type that should be used for arithmetic between * operands of the two specified item types */ public static ItemType promote(ItemType v1, ItemType v2, TypeHierarchy typeHierarchy) { ItemType t1 = (typeHierarchy.isSubType(v1, BuiltInAtomicType.NUMERIC) ? v1 : BuiltInAtomicType.DOUBLE); ItemType t2 = (typeHierarchy.isSubType(v2, BuiltInAtomicType.NUMERIC) ? v2 : BuiltInAtomicType.DOUBLE); if (t1 == t2) return t1; if (t1.equals(BuiltInAtomicType.DOUBLE) || t2.equals(BuiltInAtomicType.DOUBLE)) { return BuiltInAtomicType.DOUBLE; } if (t1.equals(BuiltInAtomicType.FLOAT) || t2.equals(BuiltInAtomicType.FLOAT)) { return BuiltInAtomicType.FLOAT; } if (t1.equals(BuiltInAtomicType.DECIMAL) || t2.equals(BuiltInAtomicType.DECIMAL)) { return BuiltInAtomicType.DECIMAL; } return BuiltInAtomicType.INTEGER; } /** * hashCode() must be the same for two values that are equal. One * way to ensure this is to convert the value to a double, and take the * hashCode of the double. But this is expensive in the common case where * we are comparing integers. So we adopt the rule: for values that are in * the range of a Java Integer, we use the int value as the hashcode. For * values outside that range, we convert to a double and take the hashCode of * the double. This method needs to have a compatible implementation in * each subclass. * * @return the hash code of the numeric value */ public abstract int hashCode(); /** * Produce a string representation of the value * @return The result of casting the number to a string */ public String toString() { return getStringValue(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Saxonica Limited // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none //saxonb-9.1.0.8/bj/net/sf/saxon/value/QualifiedNameValue.java0000644000175000017500000001755011033112257023067 0ustar eugeneeugenepackage net.sf.saxon.value; import net.sf.saxon.Configuration; import net.sf.saxon.sort.StringCollator; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.NamePool; import net.sf.saxon.om.StandardNames; import net.sf.saxon.om.StructuredQName; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.AtomicType; import net.sf.saxon.type.BuiltInAtomicType; import net.sf.saxon.type.ValidationFailure; /** * A qualified name: this is an abstract superclass for QNameValue and NotationValue, representing the * XPath primitive types xs:QName and xs:NOTATION respectively */ public abstract class QualifiedNameValue extends AtomicValue { protected StructuredQName qName; /** * Factory method to construct either a QName or a NOTATION value, or a subtype of either of these. * Note that it is the caller's responsibility to resolve the QName prefix into a URI * @param prefix the prefix part of the value. Use "" or null for the empty prefix. * @param uri the namespace URI part of the value. Use "" or null for the non-namespace * @param local the local part of the value * @param targetType the target type, which must be xs:QName or a subtype of xs:NOTATION or xs:QName * @param lexicalForm the original lexical form of the value. This is needed in case there are facets * such as pattern that check the lexical form * @param config the Saxon configuration * @return the converted value * @throws XPathException if the value cannot be converted. */ public static AtomicValue makeQName(String prefix, String uri, String local, AtomicType targetType, CharSequence lexicalForm, Configuration config) throws XPathException { if (targetType.getFingerprint() == StandardNames.XS_QNAME) { return new QNameValue(prefix, uri, local, BuiltInAtomicType.QNAME, null); } else { QualifiedNameValue qnv; if (config.getTypeHierarchy().isSubType(targetType, BuiltInAtomicType.QNAME)) { qnv = new QNameValue(prefix, uri, local, targetType, null); } else { qnv = new NotationValue(prefix, uri, local, (AtomicType)null); } ValidationFailure vf = targetType.validate(qnv, lexicalForm, config.getNameChecker()); if (vf != null) { throw vf.makeException(); } qnv.setTypeLabel(targetType); return qnv; } } /** * Get the string value as a String. Returns the QName as a lexical QName, retaining the original * prefix if available. */ public final String getStringValue() { return qName.getDisplayName(); } /** * Get the name in Clark notation, that is "{uri}local" if in a namespace, or "local" otherwise */ public final String getClarkName() { return qName.getClarkName(); } /** * Get the local part */ public final String getLocalName() { return qName.getLocalName(); } /** * Get the namespace part. Returns the empty string for a name in no namespace. */ public final String getNamespaceURI() { return qName.getNamespaceURI(); } /** * Get the prefix. Returns the empty string if the name is unprefixed. */ public final String getPrefix() { return qName.getPrefix(); } /** * Allocate a nameCode for this QName in the NamePool * @param pool the NamePool to be used * @return the allocated nameCode */ public int allocateNameCode(NamePool pool) { return pool.allocate(getPrefix(), getNamespaceURI(), getLocalName()); } /** * Get an object value that implements the XPath equality and ordering comparison semantics for this value. * If the ordered parameter is set to true, the result will be a Comparable and will support a compareTo() * method with the semantics of the XPath lt/gt operator, provided that the other operand is also obtained * using the getXPathComparable() method. In all cases the result will support equals() and hashCode() methods * that support the semantics of the XPath eq operator, again provided that the other operand is also obtained * using the getXPathComparable() method. A context argument is supplied for use in cases where the comparison * semantics are context-sensitive, for example where they depend on the implicit timezone or the default * collation. * * @param ordered true if an ordered comparison is required. In this case the result is null if the * type is unordered; in other cases the returned value will be a Comparable. * @param collator * @param context the XPath dynamic evaluation context, used in cases where the comparison is context * sensitive @return an Object whose equals() and hashCode() methods implement the XPath comparison semantics * with respect to this atomic value. If ordered is specified, the result will either be null if * no ordering is defined, or will be a Comparable */ public Object getXPathComparable(boolean ordered, StringCollator collator, XPathContext context) { return (ordered ? null : this); } public int hashCode() { return qName.hashCode(); } /** * Convert to Java object (for passing to external functions) */ // public Object convertAtomicToJava(Class target, XPathContext context) throws XPathException { // if (target.isAssignableFrom(QualifiedNameValue.class)) { // return this; // } else if (target == Object.class) { // return getStringValue(); // } else if (target.getName().equals("javax.xml.namespace.QName")) { // // TODO: rewrite this under JDK 1.5 // return makeQName(context.getConfiguration()); // } else { // Object o = super.convertToJava(target, context); // if (o == null) { // throw new XPathException("Conversion of QName to " + target.getName() + // " is not supported"); // } // return o; // } // } /** * The toString() method returns the name in the form QName("uri", "local") * @return the name in in the form QName("uri", "local") */ public String toString() { return "QName(\"" + getNamespaceURI() + "\", \"" + getLocalName() + "\")"; } /** * Temporary method to construct a javax.xml.namespace.QName without actually mentioning it * by name (because the class is not available in JDK 1.4) */ public Object makeQName(Configuration config) { return qName.makeQName(config); } // public static void main(String[] args) throws Exception { // QName q = (QName)new QNameValue("a", "b", "c").makeQName(); // QNameValue v = Value.makeQNameValue(q); // System.err.println(q); // System.err.println(v); // } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/value/Closure.java0000644000175000017500000002567511033112257021011 0ustar eugeneeugenepackage net.sf.saxon.value; import net.sf.saxon.event.SequenceReceiver; import net.sf.saxon.expr.*; import net.sf.saxon.instruct.SlotManager; import net.sf.saxon.om.*; import net.sf.saxon.trace.Location; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.AnyItemType; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.TypeHierarchy; /** * A Closure represents a value that has not yet been evaluated: the value is represented * by an expression, together with saved values of all the context variables that the * expression depends on. * *

    This Closure is designed for use when the value is only read once. If the value * is read more than once, a new iterator over the underlying expression is obtained * each time: this may (for example in the case of a filter expression) involve * significant re-calculation.

    * *

    The expression may depend on local variables and on the context item; these values * are held in the saved XPathContext object that is kept as part of the Closure, and they * will always be read from that object. The expression may also depend on global variables; * these are unchanging, so they can be read from the Bindery in the normal way. Expressions * that depend on other contextual information, for example the values of position(), last(), * current(), current-group(), should not be evaluated using this mechanism: they should * always be evaluated eagerly. This means that the Closure does not need to keep a copy * of these context variables.

    * */ public class Closure extends Value { protected Expression expression; protected XPathContextMajor savedXPathContext; protected int depth = 0; // The base iterator is used to copy items on demand from the underlying value // to the reservoir. It only ever has one instance (for each Closure) and each // item is read only once. protected SequenceIterator inputIterator; // private static int countClosures = 0; // private static int countMemoClosures = 0; /** * Constructor should not be called directly, instances should be made using the make() method. */ public Closure() { } /** * Construct a Closure over an existing SequenceIterator. This is used when an extension function * returns a SequenceIterator as its result (it replaces the old SequenceIntent class for this * purpose). There is no known expression in this case. Note that the caller must * ensure this is a "clean" iterator: it must be positioned at the start, and must * not be shared by anyone else. * @param iterator the supplied iterator * @return the Closure over this iterator */ public static Closure makeIteratorClosure(SequenceIterator iterator) { Closure c = new Closure(); c.inputIterator = iterator; return c; } /** * Construct a Closure by supplying the expression and the set of context variables. * @param expression the expression to be lazily evaluated * @param context the dynamic context of the expression including for example the variables * on which it depends * @param ref the number of references to the value being lazily evaluated; this affects * the kind of Closure that is created * @return the Closure, a virtual value that can later be materialized when its content is required */ public static Value make(Expression expression, XPathContext context, int ref) throws XPathException { // special cases such as TailExpressions and shared append expressions are now picked up before // this method is called (where possible, at compile time) Value v = context.getConfiguration().getOptimizer().makeClosure(expression, ref, context); if (v instanceof Closure) { Closure c = (Closure)v; c.expression = expression; c.savedXPathContext = context.newContext(); c.savedXPathContext.setOriginatingConstructType(Location.LAZY_EVALUATION); c.saveContext(expression, context); return c; } else { return v; } } protected void saveContext(Expression expression, XPathContext context) throws XPathException { // Make a copy of all local variables. If the value of any local variable is a closure // whose depth exceeds a certain threshold, we evaluate the closure eagerly to avoid // creating deeply nested lists of Closures, which consume memory unnecessarily // We only copy the local variables if the expression has dependencies on local variables. // What's more, we only copy those variables that the expression actually depends on. if ((expression.getDependencies() & StaticProperty.DEPENDS_ON_LOCAL_VARIABLES) != 0) { StackFrame localStackFrame = context.getStackFrame(); ValueRepresentation[] local = localStackFrame.getStackFrameValues(); int[] slotsUsed = expression.getSlotsUsed(); // computed on first call if (local != null) { final SlotManager stackFrameMap = localStackFrame.getStackFrameMap(); final ValueRepresentation[] savedStackFrame = new ValueRepresentation[stackFrameMap.getNumberOfVariables()]; for (int s=0; s= 10) { local[i] = SequenceExtent.makeSequenceExtent(((Closure)local[i]).iterate()); } else if (cdepth + 1 > depth) { depth = cdepth + 1; } } savedStackFrame[i] = local[i]; } savedXPathContext.setStackFrame(stackFrameMap, savedStackFrame); } } // Make a copy of the context item SequenceIterator currentIterator = context.getCurrentIterator(); if (currentIterator != null) { Item contextItem = currentIterator.current(); UnfailingIterator single = SingletonIterator.makeIterator(contextItem); single.next(); savedXPathContext.setCurrentIterator(single); // we don't save position() and last() because we have no way // of restoring them. So the caller must ensure that a Closure is not // created if the expression depends on position() or last() } savedXPathContext.setReceiver(null); } /** * Get the static item type * @param th the type hierarchy cache */ public ItemType getItemType(TypeHierarchy th) { if (expression == null) { return AnyItemType.getInstance(); } else { return expression.getItemType(th); } // This is probably rarely used, because a Closure has no static existence, and // run-time polymorphism applies mainly to singletons, which are rarely evaluated as Closures. } /** * Get the cardinality */ public int getCardinality() { if (expression == null) { return StaticProperty.ALLOWS_ZERO_OR_MORE; } else { return expression.getCardinality(); } } /** * Evaluate the expression in a given context to return an iterator over a sequence */ public SequenceIterator iterate() throws XPathException { if (inputIterator == null) { inputIterator = expression.iterate(savedXPathContext); return inputIterator; } else { // In an ideal world this shouldn't happen: if the value is needed more than once, we should // have chosen a MemoClosure. In fact, this path is never taken when executing the standard // test suite (April 2005). However, it provides robustness in case the compile-time analysis // is flawed. I believe it's also possible that this path can be taken if a Closure needs to be // evaluated when the chain of dependencies gets too long: this was happening routinely when // all local variables were saved, rather than only those that the expression depends on. return inputIterator.getAnother(); } } /** * Process the instruction, without returning any tail calls * @param context The dynamic context, giving access to the current node, * the current variables, etc. */ public void process(XPathContext context) throws XPathException { if (expression == null) { // This is a Closure that simply wraps a SequenceIterator supplied from the Java level SequenceReceiver out = context.getReceiver(); while (true) { Item item = inputIterator.next(); if (item == null) { break; } out.append(item, 0, NodeInfo.ALL_NAMESPACES); } inputIterator = inputIterator.getAnother(); } else { // To evaluate the closure in push mode, we need to use the original context of the // expression for everything except the current output destination, which is newly created XPathContext c2 = savedXPathContext.newContext(); SequenceReceiver out = context.getReceiver(); c2.setTemporaryReceiver(out); expression.process(c2); } } /** * Reduce a value to its simplest form. If the value is a closure or some other form of deferred value * such as a FunctionCallPackage, then it is reduced to a SequenceExtent. If it is a SequenceExtent containing * a single item, then it is reduced to that item. One consequence that is exploited by class FilterExpression * is that if the value is a singleton numeric value, then the result will be an instance of NumericValue */ public Value reduce() throws XPathException { return new SequenceExtent(iterate()).reduce(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/value/NotationValue.java0000644000175000017500000001535211033112257022154 0ustar eugeneeugenepackage net.sf.saxon.value; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.NameChecker; import net.sf.saxon.om.StructuredQName; import net.sf.saxon.om.StandardNames; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.*; /** * An xs:NOTATION value. */ public final class NotationValue extends QualifiedNameValue { /** * Constructor * @param prefix The prefix part of the QName (not used in comparisons). Use null or "" to represent the * default prefix. * @param uri The namespace part of the QName. Use null or "" to represent the null namespace. * @param localName The local part of the QName * @param checker Used for checking names against XML 1.0 or XML 1.1 syntax rules */ public NotationValue(String prefix, String uri, String localName, NameChecker checker) throws XPathException { if (checker != null && !checker.isValidNCName(localName)) { XPathException err = new XPathException("Malformed local name in NOTATION: '" + localName + '\''); err.setErrorCode("FORG0001"); throw err; } prefix = (prefix==null ? "" : prefix); uri = (uri==null ? "" : uri); if (checker != null && uri.length() == 0 && prefix.length() != 0) { XPathException err = new XPathException("NOTATION has null namespace but non-empty prefix"); err.setErrorCode("FOCA0002"); throw err; } qName = new StructuredQName(prefix, uri, localName); typeLabel = BuiltInAtomicType.NOTATION; } /** * Constructor for a value that is known to be valid * @param prefix The prefix part of the QName (not used in comparisons). Use null or "" to represent the * default prefix. * @param uri The namespace part of the QName. Use null or "" to represent the null namespace. * @param localName The local part of the QName */ public NotationValue(String prefix, String uri, String localName) { qName = new StructuredQName(prefix, uri, localName); typeLabel = BuiltInAtomicType.NOTATION; } /** * Constructor for a value that is known to be valid * @param prefix The prefix part of the QName (not used in comparisons). Use null or "" to represent the * default prefix. * @param uri The namespace part of the QName. Use null or "" to represent the null namespace. * @param localName The local part of the QName * @param typeLabel A type derived from xs:NOTATION to be used for the new value */ public NotationValue(String prefix, String uri, String localName, AtomicType typeLabel) { qName = new StructuredQName(prefix, uri, localName); this.typeLabel = typeLabel; } /** * Create a copy of this atomic value, with a different type label * * @param typeLabel the type label of the new copy. The caller is responsible for checking that * the value actually conforms to this type. */ public AtomicValue copyAsSubType(AtomicType typeLabel) { NotationValue v = new NotationValue(getPrefix(), getNamespaceURI(), getLocalName()); v.typeLabel = typeLabel; return v; } /** * Determine the primitive type of the value. This delivers the same answer as * getItemType().getPrimitiveItemType(). The primitive types are * the 19 primitive types of XML Schema, plus xs:integer, xs:dayTimeDuration and xs:yearMonthDuration, * and xs:untypedAtomic. For external objects, the result is AnyAtomicType. */ public BuiltInAtomicType getPrimitiveType() { return BuiltInAtomicType.NOTATION; } /** * Convert to target data type * @param requiredType an integer identifying the required atomic type * @param context The XPath dynamic context * @return an AtomicValue, a value of the required type; or an ErrorValue */ public ConversionResult convertPrimitive(BuiltInAtomicType requiredType, boolean validate, XPathContext context) { switch (requiredType.getPrimitiveType()) { case StandardNames.XS_ANY_ATOMIC_TYPE: case StandardNames.XS_NOTATION: return this; case StandardNames.XS_STRING: return new StringValue(getStringValue()); case StandardNames.XS_UNTYPED_ATOMIC: return new UntypedAtomicValue(getStringValue()); default: ValidationFailure err = new ValidationFailure("Cannot convert NOTATION to " + requiredType.getDisplayName()); err.setErrorCode("XPTY0004"); return err; } } /** * Determine if two Notation values are equal. This comparison ignores the prefix part * of the value. * @throws ClassCastException if they are not comparable * @throws IllegalStateException if the two QNames are in different name pools */ public boolean equals(Object other) { return qName.equals(((NotationValue)other).qName); } public Comparable getSchemaComparable() { return new NotationComparable(); } private class NotationComparable implements Comparable { public NotationValue getNotationValue() { return NotationValue.this; } public int compareTo(Object o) { return equals(o) ? 0 : INDETERMINATE_ORDERING; } public boolean equals(Object o) { return (o instanceof NotationComparable && qName.equals(((NotationComparable)o).getNotationValue().qName)); } public int hashCode() { return qName.hashCode(); } } /** * The toString() method returns the name in the form QName("uri", "local") * @return the name in Clark notation: {uri}local */ public String toString() { return "NOTATION(" + getClarkName() + ')'; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/value/FloatingPointConverter.java0000644000175000017500000007123711033112257024035 0ustar eugeneeugenepackage net.sf.saxon.value; import net.sf.saxon.om.FastStringBuffer; import java.math.BigInteger; /** * This is a utility class that handles formatting of numbers as strings. *

    * The algorithm for converting a floating point number to a string is taken from Guy L. Steele and * Jon L. White, How to Print Floating-Point Numbers Accurately, ACM SIGPLAN 1990. It is algorithm * (FPP)2 from that paper. There are three separate implementations of the algorithm: *

      *
    • One using long arithmetic and generating non-exponential output representations *
    • One using BigInteger arithmetic and generating non-exponential output representation *
    • One using BigInteger arithmetic and generating exponential output representations *
    *

    * The choice of method depends on the value of the number being formatted. *

    * The module contains some residual code (mainly the routine for formatting integers) from the class * AppenderHelper by Jack Shirazi in the O'Reilly book Java Performance Tuning. The floating point routines * in that module were found to be unsuitable, since they used floating point arithmetic which introduces * rounding errors. *

    * There are several reasons for doing this conversion within Saxon, rather than leaving it all to Java. * Firstly, there are differences in the required output format, notably the absence of ".0" when formatting * whole numbers, and the different rules for the range of numbers where exponential notation is used. * Secondly, there are bugs in some Java implementations, for example JDK outputs 0.001 as 0.0010, and * IKVM/GNU gets things very wrong sometimes. Finally, this implementation is faster for "everyday" numbers, * though it is slower for more extreme numbers. It would probably be reasonable to hand over formatting * to the Java platform (at least when running the Sun JDK) for exponents outside the range -7 to +7. */ public class FloatingPointConverter { public static FloatingPointConverter THE_INSTANCE = new FloatingPointConverter(); private FloatingPointConverter(){} /** * char array holding the characters for the string "-Infinity". */ private static final char[] NEGATIVE_INFINITY = {'-', 'I', 'N', 'F'}; /** * char array holding the characters for the string "Infinity". */ private static final char[] POSITIVE_INFINITY = {'I', 'N', 'F'}; /** * char array holding the characters for the string "NaN". */ private static final char[] NaN = {'N', 'a', 'N'}; private static final char[] charForDigit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' }; private static final long doubleSignMask = 0x8000000000000000L; private static final long doubleExpMask = 0x7ff0000000000000L; private static final int doubleExpShift = 52; private static final int doubleExpBias = 1023; private static final long doubleFractMask = 0xfffffffffffffL; private static final int floatSignMask = 0x80000000; private static final int floatExpMask = 0x7f800000; private static final int floatExpShift = 23; private static final int floatExpBias = 127; private static final int floatFractMask = 0x7fffff; private static final BigInteger TEN = BigInteger.valueOf(10); private static final BigInteger NINE = BigInteger.valueOf(9); /** * Format an integer, appending the string representation of the integer to a string buffer * @param s the string buffer * @param i the integer to be formatted * @return the supplied string buffer, containing the appended integer */ public static FastStringBuffer appendInt(FastStringBuffer s, int i) { if (i < 0) { if (i == Integer.MIN_VALUE) { //cannot make this positive due to integer overflow s.append("-2147483648"); return s; } s.append('-'); i = -i; } int c; if (i < 10) { //one digit s.append(charForDigit[i]); return s; } else if (i < 100) { //two digits s.append(charForDigit[i / 10]); s.append(charForDigit[i % 10]); return s; } else if (i < 1000) { //three digits s.append(charForDigit[i / 100]); s.append(charForDigit[(c = i % 100) / 10]); s.append(charForDigit[c % 10]); return s; } else if (i < 10000) { //four digits s.append(charForDigit[i / 1000]); s.append(charForDigit[(c = i % 1000) / 100]); s.append(charForDigit[(c %= 100) / 10]); s.append(charForDigit[c % 10]); return s; } else if (i < 100000) { //five digits s.append(charForDigit[i / 10000]); s.append(charForDigit[(c = i % 10000) / 1000]); s.append(charForDigit[(c %= 1000) / 100]); s.append(charForDigit[(c %= 100) / 10]); s.append(charForDigit[c % 10]); return s; } else if (i < 1000000) { //six digits s.append(charForDigit[i / 100000]); s.append(charForDigit[(c = i % 100000) / 10000]); s.append(charForDigit[(c %= 10000) / 1000]); s.append(charForDigit[(c %= 1000) / 100]); s.append(charForDigit[(c %= 100) / 10]); s.append(charForDigit[c % 10]); return s; } else if (i < 10000000) { //seven digits s.append(charForDigit[i / 1000000]); s.append(charForDigit[(c = i % 1000000) / 100000]); s.append(charForDigit[(c %= 100000) / 10000]); s.append(charForDigit[(c %= 10000) / 1000]); s.append(charForDigit[(c %= 1000) / 100]); s.append(charForDigit[(c %= 100) / 10]); s.append(charForDigit[c % 10]); return s; } else if (i < 100000000) { //eight digits s.append(charForDigit[i / 10000000]); s.append(charForDigit[(c = i % 10000000) / 1000000]); s.append(charForDigit[(c %= 1000000) / 100000]); s.append(charForDigit[(c %= 100000) / 10000]); s.append(charForDigit[(c %= 10000) / 1000]); s.append(charForDigit[(c %= 1000) / 100]); s.append(charForDigit[(c %= 100) / 10]); s.append(charForDigit[c % 10]); return s; } else if (i < 1000000000) { //nine digits s.append(charForDigit[i / 100000000]); s.append(charForDigit[(c = i % 100000000) / 10000000]); s.append(charForDigit[(c %= 10000000) / 1000000]); s.append(charForDigit[(c %= 1000000) / 100000]); s.append(charForDigit[(c %= 100000) / 10000]); s.append(charForDigit[(c %= 10000) / 1000]); s.append(charForDigit[(c %= 1000) / 100]); s.append(charForDigit[(c %= 100) / 10]); s.append(charForDigit[c % 10]); return s; } else { //ten digits s.append(charForDigit[i / 1000000000]); s.append(charForDigit[(c = i % 1000000000) / 100000000]); s.append(charForDigit[(c %= 100000000) / 10000000]); s.append(charForDigit[(c %= 10000000) / 1000000]); s.append(charForDigit[(c %= 1000000) / 100000]); s.append(charForDigit[(c %= 100000) / 10000]); s.append(charForDigit[(c %= 10000) / 1000]); s.append(charForDigit[(c %= 1000) / 100]); s.append(charForDigit[(c %= 100) / 10]); s.append(charForDigit[c % 10]); return s; } } /** * Implementation of the (FPP)2 algorithm from Steele and White, for doubles in the range * 0.01 to 1000000, and floats in the range 0.000001 to 1000000. * In this range (a) XPath requires that the output should not be in exponential * notation, and (b) the arithmetic can be handled using longs rather than BigIntegers * @param sb the string buffer to which the formatted result is to be appended * @param e the exponent of the floating point number * @param f the fraction part of the floating point number, such that the "real" value of the * number is f * 2^(e-p), with p>=0 and 0 lt f lt 2^p * @param p the precision */ private static void fppfpp(FastStringBuffer sb, int e, long f, int p) { long R = f << Math.max(e-p, 0); long S = 1L << Math.max(0, -(e-p)); long Mminus = 1L << Math.max(e-p, 0); long Mplus = Mminus; boolean initial = true; // simpleFixup if (f == 1L << (p-1)) { Mplus = Mplus << 1; R = R << 1; S = S << 1; } int k = 0; while (R < (S+9)/10) { // (S+9)/10 == ceiling(S/10) k--; R = R*10; Mminus = Mminus * 10; Mplus = Mplus * 10; } while (2*R + Mplus >= 2*S) { S = S*10; k++; } for (int z=k; z<0; z++) { if (initial) { sb.append("0."); } initial = false; sb.append('0'); } // end simpleFixup //int H = k-1; boolean low; boolean high; int U; while (true) { k--; long R10 = R*10; U = (int)(R10 / S); R = R10 - (U * S); // = R*10 % S, but faster - saves a division Mminus = Mminus * 10; Mplus = Mplus * 10; low = 2*R < Mminus; high = 2*R > 2*S - Mplus; if (low || high) break; if (k == -1) { if (initial) { sb.append('0'); } sb.append('.'); } sb.append(charForDigit[U]); initial = false; } if (high && (!low || 2*R > S)) { U++; } if (k == -1) { if (initial) { sb.append('0'); } sb.append('.'); } sb.append(charForDigit[U]); for (int z=0; z=0 and 0 lt f lt 2^p * @param p the precision */ private static void fppfppBig(FastStringBuffer sb, int e, long f, int p) { //long R = f << Math.max(e-p, 0); BigInteger R = BigInteger.valueOf(f).shiftLeft(Math.max(e-p, 0)); //long S = 1L << Math.max(0, -(e-p)); BigInteger S = BigInteger.ONE.shiftLeft(Math.max(0, -(e-p))); //long Mminus = 1 << Math.max(e-p, 0); BigInteger Mminus = BigInteger.ONE.shiftLeft(Math.max(e-p, 0)); //long Mplus = Mminus; BigInteger Mplus = Mminus; boolean initial = true; // simpleFixup if (f == 1L << (p-1)) { Mplus = Mplus.shiftLeft(1); R = R.shiftLeft(1); S = S.shiftLeft(1); } int k = 0; while (R.compareTo(S.add(NINE).divide(TEN)) < 0) { // (S+9)/10 == ceiling(S/10) k--; R = R.multiply(TEN); Mminus = Mminus.multiply(TEN); Mplus = Mplus.multiply(TEN); } while (R.shiftLeft(1).add(Mplus).compareTo(S.shiftLeft(1)) >= 0) { S = S.multiply(TEN); k++; } for (int z=k; z<0; z++) { if (initial) { sb.append("0."); } initial = false; sb.append('0'); } // end simpleFixup //int H = k-1; boolean low; boolean high; int U; while (true) { k--; BigInteger R10 = R.multiply(TEN); U = R10.divide(S).intValue(); R = R10.mod(S); Mminus = Mminus.multiply(TEN); Mplus = Mplus.multiply(TEN); BigInteger R2 = R.shiftLeft(1); low = R2.compareTo(Mminus) < 0; high = R2.compareTo(S.shiftLeft(1).subtract(Mplus)) > 0; if (low || high) break; if (k == -1) { if (initial) { sb.append('0'); } sb.append('.'); } sb.append(charForDigit[U]); initial = false; } if (high && (!low || R.shiftLeft(1).compareTo(S) > 0)) { U++; } if (k == -1) { if (initial) { sb.append('0'); } sb.append('.'); } sb.append(charForDigit[U]); for (int z=0; z=0 and 0 lt f lt 2^p * @param p the precision */ private static void fppfppExponential(FastStringBuffer sb, int e, long f, int p) { //long R = f << Math.max(e-p, 0); BigInteger R = BigInteger.valueOf(f).shiftLeft(Math.max(e-p, 0)); //long S = 1L << Math.max(0, -(e-p)); BigInteger S = BigInteger.ONE.shiftLeft(Math.max(0, -(e-p))); //long Mminus = 1 << Math.max(e-p, 0); BigInteger Mminus = BigInteger.ONE.shiftLeft(Math.max(e-p, 0)); //long Mplus = Mminus; BigInteger Mplus = Mminus; boolean initial = true; boolean doneDot = false; // simpleFixup if (f == 1L << (p-1)) { Mplus = Mplus.shiftLeft(1); R = R.shiftLeft(1); S = S.shiftLeft(1); } int k = 0; while (R.compareTo(S.add(NINE).divide(TEN)) < 0) { // (S+9)/10 == ceiling(S/10) k--; R = R.multiply(TEN); Mminus = Mminus.multiply(TEN); Mplus = Mplus.multiply(TEN); } while (R.shiftLeft(1).add(Mplus).compareTo(S.shiftLeft(1)) >= 0) { S = S.multiply(TEN); k++; } // end simpleFixup int H = k-1; boolean low; boolean high; int U; while (true) { k--; BigInteger R10 = R.multiply(TEN); U = R10.divide(S).intValue(); R = R10.mod(S); Mminus = Mminus.multiply(TEN); Mplus = Mplus.multiply(TEN); BigInteger R2 = R.shiftLeft(1); low = R2.compareTo(Mminus) < 0; high = R2.compareTo(S.shiftLeft(1).subtract(Mplus)) > 0; if (low || high) break; sb.append(charForDigit[U]); if (initial) { sb.append('.'); doneDot = true; } initial = false; } if (high && (!low || R.shiftLeft(1).compareTo(S) > 0)) { U++; } sb.append(charForDigit[U]); if (!doneDot) { sb.append(".0"); } sb.append('E'); appendInt(sb, H); } /** * Append a string representation of a double value to a string buffer * @param s the string buffer to which the result will be appended * @param value the double to be formatted * @return the original string buffer, now containing the string representation of the supplied double */ public static FastStringBuffer appendDouble(FastStringBuffer s, double value) { double d = value; if (d == Double.NEGATIVE_INFINITY) { s.append(NEGATIVE_INFINITY); } else if (d == Double.POSITIVE_INFINITY) { s.append(POSITIVE_INFINITY); } else if (d != d) { s.append(NaN); } else if (d == 0.0) { if ((Double.doubleToLongBits(d) & doubleSignMask) != 0) { s.append('-'); } s.append('0'); } else if (d == Double.MAX_VALUE) { s.append("1.7976931348623157E308"); } else if (d == -Double.MAX_VALUE) { s.append("-1.7976931348623157E308"); } else if (d == Double.MIN_VALUE) { s.append("4.9E-324"); } else if (d == -Double.MIN_VALUE) { s.append("-4.9E-324"); } else { if (d < 0) { s.append('-'); d = -d; } boolean exponential = (d >= 1000000 || d < 0.000001); long bits = Double.doubleToLongBits(d); long fraction = (1L<<52) | (bits & doubleFractMask); long rawExp = (bits & doubleExpMask) >> doubleExpShift; int exp = (int)rawExp - doubleExpBias; if (rawExp == 0) { // don't know how to handle this currently: hand it over to Java to deal with s.append(Double.toString(value)); return s; } if (exponential) { fppfppExponential(s, exp, fraction, 52); } else { if (d <= 0.01) { fppfppBig(s, exp, fraction, 52); } else { fppfpp(s, exp, fraction, 52); } } // test code // try { // if (Double.parseDouble(s.toString()) != value) { // System.err.println("*** Round-trip failed: input " + value + // '(' + Double.doubleToLongBits(value) + ')' + // " != output " + s.toString() + // '(' + Double.doubleToLongBits(Double.parseDouble(s.toString())) + ')' ); // } // } catch (NumberFormatException e) { // System.err.println("*** Bad float " + s.toString() + " for input " + value); // } } return s; } /** * Append a string representation of a double value to a string buffer, forcing use of * exponential notation * @param s the string buffer to which the result will be appended * @param value the double to be formatted * @return the original string buffer, now containing the string representation of the supplied double */ public static FastStringBuffer appendDoubleExponential(FastStringBuffer s, double value) { double d = value; if (d == Double.NEGATIVE_INFINITY) { s.append(NEGATIVE_INFINITY); } else if (d == Double.POSITIVE_INFINITY) { s.append(POSITIVE_INFINITY); } else if (d != d) { s.append(NaN); } else if (d == 0.0) { if ((Double.doubleToLongBits(d) & doubleSignMask) != 0) { s.append('-'); } s.append('0'); } else if (d == Double.MAX_VALUE) { s.append("1.7976931348623157E308"); } else if (d == -Double.MAX_VALUE) { s.append("-1.7976931348623157E308"); } else if (d == Double.MIN_VALUE) { s.append("4.9E-324"); } else if (d == -Double.MIN_VALUE) { s.append("-4.9E-324"); } else { if (d < 0) { s.append('-'); d = -d; } long bits = Double.doubleToLongBits(d); long fraction = (1L<<52) | (bits & doubleFractMask); long rawExp = (bits & doubleExpMask) >> doubleExpShift; int exp = (int)rawExp - doubleExpBias; if (rawExp == 0) { // don't know how to handle this currently: hand it over to Java to deal with s.append(Double.toString(value)); return s; } fppfppExponential(s, exp, fraction, 52); } return s; } /** * Append a string representation of a float value to a string buffer * @param s the string buffer to which the result will be appended * @param value the float to be formatted * @return the original string buffer, now containing the string representation of the supplied float */ public static FastStringBuffer appendFloat(FastStringBuffer s, float value) { float f = value; if (f == Float.NEGATIVE_INFINITY) { s.append(NEGATIVE_INFINITY); } else if (f == Float.POSITIVE_INFINITY) { s.append(POSITIVE_INFINITY); } else if (f != f) { s.append(NaN); } else if (f == 0.0) { if ((Float.floatToIntBits(f) & floatSignMask) != 0) { s.append('-'); } s.append('0'); } else if (f == Float.MAX_VALUE) { s.append("3.4028235E38"); } else if (f == -Float.MAX_VALUE) { s.append("-3.4028235E38"); } else if (f == Float.MIN_VALUE) { s.append("1.4E-45"); } else if (f == -Float.MIN_VALUE) { s.append("-1.4E-45"); } else { if (f < 0) { s.append('-'); f = -f; } boolean exponential = (f >= 1000000 || f < 0.000001F); int bits = Float.floatToIntBits(f); int fraction = (1<<23) | (bits & floatFractMask); int rawExp = ((bits & floatExpMask) >> floatExpShift); int exp = rawExp - floatExpBias; int precision = 23; if (rawExp == 0) { // don't know how to handle this currently: hand it over to Java to deal with s.append(Float.toString(value)); return s; } if (exponential) { fppfppExponential(s, exp, fraction, precision); } else { fppfpp(s, exp, fraction, precision); } // test code // try { // if (Float.parseFloat(s.toString()) != value) { // System.err.println("*** Round-trip failed: input " + value + // '(' + Float.floatToIntBits(value) + ')' + // " != output " + s.toString() + // '(' + Float.floatToIntBits(Float.parseFloat(s.toString())) + ')' ); // } // } catch (NumberFormatException e) { // System.err.println("*** Bad float " + s.toString() + " for input " + value); // } } return s; } /** * Append a string representation of a float value to a string buffer, forcing use of exponential * notation * @param s the string buffer to which the result will be appended * @param value the float to be formatted * @return the original string buffer, now containing the string representation of the supplied float */ public static FastStringBuffer appendFloatExponential(FastStringBuffer s, float value) { float f = value; if (f == Float.NEGATIVE_INFINITY) { s.append(NEGATIVE_INFINITY); } else if (f == Float.POSITIVE_INFINITY) { s.append(POSITIVE_INFINITY); } else if (f != f) { s.append(NaN); } else if (f == 0.0) { if ((Float.floatToIntBits(f) & floatSignMask) != 0) { s.append('-'); } s.append('0'); } else if (f == Float.MAX_VALUE) { s.append("3.4028235E38"); } else if (f == -Float.MAX_VALUE) { s.append("-3.4028235E38"); } else if (f == Float.MIN_VALUE) { s.append("1.4E-45"); } else if (f == -Float.MIN_VALUE) { s.append("-1.4E-45"); } else { if (f < 0) { s.append('-'); f = -f; } int bits = Float.floatToIntBits(f); int fraction = (1<<23) | (bits & floatFractMask); int rawExp = ((bits & floatExpMask) >> floatExpShift); int exp = rawExp - floatExpBias; int precision = 23; if (rawExp == 0) { // don't know how to handle this currently: hand it over to Java to deal with s.append(Float.toString(value)); return s; } fppfppExponential(s, exp, fraction, precision); } return s; } // public static void main(String[] args) { // if (args.length > 0 && args[0].equals("F")) { // if (args.length == 2) { // StringTokenizer tok = new StringTokenizer(args[1], ","); // while (tok.hasMoreElements()) { // String input = tok.nextToken(); // float f = Float.parseFloat(input); // FastStringBuffer sb = new FastStringBuffer(20); // appendFloat(sb, f); // System.err.println("input: " + input + " output: " + sb.toString() + " java: " + f); // } // } else { // Random gen = new Random(); // for (int i=1; i<1000; i++) { // int p=gen.nextInt(999*i*i); // int q=gen.nextInt(999*i*i); // String input = (p + "." + q); // float f = Float.parseFloat(input); // FastStringBuffer sb = new FastStringBuffer(20); // appendFloat(sb, f); // System.err.println("input: " + input + " output: " + sb.toString() + " java: " + f); // } // } // } else { // if (args.length == 2) { // StringTokenizer tok = new StringTokenizer(args[1], ","); // while (tok.hasMoreElements()) { // String input = tok.nextToken(); // double f = Double.parseDouble(input); // FastStringBuffer sb = new FastStringBuffer(20); // appendDouble(sb, f); // System.err.println("input: " + input + " output: " + sb.toString() + " java: " + f); // } // } else { // long start = System.currentTimeMillis(); // Random gen = new Random(); // for (int i=1; i<100000; i++) { // //int p=gen.nextInt(999*i*i); // int q=gen.nextInt(999*i); // //String input = (p + "." + q); // String input = "0.000" + q; // double f = Double.parseDouble(input); // FastStringBuffer sb = new FastStringBuffer(20); // appendDouble(sb, f); // //System.err.println("input: " + input + " output: " + sb.toString() + " java: " + f); // } // System.err.println("** elapsed time " + (System.currentTimeMillis() - start)); // } // } // } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay, based on a published algorithm by // Guy L. Steele and Jon L. White. // // Contributor(s): the appendInt routine, and some of the constant declarations (and some of the ideas) are // from the class AppenderHelper by Jack Shirazi in the O'Reilly book Java Performance Tuning.. // saxonb-9.1.0.8/bj/net/sf/saxon/value/EmptySequence.java0000644000175000017500000001043311033112257022146 0ustar eugeneeugenepackage net.sf.saxon.value; import net.sf.saxon.expr.StaticProperty; import net.sf.saxon.om.EmptyIterator; import net.sf.saxon.om.GroundedValue; import net.sf.saxon.om.Item; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.pattern.EmptySequenceTest; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.TypeHierarchy; /** * An EmptySequence object represents a sequence containing no members. */ public final class EmptySequence extends Value implements GroundedValue { // This class has a single instance private static EmptySequence THE_INSTANCE = new EmptySequence(); /** * Private constructor: only the predefined instances of this class can be used */ private EmptySequence() {} /** * Get the implicit instance of this class */ public static EmptySequence getInstance() { return THE_INSTANCE; } /** * Return an iteration over the sequence */ public SequenceIterator iterate() { return EmptyIterator.getInstance(); } /** * Return the value in the form of an Item * @return the value in the form of an Item */ public Item asItem() { return null; } /** * Determine the item type * @param th the type hierarchy cache */ public ItemType getItemType(TypeHierarchy th) { return EmptySequenceTest.getInstance(); } /** * Determine the static cardinality */ public int getCardinality() { return StaticProperty.EMPTY; } /** * Get the length of the sequence * @return always 0 for an empty sequence */ public final int getLength() { return 0; } /** * Is this expression the same as another expression? * @throws ClassCastException if the values are not comparable */ public boolean equals(Object other) { if (!(other instanceof EmptySequence)) { throw new ClassCastException("Cannot compare " + other.getClass() + " to empty sequence"); } return true; } public int hashCode() { return 42; } /** * Get the effective boolean value - always false */ public boolean effectiveBooleanValue() { return false; } /** * Get the n'th item in the sequence (starting from 0). This is defined for all * Values, but its real benefits come for a sequence Value stored extensionally * (or for a MemoClosure, once all the values have been read) * * @param n position of the required item, counting from zero. * @return the n'th item in the sequence, where the first item in the sequence is * numbered zero. If n is negative or >= the length of the sequence, returns null. */ public Item itemAt(int n) { return null; } /** * Get a subsequence of the value * * @param min the index of the first item to be included in the result, counting from zero. * A negative value is taken as zero. If the value is beyond the end of the sequence, an empty * sequence is returned * @param length the number of items to be included in the result. Specify Integer.MAX_VALUE to * get the subsequence up to the end of the base sequence. If the value is negative, an empty sequence * is returned. If the value goes off the end of the sequence, the result returns items up to the end * of the sequence * @return the required subsequence. If min is */ public GroundedValue subsequence(int min, int length) { return this; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/value/BooleanValue.java0000644000175000017500000002660311033112257021741 0ustar eugeneeugenepackage net.sf.saxon.value; import net.sf.saxon.trans.Err; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.StandardNames; import net.sf.saxon.sort.StringCollator; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.AtomicType; import net.sf.saxon.type.BuiltInAtomicType; import net.sf.saxon.type.ConversionResult; import net.sf.saxon.type.ValidationFailure; /** * A boolean XPath value */ public final class BooleanValue extends AtomicValue implements Comparable { private boolean value; /** * The boolean value TRUE */ public static final BooleanValue TRUE = new BooleanValue(true); /** * The boolean value FALSE */ public static final BooleanValue FALSE = new BooleanValue(false); /** * Private Constructor: create a boolean value. Only two instances of this class are * ever created, one to represent true and one to represent false. * @param value the initial value, true or false */ private BooleanValue(boolean value) { this.value = value; typeLabel = BuiltInAtomicType.BOOLEAN; } /** * Factory method: get a BooleanValue * * @param value true or false, to determine which boolean value is * required * @return the BooleanValue requested */ public static BooleanValue get(boolean value) { return (value ? TRUE : FALSE); } /** * Create a new Boolean value with a user-supplied type label. * It is the caller's responsibility to ensure that the value is valid for the subtype * @param value the boolean value * @param typeLabel the type label, xs:boolean or a subtype */ public BooleanValue(boolean value, AtomicType typeLabel) { this.value = value; this.typeLabel = typeLabel; } /** * Create a copy of this atomic value (usually so that the type label can be changed). * The type label of the copy will be reset to the primitive type. * @param typeLabel the atomic type label to be added to the copied value */ public AtomicValue copyAsSubType(AtomicType typeLabel) { BooleanValue v = new BooleanValue(value); v.typeLabel = typeLabel; return v; } /** * Convert a string to a boolean value, using the XML Schema rules (including * whitespace trimming) * @param s the input string * @return the relevant BooleanValue if validation succeeds; or a ValidationFailure if not. */ public static ConversionResult fromString(CharSequence s) { // implementation designed to avoid creating new objects s = Whitespace.trimWhitespace(s); int len = s.length(); if (len == 1) { char c = s.charAt(0); if (c == '1') { return TRUE; } else if (c == '0') { return FALSE; } } else if (len == 4) { if (s.charAt(0) == 't' && s.charAt(1) == 'r' && s.charAt(2) == 'u' && s.charAt(3) == 'e') { return TRUE; } } else if (len == 5) { if (s.charAt(0) == 'f' && s.charAt(1) == 'a' && s.charAt(2) == 'l' && s.charAt(3) == 's' && s.charAt(4) == 'e') { return FALSE; } } ValidationFailure err = new ValidationFailure( "The string " + Err.wrap(s, Err.VALUE) + " cannot be cast to a boolean"); err.setErrorCode("FORG0001"); return err; } /** * Get the value * @return true or false, the actual boolean value of this BooleanValue */ public boolean getBooleanValue() { return value; } /** * Get the effective boolean value of this expression * * @return the boolean value */ public boolean effectiveBooleanValue() { return value; } /** * Determine the primitive type of the value. This delivers the same answer as * getItemType().getPrimitiveItemType(). The primitive types are * the 19 primitive types of XML Schema, plus xs:integer, xs:dayTimeDuration and xs:yearMonthDuration, * and xs:untypedAtomic. For external objects, the result is AnyAtomicType. */ public BuiltInAtomicType getPrimitiveType() { return BuiltInAtomicType.BOOLEAN; } /** * Convert to target data type * @param requiredType an integer identifying the required atomic type * @param context XPath dynamic context * @return an AtomicValue, a value of the required type */ public ConversionResult convertPrimitive(BuiltInAtomicType requiredType, boolean validate, XPathContext context) { switch(requiredType.getPrimitiveType()) { case StandardNames.XS_BOOLEAN: case StandardNames.XS_ANY_ATOMIC_TYPE: return this; case StandardNames.XS_NUMERIC: case StandardNames.XS_INTEGER: return (value ? Int64Value.PLUS_ONE : Int64Value.ZERO); case StandardNames.XS_DECIMAL: return (value ? DecimalValue.ONE : DecimalValue.ZERO); case StandardNames.XS_FLOAT: return (value ? FloatValue.ONE : FloatValue.ZERO); case StandardNames.XS_DOUBLE: return (value ? DoubleValue.ONE : DoubleValue.ZERO); case StandardNames.XS_STRING: return (value ? StringValue.TRUE : StringValue.FALSE); case StandardNames.XS_UNTYPED_ATOMIC: return new UntypedAtomicValue(getStringValueCS()); default: ValidationFailure err = new ValidationFailure("Cannot convert boolean to " + requiredType.getDisplayName()); err.setErrorCode("XPTY0004"); return err; } } /** * Convert to string * @return "true" or "false" */ public String getStringValue() { return (value ? "true" : "false"); } /** * Convert to Java object (for passing to external functions) * * @param target the Java class to which conversion is required * @exception XPathException if conversion is not possible or fails * @return An object of the specified Java class */ // public Object convertAtomicToJava(Class target, XPathContext context) throws XPathException { // if (target==Object.class) { // return Boolean.valueOf(value); // } else if (target.isAssignableFrom(BooleanValue.class)) { // return this; // } else if (target==boolean.class) { // return Boolean.valueOf(value); // } else if (target==Boolean.class) { // return Boolean.valueOf(value); // } else { // Object o = super.convertSequenceToJava(target, context); // if (o == null) { // XPathException err = new XPathException("Conversion of xs:boolean to " + target.getName() + // " is not supported"); // err.setXPathContext(context); // err.setErrorCode(SaxonErrorCode.SXJE0001); // throw err; // } // return o; // } // } /** * Get a Comparable value that implements the XML Schema ordering comparison semantics for this value. * The default implementation returns "this". This is overridden for particular atomic types. *

    *

    In the case of data types that are partially ordered, the returned Comparable extends the standard * semantics of the compareTo() method by returning the value {@link #INDETERMINATE_ORDERING} when there * is no defined order relationship between two given values.

    * * @return a Comparable that follows XML Schema comparison rules */ public Comparable getSchemaComparable() { return new BooleanComparable(); } private class BooleanComparable implements Comparable { public boolean asBoolean() { return BooleanValue.this.getBooleanValue(); } public int compareTo(Object o) { return equals(o) ? 0 : INDETERMINATE_ORDERING; } public boolean equals(Object o) { return o instanceof BooleanComparable && asBoolean() == ((BooleanComparable)o).asBoolean(); } public int hashCode() { return asBoolean() ? 9999999 : 8888888; } } /** * Get a Comparable value that implements the XPath ordering comparison semantics for this value. * Returns null if the value is not comparable according to XPath rules. The default implementation * returns null. This is overridden for types that allow ordered comparisons in XPath: numeric, boolean, * string, date, time, dateTime, yearMonthDuration, dayTimeDuration, and anyURI. * @param ordered * @param collator * @param context */ public Object getXPathComparable(boolean ordered, StringCollator collator, XPathContext context) { return this; } /** * Compare the value to another boolean value * * @throws ClassCastException if the other value is not a BooleanValue * (the parameter is declared as Object to satisfy the Comparable * interface) * @param other The other boolean value * @return -1 if this one is the lower, 0 if they are equal, +1 if this * one is the higher. False is considered to be less than true. */ public int compareTo(Object other) { if (!(other instanceof BooleanValue)) { throw new ClassCastException("Boolean values are not comparable to " + other.getClass()); } if (value == ((BooleanValue)other).value) return 0; if (value) return +1; return -1; } /** * Determine whether two boolean values are equal * * @param other the value to be compared to this value * @return true if the other value is a boolean value and is equal to this * value * @throws ClassCastException if other value is not xs:boolean or derived therefrom */ public boolean equals(Object other) { BooleanValue val = (BooleanValue)other; return (value == val.value); } /** * Get a hash code for comparing two BooleanValues * * @return the hash code */ public int hashCode() { return (value ? 0 : 1); } /** * Diagnostic display of this value as a string * @return a string representation of this value: "true()" or "false()" */ public String toString() { return getStringValue() + "()"; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/value/DayTimeDurationValue.java0000644000175000017500000005270011033112257023421 0ustar eugeneeugenepackage net.sf.saxon.value; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.FastStringBuffer; import net.sf.saxon.sort.StringCollator; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.*; import java.math.BigDecimal; import java.math.BigInteger; import java.util.StringTokenizer; /** * A value of type xs:dayTimeDuration */ public final class DayTimeDurationValue extends DurationValue implements Comparable { /** * Private constructor for internal use */ private DayTimeDurationValue() { typeLabel = BuiltInAtomicType.DAY_TIME_DURATION; } /** * Factory method: create a duration value from a supplied string, in * ISO 8601 format [-]PnDTnHnMnS * * @param s the lexical representation of the xs:dayTimeDuration value * @return a DayTimeDurationValue if the format is correct, or a ValidationErrorValue if not */ public static ConversionResult makeDayTimeDurationValue(CharSequence s) { int days = 0, hours = 0, minutes = 0, seconds = 0, microseconds = 0; boolean negative = false; int components = 0; StringTokenizer tok = new StringTokenizer(Whitespace.trimWhitespace(s).toString(), "-+.PDTHMS", true); if (!tok.hasMoreElements()) { return badDuration("empty string", s); } String part = (String)tok.nextElement(); if ("+".equals(part)) { return badDuration("+ sign not allowed in a duration", s); } else if ("-".equals(part)) { negative = true; part = (String)tok.nextElement(); } if (!"P".equals(part)) { return badDuration("missing 'P'", s); } int state = 0; while (tok.hasMoreElements()) { part = (String)tok.nextElement(); if ("T".equals(part)) { state = 4; if (!tok.hasMoreElements()) { return badDuration("T must be followed by time components", s); } part = (String)tok.nextElement(); } int value = simpleInteger(part); if (value < 0) { return badDuration("non-numeric component", s); } if (!tok.hasMoreElements()) { return badDuration("missing unit letter at end", s); } char delim = ((String)tok.nextElement()).charAt(0); switch (delim) { case'D': if (state > 2) { return badDuration("D is out of sequence", s); } days = value; components++; state = 3; break; case'H': if (state != 4) { return badDuration("H is out of sequence", s); } hours = value; components++; state = 5; break; case'M': if (state < 4 || state > 5) { return badDuration("M is out of sequence", s); } minutes = value; components++; state = 6; break; case'.': if (state < 4 || state > 6) { return badDuration("misplaced decimal point", s); } seconds = value; components++; state = 7; break; case'S': if (state < 4 || state > 7) { return badDuration("S is out of sequence", s); } if (state == 7) { while (part.length() < 6) { part += "0"; } if (part.length() > 6) { part = part.substring(0, 6); } value = simpleInteger(part); if (value < 0) { return badDuration("non-numeric microseconds component", s); } microseconds = value; } else { seconds = value; } components++; state = 8; break; default: return badDuration("misplaced " + delim, s); } } if (components == 0) { return badDuration("Duration specifies no components", s); } try { //System.err.println(days + "days " + hours + " hours " + minutes + " minutes " + seconds + " seconds"); return new DayTimeDurationValue((negative ? -1 : +1), days, hours, minutes, seconds, microseconds); } catch (IllegalArgumentException err) { return new ValidationFailure(err.getMessage()); } } /** * Create a dayTimeDuration given the number of days, hours, minutes, and seconds. This * constructor performs no validation. The components (apart from sign) must all be non-negative * integers; they need not be normalized (for example, 36 hours is acceptable) * * @param sign positive number for positive durations, negative for negative duratoins * @param days number of days * @param hours number of hours * @param minutes number of minutes * @param seconds number of seconds * @param microseconds number of microseconds * @throws IllegalArgumentException if the value is out of range; specifically, if the total * number of seconds exceeds 2^63; or if any of the values is negative */ public DayTimeDurationValue(int sign, int days, int hours, int minutes, long seconds, int microseconds) throws IllegalArgumentException { if (days < 0 || hours < 0 || minutes < 0 || seconds < 0 || microseconds < 0) { throw new IllegalArgumentException("Negative component value"); } if (((double)days)*(24*60*60) + ((double)hours)*(60*60) + ((double)minutes)*60 + (double)seconds > Long.MAX_VALUE) { throw new IllegalArgumentException("Duration seconds limit exceeded"); } negative = (sign < 0); months = 0; long h = (long)days * 24L + (long)hours; long m = h * 60L + (long)minutes; long s = m * 60L + seconds; if (microseconds > 1000000) { s += microseconds / 1000000; microseconds %= 1000000; } this.seconds = s; this.microseconds = microseconds; if (s == 0 && microseconds == 0) { negative = false; } typeLabel = BuiltInAtomicType.DAY_TIME_DURATION; } /** * Create a copy of this atomic value, with a different type label * * @param typeLabel the type label of the new copy. The caller is responsible for checking that * the value actually conforms to this type. */ public AtomicValue copyAsSubType(AtomicType typeLabel) { DayTimeDurationValue v = DayTimeDurationValue.fromMicroseconds(getLengthInMicroseconds()); v.typeLabel = typeLabel; return v; } /** * Determine the primitive type of the value. This delivers the same answer as * getItemType().getPrimitiveItemType(). The primitive types are * the 19 primitive types of XML Schema, plus xs:integer, xs:dayTimeDuration and xs:yearMonthDuration, * and xs:untypedAtomic. For external objects, the result is AnyAtomicType. */ public BuiltInAtomicType getPrimitiveType() { return BuiltInAtomicType.DAY_TIME_DURATION; } /** * Convert to string * * @return ISO 8601 representation. */ public CharSequence getStringValueCS() { FastStringBuffer sb = new FastStringBuffer(32); if (negative) { sb.append('-'); } int days = getDays(); int hours = getHours(); int minutes = getMinutes(); int seconds = getSeconds(); sb.append('P'); if (days != 0) { sb.append(days + "D"); } if (days == 0 || hours != 0 || minutes != 0 || seconds != 0 || microseconds != 0) { sb.append('T'); } if (hours != 0) { sb.append(hours + "H"); } if (minutes != 0) { sb.append(minutes + "M"); } if (seconds != 0 || microseconds != 0 || (days == 0 && minutes == 0 && hours == 0)) { if (microseconds == 0) { sb.append(seconds + "S"); } else { long ms = (seconds * 1000000) + microseconds; String mss = ms + ""; if (seconds == 0) { mss = "0000000" + mss; mss = mss.substring(mss.length() - 7); } sb.append(mss.substring(0, mss.length() - 6)); sb.append('.'); int lastSigDigit = mss.length() - 1; while (mss.charAt(lastSigDigit) == '0') { lastSigDigit--; } sb.append(mss.substring(mss.length() - 6, lastSigDigit + 1)); sb.append('S'); } } return sb; } // /** // * Normalize the value, for example 90M becomes 1H30M // */ // // public void normalize() throws ValidationException { // long seconds2 = seconds; // long minutes2 = minutes; // long hours2 = hours; // long days2 = days; // if (microseconds >= 1000000) { // seconds2 += (microseconds / 1000000); // microseconds = microseconds % 1000000; // } // if (seconds >= 60) { // minutes2 += (seconds2 / 60); // seconds2 = (int)(seconds2 % 60); // } // if (minutes2 >= 60) { // hours2 += (minutes2 / 60); // minutes2 = (int)(minutes2 % 60); // } // if (hours2 >= 24) { // days2 += (hours2 / 24); // if (days2 > Integer.MAX_VALUE || days2 < Integer.MIN_VALUE) { // throw new ValidationException("Duration exceeds implementation-defined limits"); // } // hours2 = (int)(hours2 % 24); // } // days = (int)days2; // hours = (int)hours2; // minutes = (int)minutes2; // seconds = (int)seconds2; // normalizeZeroDuration(); // normalized = true; // } /** * Get length of duration in seconds */ public double getLengthInSeconds() { double a = seconds + ((double)microseconds / 1000000); // System.err.println("Duration length " + days + "/" + hours + "/" + minutes + "/" + seconds + " is " + a); return (negative ? -a : a); } /** * Get length of duration in milliseconds, as a long * * @return the length of the duration rounded to milliseconds (may be negative) */ public long getLengthInMilliseconds() { long a = seconds * 1000 + (microseconds / 1000); return (negative ? -a : a); } /** * Get length of duration in microseconds, as a long * * @return the length in microseconds */ public long getLengthInMicroseconds() { long a = seconds * 1000000 + microseconds; return (negative ? -a : a); } /** * Construct a duration value as a number of seconds. * * @param seconds the number of seconds in the duration. May be negative * @return the xs:dayTimeDuration value with the specified length */ public static DayTimeDurationValue fromSeconds(BigDecimal seconds) throws XPathException { DayTimeDurationValue sdv = new DayTimeDurationValue(); sdv.negative = (seconds.signum() < 0); if (sdv.negative) { seconds = seconds.negate(); } BigDecimal microseconds = seconds.multiply(DecimalValue.BIG_DECIMAL_ONE_MILLION); BigInteger intMicros = microseconds.toBigInteger(); BigInteger[] parts = intMicros.divideAndRemainder(BigInteger.valueOf(1000000)); sdv.seconds = parts[0].longValue(); sdv.microseconds = parts[1].intValue(); return sdv; } /** * Construct a duration value as a number of milliseconds. * * @param milliseconds the number of milliseconds in the duration (may be negative) * @return the corresponding xs:dayTimeDuration value * @throws ValidationException if implementation-defined limits are exceeded, specifically * if the total number of seconds exceeds 2^63. */ public static DayTimeDurationValue fromMilliseconds(long milliseconds) throws ValidationException { int sign = longSignum(milliseconds); if (sign < 0) { milliseconds = -milliseconds; } try { return new DayTimeDurationValue( sign, 0, 0, 0, milliseconds / 1000, (int)(milliseconds % 1000) * 1000); } catch (IllegalArgumentException err) { // limits exceeded throw new ValidationException("Duration exceeds limits"); } } /** * Get the signum of a long (Not available as Long.signum() until JDK 1.5) * @param value the supplied long * @return the signum of the supplied value */ private static int longSignum(long value) { if (value > 0) { return +1; } else if (value == 0) { return 0; } else { return -1; } } /** * Construct a duration value as a number of microseconds. * * @param microseconds the number of microseconds in the duration. The maximum and minimum * limits are such that the number of days in the duration must fit in a 32-bit signed integer. * @return the xs:dayTimeDuration represented by the given number of microseconds * @throws IllegalArgumentException if the value is out of range. */ public static DayTimeDurationValue fromMicroseconds(long microseconds) throws IllegalArgumentException { int sign = longSignum(microseconds); if (sign < 0) { microseconds = -microseconds; } return new DayTimeDurationValue( sign, 0, 0, 0, microseconds / 1000000, (int)(microseconds % 1000000)); } /** * Multiply duration by a number. This is also used when dividing a duration by a number. */ public DurationValue multiply(double n) throws XPathException { if (Double.isNaN(n)) { XPathException err = new XPathException("Cannot multiply/divide a duration by NaN"); err.setErrorCode("FOCA0005"); throw err; } double m = (double)getLengthInMicroseconds(); double product = n * m; if (Double.isInfinite(product) || Double.isNaN(product) || product > Long.MAX_VALUE || product < Long.MIN_VALUE) { XPathException err = new XPathException("Overflow when multiplying/dividing a duration by a number"); err.setErrorCode("FODT0002"); throw err; } try { return fromMicroseconds((long)product); } catch (IllegalArgumentException err) { if (err.getCause() instanceof XPathException) { throw (XPathException)err.getCause(); } else { XPathException err2 = new XPathException("Overflow when multiplying/dividing a duration by a number", err); err2.setErrorCode("FODT0002"); throw err2; } } } /** * Find the ratio between two durations * * @param other the dividend * @return the ratio, as a decimal * @throws XPathException */ public DecimalValue divide(DurationValue other) throws XPathException { if (other instanceof DayTimeDurationValue) { BigDecimal v1 = BigDecimal.valueOf(getLengthInMicroseconds()); BigDecimal v2 = BigDecimal.valueOf(((DayTimeDurationValue)other).getLengthInMicroseconds()); if (v2.signum() == 0) { XPathException err = new XPathException("Divide by zero (durations)"); err.setErrorCode("FOAR0001"); throw err; } return new DecimalValue(v1.divide(v2, 20, BigDecimal.ROUND_HALF_EVEN)); } else { XPathException err = new XPathException("Cannot divide two durations of different type"); err.setErrorCode("XPTY0004"); throw err; } } /** * Add two dayTimeDurations */ public DurationValue add(DurationValue other) throws XPathException { if (other instanceof DayTimeDurationValue) { try { return fromMicroseconds(getLengthInMicroseconds() + ((DayTimeDurationValue)other).getLengthInMicroseconds()); } catch (IllegalArgumentException e) { XPathException err = new XPathException("Overflow when adding two durations"); err.setErrorCode("FODT0002"); throw err; } } else { XPathException err = new XPathException("Cannot add two durations of different type"); err.setErrorCode("XPTY0004"); throw err; } } /** * Subtract two dayTime-durations */ public DurationValue subtract(DurationValue other) throws XPathException { if (other instanceof DayTimeDurationValue) { try { return fromMicroseconds(getLengthInMicroseconds() - ((DayTimeDurationValue)other).getLengthInMicroseconds()); } catch (IllegalArgumentException e) { XPathException err = new XPathException("Overflow when subtracting two durations"); err.setErrorCode("FODT0002"); throw err; } } else { XPathException err = new XPathException("Cannot subtract two durations of different type"); err.setErrorCode("XPTY0004"); throw err; } } /** * Negate a duration (same as subtracting from zero, but it preserves the type of the original duration) * * @throws IllegalArgumentException in the extremely unlikely event that the duration is one that cannot * be negated (because the limit for positive durations is one second * off from the limit for negative durations) */ public DurationValue negate() throws IllegalArgumentException { return fromMicroseconds(-getLengthInMicroseconds()); } /** * Compare the value to another duration value * * @param other The other dateTime value * @return negative value if this one is the earler, 0 if they are chronologically equal, * positive value if this one is the later. For this purpose, dateTime values with an unknown * timezone are considered to be UTC values (the Comparable interface requires * a total ordering). * @throws ClassCastException if the other value is not a DateTimeValue (the parameter * is declared as Object to satisfy the Comparable interface) */ public int compareTo(Object other) { if (other instanceof DayTimeDurationValue) { long diff = getLengthInMicroseconds() - ((DayTimeDurationValue)other).getLengthInMicroseconds(); if (diff < 0) { return -1; } else if (diff > 0) { return +1; } else { return 0; } } else { throw new ClassCastException("Cannot compare a dayTimeDuration to an object of class " + other.getClass()); } } /** * Get a Comparable value that implements the XPath ordering comparison semantics for this value. * Returns null if the value is not comparable according to XPath rules. The default implementation * returns the value itself. This is modified for types such as * xs:duration which allow ordering comparisons in XML Schema, but not in XPath. * @param ordered true if an ordered comparable is needed * @param collator Collation used for string comparison * @param context XPath dynamic context */ public Object getXPathComparable(boolean ordered, StringCollator collator, XPathContext context) { return this; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/value/GDateValue.java0000644000175000017500000004155111133630214021344 0ustar eugeneeugenepackage net.sf.saxon.value; import net.sf.saxon.trans.Err; import net.sf.saxon.functions.Component; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.StandardNames; import net.sf.saxon.sort.ComparisonKey; import net.sf.saxon.trans.NoDynamicContextException; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ConversionResult; import net.sf.saxon.type.ValidationFailure; import java.util.*; /** * Abstract superclass for the primitive types containing date components: xs:date, xs:gYear, * xs:gYearMonth, xs:gMonth, xs:gMonthDay, xs:gDay */ public abstract class GDateValue extends CalendarValue { protected int year; // unlike the lexical representation, includes a year zero protected byte month; protected byte day; /** * Test whether a candidate date is actually a valid date in the proleptic Gregorian calendar */ protected static byte[] daysPerMonth = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; protected static final short[] monthData = {306, 337, 0, 31, 61, 92, 122, 153, 184, 214, 245, 275}; /** * Get the year component of the date (in local form) * @return the year component */ public int getYear() { return year; } /** * Get the month component of the date (in local form) * @return the month component (1-12) */ public byte getMonth() { return month; } /** * Get the day component of the date (in local form) * @return the day component (1-31) */ public byte getDay() { return day; } public GregorianCalendar getCalendar() { int tz = (hasTimezone() ? getTimezoneInMinutes() : 0); TimeZone zone = new SimpleTimeZone(tz * 60000, "LLL"); GregorianCalendar calendar = new GregorianCalendar(zone); calendar.setGregorianChange(new Date(Long.MIN_VALUE)); calendar.clear(); calendar.setLenient(false); int yr = year; if (year <= 0) { yr = 1 - year; calendar.set(Calendar.ERA, GregorianCalendar.BC); } calendar.set(yr, month - 1, day); calendar.set(Calendar.ZONE_OFFSET, tz * 60000); calendar.set(Calendar.DST_OFFSET, 0); calendar.getTime(); return calendar; } /** * Convert to Java object (for passing to external functions) */ // public Object convertAtomicToJava(Class target, XPathContext context) throws XPathException { // if (target.isAssignableFrom(Date.class)) { // return getCalendar().getTime(); // } else if (target.isAssignableFrom(GregorianCalendar.class)) { // return getCalendar(); // } else if (target.isAssignableFrom(DateValue.class)) { // return this; // } else if (target == Object.class) { // return getStringValue(); // } else { // Object o = convertSequenceToJava(target, context); // if (o == null) { // throw new XPathException("Conversion of date to " + target.getName() + // " is not supported"); // } // return o; // } // } // /** * Initialize the DateValue using a character string in the format yyyy-mm-dd and an optional time zone. * Input must have format [-]yyyy-mm-dd[([+|-]hh:mm | Z)] * @param d the "raw" DateValue to be populated * @param s the supplied string value * @return either the supplied GDateValue, with its data initialized; or a ValidationFailure */ protected static ConversionResult setLexicalValue(GDateValue d, CharSequence s) { StringTokenizer tok = new StringTokenizer(Whitespace.trimWhitespace(s).toString(), "-:+Z", true); try { if (!tok.hasMoreElements()) { return badDate("Too short", s); } String part = (String)tok.nextElement(); int era = +1; if ("+".equals(part)) { return badDate("Date may not start with '+' sign", s); } else if ("-".equals(part)) { era = -1; if (!tok.hasMoreElements()) { return badDate("No year after '-'", s); } part = (String)tok.nextElement(); } if (part.length() < 4) { return badDate("Year is less than four digits", s); } if (part.length() > 4 && part.charAt(0) == '0') { return badDate("When year exceeds 4 digits, leading zeroes are not allowed", s); } int value = DurationValue.simpleInteger(part); if (value < 0) { return badDate("Non-numeric year component", s); } d.year = value * era; if (d.year == 0) { return badDate("Year zero is not allowed", s); } if (era < 0) { d.year++; // internal representation allows a year zero. } if (!tok.hasMoreElements()) { return badDate("Too short", s); } if (!"-".equals(tok.nextElement())) { return badDate("Wrong delimiter after year", s); } if (!tok.hasMoreElements()) { return badDate("Too short", s); } part = (String)tok.nextElement(); if (part.length() != 2) { return badDate("Month must be two digits", s); } value = DurationValue.simpleInteger(part); if (value < 0) { return badDate("Non-numeric month component", s); } d.month = (byte)value; if (d.month < 1 || d.month > 12) { return badDate("Month is out of range", s); } if (!tok.hasMoreElements()) { return badDate("Too short", s); } if (!"-".equals(tok.nextElement())) { return badDate("Wrong delimiter after month", s); } if (!tok.hasMoreElements()) { return badDate("Too short", s); } part = (String)tok.nextElement(); if (part.length() != 2) { return badDate("Day must be two digits", s); } value = DurationValue.simpleInteger(part); if (value < 0) { return badDate("Non-numeric day component", s); } d.day = (byte)value; if (d.day < 1 || d.day > 31) { return badDate("Day is out of range", s); } int tzOffset; if (tok.hasMoreElements()) { String delim = (String)tok.nextElement(); if ("Z".equals(delim)) { tzOffset = 0; if (tok.hasMoreElements()) { return badDate("Continues after 'Z'", s); } d.setTimezoneInMinutes(tzOffset); } else if (!(!"+".equals(delim) && !"-".equals(delim))) { if (!tok.hasMoreElements()) { return badDate("Missing timezone", s); } part = (String)tok.nextElement(); value = DurationValue.simpleInteger(part); if (value < 0) { return badDate("Non-numeric timezone hour component", s); } int tzhour = value; if (part.length() != 2) { return badDate("Timezone hour must be two digits", s); } if (tzhour > 14) { return badDate("Timezone hour is out of range", s); } if (!tok.hasMoreElements()) { return badDate("No minutes in timezone", s); } if (!":".equals(tok.nextElement())) { return badDate("Wrong delimiter after timezone hour", s); } if (!tok.hasMoreElements()) { return badDate("No minutes in timezone", s); } part = (String)tok.nextElement(); value = DurationValue.simpleInteger(part); if (value < 0) { return badDate("Non-numeric timezone minute component", s); } int tzminute = value; if (part.length() != 2) { return badDate("Timezone minute must be two digits", s); } if (tzminute > 59) { return badDate("Timezone minute is out of range", s); } if (tok.hasMoreElements()) { return badDate("Continues after timezone", s); } tzOffset = (tzhour * 60 + tzminute); if ("-".equals(delim)) { tzOffset = -tzOffset; } d.setTimezoneInMinutes(tzOffset); } else { return badDate("Timezone format is incorrect", s); } } if (!isValidDate(d.year, d.month, d.day)) { return badDate("Non-existent date", s); } } catch (NumberFormatException err) { return badDate("Non-numeric component", s); } return d; } private static ValidationFailure badDate(String msg, CharSequence value) { ValidationFailure err = new ValidationFailure( "Invalid date " + Err.wrap(value, Err.VALUE) + " (" + msg + ")"); err.setErrorCode("FORG0001"); return err; } /** * Determine whether a given date is valid * @param year the year * @param month the month (1-12) * @param day the day (1-31) * @return true if this is a valid date */ public static boolean isValidDate(int year, int month, int day) { return month > 0 && month <= 12 && day > 0 && day <= daysPerMonth[month - 1] || month == 2 && day == 29 && isLeapYear(year); } /** * Test whether a year is a leap year * @param year the year * @return true if the supplied year is a leap year */ public static boolean isLeapYear(int year) { return (year % 4 == 0) && !(year % 100 == 0 && !(year % 400 == 0)); } /** * The equals() methods on atomic values is defined to follow the semantics of eq when applied * to two atomic values. When the other operand is not an atomic value, the result is undefined * (may be false, may be an exception). When the other operand is an atomic value that cannot be * compared with this one, the method returns false. *

    *

    The hashCode() method is consistent with equals().

    * *

    This implementation performs a context-free comparison: it fails with ClassCastException * if one value has a timezone and the other does not.

    * * @param o the other value * @return true if the other operand is an atomic value and the two values are equal as defined * by the XPath eq operator * @throws ClassCastException if the values are not comparable */ public boolean equals(Object o) { GDateValue gdv = (GDateValue)o; if (getPrimitiveType() == gdv.getPrimitiveType()) { return toDateTime().equals(gdv.toDateTime()); } else { throw new ClassCastException(GDateValue.class.getName()); } } public int hashCode() { return DateTimeValue.hashCode(year, month, day, (byte)12, (byte)0, (byte)0, 0, getTimezoneInMinutes()); } /** * Compare this value to another value of the same type, using the supplied context object * to get the implicit timezone if required. This method implements the XPath comparison semantics. * @param other the value to be compared * @param context the XPath dynamic evaluation context (needed only to get the implicit timezone) * @return -1 if this value is less, 0 if equal, +1 if greater */ public int compareTo(CalendarValue other, XPathContext context) throws NoDynamicContextException { if (getPrimitiveType() != other.getPrimitiveType()) { throw new ClassCastException("Cannot compare dates of different types"); // covers, for example, comparing a gYear to a gYearMonth } GDateValue v2 = (GDateValue)other; if (getTimezoneInMinutes() == other.getTimezoneInMinutes()) { // both values are in the same timezone (explicitly or implicitly) if (year != v2.year) { return IntegerValue.signum(year - v2.year); } if (month != v2.month) { return IntegerValue.signum(month - v2.month); } if (day != v2.day) { return IntegerValue.signum(day - v2.day); } return 0; } return toDateTime().compareTo(other.toDateTime(), context); } /** * Convert to DateTime. * @return the starting instant of the GDateValue (with the same timezone) */ public DateTimeValue toDateTime() { return new DateTimeValue(year, month, day, (byte)0, (byte)0, (byte)0, 0, getTimezoneInMinutes()); } public Comparable getSchemaComparable() { return new GDateComparable(); } /** * Get a component of the value. Returns null if the timezone component is * requested and is not present. */ public AtomicValue getComponent(int component) throws XPathException { switch (component) { case Component.YEAR_ALLOWING_ZERO: return Int64Value.makeIntegerValue(year); case Component.YEAR: return Int64Value.makeIntegerValue(year > 0 ? year : year-1); case Component.MONTH: return Int64Value.makeIntegerValue(month); case Component.DAY: return Int64Value.makeIntegerValue(day); case Component.TIMEZONE: if (hasTimezone()) { return DayTimeDurationValue.fromMilliseconds(getTimezoneInMinutes()*60000); } else { return null; } default: throw new IllegalArgumentException("Unknown component for date: " + component); } } private class GDateComparable implements Comparable { public GDateValue asGDateValue() { return GDateValue.this; } public int compareTo(Object o) { if (o instanceof GDateComparable) { if (asGDateValue().getPrimitiveType() != ((GDateComparable)o).asGDateValue().getPrimitiveType()) { return INDETERMINATE_ORDERING; } DateTimeValue dt0 = GDateValue.this.toDateTime(); DateTimeValue dt1 = ((GDateComparable)o).asGDateValue().toDateTime(); return dt0.getSchemaComparable().compareTo(dt1.getSchemaComparable()); } else { return INDETERMINATE_ORDERING; } } public boolean equals(Object o) { return compareTo(o) == 0; } public int hashCode() { return GDateValue.this.toDateTime().getSchemaComparable().hashCode(); } } /** * Get a comparison key for this value. Two values are equal if and only if they their comparison * keys are equal * @param context XPath dynamic evaluation context * @throws NoDynamicContextException if the implicit timezone is required and is not available * (because the method is being called at compile time) */ public ComparisonKey getComparisonKey(XPathContext context) throws NoDynamicContextException { return new ComparisonKey(StandardNames.XS_DATE, toDateTime().normalize(context)); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/value/IntegerValue.java0000644000175000017500000003263411033112257021760 0ustar eugeneeugenepackage net.sf.saxon.value; import net.sf.saxon.type.*; import net.sf.saxon.trans.Err; import net.sf.saxon.om.StandardNames; import net.sf.saxon.trans.XPathException; import java.math.BigInteger; /** * This class represents the XPath built-in type xs:integer. It is used for all * subtypes of xs:integer, other than user-defined subtypes. There are two implementations * of IntegerValue: {@link Int64Value}, which accommodates values up to 2^63, and * {@link BigIntegerValue}, which accommodates unlimited-length integers. */ public abstract class IntegerValue extends NumericValue { // static { // BuiltInAtomicType.init(); // } /** * IntegerValue representing the value -1 */ public static final Int64Value MINUS_ONE = new Int64Value(-1); /** * IntegerValue representing the value zero */ public static final Int64Value ZERO = new Int64Value(0); /** * IntegerValue representing the value +1 */ public static final Int64Value PLUS_ONE = new Int64Value(+1); /** * Array of small integer values */ public static final Int64Value[] SMALL_INTEGERS = { ZERO, PLUS_ONE, new Int64Value(2), new Int64Value(3), new Int64Value(4), new Int64Value(5), new Int64Value(6), new Int64Value(7), new Int64Value(8), new Int64Value(9), new Int64Value(10), new Int64Value(11), new Int64Value(12), new Int64Value(13), new Int64Value(14), new Int64Value(15), new Int64Value(16), new Int64Value(17), new Int64Value(18), new Int64Value(19), new Int64Value(20) }; /** * IntegerValue representing the maximum value for a long */ public static final Int64Value MAX_LONG = new Int64Value(Long.MAX_VALUE); /** * IntegerValue representing the minimum value for a long */ public static final Int64Value MIN_LONG = new Int64Value(Long.MIN_VALUE); /** * Static data identifying the min and max values for each built-in subtype of xs:integer. * This is a sequence of triples, each holding the fingerprint of the type, the minimum * value, and the maximum value. The special value NO_LIMIT indicates that there is no * minimum (or no maximum) for this type. The special value MAX_UNSIGNED_LONG represents the * value 2^64-1 */ private static long NO_LIMIT = -9999; private static long MAX_UNSIGNED_LONG = -9998; private static long[] ranges = { // arrange so the most frequently used types are near the start StandardNames.XS_INTEGER, NO_LIMIT, NO_LIMIT, StandardNames.XS_LONG, Long.MIN_VALUE, Long.MAX_VALUE, StandardNames.XS_INT, Integer.MIN_VALUE, Integer.MAX_VALUE, StandardNames.XS_SHORT, Short.MIN_VALUE, Short.MAX_VALUE, StandardNames.XS_BYTE, Byte.MIN_VALUE, Byte.MAX_VALUE, StandardNames.XS_NON_NEGATIVE_INTEGER, 0, NO_LIMIT, StandardNames.XS_POSITIVE_INTEGER, 1, NO_LIMIT, StandardNames.XS_NON_POSITIVE_INTEGER, NO_LIMIT, 0, StandardNames.XS_NEGATIVE_INTEGER, NO_LIMIT, -1, StandardNames.XS_UNSIGNED_LONG, 0, MAX_UNSIGNED_LONG, StandardNames.XS_UNSIGNED_INT, 0, 4294967295L, StandardNames.XS_UNSIGNED_SHORT, 0, 65535, StandardNames.XS_UNSIGNED_BYTE, 0, 255}; /** * Factory method: makes either an Int64Value or a BigIntegerValue depending on the value supplied * @param value the supplied integer value * @return the value as a BigIntegerValue or Int64Value as appropriate */ public static IntegerValue makeIntegerValue(BigInteger value) { if (value.compareTo(BigIntegerValue.MAX_LONG) > 0 || value.compareTo(BigIntegerValue.MIN_LONG) < 0) { return new BigIntegerValue(value); } else { return Int64Value.makeIntegerValue(value.longValue()); } } /** * This class allows subtypes of xs:integer to be held, as well as xs:integer values. * This method sets the required type label. Note that this method modifies the value in situ. * @param type the subtype of integer required * @param validate true if validation is required, false if the caller warrants that the value * is valid for the subtype * @return null if the operation succeeds, or a ValidationException if the value is out of range */ public abstract ValidationFailure convertToSubType(BuiltInAtomicType type, boolean validate); /** * This class allows subtypes of xs:integer to be held, as well as xs:integer values. * This method sets the required type label. Note that this method modifies the value in situ. * @param type the subtype of integer required * @return null if the operation succeeds, or a ValidationException if the value is out of range */ public abstract ValidationFailure validateAgainstSubType(BuiltInAtomicType type); /** * Check that a value is in range for the specified subtype of xs:integer * * @param value the value to be checked * @param type the required item type, a subtype of xs:integer * @return true if successful, false if value is out of range for the subtype */ public static boolean checkRange(long value, BuiltInAtomicType type) { int fp = type.getFingerprint(); for (int i = 0; i < ranges.length; i += 3) { if (ranges[i] == fp) { long min = ranges[i+1]; if (min != NO_LIMIT && value < min) { return false; } long max = ranges[i+2]; return (max == NO_LIMIT || max == MAX_UNSIGNED_LONG || value <= max); } } throw new IllegalArgumentException( "No range information found for integer subtype " + type.getDescription()); } /** * Check that a BigInteger is within the required range for a given integer subtype. * This method is expensive, so it should not be used unless the BigInteger is outside the range of a long. * @param big the supplied BigInteger * @param type the derived type (a built-in restriction of xs:integer) to check the value against * @return true if the value is within the range for the derived type */ public static boolean checkBigRange(BigInteger big, BuiltInAtomicType type) { for (int i = 0; i < ranges.length; i += 3) { if (ranges[i] == type.getFingerprint()) { long min = ranges[i+1]; if (min != NO_LIMIT && BigInteger.valueOf(min).compareTo(big) > 0) { return false; } long max = ranges[i+2]; if (max == NO_LIMIT) { return true; } else if (max == MAX_UNSIGNED_LONG) { return BigIntegerValue.MAX_UNSIGNED_LONG.compareTo(big) >= 0; } else { return BigInteger.valueOf(max).compareTo(big) >= 0; } } } throw new IllegalArgumentException( "No range information found for integer subtype " + type.getDescription()); } /** * Static factory method to convert strings to integers. * @param s CharSequence representing the string to be converted * @return either an Int64Value or a BigIntegerValue representing the value of the String, or * a ValidationFailure encapsulating an Exception if the value cannot be converted. */ public static ConversionResult stringToInteger(CharSequence s) { int len = s.length(); int start = 0; int last = len - 1; while (start < len && s.charAt(start) <= 0x20) { start++; } while (last > start && s.charAt(last) <= 0x20) { last--; } if (start > last) { return numericError("Cannot convert zero-length string to an integer"); } if (last - start < 16) { // for short numbers, we do the conversion ourselves, to avoid throwing unnecessary exceptions boolean negative = false; long value = 0; int i=start; if (s.charAt(i) == '+') { i++; } else if (s.charAt(i) == '-') { negative = true; i++; } if (i > last) { return numericError("Cannot convert string " + Err.wrap(s, Err.VALUE) + " to integer: no digits after the sign"); } while (i <= last) { char d = s.charAt(i++); if (d >= '0' && d <= '9') { value = 10*value + (d-'0'); } else { return numericError("Cannot convert string " + Err.wrap(s, Err.VALUE) + " to an integer"); } } return Int64Value.makeIntegerValue((negative ? -value : value)); } else { // for longer numbers, rely on library routines try { CharSequence t = Whitespace.trimWhitespace(s); if (t.charAt(0) == '+') { t = t.subSequence(1, t.length()); } if (t.length() < 16) { return new Int64Value(Long.parseLong(t.toString())); } else { return new BigIntegerValue(new BigInteger(t.toString())); } } catch (NumberFormatException err) { return numericError("Cannot convert string " + Err.wrap(s, Err.VALUE) + " to an integer"); } } } /** * Helper method to handle errors converting a string to a number * @param message error message * @return a ValidationFailure encapsulating an Exception describing the error */ private static ValidationFailure numericError(String message) { ValidationFailure err = new ValidationFailure(message); err.setErrorCode("FORG0001"); return err; } /** * Determine the primitive type of the value. This delivers the same answer as * getItemType().getPrimitiveItemType(). The primitive types are * the 19 primitive types of XML Schema, plus xs:integer, xs:dayTimeDuration and xs:yearMonthDuration, * and xs:untypedAtomic. For external objects, the result is AnyAtomicType. */ public BuiltInAtomicType getPrimitiveType() { return BuiltInAtomicType.INTEGER; } /** * Determine whether the value is a whole number, that is, whether it compares * equal to some integer * * @return always true for this implementation */ public boolean isWholeNumber() { return true; } /** * Add another integer * @param other the other integer * @return the result of the addition */ public abstract IntegerValue plus(IntegerValue other); /** * Subtract another integer * @param other the other integer * @return the result of the subtraction */ public abstract IntegerValue minus(IntegerValue other); /** * Multiply by another integer * @param other the other integer * @return the result of the multiplication */ public abstract IntegerValue times(IntegerValue other); /** * Divide by another integer * @param other the other integer * @return the result of the division * @throws XPathException if the other integer is zero */ public abstract NumericValue div(IntegerValue other) throws XPathException; /** * Take modulo another integer * @param other the other integer * @return the result of the modulo operation (the remainder) * @throws XPathException if the other integer is zero */ public abstract IntegerValue mod(IntegerValue other) throws XPathException; /** * Integer divide by another integer * @param other the other integer * @return the result of the integer division * @throws XPathException if the other integer is zero */ public abstract IntegerValue idiv(IntegerValue other) throws XPathException; /** * Get the value as a BigInteger * @return the value, as a BigInteger */ public abstract BigInteger asBigInteger(); /** * Get the signum of an int * @param i the int * @return -1 if the integer is negative, 0 if it is zero, +1 if it is positive */ protected static int signum(int i) { return (i >> 31) | (-i >>> 31); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/value/TimeValue.java0000644000175000017500000006125711033112257021264 0ustar eugeneeugenepackage net.sf.saxon.value; import net.sf.saxon.trans.Err; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.functions.Component; import net.sf.saxon.om.FastStringBuffer; import net.sf.saxon.om.StandardNames; import net.sf.saxon.sort.ComparisonKey; import net.sf.saxon.trans.NoDynamicContextException; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.AtomicType; import net.sf.saxon.type.BuiltInAtomicType; import net.sf.saxon.type.ConversionResult; import net.sf.saxon.type.ValidationFailure; import java.math.BigDecimal; import java.util.*; /** * A value of type xs:time */ public final class TimeValue extends CalendarValue implements Comparable { private byte hour; private byte minute; private byte second; private int microsecond; private TimeValue() { } /** * Construct a time value given the hour, minute, second, and microsecond components. * This constructor performs no validation. * * @param hour the hour value, 0-23 * @param minute the minutes value, 0-59 * @param second the seconds value, 0-59 * @param microsecond the number of microseconds, 0-999999 * @param tz the timezone displacement in minutes from UTC. Supply the value * {@link CalendarValue#NO_TIMEZONE} if there is no timezone component. */ public TimeValue(byte hour, byte minute, byte second, int microsecond, int tz) { this.hour = hour; this.minute = minute; this.second = second; this.microsecond = microsecond; setTimezoneInMinutes(tz); typeLabel = BuiltInAtomicType.TIME; } /** * Constructor: create a time value given a Java calendar object * * @param calendar holds the date and time * @param tz the timezone offset in minutes, or NO_TIMEZONE indicating that there is no timezone */ public TimeValue(GregorianCalendar calendar, int tz) { hour = (byte)(calendar.get(Calendar.HOUR_OF_DAY)); minute = (byte)(calendar.get(Calendar.MINUTE)); second = (byte)(calendar.get(Calendar.SECOND)); microsecond = calendar.get(Calendar.MILLISECOND) * 1000; setTimezoneInMinutes(tz); typeLabel = BuiltInAtomicType.TIME; } /** * Static factory method: create a time value from a supplied string, in * ISO 8601 format * * @param s the time in the lexical format hh:mm:ss[.ffffff] followed optionally by * timezone in the form [+-]hh:mm or Z * @return either a TimeValue corresponding to the xs:time, or a ValidationFailure * if the supplied value was invalid */ public static ConversionResult makeTimeValue(CharSequence s) throws XPathException { // input must have format hh:mm:ss[.fff*][([+|-]hh:mm | Z)] TimeValue tv = new TimeValue(); StringTokenizer tok = new StringTokenizer(Whitespace.trimWhitespace(s).toString(), "-:.+Z", true); if (!tok.hasMoreElements()) { return badTime("too short", s); } String part = (String)tok.nextElement(); if (part.length() != 2) { return badTime("hour must be two digits", s); } int value = DurationValue.simpleInteger(part); if (value < 0) { return badTime("Non-numeric hour component", s); } tv.hour = (byte)value; if (tv.hour > 24) { return badTime("hour is out of range", s); } if (!tok.hasMoreElements()) { return badTime("too short", s); } if (!":".equals(tok.nextElement())) { return badTime("wrong delimiter after hour", s); } if (!tok.hasMoreElements()) { return badTime("too short", s); } part = (String)tok.nextElement(); if (part.length() != 2) { return badTime("minute must be two digits", s); } value = DurationValue.simpleInteger(part); if (value < 0) { return badTime("Non-numeric minute component", s); } tv.minute = (byte)value; if (tv.minute > 59) { return badTime("minute is out of range", s); } if (tv.hour == 24 && tv.minute != 0) { return badTime("If hour is 24, minute must be 00", s); } if (!tok.hasMoreElements()) { return badTime("too short", s); } if (!":".equals(tok.nextElement())) { return badTime("wrong delimiter after minute", s); } if (!tok.hasMoreElements()) { return badTime("too short", s); } part = (String)tok.nextElement(); if (part.length() != 2) { return badTime("second must be two digits", s); } value = DurationValue.simpleInteger(part); if (value < 0) { return badTime("Non-numeric second component", s); } tv.second = (byte)value; if (tv.second > 59) { return badTime("second is out of range", s); } if (tv.hour == 24 && tv.second != 0) { return badTime("If hour is 24, second must be 00", s); } int tz = 0; int state = 0; while (tok.hasMoreElements()) { if (state == 9) { return badTime("characters after the end", s); } String delim = (String)tok.nextElement(); if (".".equals(delim)) { if (state != 0) { return badTime("decimal separator occurs twice", s); } if (!tok.hasMoreElements()) { return badTime("decimal point must be followed by digits", s); } part = (String)tok.nextElement(); value = DurationValue.simpleInteger(part); if (value < 0) { return badTime("Non-numeric fractional seconds component", s); } double fractionalSeconds = Double.parseDouble('.' + part); tv.microsecond = (int)(Math.round(fractionalSeconds * 1000000)); if (tv.hour == 24 && tv.microsecond != 0) { return badTime("If hour is 24, fractional seconds must be 0", s); } state = 1; } else if ("Z".equals(delim)) { if (state > 1) { return badTime("Z cannot occur here", s); } tz = 0; state = 9; // we've finished tv.setTimezoneInMinutes(0); } else if ("+".equals(delim) || "-".equals(delim)) { if (state > 1) { return badTime(delim + " cannot occur here", s); } state = 2; if (!tok.hasMoreElements()) { return badTime("missing timezone", s); } part = (String)tok.nextElement(); if (part.length() != 2) { return badTime("timezone hour must be two digits", s); } value = DurationValue.simpleInteger(part); if (value < 0) { return badTime("Non-numeric timezone hour component", s); } tz = value * 60; if (tz > 14 * 60) { return badTime("timezone hour is out of range", s); } //if (tz > 12 * 60) return badTime("Because of Java limitations, Saxon currently limits the timezone to +/- 12 hours"); if ("-".equals(delim)) { tz = -tz; } } else if (":".equals(delim)) { if (state != 2) { return badTime("colon cannot occur here", s); } state = 9; part = (String)tok.nextElement(); value = DurationValue.simpleInteger(part); if (value < 0) { return badTime("Non-numeric timezone minute component", s); } int tzminute = value; if (part.length() != 2) { return badTime("timezone minute must be two digits", s); } if (tzminute > 59) { return badTime("timezone minute is out of range", s); } if (tz < 0) { tzminute = -tzminute; } tz += tzminute; tv.setTimezoneInMinutes(tz); } else { return badTime("timezone format is incorrect", s); } } if (state == 2 || state == 3) { return badTime("timezone incomplete", s); } if (tv.hour == 24) { tv.hour = 0; } tv.typeLabel = BuiltInAtomicType.TIME; return tv; } private static ValidationFailure badTime(String msg, CharSequence value) { ValidationFailure err = new ValidationFailure( "Invalid time " + Err.wrap(value, Err.VALUE) + " (" + msg + ")"); err.setErrorCode("FORG0001"); return err; } /** * Determine the primitive type of the value. This delivers the same answer as * getItemType().getPrimitiveItemType(). The primitive types are * the 19 primitive types of XML Schema, plus xs:integer, xs:dayTimeDuration and xs:yearMonthDuration, * and xs:untypedAtomic. For external objects, the result is AnyAtomicType. */ public BuiltInAtomicType getPrimitiveType() { return BuiltInAtomicType.TIME; } /** * Get the hour component, 0-23 * * @return the hour */ public byte getHour() { return hour; } /** * Get the minute component, 0-59 * * @return the minute */ public byte getMinute() { return minute; } /** * Get the second component, 0-59 * * @return the second */ public byte getSecond() { return second; } /** * Get the microsecond component, 0-999999 * * @return the microseconds */ public int getMicrosecond() { return microsecond; } /** * Convert to target data type * * @param requiredType an integer identifying the required atomic type * @param context XPath dynamic evaluation context * @return an AtomicValue, a value of the required type; or an ErrorValue */ public ConversionResult convertPrimitive(BuiltInAtomicType requiredType, boolean validate, XPathContext context) { switch (requiredType.getPrimitiveType()) { case StandardNames.XS_TIME: case StandardNames.XS_ANY_ATOMIC_TYPE: return this; case StandardNames.XS_STRING: return new StringValue(getStringValueCS()); case StandardNames.XS_UNTYPED_ATOMIC: return new UntypedAtomicValue(getStringValueCS()); default: ValidationFailure err = new ValidationFailure("Cannot convert time to " + requiredType.getDisplayName()); err.setErrorCode("XPTY0004"); return err; } } /** * Convert to string * * @return ISO 8601 representation, in the localized timezone * (the timezone held within the value). */ public CharSequence getStringValueCS() { FastStringBuffer sb = new FastStringBuffer(16); appendTwoDigits(sb, hour); sb.append(':'); appendTwoDigits(sb, minute); sb.append(':'); appendTwoDigits(sb, second); if (microsecond != 0) { sb.append('.'); int ms = microsecond; int div = 100000; while (ms > 0) { int d = ms / div; sb.append((char)(d + '0')); ms = ms % div; div /= 10; } } if (hasTimezone()) { appendTimezone(sb); } return sb; } /** * Get the canonical lexical representation as defined in XML Schema. This is not always the same * as the result of casting to a string according to the XPath rules. For an xs:time it is the * time adjusted to UTC * * @return the canonical lexical representation if defined in XML Schema */ public CharSequence getCanonicalLexicalRepresentation() { if (hasTimezone() && getTimezoneInMinutes() != 0) { return adjustTimezone(0).getStringValueCS(); } else { return getStringValueCS(); } } /** * Convert to a DateTime value. The date components represent a reference date, as defined * in the spec for comparing times. */ public DateTimeValue toDateTime() { return new DateTimeValue(1972, (byte)12, (byte)31, hour, minute, second, microsecond, getTimezoneInMinutes()); } /** * Get a Java Calendar object corresponding to this time, on a reference date */ public GregorianCalendar getCalendar() { // create a calendar using the specified timezone int tz = (hasTimezone() ? getTimezoneInMinutes() : 0); TimeZone zone = new SimpleTimeZone(tz * 60000, "LLL"); GregorianCalendar calendar = new GregorianCalendar(zone); calendar.setLenient(false); // use a reference date of 1972-12-31 int year = 1972; int month = 11; int day = 31; calendar.set(year, month, day, hour, minute, second); calendar.set(Calendar.MILLISECOND, microsecond / 1000); calendar.set(Calendar.ZONE_OFFSET, tz * 60000); calendar.set(Calendar.DST_OFFSET, 0); calendar.getTime(); return calendar; } /** * Make a copy of this time value, * but with a different type label * * @param typeLabel the new type label. This must be a subtype of xs:time. */ public AtomicValue copyAsSubType(AtomicType typeLabel) { TimeValue v = new TimeValue(hour, minute, second, microsecond, getTimezoneInMinutes()); v.typeLabel = typeLabel; return v; } /** * Return a new time with the same normalized value, but * in a different timezone. This is called only for a TimeValue that has an explicit timezone * * @param timezone the new timezone offset, in minutes * @return the time in the new timezone. This will be a new TimeValue unless no change * was required to the original value */ public CalendarValue adjustTimezone(int timezone) { DateTimeValue dt = (DateTimeValue)toDateTime().adjustTimezone(timezone); return new TimeValue(dt.getHour(), dt.getMinute(), dt.getSecond(), dt.getMicrosecond(), dt.getTimezoneInMinutes()); } /** * Convert to Java object (for passing to external functions) */ // public Object convertAtomicToJava(Class target, XPathContext context) throws XPathException { // if (target.isAssignableFrom(TimeValue.class)) { // return this; // } else if (target == String.class) { // return getStringValue(); // } else if (target == Object.class) { // return getStringValue(); // } else { // Object o = super.convertSequenceToJava(target, context); // if (o == null) { // throw new XPathException("Conversion of time to " + target.getName() + // " is not supported"); // } // return o; // } // } // /** * Get a component of the value. Returns null if the timezone component is * requested and is not present. */ public AtomicValue getComponent(int component) throws XPathException { switch (component) { case Component.HOURS: return Int64Value.makeIntegerValue(hour); case Component.MINUTES: return Int64Value.makeIntegerValue(minute); case Component.SECONDS: BigDecimal d = BigDecimal.valueOf(microsecond); d = d.divide(DecimalValue.BIG_DECIMAL_ONE_MILLION, 6, BigDecimal.ROUND_HALF_UP); d = d.add(BigDecimal.valueOf(second)); return new DecimalValue(d); case Component.WHOLE_SECONDS: //(internal use only) return Int64Value.makeIntegerValue(second); case Component.MICROSECONDS: return new Int64Value(microsecond); case Component.TIMEZONE: if (hasTimezone()) { return DayTimeDurationValue.fromMilliseconds(getTimezoneInMinutes() * 60000); } else { return null; } default: throw new IllegalArgumentException("Unknown component for time: " + component); } } /** * Get a Comparable value that implements the XPath ordering comparison semantics for this value. * Returns null if the value is not comparable according to XPath rules. The default implementation * returns null. This is overridden for types that allow ordered comparisons in XPath: numeric, boolean, * string, date, time, dateTime, yearMonthDuration, dayTimeDuration, and anyURI. * @param ordered true if an ordered comparison is required * @param collator collation to be used for strings * @param context XPath dynamic evaluation context */ // public Object getXPathComparable(boolean ordered, StringCollator collator, XPathContext context) { // return this; // } /** * Compare the value to another dateTime value * * @param other The other dateTime value * @return negative value if this one is the earler, 0 if they are chronologically equal, * positive value if this one is the later. For this purpose, dateTime values with an unknown * timezone are considered to be UTC values (the Comparable interface requires * a total ordering). * @throws ClassCastException if the other value is not a TimeValue (the parameter * is declared as Object to satisfy the Comparable interface) */ public int compareTo(Object other) { TimeValue otherTime = (TimeValue)other; if (getTimezoneInMinutes() == otherTime.getTimezoneInMinutes()) { if (hour != otherTime.hour) { return IntegerValue.signum(hour - otherTime.hour); } else if (minute != otherTime.minute) { return IntegerValue.signum(minute - otherTime.minute); } else if (second != otherTime.second) { return IntegerValue.signum(second - otherTime.second); } else if (microsecond != otherTime.microsecond) { return IntegerValue.signum(microsecond - otherTime.microsecond); } else { return 0; } } else { return toDateTime().compareTo(otherTime.toDateTime()); } } /** * Compare the value to another dateTime value * * @param other The other dateTime value * @param context the XPath dynamic evaluation context * @return negative value if this one is the earler, 0 if they are chronologically equal, * positive value if this one is the later. For this purpose, dateTime values with an unknown * timezone are considered to be UTC values (the Comparable interface requires * a total ordering). * @throws ClassCastException if the other value is not a DateTimeValue (the parameter * is declared as Object to satisfy the Comparable interface) * @throws NoDynamicContextException if the implicit timezone is required and is not available * (because the function is called at compile time) */ public int compareTo(CalendarValue other, XPathContext context) throws NoDynamicContextException { if (!(other instanceof TimeValue)) { throw new ClassCastException("Time values are not comparable to " + other.getClass()); } TimeValue otherTime = (TimeValue)other; if (getTimezoneInMinutes() == otherTime.getTimezoneInMinutes()) { // The values have the same time zone, or neither has a timezone return compareTo(other); } else { return toDateTime().compareTo(otherTime.toDateTime(), context); } } public Comparable getSchemaComparable() { return new TimeComparable(); } private class TimeComparable implements Comparable { public TimeValue asTimeValue() { return TimeValue.this; } public int compareTo(Object o) { if (o instanceof TimeComparable) { DateTimeValue dt0 = asTimeValue().toDateTime(); DateTimeValue dt1 = ((TimeComparable)o).asTimeValue().toDateTime(); return dt0.getSchemaComparable().compareTo(dt1.getSchemaComparable()); } else { return INDETERMINATE_ORDERING; } } public boolean equals(Object o) { return compareTo(o) == 0; } public int hashCode() { return TimeValue.this.toDateTime().getSchemaComparable().hashCode(); } } /** * Get a comparison key for this value. Two values are equal if and only if they their comparison * keys are equal * @param context XPath dynamic context * @throws NoDynamicContextException if the implicit timezone is required and is not available */ public ComparisonKey getComparisonKey(XPathContext context) throws NoDynamicContextException { return new ComparisonKey(StandardNames.XS_TIME, toDateTime().normalize(context)); } public boolean equals(Object other) { return compareTo(other) == 0; } public int hashCode() { return DateTimeValue.hashCode( 1951, (byte)10, (byte)11, hour, minute, second, microsecond, getTimezoneInMinutes()); } /** * Add a duration to a dateTime * * @param duration the duration to be added (may be negative) * @return the new date * @throws net.sf.saxon.trans.XPathException * if the duration is an xs:duration, as distinct from * a subclass thereof */ public CalendarValue add(DurationValue duration) throws XPathException { if (duration instanceof DayTimeDurationValue) { DateTimeValue dt = (DateTimeValue)toDateTime().add(duration); return new TimeValue(dt.getHour(), dt.getMinute(), dt.getSecond(), dt.getMicrosecond(), getTimezoneInMinutes()); } else { XPathException err = new XPathException("Time+Duration arithmetic is supported only for xs:dayTimeDuration"); err.setErrorCode("XPTY0004"); err.setIsTypeError(true); throw err; } } /** * Determine the difference between two points in time, as a duration * * @param other the other point in time * @param context XPath dynamic evaluation context * @return the duration as an xs:dayTimeDuration * @throws XPathException for example if one value is a date and the other is a time */ public DayTimeDurationValue subtract(CalendarValue other, XPathContext context) throws XPathException { if (!(other instanceof TimeValue)) { XPathException err = new XPathException("First operand of '-' is a time, but the second is not"); err.setIsTypeError(true); throw err; } return super.subtract(other, context); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/value/GYearValue.java0000644000175000017500000001235311077605201021372 0ustar eugeneeugenepackage net.sf.saxon.value; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.FastStringBuffer; import net.sf.saxon.om.StandardNames; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.*; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Implementation of the xs:gYear data type */ public class GYearValue extends GDateValue { private static Pattern regex = Pattern.compile("(-?[0-9]+)(Z|[+-][0-9][0-9]:[0-9][0-9])?"); private GYearValue(){} public static ConversionResult makeGYearValue(CharSequence value) { GYearValue g = new GYearValue(); Matcher m = regex.matcher(Whitespace.trimWhitespace(value)); if (!m.matches()) { return new ValidationFailure("Cannot convert '" + value + "' to a gYear"); } String base = m.group(1); String tz = m.group(2); String date = base + "-01-01" + (tz==null ? "" : tz); g.typeLabel = BuiltInAtomicType.G_YEAR; return setLexicalValue(g, date); } public GYearValue(int year, int tz) { this(year, tz, BuiltInAtomicType.G_YEAR); } public GYearValue(int year, int tz, AtomicType type) { this.year = year; this.month = 1; this.day = 1; setTimezoneInMinutes(tz); this.typeLabel = type; } /** * Make a copy of this date, time, or dateTime value * @param typeLabel */ public AtomicValue copyAsSubType(AtomicType typeLabel) { GYearValue v = new GYearValue(year, getTimezoneInMinutes()); v.typeLabel = typeLabel; return v; } /** * Determine the primitive type of the value. This delivers the same answer as * getItemType().getPrimitiveItemType(). The primitive types are * the 19 primitive types of XML Schema, plus xs:integer, xs:dayTimeDuration and xs:yearMonthDuration, * and xs:untypedAtomic. For external objects, the result is AnyAtomicType. */ public BuiltInAtomicType getPrimitiveType() { return BuiltInAtomicType.G_YEAR; } /** * Convert to target data type * @param requiredType an integer identifying the required atomic type * @param context * @return an AtomicValue, a value of the required type; or an ErrorValue */ public ConversionResult convertPrimitive(BuiltInAtomicType requiredType, boolean validate, XPathContext context) { switch(requiredType.getPrimitiveType()) { case StandardNames.XS_G_YEAR: case StandardNames.XS_ANY_ATOMIC_TYPE: return this; case StandardNames.XS_STRING: return new StringValue(getStringValueCS()); case StandardNames.XS_UNTYPED_ATOMIC: return new UntypedAtomicValue(getStringValueCS()); default: ValidationFailure err = new ValidationFailure("Cannot convert gYear to " + requiredType.getDisplayName()); err.setErrorCode("XPTY0004"); return err; } } public CharSequence getStringValueCS() { FastStringBuffer sb = new FastStringBuffer(16); int yr = year; if (year <= 0) { sb.append('-'); yr = -yr +1; // no year zero in lexical space } appendString(sb, yr, (yr>9999 ? (yr+"").length() : 4)); if (hasTimezone()) { appendTimezone(sb); } return sb; } /** * Add a duration to this date/time value * * @param duration the duration to be added (which might be negative) * @return a new date/time value representing the result of adding the duration. The original * object is not modified. * @throws net.sf.saxon.trans.XPathException * */ public CalendarValue add(DurationValue duration) throws XPathException { XPathException err = new XPathException("Cannot add a duration to an xs:gYear"); err.setErrorCode("XPTY0004"); throw err; } /** * Return a new date, time, or dateTime with the same normalized value, but * in a different timezone * * @param tz the new timezone, in minutes * @return the date/time in the new timezone */ public CalendarValue adjustTimezone(int tz) { DateTimeValue dt = (DateTimeValue)toDateTime().adjustTimezone(tz); return new GYearValue(dt.getYear(), dt.getTimezoneInMinutes()); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Saxonica Limited // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none //saxonb-9.1.0.8/bj/net/sf/saxon/value/SingletonClosure.java0000644000175000017500000001067311033112257022664 0ustar eugeneeugenepackage net.sf.saxon.value; import net.sf.saxon.event.SequenceReceiver; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.expr.Expression; import net.sf.saxon.om.Item; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.om.SingletonIterator; import net.sf.saxon.trans.XPathException; /** * A SingletonClosure represents a value that has not yet been evaluated: the value is represented * by an expression, together with saved values of all the context variables that the * expression depends on. The value of a SingletonClosure is always either a single item * or an empty sequence. * *

    The expression may depend on local variables and on the context item; these values * are held in the saved XPathContext object that is kept as part of the Closure, and they * will always be read from that object. The expression may also depend on global variables; * these are unchanging, so they can be read from the Bindery in the normal way. Expressions * that depend on other contextual information, for example the values of position(), last(), * current(), current-group(), should not be evaluated using this mechanism: they should * always be evaluated eagerly. This means that the Closure does not need to keep a copy * of these context variables.

    */ public class SingletonClosure extends Closure { private boolean built = false; private Item value = null; /** * Constructor should not be called directly, instances should be made using the make() method. * @param exp the expression to be lazily evaluated * @param context the context in which the expression should be evaluated */ public SingletonClosure(Expression exp, XPathContext context) throws XPathException { expression = exp; savedXPathContext = context.newContext(); saveContext(exp, context); //System.err.println("Creating SingletonClosure"); } /** * Evaluate the expression in a given context to return an iterator over a sequence */ public SequenceIterator iterate() throws XPathException { return SingletonIterator.makeIterator(asItem()); } /** * Process the expression by writing the value to the current Receiver * * @param context The dynamic context, giving access to the current node, * the current variables, etc. */ public void process(XPathContext context) throws XPathException { SequenceReceiver out = context.getReceiver(); out.append(asItem(), 0, NodeInfo.ALL_NAMESPACES); } /** * Return the value in the form of an Item * * @return the value in the form of an Item */ public Item asItem() throws XPathException { if (!built) { value = expression.evaluateItem(savedXPathContext); built = true; savedXPathContext = null; // release variables saved in the context to the garbage collector } return value; } /** * Get the n'th item in the sequence (starting from 0). This is defined for all * SequenceValues, but its real benefits come for a SequenceValue stored extensionally */ public Item itemAt(int n) throws XPathException { if (n != 0) { return null; } return asItem(); } /** * Get the length of the sequence */ public int getLength() throws XPathException { return (asItem() == null ? 0 : 1); } /** * Return a value containing all the items in the sequence returned by this * SequenceIterator * * @return the corresponding value */ public Value materialize() throws XPathException { return Value.asValue(asItem()); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/value/Int64Value.java0000644000175000017500000006050511133653116021272 0ustar eugeneeugenepackage net.sf.saxon.value; import net.sf.saxon.expr.Calculator; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.*; import net.sf.saxon.om.StandardNames; import java.math.BigDecimal; import java.math.BigInteger; /** * An integer value: note this is a subtype of decimal in XML Schema, not a primitive type. * This class supports integer values in the range permitted by a Java "long", * and also supports the built-in subtypes of xs:integer. */ public final class Int64Value extends IntegerValue { private long value; /** * Constructor supplying a long * * @param value the value of the IntegerValue */ public Int64Value(long value) { this.value = value; typeLabel = BuiltInAtomicType.INTEGER; } /** * Constructor for a subtype, supplying a long and a type label. * * @param val The supplied value, as an integer * @param type the required item type, a subtype of xs:integer * @param check Set to true if the method is required to check that the value is in range; * false if the caller can guarantee that the value has already been checked. * @throws XPathException if the supplied value is out of range for the * target type */ public Int64Value(long val, BuiltInAtomicType type, boolean check) throws XPathException { value = val; typeLabel = type; if (check && !checkRange(value, type)) { XPathException err = new XPathException("Integer value " + val + " is out of range for the requested type " + type.getDescription()); err.setErrorCode("XPTY0004"); err.setIsTypeError(true); throw err; } } /** * Factory method: allows Int64Value objects to be reused. Note that * a value obtained using this method must not be modified to set a type label, because * the value is in general shared. * @param value the integer value * @return an Int64Value with this integer value */ public static Int64Value makeIntegerValue(long value) { if (value <= 20 && value >= 0) { return SMALL_INTEGERS[(int)value]; } else { return new Int64Value(value); } } /** * Factory method to create a derived value, with no checking of the value against the * derived type * @param val the integer value * @param type the subtype of xs:integer * @return the constructed value */ public static Int64Value makeDerived(long val, AtomicType type) { Int64Value v = new Int64Value(val); v.typeLabel = type; return v; } /** * Factory method returning the integer -1, 0, or +1 according as the argument * is negative, zero, or positive * @param val the value to be tested * @return the Int64Value representing -1, 0, or +1 */ public static Int64Value signum(long val) { if (val == 0) { return IntegerValue.ZERO; } else { return (val < 0 ? IntegerValue.MINUS_ONE : IntegerValue.PLUS_ONE); } } /** * Create a copy of this atomic value, with a different type label * * @param typeLabel the type label of the new copy. The caller is responsible for checking that * the value actually conforms to this type. */ public AtomicValue copyAsSubType(AtomicType typeLabel) { Int64Value v = new Int64Value(value); v.typeLabel = typeLabel; return v; } /** * Convert the value to a subtype of xs:integer * @param subtype the target subtype * @param validate true if validation is required; false if the caller already knows that the value is valid * @return null if the conversion succeeds; a ValidationFailure describing the failure if it fails. Note * that the exception is returned, not thrown. */ public ValidationFailure convertToSubType(BuiltInAtomicType subtype, boolean validate) { if (!validate) { setSubType(subtype); return null; } else if (checkRange(subtype)) { return null; } else { ValidationFailure err = new ValidationFailure("String " + value + " cannot be converted to integer subtype " + subtype.getDescription()); err.setErrorCode("FORG0001"); return err; } } /** * This class allows subtypes of xs:integer to be held, as well as xs:integer values. * This method sets the required type label. Note that this method modifies the value in situ. * * @param type the subtype of integer required * @return null if the operation succeeds, or a ValidationException if the value is out of range */ public ValidationFailure validateAgainstSubType(BuiltInAtomicType type) { if (checkRange(value, type)) { return null; } else { ValidationFailure err = new ValidationFailure("Value " + value + " cannot be converted to integer subtype " + type.getDescription()); err.setErrorCode("FORG0001"); return err; } } /** * This class allows subtypes of xs:integer to be held, as well as xs:integer values. * This method sets the required type label. It is the caller's responsibility to check that * the value is within range. * @param type the type label to be assigned */ public void setSubType(AtomicType type) { typeLabel = type; } /** * This class allows subtypes of xs:integer to be held, as well as xs:integer values. * This method checks that the value is within range, and also sets the type label. * @param type the subtype of integer required * @return true if successful, false if value is out of range for the subtype */ public boolean checkRange(BuiltInAtomicType type) { typeLabel = type; return checkRange(value, type); } /** * Get an object that implements XML Schema comparison semantics */ public Comparable getSchemaComparable() { return new Int64Comparable(this); } protected static class Int64Comparable implements Comparable { protected Int64Value value; public Int64Comparable(Int64Value value) { this.value = value; } public long asLong() { return value.longValue(); } public int compareTo(Object o) { if (o instanceof Int64Comparable) { long long0 = value.longValue(); long long1 = ((Int64Comparable)o).value.longValue(); if (long0 <= long1) { if (long0 == long1) { return 0; } else { return -1; } } else { return 1; } } else if (o instanceof BigIntegerValue.BigIntegerComparable) { return value.asBigInteger().compareTo(((BigIntegerValue.BigIntegerComparable)o).asBigInteger()); } else if (o instanceof DecimalValue.DecimalComparable) { return value.getDecimalValue().compareTo(((DecimalValue.DecimalComparable)o).asBigDecimal()); } else { return INDETERMINATE_ORDERING; } } public boolean equals(Object o) { if (o instanceof Int64Comparable) { return (asLong() == ((Int64Comparable)o).asLong()); } else { return compareTo(o) == 0; } } public int hashCode() { // Must align with hashCodes for other subtypes of xs:decimal return (int)asLong(); } } /** * Get the hashCode. This must conform to the rules for other NumericValue hashcodes * @see NumericValue#hashCode */ public int hashCode() { if (value > Integer.MIN_VALUE && value < Integer.MAX_VALUE) { return (int) value; } else { return new Double(getDoubleValue()).hashCode(); } } /** * Get the value * @return the value of the xs:integer, as a Java long */ public long longValue() { return value; } /** * Return the effective boolean value of this integer * @return false if the integer is zero, otherwise true */ public boolean effectiveBooleanValue() { return value != 0; } /** * Compare the value to another numeric value * @param other the numeric value to be compared to this value * @return -1 if this value is less than the other, 0 if they are equal, * +1 if this value is greater */ public int compareTo(Object other) { if (other instanceof Int64Value) { long val2 = ((Int64Value) other).value; if (value == val2) return 0; if (value < val2) return -1; return 1; } else if (other instanceof BigIntegerValue) { return new BigIntegerValue(value).compareTo(other); } else { return super.compareTo(other); } } /** * Compare the value to a long * @param other the value to be compared with * @return -1 if this is less, 0 if this is equal, +1 if this is greater or if this is NaN */ public int compareTo(long other) { if (value == other) return 0; if (value < other) return -1; return 1; } /** * Convert to target data type * * @param requiredType an integer identifying the required atomic type * @param context XPath dynamic evaluation context * @return an AtomicValue, a value of the required type */ public ConversionResult convertPrimitive(BuiltInAtomicType requiredType, boolean validate, XPathContext context) { switch (requiredType.getFingerprint()) { case StandardNames.XS_BOOLEAN: return BooleanValue.get(value != 0); case StandardNames.XS_NUMERIC: case StandardNames.XS_INTEGER: case StandardNames.XS_ANY_ATOMIC_TYPE: if (typeLabel == BuiltInAtomicType.INTEGER) { return this; } else { // promote subtype to type xs:integer return copyAsSubType(BuiltInAtomicType.INTEGER); } case StandardNames.XS_NON_POSITIVE_INTEGER: case StandardNames.XS_NEGATIVE_INTEGER: case StandardNames.XS_LONG: case StandardNames.XS_INT: case StandardNames.XS_SHORT: case StandardNames.XS_BYTE: case StandardNames.XS_NON_NEGATIVE_INTEGER: case StandardNames.XS_POSITIVE_INTEGER: case StandardNames.XS_UNSIGNED_LONG: case StandardNames.XS_UNSIGNED_INT: case StandardNames.XS_UNSIGNED_SHORT: case StandardNames.XS_UNSIGNED_BYTE: Int64Value val = new Int64Value(value); ValidationFailure err = val.convertToSubType(requiredType, validate); if (err != null) { return err; } return val; case StandardNames.XS_DOUBLE: return new DoubleValue((double) value); case StandardNames.XS_FLOAT: return new FloatValue((float) value); case StandardNames.XS_DECIMAL: return new DecimalValue(value); case StandardNames.XS_STRING: return new StringValue(getStringValue()); case StandardNames.XS_UNTYPED_ATOMIC: return new UntypedAtomicValue(getStringValue()); default: ValidationFailure err2 = new ValidationFailure("Cannot convert integer to " + requiredType.getDisplayName()); err2.setErrorCode("XPTY0004"); return err2; } } /** * Get the value as a String * * @return a String representation of the value */ public String getStringValue() { return Long.toString(value); } /** * Get the numeric value as a double * * @return A double representing this numeric value; NaN if it cannot be * converted */ public double getDoubleValue() { return (double) value; } /** * Get the numeric value converted to a float * * @return a float representing this numeric value; NaN if it cannot be converted */ public float getFloatValue() { return (float)value; } /** * Get the numeric value converted to a decimal * * @return a decimal representing this numeric value; */ public BigDecimal getDecimalValue() { return BigDecimal.valueOf(value); } /** * Negate the value * * @return the result of inverting the sign of the value */ public NumericValue negate() { if (value == Long.MIN_VALUE) { return BigIntegerValue.makeIntegerValue(BigInteger.valueOf(value)).negate(); } else { return new Int64Value(-value); } } /** * Implement the XPath floor() function * @return the integer value, unchanged */ public NumericValue floor() { return this; } /** * Implement the XPath ceiling() function * @return the integer value, unchanged */ public NumericValue ceiling() { return this; } /** * Implement the XPath round() function * @return the integer value, unchanged */ public NumericValue round() { return this; } /** * Implement the XPath round-to-half-even() function * * @param scale number of digits required after the decimal point; the * value -2 (for example) means round to a multiple of 100 * @return if the scale is >=0, return this value unchanged. Otherwise * round it to a multiple of 10**-scale */ public NumericValue roundHalfToEven(int scale) { long absolute = Math.abs(value); if (scale >= 0) { return this; } else { if (scale < -15) { return new BigIntegerValue(value).roundHalfToEven(scale); } long factor = 1; for (long i = 1; i <= -scale; i++) { factor *= 10; } long modulus = absolute % factor; long rval = absolute - modulus; long d = modulus * 2; if (d > factor) { rval += factor; } else if (d < factor) { // no-op } else { // round to even if (rval % (2 * factor) == 0) { // no-op } else { rval += factor; } } if (value < 0) rval = -rval; return new Int64Value(rval); } } /** * Determine whether the value is negative, zero, or positive * @return -1 if negative, 0 if zero, +1 if positive, NaN if NaN */ public double signum() { if (value > 0) return +1; if (value == 0) return 0; return -1; } /** * Add another integer */ public IntegerValue plus(IntegerValue other) { // if either of the values is large, we use BigInteger arithmetic to be on the safe side if (other instanceof Int64Value) { long topa = (value >> 60) & 0xf; if (topa != 0 && topa != 0xf) { return new BigIntegerValue(value).plus(new BigIntegerValue(((Int64Value)other).value)); } long topb = (((Int64Value)other).value >> 60) & 0xf; if (topb != 0 && topb != 0xf) { return new BigIntegerValue(value).plus(new BigIntegerValue(((Int64Value)other).value)); } return makeIntegerValue(value + ((Int64Value)other).value); } else { return new BigIntegerValue(value).plus(other); } } /** * Subtract another integer */ public IntegerValue minus(IntegerValue other) { // if either of the values is large, we use BigInteger arithmetic to be on the safe side if (other instanceof Int64Value) { long topa = (value >> 60) & 0xf; if (topa != 0 && topa != 0xf) { return new BigIntegerValue(value).minus(new BigIntegerValue(((Int64Value)other).value)); } long topb = (((Int64Value)other).value >> 60) & 0xf; if (topb != 0 && topb != 0xf) { return new BigIntegerValue(value).minus(new BigIntegerValue(((Int64Value)other).value)); } return makeIntegerValue(value - ((Int64Value)other).value); } else { return new BigIntegerValue(value).minus(other); } } /** * Multiply by another integer */ public IntegerValue times(IntegerValue other) { // if either of the values is large, we use BigInteger arithmetic to be on the safe side if (other instanceof Int64Value) { if (isLong() || ((Int64Value)other).isLong()) { return new BigIntegerValue(value).times(new BigIntegerValue(((Int64Value)other).value)); } else { return makeIntegerValue(value * ((Int64Value)other).value); } } else { return new BigIntegerValue(value).times(other); } } /** * Divide by another integer */ public NumericValue div(IntegerValue other) throws XPathException { // if either of the values is large, we use BigInteger arithmetic to be on the safe side if (other instanceof Int64Value) { long quotient = ((Int64Value)other).value; if (quotient == 0) { throw new XPathException("Integer division by zero", "FOAR0001"); } if (isLong() || ((Int64Value)other).isLong()) { return new BigIntegerValue(value).div(new BigIntegerValue(quotient)); } // the result of dividing two integers is a decimal; but if // one divides exactly by the other, we implement it as an integer if (value % quotient == 0) { return makeIntegerValue(value / quotient); } else { return (NumericValue)Calculator.DECIMAL_DECIMAL[Calculator.DIV].compute( new DecimalValue(value), new DecimalValue(quotient), null); } } else { return new BigIntegerValue(value).div(other); } } /** * Take modulo another integer */ public IntegerValue mod(IntegerValue other) throws XPathException { // if either of the values is large, we use BigInteger arithmetic to be on the safe side if (other instanceof Int64Value) { long quotient = ((Int64Value) other).value; if (quotient == 0) { throw new XPathException("Integer modulo zero", "FOAR0001"); } if (isLong() || ((Int64Value)other).isLong()) { return new BigIntegerValue(value).mod(new BigIntegerValue(((Int64Value)other).value)); } else { return makeIntegerValue(value % quotient); } } else { return new BigIntegerValue(value).mod(other); } } /** * Integer divide by another integer */ public IntegerValue idiv(IntegerValue other) throws XPathException { // if either of the values is large, we use BigInteger arithmetic to be on the safe side if (other instanceof Int64Value) { if (isLong() || ((Int64Value)other).isLong()) { return new BigIntegerValue(value).idiv(new BigIntegerValue(((Int64Value)other).value)); } try { return makeIntegerValue(value / ((Int64Value) other).value); } catch (ArithmeticException err) { XPathException e; if ("/ by zero".equals(err.getMessage())) { e = new XPathException("Integer division by zero", "FOAR0001"); } else { e = new XPathException("Integer division failure", err); } throw e; } } else { return new BigIntegerValue(value).idiv(other); } } /** * Test whether this value needs a long to hold it. Specifically, whether * the absolute value is > 2^31. */ private boolean isLong() { long top = value >> 31; return top != 0 && top != 0x1ffffffffL; } /** * Get the value as a BigInteger */ public BigInteger asBigInteger() { return BigInteger.valueOf(value); } /** * Get conversion preference for this value to a Java class. * * @param required the Java class to which conversion is required * @return the conversion preference. A low result indicates higher * preference. */ // Note: this table gives java Long preference over Integer, even if the // XML Schema type is xs:int /** * Convert to Java object (for passing to external functions) * * @param target The Java class to which conversion is required * @exception XPathException if conversion is not possible, or fails * @return the Java object that results from the conversion; always an * instance of the target class */ // public Object convertAtomicToJava(Class target, XPathContext context) throws XPathException { // if (target == Object.class) { // return new Long(value); // } else if (target.isAssignableFrom(Int64Value.class)) { // return this; // } else if (target == double.class || target == Double.class) { // return new Double(value); // } else if (target == float.class || target == Float.class) { // return new Float(value); // } else if (target == long.class || target == Long.class) { // return new Long(value); // } else if (target == int.class || target == Integer.class) { // return new Integer((int) value); // } else if (target == short.class || target == Short.class) { // return new Short((short) value); // } else if (target == byte.class || target == Byte.class) { // return new Byte((byte) value); // } else if (target == char.class || target == Character.class) { // return new Character((char) value); // } else if (target == BigInteger.class) { // return BigInteger.valueOf(value); // } else if (target == BigDecimal.class) { // return BigDecimal.valueOf(value); // } else { // Object o = convertSequenceToJava(target, context); // if (o == null) { // throw new XPathException("Conversion of integer to " + target.getName() + // " is not supported"); // } // return o; // } // } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file except the asStringXT() and zeros() methods (not currently used). // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/value/Value.java0000644000175000017500000013571311033112257020444 0ustar eugeneeugenepackage net.sf.saxon.value; import net.sf.saxon.Configuration; import net.sf.saxon.event.SequenceReceiver; import net.sf.saxon.expr.*; import net.sf.saxon.functions.Aggregate; import net.sf.saxon.om.*; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.*; import java.io.Serializable; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.regex.Pattern; /** * A value is the result of an expression but it is also an expression in its own right. * Note that every value can be regarded as a sequence - in many cases, a sequence of * length one. */ public abstract class Value implements Serializable, SequenceIterable, ValueRepresentation /*, Comparable */ { /** * Static method to make a Value from a given Item (which may be either an AtomicValue * or a NodeInfo * @param val The supplied value, or null, indicating the empty sequence. * @return The supplied value, if it is a value, or a SingletonNode that * wraps the item, if it is a node. If the supplied value was null, * return an EmptySequence */ public static Value asValue(ValueRepresentation val) { if (val instanceof Value) { return (Value)val; } else if (val == null) { return EmptySequence.getInstance(); } else { return new SingletonNode((NodeInfo)val); } } /** * Static method to make an Item from a Value * @param value the value to be converted * @return null if the value is an empty sequence; or the only item in the value * if it is a singleton sequence * @throws XPathException if the Value contains multiple items */ public static Item asItem(ValueRepresentation value) throws XPathException { if (value instanceof Item) { return (Item)value; } else { return ((Value)value).asItem(); } } /** * Return the value in the form of an Item * @return the value in the form of an Item */ public Item asItem() throws XPathException { SequenceIterator iter = iterate(); Item item = iter.next(); if (item == null) { return null; } else if (iter.next() != null) { throw new XPathException("Attempting to access a sequence as a singleton item"); } else { return item; } } /** * Static method to get a Value from an Item * @param item the supplied item * @return the item expressed as a Value */ public static Value fromItem(Item item) { if (item == null) { return EmptySequence.getInstance(); } else if (item instanceof AtomicValue) { return (AtomicValue)item; } else { return new SingletonNode((NodeInfo)item); } } /** * Static method to get an Iterator over any ValueRepresentation (which may be either a Value * or a NodeInfo * @param val The supplied value, or null, indicating the empty sequence. * @return The supplied value, if it is a value, or a SingletonNode that * wraps the item, if it is a node. If the supplied value was null, * return an EmptySequence */ public static SequenceIterator asIterator(ValueRepresentation val) throws XPathException { if (val instanceof Value) { return ((Value)val).iterate(); } else if (val == null) { return EmptyIterator.getInstance(); } else { return SingletonIterator.makeIterator((NodeInfo)val); } } /** * Static method to convert strings to doubles. * @param s the String to be converted * @return a double representing the value of the String * @throws NumberFormatException if the value cannot be converted */ public static double stringToNumber(CharSequence s) throws NumberFormatException { // first try to parse simple numbers by hand (it's cheaper) int len = s.length(); if (len < 9) { boolean useJava = false; long num = 0; int dot = -1; int lastDigit = -1; boolean onlySpaceAllowed = false; loop: for (int i=0; i lastDigit) { return (double)num; } else { int afterPoint = lastDigit - dot; return ((double)num)/powers[afterPoint]; } } } String n = Whitespace.trimWhitespace(s).toString(); if ("INF".equals(n)) { return Double.POSITIVE_INFINITY; } else if ("-INF".equals(n)) { return Double.NEGATIVE_INFINITY; } else if ("NaN".equals(n)) { return Double.NaN; } else if (!doublePattern.matcher(n).matches()) { // Need to disallow values that are OK in Java but not in XPath, specifically // - special values like +NaN or -Infinity // - hex digits // - binary exponents // TODO: this checking incurs a performance hit. Perhaps we should do the whole conversion in-house throw new NumberFormatException("Invalid characters in float/double value"); } else { return Double.parseDouble(n); } } private static double[] powers = new double[]{1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000}; private static Pattern doublePattern = Pattern.compile("^[0-9.eE+-]+$"); /** * Get a SequenceIterator over a ValueRepresentation * @param val the value to iterate over * @return the iterator */ public static SequenceIterator getIterator(ValueRepresentation val) throws XPathException { if (val instanceof Value) { return ((Value)val).iterate(); } else if (val instanceof NodeInfo) { return SingletonIterator.makeIterator((NodeInfo)val); } else if (val == null) { throw new AssertionError("Value of variable is undefined (null)"); } else { throw new AssertionError("Unknown value representation " + val.getClass()); } } /** * Iterate over the items contained in this value. * @return an iterator over the sequence of items * @throws XPathException if a dynamic error occurs. This is possible only in the case of values * that are materialized lazily, that is, where the iterate() method leads to computation of an * expression that delivers the values. */ public abstract SequenceIterator iterate() throws XPathException; /** * Return an iterator over the results of evaluating an expression * @param context the dynamic evaluation context (not used in this implementation) * @return an iterator over the items delivered by the expression */ public final SequenceIterator iterate(XPathContext context) throws XPathException { // Note, this method, and the SequenceIterable interface, are used from XQuery compiled code return iterate(); } /** * Get the value of the item as a CharSequence. This is in some cases more efficient than * the version of the method that returns a String. */ public CharSequence getStringValueCS() throws XPathException { return getStringValue(); } /** * Get the canonical lexical representation as defined in XML Schema. This is not always the same * as the result of casting to a string according to the XPath rules. * @return the canonical lexical representation if defined in XML Schema; otherwise, the result * of casting to string according to the XPath 2.0 rules */ public CharSequence getCanonicalLexicalRepresentation() { try { return getStringValueCS(); } catch (XPathException err) { throw new IllegalStateException("Failed to get canonical lexical representation: " + err.getMessage()); } } /** * Determine the data type of the items in the expression, if possible * @return for the default implementation: AnyItemType (not known) * @param th The TypeHierarchy. Can be null if the target is an AtomicValue. */ public ItemType getItemType(TypeHierarchy th) { return AnyItemType.getInstance(); } /** * Determine the cardinality * @return the cardinality */ public int getCardinality() { try { SequenceIterator iter = iterate(); Item next = iter.next(); if (next == null) { return StaticProperty.EMPTY; } else { if (iter.next() != null) { return StaticProperty.ALLOWS_ONE_OR_MORE; } else { return StaticProperty.EXACTLY_ONE; } } } catch (XPathException err) { // can't actually happen return StaticProperty.ALLOWS_ZERO_OR_MORE; } } /** * Get the n'th item in the sequence (starting from 0). This is defined for all * Values, but its real benefits come for a sequence Value stored extensionally * (or for a MemoClosure, once all the values have been read) * @param n position of the required item, counting from zero. * @return the n'th item in the sequence, where the first item in the sequence is * numbered zero. If n is negative or >= the length of the sequence, returns null. */ public Item itemAt(int n) throws XPathException { if (n < 0) { return null; } int i = 0; // indexing is zero-based SequenceIterator iter = iterate(); while (true) { Item item = iter.next(); if (item == null) { return null; } if (i++ == n) { return item; } } } /** * Get the length of the sequence * @return the number of items in the sequence */ public int getLength() throws XPathException { return Aggregate.count(iterate()); } /** * Process the value as an instruction, without returning any tail calls * @param context The dynamic context, giving access to the current node, * the current variables, etc. */ public void process(XPathContext context) throws XPathException { SequenceIterator iter = iterate(); SequenceReceiver out = context.getReceiver(); while (true) { Item it = iter.next(); if (it==null) break; out.append(it, 0, NodeInfo.ALL_NAMESPACES); } } /** * Convert the value to a string, using the serialization rules. * For atomic values this is the same as a cast; for sequence values * it gives a space-separated list. * @throws XPathException The method can fail if evaluation of the value * has been deferred, and if a failure occurs during the deferred evaluation. * No failure is possible in the case of an AtomicValue. */ public String getStringValue() throws XPathException { FastStringBuffer sb = new FastStringBuffer(1024); SequenceIterator iter = iterate(); Item item = iter.next(); if (item != null) { while (true) { sb.append(item.getStringValueCS()); item = iter.next(); if (item == null) { break; } sb.append(' '); } } return sb.toString(); } /** * Get the effective boolean value of the expression. This returns false if the value * is the empty sequence, a zero-length string, a number equal to zero, or the boolean * false. Otherwise it returns true. * * @exception XPathException if any dynamic error occurs evaluating the * expression * @return the effective boolean value */ public boolean effectiveBooleanValue() throws XPathException { return ExpressionTool.effectiveBooleanValue(iterate()); } /** * Get a Comparable value that implements the XML Schema ordering comparison semantics for this value. * The default implementation is written to compare sequences of atomic values. * This method is overridden for AtomicValue and its subclasses. * *

    In the case of data types that are partially ordered, the returned Comparable extends the standard * semantics of the compareTo() method by returning the value {@link #INDETERMINATE_ORDERING} when there * is no defined order relationship between two given values.

    * * @return a Comparable that follows XML Schema comparison rules */ public Comparable getSchemaComparable() { return new ValueSchemaComparable(); } private class ValueSchemaComparable implements Comparable { public Value getValue() { return Value.this; } public int compareTo(Object obj) { try { if (obj instanceof ValueSchemaComparable) { SequenceIterator iter1 = getValue().iterate(); SequenceIterator iter2 = ((ValueSchemaComparable)obj).getValue().iterate(); while (true) { Item item1 = iter1.next(); Item item2 = iter2.next(); if (item1 == null && item2 == null) { return 0; } if (item1 == null) { return -1; } else if (item2 == null) { return +1; } if (item1 instanceof NodeInfo || item2 instanceof NodeInfo) { throw new UnsupportedOperationException("Sequences containing nodes are not schema-comparable"); } int c = ((AtomicValue)item1).getSchemaComparable().compareTo( ((AtomicValue)item2).getSchemaComparable()); if (c != 0) { return c; } } } else { return INDETERMINATE_ORDERING; } } catch (XPathException e) { throw new AssertionError("Failure comparing schema values: " + e.getMessage()); } } public boolean equals(Object obj) { return compareTo(obj) == 0; } public int hashCode() { try { int hash = 0x06639662; // arbitrary seed SequenceIterator iter = getValue().iterate(); while (true) { Item item = iter.next(); if (item == null) { return hash; } hash ^= ((AtomicValue)item).getSchemaComparable().hashCode(); } } catch (XPathException e) { return 0; } } } /** * Constant returned by compareTo() method to indicate an indeterminate ordering between two values */ public static final int INDETERMINATE_ORDERING = Integer.MIN_VALUE; /** * Compare two (sequence) values for equality. This method implements the XPath eq operator, for cases * where it is defined. For values containing nodes, nodes are compared for identity. * In cases where eq is not defined, it throws ClassCastException. In cases * where the result of eq is an empty sequence, this function returns false, except that two empty * sequences compare equal. The method also returns a ClassCastException * if any failure occurs evaluating either of the values. */ public boolean equals(Object obj) { throw new UnsupportedOperationException("Value.equals()"); // try { // if (obj instanceof Value) { // SequenceIterator iter1 = iterate(); // SequenceIterator iter2 = ((Value)obj).iterate(); // while (true) { // Item item1 = iter1.next(); // Item item2 = iter2.next(); // if (item1 == null || item2 == null) { // return item1 == null && item2 == null; // } // if (!item1.equals(item2)) { // return false; // } // } // } else { // return false; // } // } catch (XPathException e) { // throw new ClassCastException(e.getMessage()); // } } /** * Check statically that the results of the expression are capable of constructing the content * of a given schema type. * @param parentType The schema type * @param env the static context * @param whole true if this value accounts for the entire content of the containing node * @throws XPathException if the expression doesn't match the required content type */ public void checkPermittedContents(SchemaType parentType, StaticContext env, boolean whole) throws XPathException { //return; } /** * Reduce a value to its simplest form. If the value is a closure or some other form of deferred value * such as a FunctionCallPackage, then it is reduced to a SequenceExtent. If it is a SequenceExtent containing * a single item, then it is reduced to that item. One consequence that is exploited by class FilterExpression * is that if the value is a singleton numeric value, then the result will be an instance of NumericValue * @return the value in simplified form */ public Value reduce() throws XPathException { return this; } /** * Convert to Java object (for passing to external functions) * @param target the required target class * @param context the XPath dynamic evaluation context * @return the (boxed) Java object that best represents the XPath value. This is guaranteed * to be an instance of the target class */ // public Object convertToJava(Class target, XPathContext context) throws XPathException { // // TODO: delete this method and its implementations // // This is overridden in subclasses that handle singleton objects // return convertSequenceToJava(target, context); // } /** * Convert this value to a Java object * @param target the required class of the resulting Java object * @param context the XPath evaluation context * @return the Java object, which will always be an instance of the target class * @throws XPathException if conversion is not possible */ // public final Object convertSequenceToJava(Class target, XPathContext context) throws XPathException { // // TODO: delete this method and its implementations // if (target == Object.class) { // List list = new ArrayList(20); // return convertToJavaList(list, context); // } // // // See if the extension function is written to accept native Saxon objects // // if (target.isAssignableFrom(getClass())) { // return this; // } else if (target.isAssignableFrom(SequenceIterator.class)) { // return iterate(); // } // // // Offer the object to registered external object models // // if ((this instanceof ObjectValue || !(this instanceof AtomicValue)) && !(this instanceof EmptySequence)) { // List externalObjectModels = context.getConfiguration().getExternalObjectModels(); // for (int m=0; m= start */ public IntegerRange(long start, long end) { this.start = start; this.end = end; } /** * Get the first integer in the sequence (inclusive) * @return the first integer in the sequence (inclusive) */ public long getStart() { return start; } /** * Get the last integer in the sequence (inclusive) * @return the last integer in the sequence (inclusive) */ public long getEnd() { return end; } /** * Return an Iterator to iterate over the values of a sequence. The value of every * expression can be regarded as a sequence, so this method is supported for all * expressions. This default implementation handles iteration for expressions that * return singleton values: for non-singleton expressions, the subclass must * provide its own implementation. * * @return a SequenceIterator that can be used to iterate over the result * of the expression * @throws net.sf.saxon.trans.XPathException * if any dynamic error occurs evaluating the * expression */ public SequenceIterator iterate() throws XPathException { return new RangeIterator(start, end); } /** * Determine the data type of the items in the expression, if possible * * @return AnyItemType (not known) * @param th the type hierarchy cache */ public ItemType getItemType(TypeHierarchy th) { return BuiltInAtomicType.INTEGER; } /** * Determine the cardinality */ public int getCardinality() { return StaticProperty.ALLOWS_MANY; } /** * Get the n'th item in the sequence (starting from 0). This is defined for all * Values, but its real benefits come for a sequence Value stored extensionally * (or for a MemoClosure, once all the values have been read) */ public Item itemAt(int n) { if (n < 0 || n > (end-start)) { return null; } return Int64Value.makeIntegerValue(start + n); } /** * Get a subsequence of the value * * @param start the index of the first item to be included in the result, counting from zero. * A negative value is taken as zero. If the value is beyond the end of the sequence, an empty * sequence is returned * @param length the number of items to be included in the result. Specify Integer.MAX_VALUE to * get the subsequence up to the end of the base sequence. If the value is negative, an empty sequence * is returned. If the value goes off the end of the sequence, the result returns items up to the end * of the sequence * @return the required subsequence. */ public GroundedValue subsequence(int start, int length) { if (length <= 0) { return EmptySequence.getInstance(); } long newStart = this.start + (start > 0 ? start : 0); long newEnd = newStart + length - 1; if (newEnd > end) { newEnd = end; } if (newEnd >= newStart) { return new IntegerRange(newStart, newEnd); } else { return EmptySequence.getInstance(); } } /** * Get the length of the sequence */ public int getLength() throws XPathException { return (int)(end - start + 1); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/value/SingletonNode.java0000644000175000017500000002115611033112257022133 0ustar eugeneeugenepackage net.sf.saxon.value; import net.sf.saxon.expr.StaticProperty; import net.sf.saxon.expr.Token; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.*; import net.sf.saxon.pattern.*; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.Type; import net.sf.saxon.type.TypeHierarchy; /** * A value that is a sequence containing zero or one nodes */ public class SingletonNode extends Value implements GroundedValue{ protected NodeInfo node = null; /** * Create a node-set containing zero or one nodes * @param node The node to be contained in the node-set, or null if the node-set * is to be empty */ public SingletonNode(NodeInfo node) { this.node = node; } /** * Return the value in the form of an Item * @return the value in the form of an Item */ public Item asItem() { return node; } /** * Process the instruction, without returning any tail calls * @param context The dynamic context, giving access to the current node, * the current variables, etc. */ public void process(XPathContext context) throws XPathException { if (node != null) { context.getReceiver().append(node, 0, NodeInfo.ALL_NAMESPACES); } } /** * Determine the data type of the items in the expression. This method determines the most * precise type that it can, because it is called when testing that the node conforms to a required * type. * @return the most precise possible type of the node. * @param th the type hierarchy cache */ public ItemType getItemType(TypeHierarchy th) { switch (node.getNodeKind()) { case Type.DOCUMENT: // Need to know whether the document is well-formed and if so what the element type is AxisIterator iter = node.iterateAxis(Axis.CHILD); ItemType elementType = null; while (true) { NodeInfo n = (NodeInfo)iter.next(); if (n==null) { break; } int kind = n.getNodeKind(); if (kind==Type.TEXT) { elementType = null; break; } else if (kind==Type.ELEMENT) { if (elementType != null) { elementType = null; break; } elementType = new SingletonNode(n).getItemType(th); } } if (elementType == null) { return NodeKindTest.DOCUMENT; } else { return new DocumentNodeTest((NodeTest)elementType); } case Type.ELEMENT: int eltype = node.getTypeAnnotation(); if (eltype == -1 || eltype == StandardNames.XS_UNTYPED || eltype == StandardNames.XS_ANY_TYPE) { return new NameTest(Type.ELEMENT, node.getFingerprint(), node.getNamePool()); } else { return new CombinedNodeTest( new NameTest(Type.ELEMENT, node.getFingerprint(), node.getNamePool()), Token.INTERSECT, new ContentTypeTest(Type.ELEMENT, node.getConfiguration().getSchemaType(eltype), node.getConfiguration())); } case Type.ATTRIBUTE: int attype = node.getTypeAnnotation(); if (attype == -1 || attype == StandardNames.XS_UNTYPED_ATOMIC) { return new NameTest(Type.ATTRIBUTE, node.getFingerprint(), node.getNamePool()); } else { return new CombinedNodeTest( new NameTest(Type.ATTRIBUTE, node.getFingerprint(), node.getNamePool()), Token.INTERSECT, new ContentTypeTest(Type.ATTRIBUTE, node.getConfiguration().getSchemaType(attype), node.getConfiguration())); } case Type.TEXT: return NodeKindTest.TEXT; case Type.COMMENT: return NodeKindTest.COMMENT; case Type.PROCESSING_INSTRUCTION: return NodeKindTest.PROCESSING_INSTRUCTION; case Type.NAMESPACE: return NodeKindTest.NAMESPACE; default: throw new IllegalArgumentException("Unknown node kind " + node.getNodeKind()); } } /** * Determine the static cardinality */ public int getCardinality() { if (node==null) { return StaticProperty.EMPTY; } else { return StaticProperty.EXACTLY_ONE; } } /** * Get the length of the sequence */ public int getLength() throws XPathException { return (node==null ? 0 : 1); } /** * Get the n'th item in the sequence (starting from 0). This is defined for all * SequenceValues, but its real benefits come for a SequenceValue stored extensionally * (or for a MemoClosure, once all the values have been read) */ public Item itemAt(int n) { if (n==0 && node!=null) { return node; } else { return null; } } /** * Get a subsequence of the value * * @param start the index of the first item to be included in the result, counting from zero. * A negative value is taken as zero. If the value is beyond the end of the sequence, an empty * sequence is returned * @param length the number of items to be included in the result. Specify Integer.MAX_VALUE to * get the subsequence up to the end of the base sequence. If the value is negative, an empty sequence * is returned. If the value goes off the end of the sequence, the result returns items up to the end * of the sequence * @return the required subsequence. If min is */ public GroundedValue subsequence(int start, int length) { if (node != null && start <= 0 && start+length > 0) { return this; } else { return EmptySequence.getInstance(); } } /** * Get the node that forms the node-set. Return null if there is none. */ public NodeInfo getNode() { return node; } /** * Return an enumeration of this nodeset value. */ public SequenceIterator iterate() { return SingletonIterator.makeIterator(node); } /** * Get the effective boolean value */ public boolean effectiveBooleanValue() { return (node != null); } /** * Convert the value to a string, using the serialization rules. * For atomic values this is the same as a cast; for sequence values * it gives a space-separated list. For QNames and NOTATIONS, or lists * containing them, it fails. */ public String getStringValue() { return (node==null ? "" : node.getStringValue()); } /** * Convert to Java object (for passing to external functions) */ // public Object convertToJava(Class target, XPathContext context) throws XPathException { // if (node == null) { // return null; // } // if (target.isAssignableFrom(node.getClass())) { // return node; // } // if (target == String.class) { // return node.getStringValue(); // } // return super.convertToJava(target, context); // } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/value/FloatValue.java0000644000175000017500000003376311033112257021434 0ustar eugeneeugenepackage net.sf.saxon.value; import net.sf.saxon.trans.Err; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.FastStringBuffer; import net.sf.saxon.om.StandardNames; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.*; import java.math.BigDecimal; /** * A numeric (single precision floating point) value */ public final class FloatValue extends NumericValue { public static final FloatValue ZERO = new FloatValue((float)0.0); public static final FloatValue NEGATIVE_ZERO = new FloatValue((float)-0.0); public static final FloatValue ONE = new FloatValue((float)1.0); public static final FloatValue NaN = new FloatValue(Float.NaN); private float value; /** * Constructor supplying a string */ public FloatValue(CharSequence val) throws ValidationException { try { value = (float)Value.stringToNumber(val); } catch (NumberFormatException e) { throw new ValidationException("Cannot convert string " + Err.wrap(val, Err.VALUE) + " to a float"); } typeLabel = BuiltInAtomicType.FLOAT; } /** * Constructor supplying a float * @param value the value of the float */ public FloatValue(float value) { this.value = value; typeLabel = BuiltInAtomicType.FLOAT; } /** * Constructor supplying a float and an AtomicType, for creating * a value that belongs to a user-defined subtype of xs:float. It is * the caller's responsibility to ensure that the supplied value conforms * to the supplied type. * @param value the value of the NumericValue * @param type the type of the value. This must be a subtype of xs:float, and the * value must conform to this type. The method does not check these conditions. */ public FloatValue(float value, AtomicType type) { this.value = value; typeLabel = type; } /** * Create a copy of this atomic value, with a different type label * * @param typeLabel the type label of the new copy. The caller is responsible for checking that * the value actually conforms to this type. */ public AtomicValue copyAsSubType(AtomicType typeLabel) { FloatValue v = new FloatValue(value); v.typeLabel = typeLabel; return v; } /** * Determine the primitive type of the value. This delivers the same answer as * getItemType().getPrimitiveItemType(). The primitive types are * the 19 primitive types of XML Schema, plus xs:integer, xs:dayTimeDuration and xs:yearMonthDuration, * and xs:untypedAtomic. For external objects, the result is AnyAtomicType. */ public BuiltInAtomicType getPrimitiveType() { return BuiltInAtomicType.FLOAT; } /** * Get the value */ public float getFloatValue() { return value; } public double getDoubleValue() { return (double)value; } /** * Get the hashCode. This must conform to the rules for other NumericValue hashcodes * @see NumericValue#hashCode */ public int hashCode() { if (value > Integer.MIN_VALUE && value < Integer.MAX_VALUE) { return (int)value; } else { return new Double(getDoubleValue()).hashCode(); } } /** * Test whether the value is the double/float value NaN */ public boolean isNaN() { return Float.isNaN(value); } /** * Get the effective boolean value * @return true unless the value is zero or NaN */ public boolean effectiveBooleanValue() { return (value!=0.0 && !Float.isNaN(value)); } /** * Convert to target data type * @param requiredType an integer identifying the required atomic type * @param context XPath dynamic context. Not used when converting from float * @return an AtomicValue, a value of the required type; or an ErrorValue */ public ConversionResult convertPrimitive(BuiltInAtomicType requiredType, boolean validate, XPathContext context) { switch(requiredType.getFingerprint()) { case StandardNames.XS_BOOLEAN: return BooleanValue.get(value!=0.0 && !Float.isNaN(value)); case StandardNames.XS_FLOAT: case StandardNames.XS_NUMERIC: case StandardNames.XS_ANY_ATOMIC_TYPE: return this; case StandardNames.XS_INTEGER: if (Float.isNaN(value)) { ValidationFailure err = new ValidationFailure("Cannot convert float NaN to an integer"); err.setErrorCode("FOCA0002"); return err; } if (Float.isInfinite(value)) { ValidationFailure err = new ValidationFailure("Cannot convert float infinity to an integer"); err.setErrorCode("FOCA0002"); return err; } if (value > Long.MAX_VALUE || value < Long.MIN_VALUE) { return new BigIntegerValue(new BigDecimal(value).toBigInteger()); } return Int64Value.makeIntegerValue((long)value); case StandardNames.XS_UNSIGNED_LONG: case StandardNames.XS_UNSIGNED_INT: case StandardNames.XS_UNSIGNED_SHORT: case StandardNames.XS_UNSIGNED_BYTE: case StandardNames.XS_NON_POSITIVE_INTEGER: case StandardNames.XS_NEGATIVE_INTEGER: case StandardNames.XS_LONG: case StandardNames.XS_INT: case StandardNames.XS_SHORT: case StandardNames.XS_BYTE: case StandardNames.XS_NON_NEGATIVE_INTEGER: case StandardNames.XS_POSITIVE_INTEGER: ConversionResult iv = convertPrimitive(BuiltInAtomicType.INTEGER, validate, context); if (iv instanceof ValidationFailure) { return iv; } return ((IntegerValue)iv).convertPrimitive(requiredType, validate, context); case StandardNames.XS_DECIMAL: try { return new DecimalValue(value); } catch (ValidationException e) { return new ValidationFailure(e); } case StandardNames.XS_DOUBLE: return new DoubleValue((double)value); case StandardNames.XS_STRING: return new StringValue(getStringValueCS()); case StandardNames.XS_UNTYPED_ATOMIC: return new UntypedAtomicValue(getStringValueCS()); default: ValidationFailure err = new ValidationFailure("Cannot convert float to " + requiredType.getDisplayName()); err.setErrorCode("XPTY0004"); return err; } } /** * Get the value as a String * @return a String representation of the value */ public String getStringValue() { return getStringValueCS().toString(); } /** * Get the value as a String * @return a String representation of the value */ public CharSequence getStringValueCS() { return floatToString(value); // , Float.toString(value)); } /** * Get the canonical lexical representation as defined in XML Schema. This is not always the same * as the result of casting to a string according to the XPath rules. For xs:float, the canonical * representation always uses exponential notation. */ public CharSequence getCanonicalLexicalRepresentation() { FastStringBuffer fsb = new FastStringBuffer(20); return FloatingPointConverter.appendFloatExponential(fsb, value); } /** * Regex indicating that a number may be worth rounding */ static java.util.regex.Pattern roundablePattern = java.util.regex.Pattern.compile( ".*99999.*|.*00000.*"); /** * Internal method used for conversion of a float to a string * @param value the actual value * @return the value converted to a string, according to the XPath casting rules. */ static CharSequence floatToString(float value) { return FloatingPointConverter.appendFloat(new FastStringBuffer(20), value); } /** * Negate the value */ public NumericValue negate() { return new FloatValue(-value); } /** * Implement the XPath floor() function */ public NumericValue floor() { return new FloatValue((float)Math.floor(value)); } /** * Implement the XPath ceiling() function */ public NumericValue ceiling() { return new FloatValue((float)Math.ceil(value)); } /** * Implement the XPath round() function */ public NumericValue round() { if (Float.isNaN(value)) return this; if (Float.isInfinite(value)) return this; if (value==0.0) return this; // handles the negative zero case if (value >= -0.5 && value < 0.0) return new DoubleValue(-0.0); if (value > Integer.MIN_VALUE && value < Integer.MAX_VALUE) { return new FloatValue((float)Math.round(value)); } // if the float is larger than the maximum int, then // it can't have any significant digits after the decimal // point, so return it unchanged return this; } /** * Implement the XPath round-to-half-even() function */ public NumericValue roundHalfToEven(int scale) { try { return (FloatValue) new DoubleValue((double)value).roundHalfToEven(scale).convertPrimitive(BuiltInAtomicType.FLOAT, true, null).asAtomic(); } catch (XPathException err) { throw new AssertionError(err); } } /** * Determine whether the value is negative, zero, or positive * @return -1 if negative, 0 if zero (including negative zero), +1 if positive, NaN if NaN */ public double signum() { if (Float.isNaN(value)) { return value; } if (value > 0) return 1; if (value == 0) return 0; return -1; } /** * Determine whether the value is a whole number, that is, whether it compares * equal to some integer */ public boolean isWholeNumber() { return value == Math.floor(value) && !Float.isInfinite(value); } public int compareTo(Object other) { if (!(other instanceof NumericValue)) { throw new ClassCastException("Numeric values are not comparable to " + other.getClass()); } if (other instanceof FloatValue) { float otherFloat = ((FloatValue)other).value; if (value == otherFloat) return 0; if (value < otherFloat) return -1; return +1; } if (other instanceof DoubleValue) { return super.compareTo(other); } try { return compareTo(((NumericValue)other).convertPrimitive(BuiltInAtomicType.FLOAT, true, null).asAtomic()); } catch (XPathException err) { throw new ClassCastException("Operand of comparison cannot be promoted to xs:float"); } } /** * Compare the value to a long * @param other the value to be compared with * @return -1 if this is less, 0 if this is equal, +1 if this is greater or if this is NaN */ public int compareTo(long other) { float otherFloat = (float)other; if (value == otherFloat) return 0; if (value < otherFloat) return -1; return +1; } /** * Get an object that implements XML Schema comparison semantics */ public Comparable getSchemaComparable() { return new Float(value); } /** * Convert to Java object (for passing to external functions) */ // public Object convertAtomicToJava(Class target, XPathContext context) throws XPathException { // if (target==Object.class) { // return new Double(value); // } else if (target.isAssignableFrom(DoubleValue.class)) { // return this; // } else if (target==double.class || target==Double.class) { // return new Double((double)value); // } else if (target==float.class ||target==Float.class ) { // return new Float(value); // } else if (target==long.class || target==Long.class) { // return new Long((long)value); // } else if (target==int.class || target==Integer.class) { // return new Integer((int)value); // } else if (target==short.class || target==Short.class) { // return new Short((short)value); // } else if (target==byte.class || target==Byte.class) { // return new Byte((byte)value); // } else if (target==char.class || target==Character.class) { // return new Character((char)value); // } else { // Object o = convertSequenceToJava(target, context); // if (o == null) { // XPathException err = new XPathException("Conversion of float to " + target.getName() + // " is not supported"); // err.setXPathContext(context); // err.setErrorCode(SaxonErrorCode.SXJE0004); // } // return o; // } // } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/value/package.html0000644000175000017500000000434711033112257021004 0ustar eugeneeugene Package overview for net.sf.saxon.value

    This package provides classes representing XPath values (that is, the results of an expression). There are different classes for different types of value.

    The principal class is:

    Value:
    This represents the result of evaluating an expression. But a Value is also an expression in its own right, reflecting the fact that literal values can be used syntactically wherever expressions can be used. AtomicValue is a subclass of Value that represents an atomic value: this in turn has subclasses for the different built-in data types: StringValue, NumericValue, BooleanValue, DateValue, and so on.

    There are two classes used to represent integer values: IntegerValue for integers that fit comfortably in 64 bits, and BigIntegerValue for anything longer. Built-in subtypes of xs:integer, such as xs:int and xs:short, are always represented using an IntegerValue, except for xs:unsignedLong, which uses a BigIntegerValue.

    In general a value is a sequence. A sequence that is instantiated in memory is represented by a SequenceExtent object. The code tries to pipeline execution so that a SequenceExtent is created as rarely as possible.

    When an expression is evaluated lazily, the result is a Closure. A Closure contains the original expression, and a copy of the run-time context at the time evaluation was requested: that is, all the local variables and other information that it depends on, such as the context item. There are two kinds of Closure, and the system decides at compile time which to use. An ordinary Closure re-evaluates the expression every time the value is referenced; this is used only when the compiler decides that the value is likely to be referenced only once. A MemoClosure remembers the value the first time it is needed, so that subsequent references do not cause repeated evaluation of the expression.


    Michael H. Kay
    Saxonica Limited
    9 February 2005

    saxonb-9.1.0.8/bj/net/sf/saxon/PreparedStylesheet.java0000644000175000017500000005074711033112257022073 0ustar eugeneeugenepackage net.sf.saxon; import net.sf.saxon.event.CommentStripper; import net.sf.saxon.event.PipelineConfiguration; import net.sf.saxon.event.Sender; import net.sf.saxon.event.StartTagBuffer; import net.sf.saxon.functions.ExecutableFunctionLibrary; import net.sf.saxon.functions.FunctionLibrary; import net.sf.saxon.functions.FunctionLibraryList; import net.sf.saxon.instruct.Executable; import net.sf.saxon.instruct.UserFunction; import net.sf.saxon.om.NamePool; import net.sf.saxon.om.Validation; import net.sf.saxon.style.*; import net.sf.saxon.trace.ExpressionPresenter; import net.sf.saxon.trans.CompilerInfo; import net.sf.saxon.trans.XPathException; import net.sf.saxon.tree.DocumentImpl; import net.sf.saxon.tree.TreeBuilder; import org.xml.sax.XMLReader; import javax.xml.transform.*; import java.io.FileInputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.Serializable; import java.math.BigDecimal; import java.net.URI; import java.net.URISyntaxException; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Properties; /** * This PreparedStylesheet class represents a Stylesheet that has been * prepared for execution (or "compiled"). */ public class PreparedStylesheet implements Templates, Serializable { private Executable executable; private transient Configuration config; private NamePool targetNamePool; // the namepool used when the stylesheet was compiled, // saved here so it can be used again when the stylesheet is run private transient StyleNodeFactory nodeFactory; private int errorCount = 0; private HashMap nextStylesheetCache; // cache for stylesheets named as "saxon:next-in-chain" private transient ErrorListener errorListener; private transient URIResolver uriResolver; private boolean compileWithTracing; /** * Constructor - deliberately protected * * @param config The Configuration set up by the TransformerFactory * @param info Compilation options */ protected PreparedStylesheet(Configuration config, CompilerInfo info) { this.config = config; errorListener = info.getErrorListener(); uriResolver = info.getURIResolver(); compileWithTracing = info.isCompileWithTracing(); } /** * Factory method to make a PreparedStylesheet * @param source the source of this principal stylesheet module * @param config the Saxon configuration * @param info compile-time options for this stylesheet compilation * @return the prepared stylesheet */ public static PreparedStylesheet compile(Source source, Configuration config, CompilerInfo info) throws TransformerConfigurationException { PreparedStylesheet pss = new PreparedStylesheet(config, info); pss.prepare(source); return pss; } /** * Make a Transformer from this Templates object. * * @return the new Transformer (always a Controller) * @see net.sf.saxon.Controller */ public Transformer newTransformer() { Controller c = new Controller(config, executable); c.setPreparedStylesheet(this); return c; } /** * Set the configuration in which this stylesheet is compiled. * Intended for internal use. * @param config the configuration to be used. */ public void setConfiguration(Configuration config) { this.config = config; } /** * Get the configuration in which this stylesheet is compiled * @return the configuration in which this stylesheet is compiled */ public Configuration getConfiguration() { return config; } /** * Set the name pool * @param pool the name pool */ public void setTargetNamePool(NamePool pool) { targetNamePool = pool; } /** * Get the name pool in use. This is the namepool used for names that need to be accessible * at runtime, notably the names used in XPath expressions in the stylesheet. * * @return the name pool in use */ public NamePool getTargetNamePool() { if (targetNamePool==null) { return config.getNamePool(); } else { return targetNamePool; } } /** * Get the StyleNodeFactory in use. The StyleNodeFactory determines which subclass of StyleElement * to use for each element node in the stylesheet tree. * * @return the StyleNodeFactory */ public StyleNodeFactory getStyleNodeFactory() { return nodeFactory; } /** * Prepare a stylesheet from a Source document * * @param styleSource the source document containing the stylesheet * @exception TransformerConfigurationException if compilation of the * stylesheet fails for any reason */ protected void prepare(Source styleSource) throws TransformerConfigurationException { nodeFactory = new StyleNodeFactory(config, errorListener); DocumentImpl doc; try { doc = loadStylesheetModule(styleSource, nodeFactory); setStylesheetDocument(doc, nodeFactory); } catch (XPathException e) { try { errorListener.fatalError(e); } catch (TransformerException e2) { // ignore an exception thrown by the error handler } if (errorCount==0) { errorCount++; } } if (errorCount > 0) { throw new TransformerConfigurationException( "Failed to compile stylesheet. " + errorCount + (errorCount==1 ? " error " : " errors ") + "detected."); } } /** * Build the tree representation of a stylesheet module * * @param styleSource the source of the module * @param nodeFactory the StyleNodeFactory used for creating * element nodes in the tree * @exception XPathException if XML parsing or tree * construction fails * @return the root Document node of the tree containing the stylesheet * module */ public DocumentImpl loadStylesheetModule(Source styleSource, StyleNodeFactory nodeFactory) throws XPathException { TreeBuilder styleBuilder = new TreeBuilder(); PipelineConfiguration pipe = config.makePipelineConfiguration(); pipe.setURIResolver(uriResolver); styleBuilder.setPipelineConfiguration(pipe); styleBuilder.setSystemId(styleSource.getSystemId()); styleBuilder.setNodeFactory(nodeFactory); styleBuilder.setLineNumbering(true); StartTagBuffer startTagBuffer = new StartTagBuffer(); UseWhenFilter useWhenFilter = new UseWhenFilter(startTagBuffer); useWhenFilter.setUnderlyingReceiver(styleBuilder); startTagBuffer.setUnderlyingReceiver(useWhenFilter); StylesheetStripper styleStripper = new StylesheetStripper(); styleStripper.setUnderlyingReceiver(startTagBuffer); CommentStripper commentStripper = new CommentStripper(); commentStripper.setUnderlyingReceiver(styleStripper); // build the stylesheet document DocumentImpl doc; Sender sender = new Sender(pipe); AugmentedSource aug = AugmentedSource.makeAugmentedSource(styleSource); aug.setSchemaValidationMode(Validation.STRIP); aug.setDTDValidationMode(Validation.STRIP); aug.setLineNumbering(true); if (aug.getXMLReader() == null && Configuration.getPlatform().isJava()) { XMLReader styleParser = config.getStyleParser(); aug.setXMLReader(styleParser); sender.send(aug, commentStripper); config.reuseStyleParser(styleParser); } else { sender.send(aug, commentStripper); } doc = (DocumentImpl)styleBuilder.getCurrentRoot(); styleBuilder.reset(); if (aug.isPleaseCloseAfterUse()) { aug.close(); } return doc; } /** * Load a PreparedStylesheet from a compiled stylesheet stored in a file. * @param config The Configuration. This method changes the NamePool used by this configuration * to be the NamePool that was stored with the compiled stylesheet. The method must therefore not * be used in a multi-threaded environment where the Configuration (and NamePool) are shared between * multiple concurrent transformations. * @param fileName The name of the file containing the compiled stylesheet (which is just the Java serialization * of a PreparedStylesheet object). * @return the PreparedStylesheet, which can be used in JAXP interfaces as the Templates object */ public static PreparedStylesheet loadCompiledStylesheet(Configuration config, String fileName) throws IOException, ClassNotFoundException { ObjectInputStream ois = new ObjectInputStream(new FileInputStream(fileName)); return loadCompiledStylesheet(config, ois); } /** * Load a PreparedStylesheet from a compiled stylesheet stored in a file. * @param config The Configuration. This method changes the NamePool used by this configuration * to be the NamePool that was stored with the compiled stylesheet. The method must therefore not * be used in a multi-threaded environment where the Configuration (and NamePool) are shared between * multiple concurrent transformations. * @param ois The ObjectInputStream containing the compiled stylesheet (which is just the Java serialization * of a PreparedStylesheet object). * @return the PreparedStylesheet, which can be used in JAXP interfaces as the Templates object */ public static PreparedStylesheet loadCompiledStylesheet(Configuration config, ObjectInputStream ois) throws IOException, ClassNotFoundException { PreparedStylesheet sheet = (PreparedStylesheet)ois.readObject(); ois.close(); NamePool compiledNamePool = sheet.getTargetNamePool(); sheet.setConfiguration(config); sheet.getExecutable().setConfiguration(config); config.setNamePool(compiledNamePool); NamePool.setDefaultNamePool(compiledNamePool); return sheet; } /** * Create a PreparedStylesheet from a supplied DocumentInfo * Note: the document must have been built using the StyleNodeFactory * * @param doc the document containing the stylesheet module * @param snFactory the StyleNodeFactory used to build the tree * @exception XPathException if the document supplied * is not a stylesheet */ protected void setStylesheetDocument(DocumentImpl doc, StyleNodeFactory snFactory) throws XPathException { DocumentImpl styleDoc = doc; nodeFactory = snFactory; // If top-level node is a literal result element, stitch it into a skeleton stylesheet StyleElement topnode = (StyleElement)styleDoc.getDocumentElement(); if (topnode instanceof LiteralResultElement) { styleDoc = ((LiteralResultElement)topnode).makeStylesheet(this, snFactory); } if (!(styleDoc.getDocumentElement() instanceof XSLStylesheet)) { throw new XPathException( "Outermost element of stylesheet is not xsl:stylesheet or xsl:transform or literal result element"); } XSLStylesheet top = (XSLStylesheet)styleDoc.getDocumentElement(); if (config.isVersionWarning() && top.getVersion().equals(BigDecimal.valueOf(1))) { try { TransformerException w = new TransformerException( "Running an XSLT 1.0 stylesheet with an XSLT 2.0 processor"); w.setLocator(topnode); config.getErrorListener().warning(w); } catch (TransformerException e) { throw XPathException.makeXPathException(e); } } // Preprocess the stylesheet, performing validation and preparing template definitions top.setPreparedStylesheet(this); try { top.preprocess(); } catch (XPathException e) { Throwable e2 = e.getException(); if (e2 instanceof XPathException) { try { errorListener.fatalError((XPathException)e2); } catch (TransformerException e3) { // ignore an error thrown by the ErrorListener } } throw e; } // Compile the stylesheet, retaining the resulting executable executable = top.compileStylesheet(); } /** * Get the associated executable * * @return the Executable for this stylesheet */ public Executable getExecutable() { return executable; } /** * Determine whether trace hooks are included in the compiled code. * @return true if trace hooks are included, false if not. * @since 8.9 */ public boolean isCompileWithTracing() { return compileWithTracing; } /** * Get the properties for xsl:output. JAXP method. The object returned will * be a clone of the internal values, and thus it can be mutated * without mutating the Templates object, and then handed in to * the process method. *

    In Saxon, the properties object is a new, empty, Properties object that is * backed by the live properties to supply default values for missing properties. * This means that the property values must be read using the getProperty() method. * Calling the get() method on the underlying Hashtable will return null.

    *

    In Saxon 8.x, this method gets the output properties for the unnamed output * format in the stylesheet.

    * * @see javax.xml.transform.Transformer#setOutputProperties * @return A Properties object reflecting the output properties defined * for the default (unnamed) output format in the stylesheet. It may * be mutated and supplied to the setOutputProperties() method of the * Transformer, without affecting other transformations that use the * same stylesheet. */ public Properties getOutputProperties() { Properties details = executable.getDefaultOutputProperties(); return new Properties(details); } /** * Report a compile time error. This calls the errorListener to output details * of the error, and increments an error count. * * @param err the exception containing details of the error * @exception TransformerException if the ErrorListener decides that the * error should be reported */ public void reportError(TransformerException err) throws TransformerException { errorCount++; if (err instanceof XPathException) { if (!((XPathException)err).hasBeenReported()) { try { errorListener.fatalError(err); } catch (Exception err2) { // ignore secondary error } ((XPathException)err).setHasBeenReported(); } } else { errorListener.fatalError(err); } } /** * Get the number of errors reported so far * * @return the number of errors reported */ public int getErrorCount() { return errorCount; } /** * Report a compile time warning. This calls the errorListener to output details * of the warning. * * @param err an exception holding details of the warning condition to be * reported */ public void reportWarning(TransformerException err) { //noinspection EmptyCatchBlock try { errorListener.warning(err); } catch (TransformerException err2) {} } /** * Get a "next in chain" stylesheet. This method is intended for internal use. * @param href the relative URI of the next-in-chain stylesheet * @param baseURI the baseURI against which this relativeURI is to be resolved * @return the cached stylesheet if present in the cache, or null if not */ public PreparedStylesheet getCachedStylesheet(String href, String baseURI) { URI abs = null; try { abs = new URI(baseURI).resolve(href); } catch (URISyntaxException err) { // } PreparedStylesheet result = null; if (abs != null && nextStylesheetCache != null) { result = (PreparedStylesheet)nextStylesheetCache.get(abs); } return result; } /** * Save a "next in chain" stylesheet in compiled form, so that it can be reused repeatedly. * This method is intended for internal use. * @param href the relative URI of the stylesheet * @param baseURI the base URI against which the relative URI is resolved * @param pss the prepared stylesheet object to be cached */ public void putCachedStylesheet(String href, String baseURI, PreparedStylesheet pss) { URI abs = null; try { abs = new URI(baseURI).resolve(href); } catch (URISyntaxException err) { // } if (abs != null) { if (nextStylesheetCache == null) { nextStylesheetCache = new HashMap(4); } nextStylesheetCache.put(abs, pss); } } /** * Get the URIResolver used at compile time for resolving URIs in xsl:include and xsl:import * @return the compile-time URIResolver */ public URIResolver getURIResolver() { return uriResolver; } /** * Get the ErrorListener used at compile time for reporting static errors in the stylesheet * @return the compile time ErrorListener */ public ErrorListener getErrorListener() { return errorListener; } /** * Produce an XML representation of the compiled and optimized stylesheet * @param presenter defines the destination and format of the output */ public void explain(ExpressionPresenter presenter) { presenter.startElement("stylesheet"); getExecutable().getKeyManager().explainKeys(presenter); getExecutable().explainGlobalVariables(presenter); getExecutable().getRuleManager().explainTemplateRules(presenter); getExecutable().explainNamedTemplates(presenter); FunctionLibraryList libList = (FunctionLibraryList)getExecutable().getFunctionLibrary(); List libraryList = libList.getLibraryList(); presenter.startElement("functions"); for (int i=0; iQuery class provides a command-line interface to the Saxon XQuery processor.

    *

    * The XQuery syntax supported conforms to the W3C XQuery 1.0 drafts. * * @author Michael H. Kay */ public class Query { protected Configuration config; protected boolean showTime = false; protected int repeat = 1; protected String sourceFileName = null; protected String queryFileName = null; protected boolean useURLs = false; protected String outputFileName = null; protected String moduleURIResolverClass = null; protected String uriResolverClass = null; protected boolean explain = false; protected boolean wrap = false; protected boolean pullMode = false; protected boolean projection = false; protected boolean updating = false; protected boolean writeback = false; protected boolean backup = true; protected String explainOutputFileName = null; //private PrintStream traceDestination = System.err; private boolean closeTraceDestination = false; private boolean schemaAware = false; /** * Set the configuration. This is designed to be * overridden in a subclass * * @param schemaAware true if a schema-aware configuration is required (in this case Saxon-SA must * be installed and licensed) * @param className the name of the class to be loaded, representing the Configuration. This * allows additional control of the loading process under .NET * @return the successfully loaded Configuration */ protected Configuration makeConfiguration(boolean schemaAware, String className) { if (schemaAware) { config = Configuration.makeSchemaAwareConfiguration(null, className); } else { config = new Configuration(); // In basic XQuery, all nodes are untyped when calling from the command line config.setAllNodesUntyped(true); } return config; } /** * Get the configuration in use * * @return the configuration */ protected Configuration getConfiguration() { return config; } /** * Main program, can be used directly from the command line. *

    The format is:

    *

    java net.sf.saxon.Query [options] query-file >output-file

    *

    followed by any number of parameters in the form {keyword=value}... which can be * referenced from within the query.

    *

    This program executes the query in query-file.

    * * @param args List of arguments supplied on operating system command line * @throws Exception Indicates that a compile-time or * run-time error occurred */ public static void main(String args[]) throws Exception { // the real work is delegated to another routine so that it can be used in a subclass (new Query()).doQuery(args, "java net.sf.saxon.Query"); } /** * Support method for main program. This support method can also be invoked from subclasses * that support the same command line interface * * @param args the command-line arguments * @param command name of the class, to be used in error messages */ protected void doQuery(String args[], String command) { schemaAware = testIfSchemaAware(args); config = makeConfiguration(schemaAware, null); config.setHostLanguage(Configuration.XQUERY); StaticQueryContext staticEnv = new StaticQueryContext(config); DynamicQueryContext dynamicEnv = new DynamicQueryContext(config); Properties outputProps = new Properties(); // Check the command-line arguments. try { parseOptions(args, command, dynamicEnv, outputProps); if (updating) { staticEnv.setUpdatingEnabled(true); } if (moduleURIResolverClass != null) { Object mr = config.getInstance(moduleURIResolverClass, null); if (!(mr instanceof ModuleURIResolver)) { badUsage(command, moduleURIResolverClass + " is not a ModuleURIResolver"); } staticEnv.setModuleURIResolver((ModuleURIResolver)mr); } if (uriResolverClass != null) { config.setURIResolver(config.makeURIResolver(uriResolverClass)); dynamicEnv.setURIResolver(config.makeURIResolver(uriResolverClass)); } config.displayLicenseMessage(); if (pullMode) { //config.setLazyConstructionMode(true); } if (explain) { config.setOptimizerTracing(true); } Source sourceInput = null; if (sourceFileName != null) { sourceInput = processSourceFile(sourceFileName, useURLs); } long startTime = (new Date()).getTime(); if (showTime) { System.err.println("Analyzing query from " + queryFileName); } // Compile the query XQueryExpression exp; try { exp = compileQuery(staticEnv, queryFileName, useURLs); if (showTime) { long endTime = (new Date()).getTime(); System.err.println("Analysis time: " + (endTime - startTime) + " milliseconds"); startTime = endTime; } } catch (XPathException err) { int line = -1; String module = null; if (err.getLocator() != null) { line = err.getLocator().getLineNumber(); module = err.getLocator().getSystemId(); } if (err.hasBeenReported()) { quit("Static error(s) in query", 2); } else { if (line == -1) { System.err.println("Static error in query: " + err.getMessage()); } else { System.err.println("Static error at line " + line + " of " + module + ':'); System.err.println(err.getMessage()); } } exp = null; System.exit(2); } if (explain) { explain(exp); } // Load the source file (applying document projection if requested) exp.setAllowDocumentProjection(projection); processSource(sourceInput, exp, dynamicEnv); // Run the query (repeatedly, if the -repeat option was set) long totalTime = 0; int r; for (r = 0; r < repeat; r++) { // repeat is for internal testing/timing try { OutputStream destination; if (outputFileName != null) { File outputFile = new File(outputFileName); if (outputFile.isDirectory()) { quit("Output is a directory", 2); } destination = new FileOutputStream(outputFile); } else { destination = System.out; } runQuery(exp, dynamicEnv, destination, outputProps); } catch (TerminationException err) { throw err; } catch (XPathException err) { if (err.hasBeenReported()) { //err.printStackTrace(); throw new XPathException("Run-time errors were reported"); } else { throw err; } } if (showTime) { long endTime = (new Date()).getTime(); if (r > 3) { totalTime += (endTime - startTime); } if (repeat != 100) { System.err.println("Execution time: " + (endTime - startTime) + " milliseconds"); } else if (totalTime > 100000) { break; } startTime = endTime; } } if (repeat > 3) { System.err.println("Average execution time: " + (totalTime / (double)(r - 3)) + " milliseconds"); } } catch (TerminationException err) { quit(err.getMessage(), 1); } catch (XPathException err) { quit("Query processing failed: " + err.getMessage(), 2); } catch (TransformerFactoryConfigurationError err) { err.printStackTrace(); quit("Query processing failed", 2); } catch (SchemaException err) { quit("Schema processing failed: " + err.getMessage(), 2); } catch (Exception err2) { err2.printStackTrace(); quit("Fatal error during query: " + err2.getClass().getName() + ": " + (err2.getMessage() == null ? " (no message)" : err2.getMessage()), 2); } } /** * Prescan the command line arguments to see if any of them imply use of a schema-aware processor * @param args the command line arguments * @return true if a schema-aware processor is needed */ protected boolean testIfSchemaAware(String[] args) { for (int i = 0; i < args.length; i++) { if (args[i].equals("-sa") || args[i].startsWith("-val:") || args[i].equals("-val") || args[i].equals("-vlax") || args[i].equals("-p") || args[i].equals("-xsd:") || args[i].startsWith("-xsdversion:") || args[i].startsWith("-projection:") || args[i].startsWith("-update:")) { return true; } } return false; } /** * Parse the options supplied on the command line * @param args the command line arguments * @param command the name of the command that was used (for diagnostics only) * @param dynamicEnv the XQuery dynamic context * @param outputProps the serialization properties * @throws TransformerException if failures occur. Note, the method may also invoke System.exit(). */ protected void parseOptions(String[] args, String command, DynamicQueryContext dynamicEnv, Properties outputProps) throws TransformerException { int i = 0; String additionalSchemas = null; while (i < args.length) { if (args[i].charAt(0) == '-') { String option; String value = null; int colon = args[i].indexOf(':'); if (colon > 0 && colon < args[i].length() - 1) { option = args[i].substring(1, colon); value = args[i].substring(colon + 1); } else { option = args[i].substring(1); } if (option.equals("backup")) { if (!("on".equals(value) || "off".equals(value))) { badUsage(command, "-backup option must be -backup:on or -backup:off"); } backup = "on".equals(value); i++; } else if (option.equals("cr")) { // collection resolver i++; if (value == null) { if (args.length < i + 2) { badUsage(command, "No resolver after -cr"); } value = args[i++]; } Object resolver = config.getInstance(value, null); if (!(resolver instanceof CollectionURIResolver)) { quit(value + " is not a CollectionURIResolver", 2); } config.setCollectionURIResolver((CollectionURIResolver)resolver); } else if (option.equals("ds")) { // linked tree config.setTreeModel(Builder.LINKED_TREE); i++; } else if (option.equals("dt")) { // tiny tree (default) config.setTreeModel(Builder.TINY_TREE); i++; } else if (option.equals("dtd")) { if (!("on".equals(value) || "off".equals(value))) { badUsage(command, "-dtd option must be -dtd:on or -dtd:off"); } config.setValidation("on".equals(value)); i++; } else if (option.equals("e")) { // explain explain = true; i++; } else if (option.equals("expand")) { if (!("on".equals(value) || "off".equals(value))) { badUsage(command, "-expand option must be 'on' or 'off'"); } config.setExpandAttributeDefaults("on".equals(value)); i++; } else if (option.equals("explain")) { // explain explain = true; i++; } else if (option.startsWith("explain:")) { // explain:filename explain = true; explainOutputFileName = value; i++; } else if (option.equals("ext")) { if (!("on".equals(value) || "off".equals(value))) { badUsage(command, "-ext option must be -ext:on or -ext:off"); } config.setAllowExternalFunctions("on".equals(value)); i++; } else if (option.equals("l")) { if (!(value == null || "on".equals(value) || "off".equals(value))) { badUsage(command, "-l option must be -l:on or -l:off"); } config.setLineNumbering(!"off".equals(value)); i++; //i++; } else if (option.equals("mr")) { i++; if (value == null) { if (args.length < i + 2) { badUsage(command, "No resolver after -cr"); } value = args[i++]; } moduleURIResolverClass = value; } else if (option.equals("-noext")) { i++; config.setAllowExternalFunctions(false); } else if (option.equals("o")) { i++; if (value == null) { if (args.length < i + 2) { badUsage(command, "No output file name after -o"); } value = args[i++]; } outputFileName = value; } else if (option.equals("outval")) { if (schemaAware) { if (!(value == null || "recover".equals(value) || "fatal".equals(value))) { badUsage(command, "-outval option must be 'recover' or 'fatal'"); } config.setValidationWarnings("recover".equals(value)); } else { quit("The -outval option requires a schema-aware processor", 2); } i++; } else if (option.equals("p")) { i++; if (!(value == null || "on".equals(value) || "off".equals(value))) { badUsage(command, "-p option must be -p:on or -p:off"); } if (!"off".equals(value)) { config.setParameterizedURIResolver(); useURLs = true; } } else if (option.equals("pipe")) { i++; if (!("push".equals(value) || "pull".equals(value))) { badUsage(command, "-pipe option must be -p:push or -p:pull"); } if ("pull".equals(value)) { pullMode = true; } } else if (option.equals("projection")) { i++; if (!(value == null || "on".equals(value) || "off".equals(value))) { badUsage(command, "-projection option must be -projection:on or projection:off"); } if (!"off".equals(value)) { projection = true; } } else if (option.equals("pull")) { i++; pullMode = true; } else if (option.equals("q")) { i++; queryFileName = value; } else if (option.equals("qs")) { i++; queryFileName = "{" + value + "}"; } else if (option.equals("r")) { i++; if (value == null) { if (args.length < i + 2) { badUsage(command, "No URIResolver class after -r"); } value = args[i++]; } uriResolverClass = value; } else if (option.equals("repeat")) { i++; if (value == null) { badUsage(command, "No number after -repeat"); } else { try { repeat = Integer.parseInt(value); } catch (NumberFormatException err) { badUsage(command, "Bad number after -repeat"); } } } else if (option.equals("s")) { i++; if (value == null) { if (args.length < i + 2) { badUsage(command, "No source file name after -s"); } value = args[i++]; } sourceFileName = value; } else if (option.equals("sa")) { // already handled i++; } else if (option.equals("snone")) { config.setStripsWhiteSpace(Whitespace.NONE); i++; } else if (option.equals("sall")) { config.setStripsWhiteSpace(Whitespace.ALL); i++; } else if (option.equals("signorable")) { config.setStripsWhiteSpace(Whitespace.IGNORABLE); i++; } else if (option.equals("strip")) { i++; if (value == null) { value = "all"; } if ("none".equals(value)) { // no action|| || "ignorable".equals(value)) { } else if ("all".equals(value)) { config.setStripsWhiteSpace(Whitespace.ALL); } else if ("ignorable".equals(value)) { config.setStripsWhiteSpace(Whitespace.IGNORABLE); } else { badUsage(command, "-strip must be none, all, or ignorable"); } } else if (option.equals("t")) { System.err.println(config.getProductTitle()); System.err.println(Configuration.getPlatform().getPlatformVersion()); config.setTiming(true); showTime = true; i++; } else if (option.equals("traceout")) { i++; if (value.equals("#err")) { // no action, this is the default } else if (value.equals("#out")) { dynamicEnv.setTraceFunctionDestination(System.out); } else if (value.equals("#null")) { dynamicEnv.setTraceFunctionDestination(null); } else { try { dynamicEnv.setTraceFunctionDestination( new PrintStream(new FileOutputStream(new File(value)))); closeTraceDestination = true; } catch (FileNotFoundException e) { badUsage(command, "Trace output file " + value + " cannot be created"); } } } else if (option.equals("tree")) { if ("linked".equals(value)) { config.setTreeModel(Builder.LINKED_TREE); } else if ("tiny".equals(value)) { config.setTreeModel(Builder.TINY_TREE); } else { badUsage(command, "-tree option must be 'linked' or 'tiny'"); } i++; } else if (option.equals("T")) { i++; if (value == null) { config.setTraceListener(new XQueryTraceListener()); } else { config.setTraceListenerClass(value); } config.setLineNumbering(true); } else if (option.equals("TJ")) { i++; config.setTraceExternalFunctions(true); } else if (option.equals("TL")) { if (args.length < i + 2) { badUsage(command, "No TraceListener class specified"); } config.setTraceListenerClass(args[++i]); config.setLineNumbering(true); i++; } else if (option.equals("u")) { useURLs = true; i++; } else if (option.equals("update")) { i++; if (!(value == null || "on".equals(value) || "off".equals(value) || "discard".equals(value))) { badUsage(command, "-update option must be on|off|discard"); } if (!"off".equals(value)) { updating = true; } writeback = !("discard".equals(value)); } else if (option.equals("untyped")) { // TODO: this is an experimental undocumented option. It should be checked for consistency config.setAllNodesUntyped(true); i++; } else if (option.equals("v")) { config.setValidation(true); i++; } else if (option.equals("val")) { if (!schemaAware) { quit("The -val option requires a schema-aware processor", 2); } else if (value == null || "strict".equals(value)) { config.setSchemaValidationMode(Validation.STRICT); } else if ("lax".equals(value)) { config.setSchemaValidationMode(Validation.LAX); } else { badUsage(command, "-val option must be 'strict' or 'lax'"); } i++; } else if (option.equals("vlax")) { if (schemaAware) { config.setSchemaValidationMode(Validation.LAX); } else { quit("The -vlax option requires a schema-aware processor", 2); } i++; } else if (option.equals("vw")) { if (schemaAware) { config.setValidationWarnings(true); } else { quit("The -vw option requires a schema-aware processor", 2); } i++; } else if (option.equals("wrap")) { if (!(value == null || "on".equals(value) || "off".equals(value))) { badUsage(command, "-wrap option must be -wrap:on or -wrap:off"); } if (!"off".equals(value)) { wrap = true; } i++; } else if (option.equals("x")) { i++; config.setSourceParserClass(value); } else if (option.equals("xi")) { if (!(value == null || "on".equals(value) || "off".equals(value))) { badUsage(command, "-xi option must be -xi:on or -xi:off"); } if (!"off".equals(value)) { config.setXIncludeAware(true); } i++; } else if (option.equals("1.1")) { config.setXMLVersion(Configuration.XML11); i++; } else if (option.equals("xmlversion")) { i++; if ("1.0".equals(value)) { config.setXMLVersion(Configuration.XML10); } else if ("1.1".equals(value)) { config.setXMLVersion(Configuration.XML11); } else { badUsage(command, "-xmlversion must be 1.0 or 1.1"); } } else if (option.equals("xsd")) { i++; additionalSchemas = value; } else if (option.equals("xsdversion")) { // XSD 1.1 i++; if (!("1.0".equals(value) | "1.1".equals(value))) { badUsage(command, "-xsdversion must be 1.0 or 1.1"); } config.setConfigurationProperty(FeatureKeys.XSD_VERSION, value); } else if (option.equals("xsiloc")) { i++; if ("off".equals(value)) { config.setConfigurationProperty(FeatureKeys.USE_XSI_SCHEMA_LOCATION, Boolean.FALSE); } else if ("on".equals(value)) { config.setConfigurationProperty(FeatureKeys.USE_XSI_SCHEMA_LOCATION, Boolean.TRUE); } else { badUsage(value, "format: -xsiloc:(on|off)"); } } else if (args[i].equals("-?")) { badUsage(command, ""); } else if (args[i].equals("-")) { queryFileName = "-"; i++; } else { badUsage(command, "Unknown option " + args[i]); } } else { break; } } if (queryFileName == null) { if (args.length < i + 1) { badUsage(command, "No query file name"); } queryFileName = args[i++]; } for (int p = i; p < args.length; p++) { String arg = args[p]; int eq = arg.indexOf("="); if (eq < 1 || eq >= arg.length()) { badUsage(command, "Bad param=value pair on command line: " + arg); } String argname = arg.substring(0, eq); String argvalue = (eq == arg.length() ? "" : arg.substring(eq + 1)); if (argname.startsWith("!")) { // parameters starting with "!" are taken as output properties outputProps.setProperty(argname.substring(1), argvalue); } else if (argname.startsWith("+")) { // parameters starting with "+" are taken as input documents Object sources = Transform.loadDocuments(argvalue, useURLs, config, true); dynamicEnv.setParameter(argname.substring(1), sources); } else { dynamicEnv.setParameter(argname, new UntypedAtomicValue(argvalue)); } } if (additionalSchemas != null) { loadAdditionalSchemas(config, additionalSchemas); } } protected static void loadAdditionalSchemas(Configuration config, String additionalSchemas) throws TransformerException { StringTokenizer st = new StringTokenizer(additionalSchemas, ";"); while (st.hasMoreTokens()) { String schema = st.nextToken(); File schemaFile = new File(schema); if (!schemaFile.exists()) { throw new TransformerException("Schema document " + schema + " not found"); } config.addSchemaSource(new StreamSource(schemaFile)); } } protected Source processSourceFile(String sourceFileName, boolean useURLs) throws TransformerException { Source sourceInput; if (useURLs || sourceFileName.startsWith("http:") || sourceFileName.startsWith("file:")) { sourceInput = config.getURIResolver().resolve(sourceFileName, null); if (sourceInput == null) { sourceInput = config.getSystemURIResolver().resolve(sourceFileName, null); } } else if (sourceFileName.equals("-")) { // take input from stdin sourceInput = new StreamSource(System.in); } else { File sourceFile = new File(sourceFileName); if (!sourceFile.exists()) { quit("Source file " + sourceFile + " does not exist", 2); } if (Configuration.getPlatform().isJava()) { InputSource eis = new InputSource(sourceFile.toURI().toString()); sourceInput = new SAXSource(eis); } else { sourceInput = new StreamSource(sourceFile.toURI().toString()); } } return sourceInput; } /** * Compile the query * * @param staticEnv the static query context * @param queryFileName the filename holding the query (or "-" for the standard input) * @param useURLs true if the filename is in the form of a URI * @return the compiled query * @throws XPathException if query compilation fails * @throws IOException if the query cannot be read */ protected XQueryExpression compileQuery(StaticQueryContext staticEnv, String queryFileName, boolean useURLs) throws XPathException, IOException { XQueryExpression exp; if (queryFileName.equals("-")) { Reader queryReader = new InputStreamReader(System.in); exp = staticEnv.compileQuery(queryReader); } else if (queryFileName.startsWith("{") && queryFileName.endsWith("}")) { // query is inline on the command line String q = queryFileName.substring(1, queryFileName.length() - 1); exp = staticEnv.compileQuery(q); } else if (useURLs || queryFileName.startsWith("http:") || queryFileName.startsWith("file:")) { ModuleURIResolver resolver = staticEnv.getModuleURIResolver(); boolean isStandardResolver = false; if (resolver == null) { resolver = staticEnv.getConfiguration().getStandardModuleURIResolver(); isStandardResolver = true; } while (true) { String[] locations = {queryFileName}; Source[] sources; try { sources = resolver.resolve(null, null, locations); } catch (Exception e) { if (e instanceof XPathException) { throw (XPathException)e; } else { XPathException err = new XPathException("Exception in ModuleURIResolver: ", e); err.setErrorCode("XQST0059"); throw err; } } if (sources == null) { if (isStandardResolver) { // this should not happen quit("System problem: standard ModuleURIResolver returned null", 4); } else { resolver = staticEnv.getConfiguration().getStandardModuleURIResolver(); isStandardResolver = true; } } else { if (sources.length != 1 || !(sources[0] instanceof StreamSource)) { quit("Module URI Resolver must return a single StreamSource", 2); } String queryText = QueryReader.readSourceQuery((StreamSource)sources[0], config.getNameChecker()); exp = staticEnv.compileQuery(queryText); break; } } } else { InputStream queryStream = new FileInputStream(queryFileName); staticEnv.setBaseURI(new File(queryFileName).toURI().toString()); exp = staticEnv.compileQuery(queryStream, null); } return exp; } /** * Explain the results of query compilation * * @param exp the compiled expression * @throws FileNotFoundException if the destination for the explanation doesn't exist * @throws XPathException if other failures occur */ protected void explain(XQueryExpression exp) throws FileNotFoundException, XPathException { OutputStream explainOutput; if (explainOutputFileName == null) { explainOutput = System.err; } else { explainOutput = new FileOutputStream(new File(explainOutputFileName)); } Properties props = new Properties(); props.setProperty(OutputKeys.METHOD, "xml"); props.setProperty(OutputKeys.INDENT, "yes"); props.setProperty(SaxonOutputKeys.INDENT_SPACES, "2"); Receiver diag = config.getSerializerFactory().getReceiver( new StreamResult(explainOutput), config.makePipelineConfiguration(), props); ExpressionPresenter expressionPresenter = new ExpressionPresenter(config, diag); exp.explain(expressionPresenter); } /** * Process the supplied source file * * @param sourceInput the supplied source * @param exp the compiled XQuery expression * @param dynamicEnv the dynamic query context * @throws XPathException if processing fails */ protected void processSource(Source sourceInput, XQueryExpression exp, DynamicQueryContext dynamicEnv) throws XPathException { if (sourceInput != null) { if (showTime) { System.err.println("Processing " + sourceInput.getSystemId()); } if (!exp.usesContextItem()) { System.err.println("Source document ignored - query does not access the context item"); sourceInput = null; } else if (projection) { PathMap map = exp.getPathMap(); PathMap.PathMapRoot contextRoot = map.getContextRoot(); if (explain) { System.err.println("DOCUMENT PROJECTION: PATH MAP"); map.diagnosticDump(System.err); } if (contextRoot != null) { if (contextRoot.hasUnknownDependencies()) { System.err.println("Document projection for the context document is not possible, " + "because the query uses paths that defy analysis"); } else { ProxyReceiver filter = config.makeDocumentProjector(contextRoot); sourceInput = AugmentedSource.makeAugmentedSource(sourceInput); ((AugmentedSource)sourceInput).addFilter(filter); } } else { System.err.println("Source document supplied, but query does not access the context item"); } } if (sourceInput != null) { DocumentInfo doc = config.buildDocument(sourceInput); dynamicEnv.setContextItem(doc); } } } /** * Run the query * * @param exp the compiled query expression * @param dynamicEnv the dynamic query context * @param destination the destination for serialized results * @param outputProps serialization properties defining the output format * @throws XPathException if the query fails * @throws IOException if input or output fails */ protected void runQuery(XQueryExpression exp, DynamicQueryContext dynamicEnv, OutputStream destination, final Properties outputProps) throws XPathException, IOException { if (exp.getExpression().isUpdatingExpression() && updating) { if (writeback) { final List errors = new ArrayList(3); UpdateAgent agent = new UpdateAgent() { public void update(NodeInfo node, Controller controller) throws XPathException { try { DocumentPool pool = controller.getDocumentPool(); String documentURI = pool.getDocumentURI(node); if (documentURI != null) { QueryResult.rewriteToDisk(node, outputProps, backup, (showTime ? System.err : null)); } else if (showTime) { System.err.println("Updated document discarded because it was not read using doc()"); } } catch (XPathException err) { System.err.println(err.getMessage()); errors.add(err); } } }; exp.runUpdate(dynamicEnv, agent); if (!errors.isEmpty()) { throw (XPathException)errors.get(0); } } else { Set affectedDocuments = exp.runUpdate(dynamicEnv); if (affectedDocuments.contains(dynamicEnv.getContextItem())) { QueryResult.serialize((NodeInfo)dynamicEnv.getContextItem(), new StreamResult(destination), outputProps); } } } else if (wrap && !pullMode) { SequenceIterator results = exp.iterator(dynamicEnv); DocumentInfo resultDoc = QueryResult.wrap(results, config); QueryResult.serialize(resultDoc, new StreamResult(destination), outputProps); destination.close(); } else if (pullMode) { if (wrap) { outputProps.setProperty(SaxonOutputKeys.WRAP, "yes"); } //outputProps.setProperty(OutputKeys.METHOD, "xml"); //outputProps.setProperty(OutputKeys.INDENT, "yes"); exp.pull(dynamicEnv, new StreamResult(destination), outputProps); } else { exp.run(dynamicEnv, new StreamResult(destination), outputProps); } if (closeTraceDestination) { dynamicEnv.getTraceFunctionDestination().close(); } } /** * Exit with a message * * @param message The message to be output * @param code The result code to be returned to the operating * system shell */ protected static void quit(String message, int code) { System.err.println(message); System.exit(code); } // public void setPOption(Configuration config) { // config.getSystemURIResolver().setRecognizeQueryParameters(true); // } /** * Report incorrect usage of the command line, with a list of the options and arguments that are available * * @param name The name of the command being executed (allows subclassing) * @param message The error message */ protected void badUsage(String name, String message) { if (!"".equals(message)) { System.err.println(message); } System.err.println(config.getProductTitle()); System.err.println("Usage: " + name + " [options] query {param=value}..."); System.err.println("Options: "); System.err.println(" -backup:on|off Save updated documents before overwriting"); System.err.println(" -cr:classname Use specified CollectionURIResolver class"); System.err.println(" -dtd:on|off Validate using DTD"); System.err.println(" -expand:on|off Expand defaults defined in schema/DTD"); System.err.println(" -explain[:filename] Display compiled expression tree"); System.err.println(" -ext:[on|off] Allow|Disallow external Java functions"); System.err.println(" -l:on|off Line numbering for source document"); System.err.println(" -mr:classname Use specified ModuleURIResolver class"); System.err.println(" -o:filename Send output to named file"); System.err.println(" -outval:recover|fatal Handling of validation errors on result document"); System.err.println(" -p Recognize Saxon file extensions and query parameters"); System.err.println(" -pipe:push|pull Execute internally in push or pull mode"); System.err.println(" -projection:[on|off] Use|Don't use source document projection"); System.err.println(" -q:filename Query file name"); System.err.println(" -qs:string Query string (usually in quotes)"); System.err.println(" -r:classname Use URIResolver class"); System.err.println(" -repeat:N Repeat N times for performance measurement"); System.err.println(" -s:file|URI Provide initial context document"); System.err.println(" -sa Schema-aware query (requires Saxon-SA)"); System.err.println(" -strip:all|none|ignorable Strip whitespace text nodes"); System.err.println(" -t Display version and timing information"); System.err.println(" -traceout:file|#null Destination for fn:trace() output"); System.err.println(" -tree:tiny|linked Select tree model"); System.err.println(" -T[:classname] Use TraceListener class"); System.err.println(" -TJ Trace calls to external Java functions"); System.err.println(" -u Names are URLs not filenames"); System.err.println(" -update:on|off|discard Enable|Disable XQuery Update (needs Saxon-SA)"); System.err.println(" -val:strict|lax Validate using schema"); System.err.println(" -wrap:on|off Wrap result sequence in XML elements"); System.err.println(" -x:classname Parser (XMLReader) used for source files"); System.err.println(" -xi:on|off Expand XInclude on all documents"); System.err.println(" -xmlversion:1.0|1.1 Version of XML to be handled"); System.err.println(" -xsd:file;file.. Additional schema documents to be loaded"); System.err.println(" -xsdlversion:1.0|1.1 Version of XML Schema to be used"); System.err.println(" -xsiloc:on|off Take note of xsi:schemaLocation"); System.err.println(" -? Display this message "); System.err.println(" param=value Set query string parameter"); System.err.println(" +param=value Set query document parameter"); System.err.println(" !option=value Set serialization option"); if ("".equals(message)) { System.exit(0); } else { System.exit(2); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): changes to allow source and/or stylesheet from stdin contributed by // Gunther Schadow [gunther@aurora.regenstrief.org] // saxonb-9.1.0.8/bj/net/sf/saxon/Configuration.java0000644000175000017500000043527711061770727021110 0ustar eugeneeugenepackage net.sf.saxon; /*DOTNETONLY*/ import net.sf.saxon.dotnet.DotNetPlatform; import net.sf.saxon.event.*; import net.sf.saxon.evpull.PullEventSource; import net.sf.saxon.expr.Optimizer; import net.sf.saxon.expr.PathMap; import net.sf.saxon.expr.PendingUpdateList; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.functions.ExtensionFunctionFactory; import net.sf.saxon.functions.FunctionLibrary; import net.sf.saxon.functions.StandardCollectionURIResolver; import net.sf.saxon.functions.VendorFunctionLibrary; import net.sf.saxon.instruct.Debugger; import net.sf.saxon.instruct.SlotManager; /*JAVAONLY*/ import net.sf.saxon.java.JavaPlatform; import net.sf.saxon.om.*; import net.sf.saxon.pull.PullProvider; import net.sf.saxon.pull.PullSource; import net.sf.saxon.query.ModuleURIResolver; import net.sf.saxon.query.QueryParser; import net.sf.saxon.query.StandardModuleURIResolver; import net.sf.saxon.sort.CollationURIResolver; import net.sf.saxon.sort.StandardCollationURIResolver; import net.sf.saxon.sort.StringCollator; import net.sf.saxon.sxpath.IndependentContext; import net.sf.saxon.tinytree.TinyBuilder; import net.sf.saxon.trace.TraceListener; import net.sf.saxon.trans.DynamicLoader; import net.sf.saxon.trans.SaxonErrorCode; import net.sf.saxon.trans.XPathException; import net.sf.saxon.tree.TreeBuilder; import net.sf.saxon.type.*; import net.sf.saxon.value.Whitespace; import org.xml.sax.*; import org.xml.sax.ext.DefaultHandler2; import org.xml.sax.ext.LexicalHandler; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParserFactory; import javax.xml.transform.*; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.sax.SAXSource; import javax.xml.transform.stream.StreamSource; import java.io.Serializable; import java.util.*; /** * This class holds details of user-selected configuration options for a set of transformations * and/or queries. When running XSLT, the preferred way of setting configuration options is via * the JAXP TransformerFactory interface, but the Configuration object provides a finer * level of control. As yet there is no standard API for XQuery, so the only way of setting * Configuration information is to use the methods on this class directly. *

    *

    As well as holding configuration settings, this class acts as a factory for classes * providing service in particular areas: error handling, URI resolution, and the like. Some * of these services are chosen on the basis of the current platform (Java or .NET), some vary * depending whether the environment is schema-aware or not.

    *

    *

    The Configuration provides access to a {@link NamePool} which is used to manage * all the names used in stylesheets, queries, schemas, and source and documents: the NamePool * allocates integer codes to these names allowing efficient storage and comparison. Normally * there will be a one-to-one relationship between a NamePool and a Configuration. * It is possible, however, for several Configuration objects to share the same * NamePool. Until Saxon 8.9, by default all Configuration objects * shared a single NamePool unless configured otherwise; this changed in 8.9 so that * the default is to allocate a new NamePool for each Configuration.

    *

    *

    The Configuration establishes the scope within which node identity is managed. * Every document belongs to a Configuration, and every node has a distinct identity * within that Configuration. In consequence, it is not possible for any query or * transformation to manipulate multiple documents unless they all belong to the same * Configuration.

    *

    *

    Saxon-SA has a subclass of the Configuration class which provides the additional * services needed for schema-aware processing. The {@link com.saxonica.validate.SchemaAwareConfiguration} * also holds a cache of loaded schema components used for compiling schema-aware transformations * and queries, and for validating instance documents.

    *

    *

    Since Saxon 8.4, the JavaDoc documentation for Saxon attempts to identify interfaces * that are considered stable, and will only be changed in a backwards-incompatible way * if there is an overriding reason to do so. These interfaces and methods are labelled * with the JavaDoc "since" tag. The value 8.n indicates a method in this category that * was introduced in Saxon version 8.n: or in the case of 8.4, that was present in Saxon 8.4 * and possibly in earlier releases. (In some cases, these methods have been unchanged for * a long time.) Methods without a "since" tag, although public, are provided for internal * use or for use by advanced users, and are subject to change from one release to the next. * The presence of a "since" tag on a class or interface indicates that there are one or more * methods in the class that are considered stable; it does not mean that all methods are * stable. * * @since 8.4 */ public class Configuration implements Serializable, SourceResolver { private static Platform platform; private transient URIResolver uriResolver; private StandardURIResolver systemURIResolver = new StandardURIResolver(this); protected transient ErrorListener listener; private int xmlVersion = XML10; protected int xsdlVersion = XSD10; private int treeModel = Builder.TINY_TREE; private boolean lineNumbering = false; private boolean tracing = false; private boolean traceOptimizations = false; private transient TraceListener traceListener = null; private String traceListenerClass = null; private FunctionLibrary javaExtensionBinder; private FunctionLibrary dotNetExtensionBinder; private transient ExtensionFunctionFactory javaExtensionFunctionFactory; private transient ExtensionFunctionFactory dotNetExtensionFunctionFactory; private CollationURIResolver collationResolver = StandardCollationURIResolver.getInstance(); private CollectionURIResolver collectionResolver = new StandardCollectionURIResolver(); private ModuleURIResolver moduleURIResolver = null; private ModuleURIResolver standardModuleURIResolver = StandardModuleURIResolver.getInstance(); private SchemaURIResolver schemaURIResolver = null; private transient SourceResolver sourceResolver = this; protected VendorFunctionLibrary vendorFunctionLibrary; protected int recoveryPolicy = RECOVER_WITH_WARNINGS; private String messageEmitterClass = "net.sf.saxon.event.MessageEmitter"; private String sourceParserClass; private String styleParserClass; private boolean preferJaxpParser; private transient OutputURIResolver outputURIResolver; private boolean timing = false; private boolean versionWarning = false; private boolean allowExternalFunctions = true; private boolean traceExternalFunctions = false; private boolean validation = false; private boolean allNodesUntyped = false; private boolean lazyConstructionMode = false; private boolean allowMultiThreading = false; private boolean preEvaluateDocFunction = false; private boolean useXsiSchemaLocation = true; private int stripsWhiteSpace = Whitespace.IGNORABLE; private boolean xIncludeAware = false; private boolean useDisableOutputEscaping = false; private NamePool namePool = null; private DocumentNumberAllocator documentNumberAllocator = new DocumentNumberAllocator(); private DocumentPool globalDocumentPool = new DocumentPool(); private transient XPathContext conversionContext = null; private transient TypeHierarchy typeHierarchy; private int hostLanguage = XSLT; private int schemaValidationMode = Validation.PRESERVE; private boolean validationWarnings = false; private boolean expandDefaultAttributes = true; private boolean retainDTDattributeTypes = false; private transient Debugger debugger = null; protected Optimizer optimizer = null; private transient DynamicLoader dynamicLoader = new DynamicLoader(); private SerializerFactory serializerFactory = new SerializerFactory(); //private int implicitTimezone; private transient List sourceParserPool = new ArrayList(5); private transient List styleParserPool = new ArrayList(5); /** * The external object models are held in static so they are only loaded once in an application * that creates many Configurations repeatedly. This saves expensive searches of the classpath */ private static List sharedExternalObjectModels = null; private List externalObjectModels = null; private int domLevel = 3; /** * Constant indicating that the processor should take the recovery action * when a recoverable error occurs, with no warning message. */ public static final int RECOVER_SILENTLY = 0; /** * Constant indicating that the processor should produce a warning * when a recoverable error occurs, and should then take the recovery * action and continue. */ public static final int RECOVER_WITH_WARNINGS = 1; /** * Constant indicating that when a recoverable error occurs, the * processor should not attempt to take the defined recovery action, * but should terminate with an error. */ public static final int DO_NOT_RECOVER = 2; /** * Constant indicating the XML Version 1.0 */ public static final int XML10 = 10; /** * Constant indicating the XML Version 1.1 */ public static final int XML11 = 11; /** * Constant indicating that the host language is XSLT */ public static final int XSLT = 50; /** * Constant indicating that the host language is XQuery */ public static final int XQUERY = 51; /** * Constant indicating that the "host language" is XML Schema */ public static final int XML_SCHEMA = 52; /** * Constant indicating that the host language is Java: that is, this is a free-standing * Java application with no XSLT or XQuery content */ public static final int JAVA_APPLICATION = 53; /** * Constant indicating that the host language is XPATH itself - that is, a free-standing XPath environment */ public static final int XPATH = 54; /** * Language versions for XML Schema */ public static int XSD10 = 10; public static int XSD11 = 11; /** * Static initialization */ static { // This code is designed to be modified by the build process so only the appropriate code for the // platform is included. However, it's also designed so that it can run correctly without any // special build action. /*JAVAONLY*/ platform = JavaPlatform.getInstance(); /*DOTNETONLY*/ /*JAVAONLY*/ if (System.getProperty("java.vendor").equals("Jeroen Frijters")) { //System.err.println("Call to create .NET platform currently disabled in Configuration.java (needed for JDK1.4)"); /*DOTNETONLY*/ platform = DotNetPlatform.getInstance(); /*DOTNETONLY*/ /*JAVAONLY*/ } // System.err.println(System.getProperty("java.vendor")); // System.err.println(platform.getClass().getName()); } /** * Create a non-schema-aware configuration object with default settings for all options. * * @since 8.4 */ public Configuration() { init(); } /** * Factory method to create a Configuration. The resulting configuration will be schema-aware if * Saxon-SA is installed and if a license is available; otherwise it will be non-schema-aware. * Note that the license might not permit all processing options. * * @param classLoader - the class loader to be used. If null, the context class loader for the current * thread is used. * @param className - the name of the schema aware configuration class. Defaults to * "com.saxonica.validate.SchemaAwareConfiguration" if null is supplied. This allows an assembly * qualified name to be supplied under .NET. The class, once instantiated, must be an instance * of Configuration, but despite the name of this method there is nothing that requires it to * be schema-aware. * @return a schema-aware configuration object if Saxon-SA can be loaded and a valid license is * installed; otherwise, a non-schema-aware configuration object * @since 9.0 */ public static Configuration makeConfiguration(ClassLoader classLoader, String className) { try { Configuration c = makeSchemaAwareConfiguration(classLoader, className); if (c.isSchemaAware(XML_SCHEMA)) { return c; } else { return new Configuration(); } } catch (RuntimeException err) { return new Configuration(); } } protected void init() { //BuiltInListType.init(); platform.initialize(this); if (platform.isDotNet()) { externalObjectModels = new ArrayList(3); } else { synchronized (Configuration.class) { if (sharedExternalObjectModels == null) { registerStandardObjectModels(); } externalObjectModels = new ArrayList(sharedExternalObjectModels); } } //namePool = NamePool.getDefaultNamePool(); namePool = new NamePool(); platform.makeExtensionLibrary(this); // Get the implicit timezone from the current system clock //GregorianCalendar calendar = new GregorianCalendar(); //int tzmsecs = (calendar.get(Calendar.ZONE_OFFSET) + calendar.get(Calendar.DST_OFFSET)); //implicitTimezone = tzmsecs / 60000; } /** * Static method to instantiate a schema-aware configuration. *

    On the .NET platform, this method should not be called unless it is known that the assembly * saxon9sa.dll has already been loaded. This can be achieved by an appropriate call on Assembly.Load(): * for an example, see the C# Configuration.cs class in the Saxon.Api namespace.

    *

    This method fails if Saxon-SA cannot be loaded, but it does not fail if there is no license * available. In that case it returns a schema-aware configuration object, but any attempt to use * schema-aware processing will fail. * * @param classLoader - the class loader to be used. If null, the context class loader for the current * thread is used. * @param className - the name of the schema aware configuration class. Defaults to * "com.saxonica.validate.SchemaAwareConfiguration" if null is supplied. This allows an assembly * qualified name to be supplied under .NET. The class, once instantiated, must be an instance * of Configuration, but despite the name of this method there is nothing that requires it to * be schema-aware. * @return the new SchemaAwareConfiguration * @throws RuntimeException if the Saxon-SA product cannot be loaded */ public static Configuration makeSchemaAwareConfiguration(ClassLoader classLoader, String className) throws RuntimeException { if (className == null) { className = "com.saxonica.validate.SchemaAwareConfiguration"; } try { Class theClass; ClassLoader loader = classLoader; if (loader == null) { try { loader = Thread.currentThread().getContextClassLoader(); } catch (Exception err) { System.err.println("Failed to getContextClassLoader() - continuing"); } } if (loader != null) { try { theClass = loader.loadClass(className); } catch (Exception ex) { theClass = Class.forName(className); } } else { theClass = Class.forName(className); } return (Configuration)theClass.newInstance(); } catch (ClassNotFoundException e) { throw new RuntimeException(e); } catch (InstantiationException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } } /** * Copy an existing Configuration to create a new Configuration. * This is a shallow copy. The new Configuration will share all the option settings of the old; * it will also share the same NamePool, and the same DocumentNumberAllocator. If this configuration * is schema-aware then the new one will also be schema-aware, and will share the same Schema manager * and so on. (So any schema component loaded into one configuration will affect both). *

    *

    Note that creating a new SchemaAwareConfiguration using this method can be significantly cheaper * than creating one from scratch, because it avoids the need to verify the Saxon-SA license key if this * has already been done.

    * * @return a shallow copy of this Configuration */ public Configuration copy() { Configuration c = new Configuration(); copyTo(c); return c; } protected void copyTo(Configuration c) { c.uriResolver = uriResolver; c.systemURIResolver = systemURIResolver; c.listener = listener; c.xmlVersion = xmlVersion; c.treeModel = treeModel; c.lineNumbering = lineNumbering; c.tracing = tracing; c.traceOptimizations = traceOptimizations; c.traceListener = traceListener; c.javaExtensionBinder = javaExtensionBinder; c.dotNetExtensionBinder = dotNetExtensionBinder; c.javaExtensionFunctionFactory = javaExtensionFunctionFactory; c.dotNetExtensionFunctionFactory = dotNetExtensionFunctionFactory; c.collationResolver = collationResolver; c.collectionResolver = collectionResolver; c.moduleURIResolver = moduleURIResolver; c.standardModuleURIResolver = standardModuleURIResolver; c.schemaURIResolver = schemaURIResolver; c.sourceResolver = sourceResolver; c.vendorFunctionLibrary = vendorFunctionLibrary; c.recoveryPolicy = recoveryPolicy; c.messageEmitterClass = messageEmitterClass; c.sourceParserClass = sourceParserClass; c.styleParserClass = styleParserClass; c.outputURIResolver = outputURIResolver; c.timing = timing; c.versionWarning = versionWarning; c.allowExternalFunctions = allowExternalFunctions; c.validation = validation; c.allNodesUntyped = allNodesUntyped; c.lazyConstructionMode = lazyConstructionMode; c.allowMultiThreading = allowMultiThreading; c.preEvaluateDocFunction = preEvaluateDocFunction; c.stripsWhiteSpace = stripsWhiteSpace; c.xIncludeAware = xIncludeAware; c.namePool = namePool; c.documentNumberAllocator = documentNumberAllocator; c.conversionContext = conversionContext; c.typeHierarchy = typeHierarchy; c.hostLanguage = hostLanguage; c.schemaValidationMode = schemaValidationMode; c.validationWarnings = validationWarnings; c.expandDefaultAttributes = expandDefaultAttributes; c.retainDTDattributeTypes = retainDTDattributeTypes; c.debugger = debugger; c.optimizer = optimizer; c.serializerFactory = serializerFactory; c.dynamicLoader = dynamicLoader; c.sourceParserPool = sourceParserPool; c.externalObjectModels = externalObjectModels; c.domLevel = domLevel; } /** * Get a message used to identify this product when a transformation is run using the -t option * * @return A string containing both the product name and the product * version * @since 8.4 */ public String getProductTitle() { return "Saxon " + Version.getProductVersion() + platform.getPlatformSuffix() + " from Saxonica"; } /** * Determine if the configuration is schema-aware, for the given host language * * @param language the required host language: XSLT, XQUERY, or XML_SCHEMA * @return true if the configuration is schema-aware * @since 8.4 */ public boolean isSchemaAware(int language) { return false; // changing this to true will do no good! } /** * Display a message about the license status */ public void displayLicenseMessage() { } /** * Get the host language used in this configuration. The typical values * are XSLT and XQUERY. The values XML_SCHEMA and JAVA_APPLICATION may also * be encountered. *

    * This method is problematic because it is possible to run multiple transformations * or queries within the same configuration. The method is therefore best avoided. * Instead, use {@link net.sf.saxon.expr.Container#getHostLanguage}. * Internally its only use is in deciding (in Saxon-SA only) which error listener to * use by default at compile time, and since the standard XSLT and XQuery listeners have * no differences when used for static errors, the choice is immaterial. * * @return Configuration.XSLT or Configuration.XQUERY */ public int getHostLanguage() { return hostLanguage; } /** * Set the host language used in this configuration. The possible values * are XSLT and XQUERY. * * @param hostLanguage Configuration.XSLT or Configuration.XQUERY */ public void setHostLanguage(int hostLanguage) { this.hostLanguage = hostLanguage; } // /** // * Set the Platform to be used for platform-dependent methods // * @param platform the platform to be used // */ // // public void setPlatform(Platform platform) { // this.platform = platform; // } /** * Get the Platform to be used for platform-dependent methods * * @return the platform to be used */ public static Platform getPlatform() { return platform; } /** * Set the DynamicLoader to be used. By default an instance of {@link DynamicLoader} is used * for all dynamic loading of Java classes. This method allows the actions of the standard * DynamicLoader to be overridden * * @param dynamicLoader the DynamicLoader to be used by this Configuration */ public void setDynamicLoader(DynamicLoader dynamicLoader) { this.dynamicLoader = dynamicLoader; } /** * Get the DynamicLoader used by this Configuration. By default the standard system-supplied * dynamic loader is returned. * * @return the DynamicLoader in use - either a user-supplied DynamicLoader, or the standard one * supplied by the system. */ public DynamicLoader getDynamicLoader() { return dynamicLoader; } /** * Load a class using the class name provided. * Note that the method does not check that the object is of the right class. *

    * This method is intended for internal use only. The call is delegated to the * DynamicLoader, which may be overridden by a user-defined DynamicLoader. * * @param className A string containing the name of the * class, for example "com.microstar.sax.LarkDriver" * @param tracing true if diagnostic tracing is required * @param classLoader The ClassLoader to be used to load the class, or null to * use the ClassLoader selected by the DynamicLoader. * @return an instance of the class named, or null if it is not * loadable. * @throws XPathException if the class cannot be loaded. */ public Class getClass(String className, boolean tracing, ClassLoader classLoader) throws XPathException { return dynamicLoader.getClass(className, tracing, classLoader); } /** * Instantiate a class using the class name provided. * Note that the method does not check that the object is of the right class. *

    * This method is intended for internal use only. The call is delegated to the * DynamicLoader, which may be overridden by a user-defined DynamicLoader. *

    * Diagnostic output is produced if the option "isTiming" is set (corresponding to the -t option on * the command line). * * @param className A string containing the name of the * class, for example "com.microstar.sax.LarkDriver" * @param classLoader The ClassLoader to be used to load the class, or null to * use the ClassLoader selected by the DynamicLoader. * @return an instance of the class named, or null if it is not * loadable. * @throws XPathException if the class cannot be loaded. */ public Object getInstance(String className, ClassLoader classLoader) throws XPathException { return dynamicLoader.getInstance(className, isTiming(), classLoader); } /** * Get the URIResolver used in this configuration * * @return the URIResolver. If no URIResolver has been set explicitly, the * default URIResolver is used. * @since 8.4 */ public URIResolver getURIResolver() { if (uriResolver == null) { return systemURIResolver; } return uriResolver; } /** * Set the URIResolver to be used in this configuration. This will be used to * resolve the URIs used statically (e.g. by xsl:include) and also the URIs used * dynamically by functions such as document() and doc(). Note that the URIResolver * does not resolve the URI in the sense of RFC 2396 (which is also the sense in which * the resolve-uri() function uses the term): rather it dereferences an absolute URI * to obtain an actual resource, which is returned as a Source object. * * @param resolver The URIResolver to be used. * @since 8.4 */ public void setURIResolver(URIResolver resolver) { uriResolver = resolver; if (resolver instanceof StandardURIResolver) { ((StandardURIResolver)resolver).setConfiguration(this); } } /** * Set the URIResolver to a URI resolver that allows query parameters after the URI, * and in the case of Saxon-SA, that inteprets the file extension .ptree */ public void setParameterizedURIResolver() { getSystemURIResolver().setRecognizeQueryParameters(true); } /** * Get the system-defined URI Resolver. This is used when the user-defined URI resolver * returns null as the result of the resolve() method * * @return the system-defined URI resolver */ public StandardURIResolver getSystemURIResolver() { return systemURIResolver; } /** * Create an instance of a URIResolver with a specified class name. * Note that this method does not register the URIResolver with this Configuration. * * @param className The fully-qualified name of the URIResolver class * @return The newly created URIResolver * @throws TransformerException if the requested class does not * implement the javax.xml.transform.URIResolver interface */ public URIResolver makeURIResolver(String className) throws TransformerException { Object obj = dynamicLoader.getInstance(className, null); if (obj instanceof StandardURIResolver) { ((StandardURIResolver)obj).setConfiguration(this); } if (obj instanceof URIResolver) { return (URIResolver)obj; } throw new XPathException("Class " + className + " is not a URIResolver"); } /** * Get the ErrorListener used in this configuration. If no ErrorListener * has been supplied explicitly, the default ErrorListener is used. * * @return the ErrorListener. * @since 8.4 */ public ErrorListener getErrorListener() { if (listener == null) { listener = new StandardErrorListener(); ((StandardErrorListener)listener).setRecoveryPolicy(recoveryPolicy); } return listener; } /** * Set the ErrorListener to be used in this configuration. The ErrorListener * is informed of all static and dynamic errors detected, and can decide whether * run-time warnings are to be treated as fatal. * * @param listener the ErrorListener to be used * @since 8.4 */ public void setErrorListener(ErrorListener listener) { this.listener = listener; } /** * Report a fatal error * * @param err the exception to be reported */ public void reportFatalError(XPathException err) { if (!err.hasBeenReported()) { try { getErrorListener().fatalError(err); } catch (TransformerException e) { // } err.setHasBeenReported(); } } /** * Set whether multithreading optimizations are allowed * * @param multithreading true if multithreading optimizations area allowed */ public void setMultiThreading(boolean multithreading) { allowMultiThreading = multithreading; } /** * Determine whether multithreading optimizations are allowed * * @return true if multithreading optimizations are allowed */ public boolean isMultiThreading() { return allowMultiThreading; } /** * Set the XML version to be used by default for validating characters and names. * Note that source documents specifying xml version="1.0" or "1.1" are accepted * regardless of this setting. The effect of this switch is to change the validation * rules for types such as Name and NCName, to change the meaning of \i and \c in * regular expressions, and to determine whether the serializer allows XML 1.1 documents * to be constructed. * * @param version one of the constants XML10 or XML11 * @since 8.6 */ public void setXMLVersion(int version) { xmlVersion = version; } /** * Get the XML version to be used by default for validating characters and names * * @return one of the constants {@link #XML10} or {@link #XML11} * @since 8.6 */ public int getXMLVersion() { return xmlVersion; } /** * Get a class that can be used to check names against the selected XML version * * @return a class that can be used for name checking * @since 8.6 */ public NameChecker getNameChecker() { //noinspection RedundantCast return (xmlVersion == XML10 ? (NameChecker)Name10Checker.getInstance() : (NameChecker)Name11Checker.getInstance()); } /** * Get an XPathContext object with sufficient capability to perform comparisons and conversions * * @return a dynamic context for performing conversions */ public XPathContext getConversionContext() { if (conversionContext == null) { conversionContext = new IndependentContext(this).makeEarlyEvaluationContext(); } return conversionContext; } /** * Get the Tree Model used by this Configuration. This is either * {@link Builder#LINKED_TREE} or {@link Builder#TINY_TREE}. The default (confusingly) * is Builder.TINY_TREE. * * @return the selected Tree Model * @since 8.4 */ public int getTreeModel() { return treeModel; } /** * Set the Tree Model used by this Configuration. This is either * {@link Builder#LINKED_TREE} or {@link Builder#TINY_TREE}. The default (confusingly) * is Builder.TINY_TREE. * * @param treeModel the selected Tree Model * @since 8.4 */ public void setTreeModel(int treeModel) { this.treeModel = treeModel; } /** * Determine whether source documents will maintain line numbers, for the * benefit of the saxon:line-number() extension function as well as run-time * tracing. * * @return true if line numbers are maintained in source documents * @since 8.4 */ public boolean isLineNumbering() { return lineNumbering; } /** * Determine whether source documents will maintain line numbers, for the * benefit of the saxon:line-number() extension function as well as run-time * tracing. * * @param lineNumbering true if line numbers are maintained in source documents * @since 8.4 */ public void setLineNumbering(boolean lineNumbering) { this.lineNumbering = lineNumbering; } /** * Set whether or not source documents (including stylesheets and schemas) are have * XInclude processing applied to them, or not. Default is false. * * @param state true if XInclude elements are to be expanded, false if not * @since 8.9 */ public void setXIncludeAware(boolean state) { xIncludeAware = state; } /** * Test whether or not source documents (including stylesheets and schemas) are to have * XInclude processing applied to them, or not * * @return true if XInclude elements are to be expanded, false if not * @since 8.9 */ public boolean isXIncludeAware() { return xIncludeAware; } /** * Get the TraceListener used for run-time tracing of instruction execution. * * @return the TraceListener that was set using {@link #getTraceListener()} if set. * Otherwise, returns null. * @since 8.4. Modified in 9.1. */ public TraceListener getTraceListener() { return traceListener; } /** * Get or create the TraceListener used for run-time tracing of instruction execution. * * @return If a TraceListener has been set using {@link #setTraceListener(net.sf.saxon.trace.TraceListener)}, * returns that TraceListener. Otherwise, if a TraceListener class has been set using * {@link #setTraceListenerClass(String)}, returns a newly created instance of that class. * Otherwise, returns null. * @throws XPathException if the supplied TraceListenerClass cannot be instantiated as an instance * of TraceListener * @since 9.1. */ public TraceListener makeTraceListener() throws XPathException { if (traceListener != null) { return traceListener; } else if (traceListenerClass != null) { try { return makeTraceListener(traceListenerClass); } catch (ClassCastException e) { throw new XPathException(e); } } else { return null; } } /** * Set the TraceListener to be used for run-time tracing of instruction execution. *

    *

    Note: this method should not be used if the Configuration is multithreading. In that situation, * use {@link #setCompileWithTracing(boolean)} to force stylesheets and queries to be compiled * with trace code enabled, and use {@link Controller#addTraceListener(net.sf.saxon.trace.TraceListener)} to * supply a TraceListener at run time.

    * * @param traceListener The TraceListener to be used. * @since 8.4 */ public void setTraceListener(TraceListener traceListener) { this.traceListener = traceListener; setCompileWithTracing(true); setMultiThreading(false); } /** * Set the name of the trace listener class to be used for run-time tracing of instruction * execution. A new instance of this class will be created for each query or transformation * that requires tracing. The class must be an instance of {@link TraceListener}. * @param className the name of the trace listener class * @throws IllegalArgumentException if the class cannot be instantiated or does not implement * TraceListener * @since 9.1 */ public void setTraceListenerClass(String className) { try { makeTraceListener(className); } catch (XPathException err) { throw new IllegalArgumentException(className + ": " + err.getMessage()); } this.traceListenerClass = className; setCompileWithTracing(true); } /** * Get the name of the trace listener class to be used for run-time tracing of instruction * execution. A new instance of this class will be created for each query or transformation * that requires tracing. The class must be an instance of {@link TraceListener}. * @return the name of the trace listener class, or null if no trace listener class * has been nominated. * @since 9.1 */ public String getTraceListenerClass() { return traceListenerClass; } /** * Determine whether compile-time generation of trace code was requested * * @return true if compile-time generation of code was requested * @since 8.8 */ public boolean isCompileWithTracing() { return tracing; } /** * Request compile-time generation of trace code (or not) * * @param trace true if compile-time generation of trace code is required * @since 8.8 */ public void setCompileWithTracing(boolean trace) { tracing = trace; } /** * Set optimizer tracing on or off * * @param trace set to true to switch optimizer tracing on, false to switch it off */ public void setOptimizerTracing(boolean trace) { traceOptimizations = trace; } /** * Test whether optimizer tracing is on or off * * @return true if optimizer tracing is switched on */ public boolean isOptimizerTracing() { return traceOptimizations; } /** * Create an instance of a TraceListener with a specified class name * * @param className The fully qualified class name of the TraceListener to * be constructed * @return the newly constructed TraceListener * @throws net.sf.saxon.trans.XPathException * if the requested class does not * implement the net.sf.saxon.trace.TraceListener interface */ public TraceListener makeTraceListener(String className) throws XPathException { Object obj = dynamicLoader.getInstance(className, null); if (obj instanceof TraceListener) { return (TraceListener)obj; } throw new XPathException("Class " + className + " is not a TraceListener"); } /** * Set the FunctionLibrary used to bind calls on extension functions. This allows the * rules for identifying extension functions to be customized (in principle, it would * allow support for extension functions in other languages to be provided). *

    * When an application supplies its own FunctionLibrary for binding extension functions, * this replaces the default binding mechanism for Java extension functions, namely * {@link net.sf.saxon.functions.JavaExtensionLibrary}. It thus disables the function libraries * for built-in Saxon extensions and for EXSLT extensions. It is possible to create a * function library that adds to the existing mechanisms, rather than replacing them, * by supplying as the FunctionLibrary a {@link net.sf.saxon.functions.FunctionLibraryList} * that itself contains two FunctionLibrary objects: a JavaExtensionLibrary, and a user-written * FunctionLibrary. * * @param scheme The URI scheme served by the extension binder. Currently this must be one * of "java" or "clitype". On the Java platform, the only scheme currently supported is "java"; * on the .NET platform, the "java" and "clitype" schemes coexist. * @param binder The FunctionLibrary object used to locate implementations of extension * functions, based on their name and arity * @see #setExtensionFunctionFactory */ public void setExtensionBinder(String scheme, FunctionLibrary binder) { if (scheme.equals("java")) { javaExtensionBinder = binder; } else if (scheme.equals("clitype")) { dotNetExtensionBinder = binder; } else { throw new IllegalArgumentException("Unknown scheme " + scheme + " - must be java or clitype"); } } /** * Get the FunctionLibrary used to bind calls on extension functions on the specified * platform. *

    * This mechanism is for advanced users only, and the details are subject to change. * * @param scheme The URI scheme served by the extension binder. Currently this must be one * of "java" or "clitype". On the Java platform, the only scheme currently supported is "java"; * on the .NET platform, the "java" and "clitype" schemes coexist. * @return the registered FunctionLibrary for extension functions if one has been * registered; or the default FunctionLibrary for extension functions otherwise */ public FunctionLibrary getExtensionBinder(String scheme) { if (scheme.equals("java")) { return javaExtensionBinder; } else if (scheme.equals("clitype")) { return dotNetExtensionBinder; } else { throw new IllegalArgumentException("Unknown scheme " + scheme + " - must be java or clitype"); } } /** * Get the FunctionLibrary used to bind calls on Saxon-defined extension functions. *

    * This method is intended for internal use only. * * @return the FunctionLibrary used for extension functions in the Saxon library. */ public VendorFunctionLibrary getVendorFunctionLibrary() { if (vendorFunctionLibrary == null) { vendorFunctionLibrary = new VendorFunctionLibrary(); } return vendorFunctionLibrary; } /** * Set a CollationURIResolver to be used to resolve collation URIs (that is, * to take a URI identifying a collation, and return the corresponding collation). * Note that Saxon attempts first to resolve a collation URI using the resolver * registered with the Controller; if that returns null, it tries again using the * resolver registered with the Configuration. *

    * Note that it is undefined whether collation URIs are resolved at compile time * or at run-time. It is therefore inadvisable to change the CollationURIResolver after * compiling a query or stylesheet and before running it. * * @param resolver the collation URI resolver to be used. This replaces any collation * URI resolver previously registered. * @since 8.5 */ public void setCollationURIResolver(CollationURIResolver resolver) { collationResolver = resolver; } /** * Get the collation URI resolver associated with this configuration. This will * return the CollationURIResolver previously set using the {@link #setCollationURIResolver} * method; if this has not been called, it returns the system-defined collation URI resolver * * @return the registered CollationURIResolver * @since 8.5 */ public CollationURIResolver getCollationURIResolver() { return collationResolver; } /** * Set a CollectionURIResolver to be used to resolve collection URIs (that is, * the URI supplied in a call to the collection() function). *

    * Collection URIs are always resolved at run-time, using the CollectionURIResolver * in force at the time the collection() function is called. * * @param resolver the collection URI resolver to be used. This replaces any collection * URI resolver previously registered. * @since 8.5 */ public void setCollectionURIResolver(CollectionURIResolver resolver) { collectionResolver = resolver; } /** * Get the collection URI resolver associated with this configuration. This will * return the CollectionURIResolver previously set using the {@link #setCollectionURIResolver} * method; if this has not been called, it returns the system-defined collection URI resolver * * @return the registered CollationURIResolver * @since 8.5 */ public CollectionURIResolver getCollectionURIResolver() { return collectionResolver; } /** * Set a user-defined ModuleURIResolver for resolving URIs used in "import module" * declarations in an XQuery prolog. * This acts as the default value for the ModuleURIResolver in the StaticQueryContext, and may be * overridden by a more specific ModuleURIResolver nominated as part of the StaticQueryContext. * * @param resolver the URI resolver for XQuery modules */ public void setModuleURIResolver(ModuleURIResolver resolver) { moduleURIResolver = resolver; } /** * Create and register an instance of a ModuleURIResolver with a specified class name. * This will be used for resolving URIs in XQuery "import module" declarations, unless * a more specific ModuleURIResolver has been nominated as part of the StaticQueryContext. * * @param className The fully-qualified name of the LocationHintResolver class * @throws TransformerException if the requested class does not * implement the net.sf.saxon.LocationHintResolver interface */ public void setModuleURIResolver(String className) throws TransformerException { Object obj = dynamicLoader.getInstance(className, null); if (obj instanceof ModuleURIResolver) { setModuleURIResolver((ModuleURIResolver)obj); } else { throw new XPathException("Class " + className + " is not a LocationHintResolver"); } } /** * Get the user-defined ModuleURIResolver for resolving URIs used in "import module" * declarations in the XQuery prolog; returns null if none has been explicitly set. * * @return the resolver for Module URIs */ public ModuleURIResolver getModuleURIResolver() { return moduleURIResolver; } /** * Get the standard system-defined ModuleURIResolver for resolving URIs used in "import module" * declarations in the XQuery prolog. * * @return the standard system-defined ModuleURIResolver for resolving URIs */ public ModuleURIResolver getStandardModuleURIResolver() { return standardModuleURIResolver; } /** * Set a user-defined SchemaURIResolver for resolving URIs used in "import schema" * declarations. * * @param resolver the URI resolver used for import schema declarations */ public void setSchemaURIResolver(SchemaURIResolver resolver) { schemaURIResolver = resolver; } /** * Get the user-defined SchemaURIResolver for resolving URIs used in "import schema" * declarations; if none has been explicitly set, returns null. * * @return the user-defined SchemaURIResolver for resolving URIs */ public SchemaURIResolver getSchemaURIResolver() { return schemaURIResolver; } /** * Determine how recoverable run-time errors are to be handled. This applies * only if the standard ErrorListener is used. * * @return the current recovery policy. The options are {@link #RECOVER_SILENTLY}, * {@link #RECOVER_WITH_WARNINGS}, or {@link #DO_NOT_RECOVER}. * @since 8.4 */ public int getRecoveryPolicy() { return recoveryPolicy; } /** * Determine how recoverable run-time errors are to be handled. This applies * only if the standard ErrorListener is used. The recovery policy applies to * errors classified in the XSLT 2.0 specification as recoverable dynamic errors, * but only in those cases where Saxon provides a choice over how the error is handled: * in some cases, Saxon makes the decision itself. * * @param recoveryPolicy the recovery policy to be used. The options are {@link #RECOVER_SILENTLY}, * {@link #RECOVER_WITH_WARNINGS}, or {@link #DO_NOT_RECOVER}. * @since 8.4 */ public void setRecoveryPolicy(int recoveryPolicy) { this.recoveryPolicy = recoveryPolicy; } /** * Get the name of the class that will be instantiated to create a MessageEmitter, * to process the output of xsl:message instructions in XSLT. * * @return the full class name of the message emitter class. * @since 8.4 */ public String getMessageEmitterClass() { return messageEmitterClass; } /** * Set the name of the class that will be instantiated to create a MessageEmitter, * to process the output of xsl:message instructions in XSLT. * * @param messageEmitterClass the full class name of the message emitter class. This * must implement net.sf.saxon.event.Emitter. * @since 8.4 */ public void setMessageEmitterClass(String messageEmitterClass) { this.messageEmitterClass = messageEmitterClass; } /** * Get the name of the class that will be instantiated to create an XML parser * for parsing source documents (for example, documents loaded using the document() * or doc() functions). *

    * This method is retained in Saxon for backwards compatibility, but the preferred way * of choosing an XML parser is to use JAXP interfaces, for example by supplying a * JAXP Source object initialized with an appropriate implementation of org.xml.sax.XMLReader. * * @return the fully qualified name of the XML parser class */ public String getSourceParserClass() { return sourceParserClass; } /** * Set the name of the class that will be instantiated to create an XML parser * for parsing source documents (for example, documents loaded using the document() * or doc() functions). *

    * This method is retained in Saxon for backwards compatibility, but the preferred way * of choosing an XML parser is to use JAXP interfaces, for example by supplying a * JAXP Source object initialized with an appropriate implementation of org.xml.sax.XMLReader. * * @param sourceParserClass the fully qualified name of the XML parser class. This must implement * the SAX2 XMLReader interface. */ public void setSourceParserClass(String sourceParserClass) { this.sourceParserClass = sourceParserClass; } /** * Get the name of the class that will be instantiated to create an XML parser * for parsing stylesheet modules. *

    * This method is retained in Saxon for backwards compatibility, but the preferred way * of choosing an XML parser is to use JAXP interfaces, for example by supplying a * JAXP Source object initialized with an appropriate implementation of org.xml.sax.XMLReader. * * @return the fully qualified name of the XML parser class */ public String getStyleParserClass() { return styleParserClass; } /** * Set the name of the class that will be instantiated to create an XML parser * for parsing stylesheet modules. *

    * This method is retained in Saxon for backwards compatibility, but the preferred way * of choosing an XML parser is to use JAXP interfaces, for example by supplying a * JAXP Source object initialized with an appropriate implementation of org.xml.sax.XMLReader. * * @param styleParserClass the fully qualified name of the XML parser class */ public void setStyleParserClass(String styleParserClass) { this.styleParserClass = styleParserClass; } /** * Get the OutputURIResolver that will be used to resolve URIs used in the * href attribute of the xsl:result-document instruction. * * @return the OutputURIResolver. If none has been supplied explicitly, the * default OutputURIResolver is returned. * @since 8.4 */ public OutputURIResolver getOutputURIResolver() { if (outputURIResolver == null) { outputURIResolver = StandardOutputResolver.getInstance(); } return outputURIResolver; } /** * Set the OutputURIResolver that will be used to resolve URIs used in the * href attribute of the xsl:result-document instruction. * * @param outputURIResolver the OutputURIResolver to be used. * @since 8.4 */ public void setOutputURIResolver(OutputURIResolver outputURIResolver) { this.outputURIResolver = outputURIResolver; } /** * Set a custom SerializerFactory. This will be used to create a serializer for a given * set of output properties and result destination. * * @param factory a custom SerializerFactory * @since 8.8 */ public void setSerializerFactory(SerializerFactory factory) { serializerFactory = factory; } /** * Get the SerializerFactory. This returns the standard built-in SerializerFactory, unless * a custom SerializerFactory has been registered. * * @return the SerializerFactory in use * @since 8.8 */ public SerializerFactory getSerializerFactory() { return serializerFactory; } /** * Determine whether brief progress messages and timing information will be output * to System.err. *

    * This method is provided largely for internal use. Progress messages are normally * controlled directly from the command line interfaces, and are not normally used when * driving Saxon from the Java API. * * @return true if these messages are to be output. */ public boolean isTiming() { return timing; } /** * Determine whether brief progress messages and timing information will be output * to System.err. *

    * This method is provided largely for internal use. Progress messages are normally * controlled directly from the command line interfaces, and are not normally used when * * @param timing true if these messages are to be output. */ public void setTiming(boolean timing) { this.timing = timing; } /** * Determine whether a warning is to be output when running against a stylesheet labelled * as version="1.0". The XSLT specification requires such a warning unless the user disables it. * * @return true if these messages are to be output. * @since 8.4 */ public boolean isVersionWarning() { return versionWarning; } /** * Determine whether a warning is to be output when running against a stylesheet labelled * as version="1.0". The XSLT specification requires such a warning unless the user disables it. * * @param warn true if these messages are to be output. * @since 8.4 */ public void setVersionWarning(boolean warn) { versionWarning = warn; } /** * Determine whether calls to external Java functions are permitted. * * @return true if such calls are permitted. * @since 8.4 */ public boolean isAllowExternalFunctions() { return allowExternalFunctions; } /** * Determine whether calls to external Java functions are permitted. Allowing * external function calls is potentially a security risk if the stylesheet or * Query is untrusted, as it allows arbitrary Java methods to be invoked, which can * examine or modify the contents of filestore and other resources on the machine * where the query/stylesheet is executed. *

    *

    Setting the value to false disallows all of the following:

    *

    *

      *
    • Calls to Java extension functions
    • *
    • Use of the XSLT system-property() function to access Java system properties
    • *
    • Use of a relative URI in the xsl:result-document instruction
    • *
    • Calls to XSLT extension instructions
    • *
    *

    *

    Note that this option does not disable use of the doc() function or similar * functions to access the filestore of the machine where the transformation or query is running. * That should be done using a user-supplied URIResolver

    * * @param allowExternalFunctions true if external function calls are to be * permitted. * @since 8.4 */ public void setAllowExternalFunctions(boolean allowExternalFunctions) { this.allowExternalFunctions = allowExternalFunctions; } /** * Determine whether calls on external functions are to be traced for diagnostic * purposes. * * @return true if tracing is enabled for calls to external Java functions */ public boolean isTraceExternalFunctions() { return traceExternalFunctions; } /** * Determine whether attribute types obtained from a DTD are to be used to set type annotations * on the resulting nodes. * * @param useTypes set to true if DTD types are to be taken into account * @since 8.4 */ public void setRetainDTDAttributeTypes(boolean useTypes) throws TransformerFactoryConfigurationError { if (useTypes && !isSchemaAware(Configuration.XML_SCHEMA)) { throw new TransformerFactoryConfigurationError( "Retaining DTD attribute types requires the schema-aware product"); } retainDTDattributeTypes = useTypes; } /** * Determine whether attribute types obtained from a DTD are to be used to set type annotations * on the resulting nodes * * @return true if DTD types are to be taken into account * @since 8.4 */ public boolean isRetainDTDAttributeTypes() { return retainDTDattributeTypes; } /** * Determine whether calls on external functions are to be traced for diagnostic * purposes. * * @param traceExternalFunctions true if tracing is to be enabled * for calls to external Java functions */ public void setTraceExternalFunctions(boolean traceExternalFunctions) { this.traceExternalFunctions = traceExternalFunctions; } /** * Get an ExtensionFunctionFactory. This is used at compile time for generating * the code that calls Java or .NET extension functions. It is possible to supply a user-defined * ExtensionFunctionFactory to customize the way extension functions are bound. *

    * This mechanism is intended for advanced use only, and is subject to change. * * @param scheme - the extension function scheme. This must be one of "java" or "clitype", * corresponding to the scheme name in the namespace URI of the extension function call * @return the factory object registered to generate calls on extension functions, * if one has been registered; if not, the default factory used by Saxon. The result * will always be a {@link net.sf.saxon.functions.JavaExtensionFunctionFactory} in the case of the Java platform, * or a net.sf.saxon.dotnet.DotNetExtensionFunctionFactory on the .NET platform */ public ExtensionFunctionFactory getExtensionFunctionFactory(String scheme) { if ("java".equals(scheme)) { return javaExtensionFunctionFactory; } else if ("clitype".equals(scheme)) { return dotNetExtensionFunctionFactory; } else { throw new IllegalArgumentException("Unknown extension function scheme"); } } /** * Set an ExtensionFunctionFactory. This is used at compile time for generating * the code that calls Java extension functions. It is possible to supply a user-defined * ExtensionFunctionFactory to customize the way extension functions are called. The * ExtensionFunctionFactory determines how external methods are called, but is not * involved in binding the external method corresponding to a given function name or URI. *

    * This mechanism is intended for advanced use only, and is subject to change. * * @param scheme - the extension function scheme. This must be one of "java" or "clitype", * corresponding to the scheme name in the namespace URI of the extension function call * @param factory The extension function factory. This must * always be a {@link net.sf.saxon.functions.JavaExtensionFunctionFactory} for the "java" scheme, * or a net.sf.saxon.dotnet.DotNetExtensionFunctionFactory for the "clitype" scheme * @see #setExtensionBinder */ public void setExtensionFunctionFactory(String scheme, ExtensionFunctionFactory factory) { if ("java".equals(scheme)) { javaExtensionFunctionFactory = factory; } else if ("clitype".equals(scheme)) { dotNetExtensionFunctionFactory = factory; } else { throw new IllegalArgumentException("Unknown extension function scheme"); } } /** * Determine whether the XML parser for source documents will be asked to perform * \ validation of source documents * * @return true if DTD validation is requested. * @since 8.4 */ public boolean isValidation() { return validation; } /** * Determine whether the XML parser for source documents will be asked to perform * DTD validation of source documents * * @param validation true if DTD validation is to be requested. * @since 8.4 */ public void setValidation(boolean validation) { this.validation = validation; } /** * Specify that all nodes encountered within this query or transformation will be untyped * * @param allUntyped true if all nodes will be untyped */ public void setAllNodesUntyped(boolean allUntyped) { allNodesUntyped = allUntyped; } /** * Determine whether all nodes encountered within this query or transformation are guaranteed to be * untyped * * @return true if it is known that all nodes will be untyped */ public boolean areAllNodesUntyped() { return allNodesUntyped; } /** * Create a document projector for a given path map. Document projection is available only * in Saxon-SA, so the Saxon-B version of this method throws an exception * * @param map the path map used to control document projection * @return a push filter that implements document projection * @throws UnsupportedOperationException if this is not a schema-aware configuration, or * if no Saxon-SA license is available */ public ProxyReceiver makeDocumentProjector(PathMap.PathMapRoot map) { throw new UnsupportedOperationException("Document projection requires a schema-aware Configuration"); } /** * Determine whether source documents (supplied as a StreamSource or SAXSource) * should be subjected to schema validation * * @return the schema validation mode previously set using setSchemaValidationMode(), * or the default mode {@link Validation#STRIP} otherwise. */ public int getSchemaValidationMode() { return schemaValidationMode; } /** * Indicate whether source documents (supplied as a StreamSource or SAXSource) * should be subjected to schema validation * * @param validationMode the validation (or construction) mode to be used for source documents. * One of {@link Validation#STRIP}, {@link Validation#PRESERVE}, {@link Validation#STRICT}, * {@link Validation#LAX} * @since 8.4 */ public void setSchemaValidationMode(int validationMode) { switch (validationMode) { case Validation.STRIP: case Validation.PRESERVE: break; case Validation.LAX: case Validation.STRICT: if (!isSchemaAware(XML_SCHEMA)) { needSchemaAwareVersion(); } break; default: throw new IllegalArgumentException("Unsupported validation mode " + validationMode); } schemaValidationMode = validationMode; } /** * Indicate whether schema validation failures on result documents are to be treated * as fatal errors or as warnings. * * @param warn true if schema validation failures are to be treated as warnings; false if they * are to be treated as fatal errors. * @since 8.4 */ public void setValidationWarnings(boolean warn) { validationWarnings = warn; } /** * Determine whether schema validation failures on result documents are to be treated * as fatal errors or as warnings. * * @return true if validation errors are to be treated as warnings (that is, the * validation failure is reported but processing continues as normal); false * if validation errors are fatal. * @since 8.4 */ public boolean isValidationWarnings() { return validationWarnings; } /** * Indicate whether attributes that have a fixed or default value are to be expanded when * generating a final result tree. By default (and for conformance with the W3C specifications) * it is required that fixed and default values should be expanded. However, there are use cases * for example when generating XHTML when this serves no useful purpose and merely bloats the output. *

    *

    This option can be overridden at the level of a PipelineConfiguration

    * * @param expand true if fixed and default values are to be expanded as required by the W3C * specifications; false if this action is to be disabled. Note that this only affects the validation * of final result trees; it is not possible to suppress expansion of fixed or default values on input * documents, as this would make the type annotations on input nodes unsound. * @since 9.0 */ public void setExpandAttributeDefaults(boolean expand) { expandDefaultAttributes = expand; } /** * Determine whether elements and attributes that have a fixed or default value are to be expanded. * This option applies both to DTD-defined attribute defaults and to schema-defined defaults for * elements and attributes. If an XML parser is used that does not report whether defaults have * been used, this option is ignored. *

    * *

    This option can be overridden at the level of a PipelineConfiguration

    * * @return true if elements and attributes that have a fixed or default value are to be expanded, * false if defaults are not to be expanded. The default value is true. Note that the setting "false" * is potentially non-conformant with the W3C specifications. * @since 9.0 */ public boolean isExpandAttributeDefaults() { return expandDefaultAttributes; } /** * Get the target namepool to be used for stylesheets/queries and for source documents. * * @return the target name pool. If no NamePool has been specified explicitly, the * default NamePool is returned. * @since 8.4 */ public NamePool getNamePool() { return namePool; } /** * Set the NamePool to be used for stylesheets/queries and for source documents. *

    *

    Using this method allows several Configurations to share the same NamePool. This * was the normal default arrangement until Saxon 8.9, which changed the default so * that each Configuration uses its own NamePool.

    *

    *

    Sharing a NamePool creates a potential bottleneck, since changes to the namepool are * synchronized.

    * * @param targetNamePool The NamePool to be used. * @since 8.4 */ public void setNamePool(NamePool targetNamePool) { namePool = targetNamePool; } /** * Get the TypeHierarchy: a cache holding type information * * @return the type hierarchy cache */ public final TypeHierarchy getTypeHierarchy() { if (typeHierarchy == null) { typeHierarchy = new TypeHierarchy(this); } return typeHierarchy; } /** * Get the document number allocator. *

    * The document number allocator is used to allocate a unique number to each document built under this * configuration. The document number forms the basis of all tests for node identity; it is therefore essential * that when two documents are accessed in the same XPath expression, they have distinct document numbers. * Normally this is ensured by building them under the same Configuration. Using this method together with * {@link #setDocumentNumberAllocator}, however, it is possible to have two different Configurations that share * a single DocumentNumberAllocator * * @return the current DocumentNumberAllocator * @since 9.0 */ public DocumentNumberAllocator getDocumentNumberAllocator() { return documentNumberAllocator; } /** * Set the document number allocator. *

    * The document number allocator is used to allocate a unique number to each document built under this * configuration. The document number forms the basis of all tests for node identity; it is therefore essential * that when two documents are accessed in the same XPath expression, they have distinct document numbers. * Normally this is ensured by building them under the same Configuration. Using this method together with * {@link #getDocumentNumberAllocator}, however, it is possible to have two different Configurations that share * a single DocumentNumberAllocator

    *

    This method is for advanced applications only. Misuse of the method can cause problems with node identity. * The method should not be used except while initializing a Configuration, and it should be used only to * arrange for two different configurations to share the same DocumentNumberAllocators. In this case they * should also share the same NamePool. * * @param allocator the DocumentNumberAllocator to be used * @since 9.0 */ public void setDocumentNumberAllocator(DocumentNumberAllocator allocator) { documentNumberAllocator = allocator; } /** * Determine whether two Configurations are compatible. When queries, transformations, and path expressions * are run, all the Configurations used to build the documents and to compile the queries and stylesheets * must be compatible. Two Configurations are compatible if they share the same NamePool and the same * DocumentNumberAllocator. * * @param other the other Configuration to be compared with this one * @return true if the two configurations are compatible */ public boolean isCompatible(Configuration other) { return namePool == other.namePool && documentNumberAllocator == other.documentNumberAllocator; } /** * Get the global document pool. This is used for documents preloaded during query or stylesheet * compilation. The user application can preload documents into the global pool, where they will be found * if any query or stylesheet requests the specified document using the doc() or document() function. * * @return the global document pool */ public DocumentPool getGlobalDocumentPool() { return globalDocumentPool; } /** * Determine whether whitespace-only text nodes are to be stripped unconditionally * from source documents. * * @return true if all whitespace-only text nodes are stripped. * @since 8.4 */ public boolean isStripsAllWhiteSpace() { return stripsWhiteSpace == Whitespace.ALL; } /** * Determine whether whitespace-only text nodes are to be stripped unconditionally * from source documents. * * @param stripsAllWhiteSpace if all whitespace-only text nodes are to be stripped. * @since 8.4 */ public void setStripsAllWhiteSpace(boolean stripsAllWhiteSpace) { if (stripsAllWhiteSpace) { stripsWhiteSpace = Whitespace.ALL; } } /** * Set which kinds of whitespace-only text node should be stripped. * * @param kind the kind of whitespace-only text node that should be stripped when building * a source tree. One of {@link Whitespace#NONE} (none), {@link Whitespace#ALL} (all), * or {@link Whitespace#IGNORABLE} (element-content whitespace as defined in a DTD or schema) */ public void setStripsWhiteSpace(int kind) { stripsWhiteSpace = kind; } /** * Set which kinds of whitespace-only text node should be stripped. * * @return kind the kind of whitespace-only text node that should be stripped when building * a source tree. One of {@link Whitespace#NONE} (none), {@link Whitespace#ALL} (all), * or {@link Whitespace#IGNORABLE} (element-content whitespace as defined in a DTD or schema) */ public int getStripsWhiteSpace() { return stripsWhiteSpace; } /** * Get a parser for source documents. The parser is allocated from a pool if any are available * from the pool: the client should ideally return the parser to the pool after use, so that it * can be reused. *

    * This method is intended primarily for internal use. * * @return a parser, in which the namespace properties must be set as follows: * namespaces=true; namespace-prefixes=false. The DTD validation feature of the parser will be set * on or off depending on the {@link #setValidation(boolean)} setting. */ public synchronized XMLReader getSourceParser() throws TransformerFactoryConfigurationError { if (sourceParserPool == null) { sourceParserPool = new ArrayList(10); } if (!sourceParserPool.isEmpty()) { int n = sourceParserPool.size() - 1; XMLReader parser = (XMLReader)sourceParserPool.get(n); sourceParserPool.remove(n); return parser; } XMLReader parser; if (getSourceParserClass() != null) { parser = makeParser(getSourceParserClass()); } else { parser = loadParser(); } try { Sender.configureParser(parser); } catch (XPathException err) { throw new TransformerFactoryConfigurationError(err); } if (isValidation()) { try { parser.setFeature("http://xml.org/sax/features/validation", true); } catch (SAXException err) { throw new TransformerFactoryConfigurationError("The XML parser does not support validation"); } } return parser; } /** * Return a source parser to the pool, for reuse * * @param parser The parser: the caller must not supply a parser that was obtained by any * mechanism other than calling the getSourceParser() method. */ public synchronized void reuseSourceParser(XMLReader parser) { if (sourceParserPool == null) { sourceParserPool = new ArrayList(10); } try { // give things back to the garbage collecter parser.setContentHandler(null); parser.setEntityResolver(null); parser.setDTDHandler(null); parser.setErrorHandler(null); // Unfortunately setting the lexical handler to null doesn't work on Xerces, because // it tests "value instanceof LexicalHandler". So we set it to a lexical handler that // holds no references parser.setProperty("http://xml.org/sax/properties/lexical-handler", dummyLexicalHandler); } catch (Exception err) { // } sourceParserPool.add(parser); } /** * Get a parser by instantiating the SAXParserFactory * * @return the parser (XMLReader) */ private XMLReader loadParser() { XMLReader parser; try { parser = SAXParserFactory.newInstance().newSAXParser().getXMLReader(); } catch (ParserConfigurationException err) { throw new TransformerFactoryConfigurationError(err); } catch (SAXException err) { throw new TransformerFactoryConfigurationError(err); } return parser; } /** * Get the parser for stylesheet documents. This parser is also used for schema documents. *

    * This method is intended for internal use only. * * @return an XML parser (a SAX2 parser) that can be used for stylesheets and schema documents */ public synchronized XMLReader getStyleParser() throws TransformerFactoryConfigurationError { if (styleParserPool == null) { styleParserPool = new ArrayList(10); } if (!styleParserPool.isEmpty()) { int n = styleParserPool.size() - 1; XMLReader parser = (XMLReader)styleParserPool.get(n); styleParserPool.remove(n); return parser; } XMLReader parser; if (getStyleParserClass() != null) { parser = makeParser(getStyleParserClass()); } else { parser = loadParser(); } try { parser.setFeature("http://xml.org/sax/features/namespaces", true); parser.setFeature("http://xml.org/sax/features/namespace-prefixes", false); } catch (SAXNotRecognizedException e) { throw new TransformerFactoryConfigurationError(e); } catch (SAXNotSupportedException e) { throw new TransformerFactoryConfigurationError(e); } return parser; } private static LexicalHandler dummyLexicalHandler = new DefaultHandler2(); /** * Return a stylesheet (or schema) parser to the pool, for reuse * * @param parser The parser: the caller must not supply a parser that was obtained by any * mechanism other than calling the getStyleParser() method. */ public synchronized void reuseStyleParser(XMLReader parser) { if (styleParserPool == null) { styleParserPool = new ArrayList(10); } try { // give things back to the garbage collecter parser.setContentHandler(null); parser.setEntityResolver(null); parser.setDTDHandler(null); parser.setErrorHandler(null); // Unfortunately setting the lexical handler to null doesn't work on Xerces, because // it tests "value instanceof LexicalHandler". Instead we set the lexical handler to one // that holds no references parser.setProperty("http://xml.org/sax/properties/lexical-handler", dummyLexicalHandler); } catch (Exception err) { // } styleParserPool.add(parser); } /** * Simple interface to load a schema document * * @param absoluteURI the absolute URI of the location of the schema document */ public void loadSchema(String absoluteURI) throws SchemaException { readSchema(makePipelineConfiguration(), "", absoluteURI, null); } /** * Read a schema from a given schema location *

    * This method is intended for internal use. * * @param pipe the PipelineConfiguration * @param baseURI the base URI of the instruction requesting the reading of the schema * @param schemaLocation the location of the schema to be read * @param expected The expected targetNamespace of the schema being read. * @return the target namespace of the schema; null if there is no expectation * @throws UnsupportedOperationException when called in the non-schema-aware version of the product */ public String readSchema(PipelineConfiguration pipe, String baseURI, String schemaLocation, String expected) throws SchemaException { needSchemaAwareVersion(); return null; } /** * Read schemas from a list of schema locations. *

    * This method is intended for internal use. * * @param pipe the pipeline configuration * @param baseURI the base URI against which the schema locations are to be resolved * @param schemaLocations the relative URIs specified as schema locations * @param expected the namespace URI which is expected as the target namespace of the loaded schema */ public void readMultipleSchemas(PipelineConfiguration pipe, String baseURI, Collection schemaLocations, String expected) throws SchemaException { needSchemaAwareVersion(); } /** * Read an inline schema from a stylesheet. *

    * This method is intended for internal use. * * @param root the xs:schema element in the stylesheet * @param expected the target namespace expected; null if there is no * expectation. * @param errorListener The destination for error messages. May be null, in which case * the errorListener registered with this Configuration is used. * @return the actual target namespace of the schema */ public String readInlineSchema(NodeInfo root, String expected, ErrorListener errorListener) throws SchemaException { needSchemaAwareVersion(); return null; } private void needSchemaAwareVersion() { throw new UnsupportedOperationException( "You need the schema-aware version of Saxon for this operation"); } /** * Load a schema, which will be available for use by all subsequent operations using * this Configuration. Any errors will be notified to the ErrorListener associated with * this Configuration. * * @param schemaSource the JAXP Source object identifying the schema document to be loaded * @throws SchemaException if the schema cannot be read or parsed or if it is invalid * @throws UnsupportedOperationException if the configuration is not schema-aware * @since 8.4 */ public void addSchemaSource(Source schemaSource) throws SchemaException { addSchemaSource(schemaSource, getErrorListener()); } /** * Load a schema, which will be available for use by all subsequent operations using * this SchemaAwareConfiguration. * * @param schemaSource the JAXP Source object identifying the schema document to be loaded * @param errorListener the ErrorListener to be notified of any errors in the schema. * @throws SchemaException if the schema cannot be read or parsed or if it is invalid */ public void addSchemaSource(Source schemaSource, ErrorListener errorListener) throws SchemaException { needSchemaAwareVersion(); } /** * Determine whether the Configuration contains a cached schema for a given target namespace * * @param targetNamespace the target namespace of the schema being sought (supply "" for the * unnamed namespace) * @return true if the schema for this namespace is available, false if not. */ public boolean isSchemaAvailable(String targetNamespace) { return false; } /** * Get the set of namespaces of imported schemas * * @return a Set whose members are the namespaces of all schemas in the schema cache, as * String objects */ public Set getImportedNamespaces() { return Collections.EMPTY_SET; } /** * Mark a schema namespace as being sealed. This is done when components from this namespace * are first used for validating a source document or compiling a source document or query. Once * a namespace has been sealed, it is not permitted to change the schema components in that namespace * by redefining them, deriving new types by extension, or adding to their substitution groups. * * @param namespace the namespace URI of the components to be sealed */ public void sealNamespace(String namespace) { // } /** * Get the set of complex types that have been defined as extensions of a given type. * Note that we do not seal the schema namespace, so this list is not necessarily final; we must * assume that new extensions of built-in simple types can be added at any time * @param type the type whose extensions are required */ public Iterator getExtensionsOfType(SchemaType type) { return Collections.EMPTY_SET.iterator(); } /** * Import a precompiled Schema Component Model from a given Source. The schema components derived from this schema * document are added to the cache of schema components maintained by this SchemaManager * * @param source the XML file containing the schema component model, as generated by a previous call on * {@link #exportComponents} */ public void importComponents(Source source) throws XPathException { needSchemaAwareVersion(); } /** * Export a precompiled Schema Component Model containing all the components (except built-in components) * that have been loaded into this Processor. * * @param out the destination to recieve the precompiled Schema Component Model in the form of an * XML document */ public void exportComponents(Receiver out) throws XPathException { needSchemaAwareVersion(); } /** * Get a global element declaration. *

    * This method is intended for internal use. * * @param fingerprint the NamePool fingerprint of the name of the required * element declaration * @return the element declaration whose name matches the given * fingerprint, or null if no element declaration with this name has * been registered. */ public SchemaDeclaration getElementDeclaration(int fingerprint) { return null; } /** * Get a global attribute declaration. *

    * This method is intended for internal use * * @param fingerprint the namepool fingerprint of the required attribute * declaration * @return the attribute declaration whose name matches the given * fingerprint, or null if no element declaration with this name has * been registered. */ public SchemaDeclaration getAttributeDeclaration(int fingerprint) { return null; } /** * Get the top-level schema type definition with a given fingerprint. *

    * This method is intended for internal use and for use by advanced * applications. (The SchemaType object returned cannot yet be considered * a stable API, and may be superseded when a JAXP API for schema information * is defined.) * * @param fingerprint the fingerprint of the schema type * @return the schema type , or null if there is none * with this name. */ public SchemaType getSchemaType(int fingerprint) { if (fingerprint < 1023) { return BuiltInType.getSchemaType(fingerprint); } if (getNamePool().getURI(fingerprint).equals(NamespaceConstant.JAVA_TYPE)) { try { Class namedClass = dynamicLoader.getClass(getNamePool().getLocalName(fingerprint), false, null); if (namedClass == null) { return null; } return new ExternalObjectType(namedClass, this); } catch (XPathException err) { return null; } } return null; } /** * Check that a type is validly derived from another type, following the rules for the Schema Component * Constraint "Is Type Derivation OK (Simple)" (3.14.6) or "Is Type Derivation OK (Complex)" (3.4.6) as * appropriate. * * @param derived the derived type * @param base the base type; the algorithm tests whether derivation from this type is permitted * @param block the derivations that are blocked by the relevant element declaration * @throws SchemaException if the derivation is not allowed */ public void checkTypeDerivationIsOK(SchemaType derived, SchemaType base, int block) throws SchemaException, ValidationException { // no action. Although the method can be used to check built-in types, it is never // needed in the non-schema-aware product } /** * Get a document-level validator to add to a Receiver pipeline. *

    * This method is intended for internal use. * * @param receiver The receiver to which events should be sent after validation * @param systemId the base URI of the document being validated * @param validationMode for example Validation.STRICT or Validation.STRIP. The integer may * also have the bit Validation.VALIDATE_OUTPUT set, indicating that the strean being validated * is to be treated as a final output stream (which means multiple errors can be reported) * @param stripSpace options for space stripping * @param schemaType The type against which the outermost element of the document must be validated * (null if there is no constraint) * @param topLevelElementName the namepool name code of the required top-level element in the instance * document, or -1 if there is no specific element required * @return A Receiver to which events can be sent for validation */ public Receiver getDocumentValidator(Receiver receiver, String systemId, int validationMode, int stripSpace, SchemaType schemaType, int topLevelElementName) { // non-schema-aware version return receiver; } /** * Get a Receiver that can be used to validate an element, and that passes the validated * element on to a target receiver. If validation is not supported, the returned receiver * will be the target receiver. *

    * This method is intended for internal use. * * @param receiver the target receiver tp receive the validated element * @param nameCode the nameCode of the element to be validated. This must correspond to the * name of an element declaration in a loaded schema * @param locationId current location in the stylesheet or query * @param schemaType the schema type (typically a complex type) against which the element is to * be validated * @param validation The validation mode, for example Validation.STRICT or Validation.LAX * @return The target receiver, indicating that with this configuration, no validation * is performed. */ public SequenceReceiver getElementValidator(SequenceReceiver receiver, int nameCode, int locationId, SchemaType schemaType, int validation) throws XPathException { return receiver; } /** * Validate an attribute value. *

    * This method is intended for internal use. * * @param nameCode the name of the attribute * @param value the value of the attribute as a string * @param validation STRICT or LAX * @return the type annotation to apply to the attribute node * @throws ValidationException if the value is invalid */ public int validateAttribute(int nameCode, CharSequence value, int validation) throws ValidationException { return StandardNames.XS_UNTYPED_ATOMIC; } /** * Add to a pipeline a receiver that strips all type annotations. This * has a null implementation in the Saxon-B product, because type annotations * can never arise. *

    * This method is intended for internal use. * * @param destination the Receiver that events will be written to after whitespace stripping * @return the Receiver to which events should be sent for stripping */ public Receiver getAnnotationStripper(Receiver destination) { return destination; } /** * Create a new SAX XMLReader object using the class name provided.
    *

    * The named class must exist and must implement the * org.xml.sax.XMLReader or Parser interface.
    *

    * This method returns an instance of the parser named. *

    * This method is intended for internal use. * * @param className A string containing the name of the * SAX parser class, for example "com.microstar.sax.LarkDriver" * @return an instance of the Parser class named, or null if it is not * loadable or is not a Parser. */ public XMLReader makeParser(String className) throws TransformerFactoryConfigurationError { Object obj; try { obj = dynamicLoader.getInstance(className, null); } catch (XPathException err) { throw new TransformerFactoryConfigurationError(err); } if (obj instanceof XMLReader) { return (XMLReader)obj; } throw new TransformerFactoryConfigurationError("Class " + className + " is not a SAX2 XMLReader"); } /** * Get a locale given a language code in XML format. *

    * This method is intended for internal use. * * @param lang the language code * @return the Java locale */ public static Locale getLocale(String lang) { int hyphen = lang.indexOf("-"); String language, country; if (hyphen < 1) { language = lang; country = ""; } else { language = lang.substring(1, hyphen); country = lang.substring(hyphen + 1); } return new Locale(language, country); } /** * Set the debugger to be used. *

    * This method is provided for advanced users only, and is subject to change. * * @param debugger the debugger to be used. */ public void setDebugger(Debugger debugger) { this.debugger = debugger; } /** * Get the debugger in use. This will be null if no debugger has been registered. *

    * This method is provided for advanced users only, and is subject to change. * * @return the debugger in use, or null if none is in use */ public Debugger getDebugger() { return debugger; } /** * Factory method to create a SlotManager. *

    * This method is provided for advanced users only, and is subject to change. * * @return a SlotManager (which is a skeletal stack frame representing the mapping of variable * names to slots on the stack frame) */ public SlotManager makeSlotManager() { if (debugger == null) { return new SlotManager(); } else { return debugger.makeSlotManager(); } } /** * Factory method to get an Optimizer. *

    * This method is intended for internal use only. * * @return the optimizer used in this configuration */ public Optimizer getOptimizer() { if (optimizer == null) { optimizer = new Optimizer(this); } return optimizer; } /** * Load a named collator class and check it is OK. *

    * This method is intended for internal use only. * * @param className the name of the collator class * @return a StringCollator to implement a collation */ public StringCollator makeCollator(String className) throws XPathException { Object handler = dynamicLoader.getInstance(className, null); if (handler instanceof StringCollator) { return (StringCollator)handler; } else { throw new XPathException("Failed to load collation class " + className + ": it is not an instance of net.sf.saxon.sort.StringCollator"); } } /** * Set lazy construction mode on or off. In lazy construction mode, element constructors * are not evaluated until the content of the tree is required. Lazy construction mode * is currently experimental and is therefore off by default. * * @param lazy true to switch lazy construction mode on, false to switch it off. */ public void setLazyConstructionMode(boolean lazy) { lazyConstructionMode = lazy; } /** * Determine whether lazy construction mode is on or off. In lazy construction mode, element constructors * are not evaluated until the content of the tree is required. Lazy construction mode * is currently experimental and is therefore off by default. * * @return true if lazy construction mode is enabled */ public boolean isLazyConstructionMode() { return lazyConstructionMode; } /** * Register the standard Saxon-supplied object models. *

    * This method is intended for internal use only. */ private void registerStandardObjectModels() { // Try to load the support classes for various object models, registering // them in the Configuration. We require both the Saxon object model definition // and an implementation of the object model itself to be loadable before // the object model is registered. String[] models = {"net.sf.saxon.dom.DOMEnvelope", "net.sf.saxon.dom.DOMObjectModel", "net.sf.saxon.jdom.JDOMObjectModel", "net.sf.saxon.xom.XOMObjectModel", "net.sf.saxon.dom4j.DOM4JObjectModel"}; String[] nodes = {"net.sf.saxon.dom.NodeOverNodeInfo", "org.w3c.dom.Node", "org.jdom.Element", "nu.xom.Node", "org.dom4j.Element"}; sharedExternalObjectModels = new ArrayList(4); for (int i = 0; i < models.length; i++) { try { dynamicLoader.getClass(nodes[i], false, null); // designed to trigger an exception if the class can't be loaded ExternalObjectModel model = (ExternalObjectModel)dynamicLoader.getInstance(models[i], null); sharedExternalObjectModels.add(model); //registerExternalObjectModel(model); } catch (XPathException err) { // ignore the failure. We can't report an exception here, and in any case a failure // is legitimate if the object model isn't on the class path. We'll fail later when // we try to process a node in the chosen object model: the node simply won't be // recognized as one that Saxon can handle } catch (ClassCastException err) { // we've loaded the class, but it isn't an ExternalObjectModel. This can apparently // happen if there's more than one ClassLoader involved. We'll output a simple warning, // and then continue as if the external object model wasn't on the class path System.err.println("Warning: external object model " + models[i] + " has been loaded, but is not an instance of net.sf.saxon.om.ExternalObjectModel"); } catch (Throwable err) { // On the .NET platform all kinds of things can go wrong, but we don't really care System.err.println("Warning: failed to load external object model: " + err.getMessage()); } } } /** * Register an external object model with this Configuration. * * @param model The external object model. * This can either be one of the system-supplied external * object models for JDOM, XOM, or DOM, or a user-supplied external object model. *

    * This method is intended for advanced users only, and is subject to change. */ public void registerExternalObjectModel(ExternalObjectModel model) { if (externalObjectModels == null) { externalObjectModels = new ArrayList(5); } if (!externalObjectModels.contains(model)) { externalObjectModels.add(model); } } /** * Get the external object model with a given URI, if registered * @param uri the identifying URI of the required external object model * @return the requested external object model if available, or null otherwise */ public ExternalObjectModel getExternalObjectModel(String uri) { for (int m=0; m * This method is intended for internal use only. * * @return a list of external object models supported. The members of the list are of * type {@link ExternalObjectModel} */ public List getExternalObjectModels() { return externalObjectModels; } /** * Get a NodeInfo corresponding to a DOM or other external Node, * either by wrapping or unwrapping the external Node. *

    * This method is intended for internal use. * * @param source A Source representing the wrapped or unwrapped external Node. This will typically * be a DOMSource, but it may be a similar Source recognized by some other registered external * object model. * @return If the Source is a DOMSource and the underlying node is a wrapper around a Saxon NodeInfo, * returns the wrapped Saxon NodeInfo. If the Source is a DOMSource and the undelying node is not such a wrapper, * returns a new Saxon NodeInfo that wraps the DOM Node. If the Source is any other kind of source, it * is offered to each registered external object model for similar treatment. The result is the * NodeInfo object obtained by wrapping or unwrapping the supplied external node. * @throws IllegalArgumentException if the source object is not of a recognized class. This method does * not call the registered {@link SourceResolver to resolve the Source}. */ public NodeInfo unravel(Source source) { List externalObjectModels = getExternalObjectModels(); for (int m = 0; m < externalObjectModels.size(); m++) { ExternalObjectModel model = (ExternalObjectModel)externalObjectModels.get(m); NodeInfo node = model.unravel(source, this); if (node != null) { if (node.getConfiguration() != this) { throw new IllegalArgumentException("Externally supplied Node belongs to the wrong Configuration"); } return node; } } if (source instanceof NodeInfo) { if (((NodeInfo)source).getConfiguration() != this) { throw new IllegalArgumentException("Externally supplied NodeInfo belongs to the wrong Configuration"); } return (NodeInfo)source; } if (source instanceof DOMSource) { throw new IllegalArgumentException("When a DOMSource is used, saxon9-dom.jar must be on the classpath"); } else { throw new IllegalArgumentException("A source of class " + source.getClass() + " is not recognized by any registered object model"); } } /** * Set the level of DOM interface to be used * * @param level the DOM level. Must be 2 or 3. By default Saxon assumes that DOM level 3 is available; * this parameter can be set to the value 2 to indicate that Saxon should not use methods unless they * are available in DOM level 2. */ public void setDOMLevel(int level) { if (!(level == 2 || level == 3)) { throw new IllegalArgumentException("DOM Level must be 2 or 3"); } domLevel = level; } /** * Get the level of DOM interface to be used * * @return the DOM level. Always 2 or 3. */ public int getDOMLevel() { return domLevel; } /** * Get a new QueryParser * * @param updating indicates whether or not XQuery update syntax may be used. Note that XQuery Update * is supported only in Saxon-SA * @return the QueryParser * @throws UnsupportedOperationException if a parser that supports update syntax is requested on Saxon-B */ public QueryParser newQueryParser(boolean updating) { if (updating) { throw new UnsupportedOperationException("XQuery Update is supported only in Saxon-SA"); } else { return new QueryParser(); } } /** * Get a new Pending Update List * * @return the new Pending Update List * @throws UnsupportedOperationException if called when using Saxon-B */ public PendingUpdateList newPendingUpdateList() { throw new UnsupportedOperationException("XQuery update is supported only in Saxon-SA"); } /** * Make a PipelineConfiguration from the properties of this Configuration * * @return a new PipelineConfiguration * @since 8.4 */ public PipelineConfiguration makePipelineConfiguration() { PipelineConfiguration pipe = new PipelineConfiguration(); pipe.setConfiguration(this); pipe.setErrorListener(getErrorListener()); pipe.setURIResolver(getURIResolver()); pipe.setSchemaURIResolver(getSchemaURIResolver()); pipe.setHostLanguage(getHostLanguage()); pipe.setExpandAttributeDefaults(isExpandAttributeDefaults()); pipe.setUseXsiSchemaLocation(useXsiSchemaLocation); return pipe; } /** * Get the configuration, given the context. This is provided as a static method to make it accessible * as an extension function. * * @param context the XPath dynamic context * @return the Saxon Configuration for a given XPath dynamic context */ public static Configuration getConfiguration(XPathContext context) { return context.getConfiguration(); } /** * Supply a SourceResolver. This is used for handling unknown implementations of the * {@link javax.xml.transform.Source} interface: a user-supplied SourceResolver can handle * such Source objects and translate them to a kind of Source that Saxon understands. * * @param resolver the source resolver. */ public void setSourceResolver(SourceResolver resolver) { sourceResolver = resolver; } /** * Get the current SourceResolver. If none has been supplied, a system-defined SourceResolver * is returned. * * @return the current SourceResolver */ public SourceResolver getSourceResolver() { return sourceResolver; } /** * Implement the SourceResolver interface */ public Source resolveSource(Source source, Configuration config) throws XPathException { if (source instanceof AugmentedSource) { return source; } if (source instanceof StreamSource) { return source; } if (source instanceof SAXSource) { return source; } if (source instanceof DOMSource) { return source; } if (source instanceof NodeInfo) { return source; } if (source instanceof PullProvider) { return source; } if (source instanceof PullSource) { return source; } if (source instanceof PullEventSource) { return source; } return null; } /** * Build a document tree, using options set on this Configuration and on the supplied source * object. Options set on the source object override options set in the Configuration. The Source * object must be one of the kinds of source recognized by Saxon, or a source that can be resolved * using the registered SourceResolver. * * @param source the Source to be used. This may be an {@link AugmentedSource}, allowing options * to be specified for the way in which this document will be built. *

    A new tree will be built, using either the Tiny Tree or the Linked Tree implementation, * except under the following circumstances:

    *
      *
    • The supplied object is a DocumentInfo. In this case a new tree will * be built only if validation or whitespace stripping has been requested in the Configuration; * otherwise the DocumentInfo will be returned unchanged.
    • *
    • The supplied object is an AugmentedSource wrapping a DocumentInfo. In this case a new tree will * be built if wrap=no has been specified, if validation has been requested, or if whitespace stripping * has been requested, either in the AugmentedSource or in the Configuration.
    • *
    • The supplied object is a DOMSource. In this case a new tree will * be built if validation or whitespace stripping has been requested in the Configuration, * or if the DOM Node is not a Document Node; in other cases the Document node of the DOMSource will be wrapped * in a Saxon {@link net.sf.saxon.dom.DocumentWrapper}, except in the case where the DOM Document node * is a {@link net.sf.saxon.dom.DocumentOverNodeInfo}, in which case the DocumentInfo that it wraps is * returned.
    • *
    • The supplied object is an AugmentedSource wrapping a DOMSource. In this case a new tree will * be built if wrap=no has been specified, if validation has been requested, or if whitespace stripping * has been requested, either in the AugmentedSource or in the Configuration.
    • *
    *

    The choice between a tiny tree and a linked tree is determined first be the properties of the * AugmentedSource if that's what is supplied; otherwise by the properties of this Configuration. * @return the document node of the constructed or wrapped document * @throws XPathException if any errors occur during document parsing or validation. Detailed * errors occurring during schema validation will be written to the ErrorListener associated * with the AugmentedSource, if supplied, or with the Configuration otherwise. * @since 8.9. Modified in 9.0 to avoid copying a supplied document where this is not * necessary. */ public DocumentInfo buildDocument(Source source) throws XPathException { if (source == null) { throw new NullPointerException("source"); } // Resolve user-defined implementations of Source source = resolveSource(source, this); if (source == null) { throw new XPathException("Unknown source class"); } boolean mustCopy = schemaValidationMode != Validation.PRESERVE || stripsWhiteSpace == Whitespace.ALL; if (!mustCopy) { // If the source is a DocumentInfo, return it unchanged if (source instanceof DocumentInfo) { return (DocumentInfo)source; } // Handle an AugmentedSource wrapping a DOMSource or DocumentInfo if (source instanceof AugmentedSource) { AugmentedSource asource = (AugmentedSource)source; Source underSource = asource.getContainedSource(); if (underSource instanceof DocumentInfo || underSource instanceof DOMSource) { boolean wrap = asource.getWrapDocument() == null || asource.getWrapDocument().booleanValue(); if (asource.getSchemaValidation() != Validation.STRIP) { wrap = false; } else if (asource.getStripSpace() != Whitespace.NONE) { wrap = false; } if (wrap) { NodeInfo node = unravel(underSource); if (node instanceof DocumentInfo) { return (DocumentInfo)node; } else { source = node; } } else { source = underSource; } } } // Handle a DOMSource if (source instanceof DOMSource) { NodeInfo node = unravel(source); if (node instanceof DocumentInfo) { return (DocumentInfo)node; } else { source = node; } } } // Create a pipeline configuration PipelineConfiguration pipe = makePipelineConfiguration(); // Create an appropriate Builder Builder b; int treeModel = Builder.UNSPECIFIED_TREE_MODEL; if (source instanceof AugmentedSource) { treeModel = ((AugmentedSource)source).getTreeModel(); } if (treeModel == Builder.UNSPECIFIED_TREE_MODEL) { treeModel = this.treeModel; } if (treeModel == Builder.TINY_TREE) { b = new TinyBuilder(); } else { b = new TreeBuilder(); } // Set builder properties b.setPipelineConfiguration(pipe); b.setTiming(isTiming()); // Decide whether line numbering is in use boolean lineNumbering = this.lineNumbering; if (source instanceof AugmentedSource && ((AugmentedSource)source).isLineNumberingSet()) { lineNumbering = ((AugmentedSource)source).isLineNumbering(); } b.setLineNumbering(lineNumbering); new Sender(pipe).send(source, b); // Get the constructed document DocumentInfo newdoc = (DocumentInfo)b.getCurrentRoot(); // Reset the builder, detaching it from the constructed document b.reset(); // If requested, close the input stream if (source instanceof AugmentedSource && ((AugmentedSource)source).isPleaseCloseAfterUse()) { ((AugmentedSource)source).close(); } // Return the constructed document return newdoc; } /** * Load a named output emitter or SAX2 ContentHandler and check it is OK. * * @param clarkName the QName of the user-supplied ContentHandler (requested as a prefixed * value of the method attribute in xsl:output, or anywhere that serialization parameters * are allowed), encoded in Clark format as {uri}local * @param controller the Controller. Allows a local class loader to be used. * @return a Receiver (despite the name, it is not required to be an Emitter) */ public Receiver makeEmitter(String clarkName, Controller controller) throws XPathException { int brace = clarkName.indexOf('}'); String localName = clarkName.substring(brace + 1); int colon = localName.indexOf(':'); String className = localName.substring(colon + 1); Object handler; try { handler = dynamicLoader.getInstance(className, controller.getClassLoader()); } catch (XPathException e) { throw new XPathException("Cannot load user-supplied output method " + className, SaxonErrorCode.SXCH0004); } if (handler instanceof Receiver) { return (Receiver)handler; } else if (handler instanceof ContentHandler) { ContentHandlerProxy emitter = new ContentHandlerProxy(); emitter.setUnderlyingContentHandler((ContentHandler)handler); emitter.setOutputProperties(controller.getOutputProperties()); return emitter; } else { throw new XPathException("Failed to load " + className + ": it is neither a Receiver nor a SAX2 ContentHandler"); } } /** * Set a property of the configuration. This method underpins the setAttribute() method of the * TransformerFactory implementation, and is provided * to enable setting of Configuration properties using URIs without instantiating a TransformerFactory: * specifically, this may be useful when running XQuery, and it is also used by the Validator API * * @param name the URI identifying the property to be set. See the class {@link FeatureKeys} for * constants representing the property names that can be set. * @param value the value of the property * @throws IllegalArgumentException if the property name is not recognized or if the value is not * a valid value for the named property */ public void setConfigurationProperty(String name, Object value) { if (name.equals(FeatureKeys.ALLOW_EXTERNAL_FUNCTIONS)) { boolean b = requireBoolean("ALLOW_EXTERNAL_FUNCTIONS", value); setAllowExternalFunctions(b); } else if (name.equals(FeatureKeys.COLLATION_URI_RESOLVER)) { if (!(value instanceof CollationURIResolver)) { throw new IllegalArgumentException( "COLLATION_URI_RESOLVER value must be an instance of net.sf.saxon.sort.CollationURIResolver"); } setCollationURIResolver((CollationURIResolver)value); } else if (name.equals(FeatureKeys.COLLATION_URI_RESOLVER_CLASS)) { if (!(value instanceof String)) { throw new IllegalArgumentException( "COLLATION_URI_RESOLVER_CLASS must be a String"); } try { Object obj = getInstance((String)value, null); setCollationURIResolver((CollationURIResolver)obj); } catch (XPathException err) { throw new IllegalArgumentException( "Cannot instantiate COLLATION_URI_RESOLVER_CLASS. " + err.getMessage()); } catch (ClassCastException err) { throw new IllegalArgumentException( "COLLATION_URI_RESOLVER_CLASS does not implement CollationURIResolver"); } } else if (name.equals(FeatureKeys.COLLECTION_URI_RESOLVER)) { if (!(value instanceof CollectionURIResolver)) { throw new IllegalArgumentException( "COLLECTION_URI_RESOLVER value must be an instance of net.sf.saxon.CollectionURIResolver"); } setCollectionURIResolver((CollectionURIResolver)value); } else if (name.equals(FeatureKeys.COLLECTION_URI_RESOLVER_CLASS)) { if (!(value instanceof String)) { throw new IllegalArgumentException( "COLLECTION_URI_RESOLVER_CLASS must be a String"); } try { Object obj = getInstance((String)value, null); setCollectionURIResolver((CollectionURIResolver)obj); } catch (XPathException err) { throw new IllegalArgumentException( "Cannot instantiate COLLECTION_URI_RESOLVER_CLASS. " + err.getMessage()); } catch (ClassCastException err) { throw new IllegalArgumentException( "COLLECTION_URI_RESOLVER_CLASS does not implement CollectionURIResolver"); } } else if (name.equals(FeatureKeys.COMPILE_WITH_TRACING)) { boolean b = requireBoolean("COMPILE_WITH_TRACING", value); setCompileWithTracing(b); } else if (name.equals(FeatureKeys.DTD_VALIDATION)) { boolean b = requireBoolean("DTD_VALIDATION", value); setValidation(b); } else if (name.equals(FeatureKeys.EXPAND_ATTRIBUTE_DEFAULTS)) { boolean b = requireBoolean("EXPAND_ATTRIBUTE_DEFAULTS", value); setExpandAttributeDefaults(b); } else if (name.equals(FeatureKeys.LINE_NUMBERING)) { boolean b = requireBoolean("LINE_NUMBERING", value); setLineNumbering(b); } else if (name.equals(FeatureKeys.MESSAGE_EMITTER_CLASS)) { if (!(value instanceof String)) { throw new IllegalArgumentException("MESSAGE_EMITTER_CLASS class must be a String"); } setMessageEmitterClass((String)value); } else if (name.equals(FeatureKeys.MODULE_URI_RESOLVER)) { if (!(value instanceof ModuleURIResolver)) { throw new IllegalArgumentException( "MODULE_URI_RESOLVER value must be an instance of net.sf.saxon.query.ModuleURIResolver"); } setModuleURIResolver((ModuleURIResolver)value); } else if (name.equals(FeatureKeys.MODULE_URI_RESOLVER_CLASS)) { if (!(value instanceof String)) { throw new IllegalArgumentException( "MODULE_URI_RESOLVER_CLASS value must be a string"); } try { Object obj = getInstance((String)value, null); setModuleURIResolver((ModuleURIResolver)obj); } catch (XPathException err) { throw new IllegalArgumentException( "Cannot instantiate MODULE_URI_RESOLVER_CLASS. " + err.getMessage()); } catch (ClassCastException err) { throw new IllegalArgumentException( "MODULE_URI_RESOLVER_RESOLVER_CLASS does not implement ModuleURIResolver"); } } else if (name.equals(FeatureKeys.NAME_POOL)) { if (!(value instanceof NamePool)) { throw new IllegalArgumentException("NAME_POOL value must be an instance of net.sf.saxon.om.NamePool"); } setNamePool((NamePool)value); } else if (name.equals(FeatureKeys.OUTPUT_URI_RESOLVER)) { if (!(value instanceof OutputURIResolver)) { throw new IllegalArgumentException( "OUTPUT_URI_RESOLVER value must be an instance of net.sf.saxon.OutputURIResolver"); } setOutputURIResolver((OutputURIResolver)value); } else if (name.equals(FeatureKeys.OUTPUT_URI_RESOLVER_CLASS)) { if (!(value instanceof String)) { throw new IllegalArgumentException( "OUTPUT_URI_RESOLVER_CLASS value must be a string"); } try { Object obj = getInstance((String)value, null); setOutputURIResolver((OutputURIResolver)obj); } catch (XPathException err) { throw new IllegalArgumentException( "Cannot instantiate OUTPUT_URI_RESOLVER_CLASS. " + err.getMessage()); } catch (ClassCastException err) { throw new IllegalArgumentException( "OUTPUT_URI_RESOLVER_RESOLVER_CLASS does not implement OutputURIResolver"); } } else if (name.equals(FeatureKeys.PRE_EVALUATE_DOC_FUNCTION)) { preEvaluateDocFunction = requireBoolean("PRE_EVALUATE_DOC_FUNCTION", value); } else if (name.equals(FeatureKeys.PREFER_JAXP_PARSER)) { preferJaxpParser = requireBoolean("PREFER_JAXP_PARSER", value); } else if (name.equals(FeatureKeys.RECOGNIZE_URI_QUERY_PARAMETERS)) { if (!(value instanceof Boolean)) { throw new IllegalArgumentException("RECOGNIZE_QUERY_URI_PARAMETERS must be a boolean"); } getSystemURIResolver().setRecognizeQueryParameters(((Boolean)value).booleanValue()); } else if (name.equals(FeatureKeys.RECOVERY_POLICY)) { if (!(value instanceof Integer)) { throw new IllegalArgumentException("RECOVERY_POLICY value must be an Integer"); } setRecoveryPolicy(((Integer)value).intValue()); } else if (name.equals(FeatureKeys.RECOVERY_POLICY_NAME)) { if (!(value instanceof String)) { throw new IllegalArgumentException("RECOVERY_POLICY_NAME value must be a String"); } int rval; if (value.equals("recoverSilently")) { rval = RECOVER_SILENTLY; } else if (value.equals("recoverWithWarnings")) { rval = RECOVER_WITH_WARNINGS; } else if (value.equals("doNotRecover")) { rval = DO_NOT_RECOVER; } else { throw new IllegalArgumentException( "Unrecognized value of RECOVERY_POLICY_NAME = '" + value + "': must be 'recoverSilently', 'recoverWithWarnings', or 'doNotRecover'"); } setRecoveryPolicy(rval); } else if (name.equals(FeatureKeys.SCHEMA_URI_RESOLVER)) { if (!(value instanceof SchemaURIResolver)) { throw new IllegalArgumentException( "SCHEMA_URI_RESOLVER value must be an instance of net.sf.saxon.type.SchemaURIResolver"); } setSchemaURIResolver((SchemaURIResolver)value); } else if (name.equals(FeatureKeys.SCHEMA_URI_RESOLVER_CLASS)) { if (!(value instanceof String)) { throw new IllegalArgumentException( "SCHEMA_URI_RESOLVER_CLASS value must be a string"); } try { Object obj = getInstance((String)value, null); setSchemaURIResolver((SchemaURIResolver)obj); } catch (XPathException err) { throw new IllegalArgumentException( "Cannot instantiate SCHEMA_URI_RESOLVER_CLASS. " + err.getMessage()); } catch (ClassCastException err) { throw new IllegalArgumentException( "SCHEMA_URI_RESOLVER_RESOLVER_CLASS does not implement SchemaURIResolver"); } } else if (name.equals(FeatureKeys.SCHEMA_VALIDATION)) { if (!(value instanceof Integer)) { throw new IllegalArgumentException("SCHEMA_VALIDATION must be an integer"); } setSchemaValidationMode(((Integer)value).intValue()); } else if (name.equals(FeatureKeys.SCHEMA_VALIDATION_MODE)) { if (!(value instanceof String)) { throw new IllegalArgumentException("SCHEMA_VALIDATION_MODE must be a string"); } setSchemaValidationMode(Validation.getCode((String)value)); } else if (name.equals(FeatureKeys.SOURCE_PARSER_CLASS)) { if (!(value instanceof String)) { throw new IllegalArgumentException("SOURCE_PARSER_CLASS class must be a String"); } setSourceParserClass((String)value); } else if (name.equals(FeatureKeys.STRIP_WHITESPACE)) { if (!(value instanceof String)) { throw new IllegalArgumentException("STRIP_WHITESPACE must be a string"); } int ival; if (value.equals("all")) { ival = Whitespace.ALL; } else if (value.equals("none")) { ival = Whitespace.NONE; } else if (value.equals("ignorable")) { ival = Whitespace.IGNORABLE; } else { throw new IllegalArgumentException( "Unrecognized value STRIP_WHITESPACE = '" + value + "': must be 'all', 'none', or 'ignorable'"); } setStripsWhiteSpace(ival); } else if (name.equals(FeatureKeys.STYLE_PARSER_CLASS)) { if (!(value instanceof String)) { throw new IllegalArgumentException("STYLE_PARSER_CLASS class must be a String"); } setStyleParserClass((String)value); } else if (name.equals(FeatureKeys.TIMING)) { setTiming(requireBoolean("TIMING", value)); } else if (name.equals(FeatureKeys.TRACE_EXTERNAL_FUNCTIONS)) { setTraceExternalFunctions(requireBoolean("TRACE_EXTERNAL_FUNCTIONS", value)); } else if (name.equals(FeatureKeys.TRACE_OPTIMIZER_DECISIONS)) { setOptimizerTracing(requireBoolean("TRACE_OPTIMIZER_DECISIONS", value)); } else if (name.equals(FeatureKeys.TRACE_LISTENER)) { if (!(value instanceof TraceListener)) { throw new IllegalArgumentException("TRACE_LISTENER is of wrong class"); } setTraceListener((TraceListener)value); } else if (name.equals(FeatureKeys.TRACE_LISTENER_CLASS)) { if (!(value instanceof String)) { throw new IllegalArgumentException("TRACE_LISTENER_CLASS must be a string"); } setTraceListenerClass((String)value); } else if (name.equals(FeatureKeys.TREE_MODEL)) { if (!(value instanceof Integer)) { throw new IllegalArgumentException("Tree model must be an Integer"); } setTreeModel(((Integer)value).intValue()); } else if (name.equals(FeatureKeys.TREE_MODEL_NAME)) { if (!(value instanceof String)) { throw new IllegalArgumentException("TREE_MODEL_NAME must be a string"); } if (value.equals("tinyTree")) { setTreeModel(Builder.TINY_TREE); } else if (value.equals("linkedTree")) { setTreeModel(Builder.LINKED_TREE); } else { throw new IllegalArgumentException( "Unrecognized value TREE_MODEL_NAME = '" + value + "': must be 'linkedTree' or 'tinyTree'"); } } else if (name.equals(FeatureKeys.USE_PI_DISABLE_OUTPUT_ESCAPING)) { useDisableOutputEscaping = requireBoolean("USE_PI_DISABLE_OUTPUT_ESCAPING", value); } else if (name.equals(FeatureKeys.USE_XSI_SCHEMA_LOCATION)) { useXsiSchemaLocation = requireBoolean("USE_XSI_SCHEMA_LOCATION", value); } else if (name.equals(FeatureKeys.VALIDATION_WARNINGS)) { setValidationWarnings(requireBoolean("VALIDATION_WARNINGS", value)); } else if (name.equals(FeatureKeys.VERSION_WARNING)) { setVersionWarning(requireBoolean("VERSION_WARNING", value)); } else if (name.equals(FeatureKeys.XINCLUDE)) { setXIncludeAware(requireBoolean("XINCLUDE", value)); } else if (name.equals(FeatureKeys.XML_VERSION) || name.equals("http://saxon.sf.bet/feature/xml-version")) { // spelling mistake retained for backwards compatibility with 8.9 and earlier if (!(value instanceof String && (value.equals("1.0") || value.equals("1.1")))) { throw new IllegalArgumentException( "XML_VERSION value must be \"1.0\" or \"1.1\" as a String"); } setXMLVersion((value.equals("1.0") ? XML10 : XML11)); } else if (name.equals(FeatureKeys.XSD_VERSION)) { if (!(value instanceof String && (value.equals("1.0") || value.equals("1.1")))) { throw new IllegalArgumentException( "XSD_VERSION value must be \"1.0\" or \"1.1\" as a String"); } xsdlVersion = ((value.equals("1.0") ? XSD10 : XSD11)); } else { throw new IllegalArgumentException("Unknown attribute " + name); } } private boolean requireBoolean(String propertyName, Object value) { if (value instanceof Boolean) { return ((Boolean)value).booleanValue(); } else if (value instanceof String) { if ("true".equals(value)) { return true; } else if ("false".equals(value)) { return false; } else { throw new IllegalArgumentException(propertyName + " must be 'true' or 'false'"); } } else { throw new IllegalArgumentException(propertyName + " must be a boolean"); } } /** * Get a property of the configuration * * @param name the name of the required property. See the class {@link FeatureKeys} for * constants representing the property names that can be requested. * @return the value of the property * @throws IllegalArgumentException thrown if the property is not one that Saxon recognizes. */ public Object getConfigurationProperty(String name) { if (name.equals(FeatureKeys.ALLOW_EXTERNAL_FUNCTIONS)) { return Boolean.valueOf(isAllowExternalFunctions()); } else if (name.equals(FeatureKeys.COLLATION_URI_RESOLVER)) { return getCollationURIResolver(); } else if (name.equals(FeatureKeys.COLLATION_URI_RESOLVER_CLASS)) { return getCollationURIResolver().getClass().getName(); } else if (name.equals(FeatureKeys.COLLECTION_URI_RESOLVER)) { return getCollectionURIResolver(); } else if (name.equals(FeatureKeys.COLLECTION_URI_RESOLVER_CLASS)) { return getCollectionURIResolver().getClass().getName(); } else if (name.equals(FeatureKeys.COMPILE_WITH_TRACING)) { return Boolean.valueOf(isCompileWithTracing()); } else if (name.equals(FeatureKeys.DTD_VALIDATION)) { return Boolean.valueOf(isValidation()); } else if (name.equals(FeatureKeys.EXPAND_ATTRIBUTE_DEFAULTS)) { return Boolean.valueOf(isExpandAttributeDefaults()); } else if (name.equals(FeatureKeys.LINE_NUMBERING)) { return Boolean.valueOf(isLineNumbering()); } else if (name.equals(FeatureKeys.MESSAGE_EMITTER_CLASS)) { return getMessageEmitterClass(); } else if (name.equals(FeatureKeys.MODULE_URI_RESOLVER)) { return getModuleURIResolver(); } else if (name.equals(FeatureKeys.MODULE_URI_RESOLVER_CLASS)) { return getModuleURIResolver().getClass().getName(); } else if (name.equals(FeatureKeys.NAME_POOL)) { return getNamePool(); } else if (name.equals(FeatureKeys.OUTPUT_URI_RESOLVER)) { return getOutputURIResolver(); } else if (name.equals(FeatureKeys.OUTPUT_URI_RESOLVER_CLASS)) { return getOutputURIResolver().getClass().getName(); } else if (name.equals(FeatureKeys.PRE_EVALUATE_DOC_FUNCTION)) { return Boolean.valueOf(preEvaluateDocFunction); } else if (name.equals(FeatureKeys.PREFER_JAXP_PARSER)) { return Boolean.valueOf(preferJaxpParser); } else if (name.equals(FeatureKeys.RECOGNIZE_URI_QUERY_PARAMETERS)) { return Boolean.valueOf(getSystemURIResolver().queryParametersAreRecognized()); } else if (name.equals(FeatureKeys.RECOVERY_POLICY)) { return new Integer(getRecoveryPolicy()); } else if (name.equals(FeatureKeys.RECOVERY_POLICY_NAME)) { switch (getRecoveryPolicy()) { case RECOVER_SILENTLY: return "recoverSilently"; case RECOVER_WITH_WARNINGS: return "recoverWithWarnings"; case DO_NOT_RECOVER: return "doNotRecover"; default: return null; } } else if (name.equals(FeatureKeys.SCHEMA_URI_RESOLVER)) { return getSchemaURIResolver(); } else if (name.equals(FeatureKeys.SCHEMA_URI_RESOLVER_CLASS)) { return getSchemaURIResolver().getClass().getName(); } else if (name.equals(FeatureKeys.SCHEMA_VALIDATION)) { return new Integer(getSchemaValidationMode()); } else if (name.equals(FeatureKeys.SCHEMA_VALIDATION_MODE)) { return Validation.toString(getSchemaValidationMode()); } else if (name.equals(FeatureKeys.SOURCE_PARSER_CLASS)) { return getSourceParserClass(); } else if (name.equals(FeatureKeys.STRIP_WHITESPACE)) { int s = getStripsWhiteSpace(); if (s == Whitespace.ALL) { return "all"; } else if (s == Whitespace.IGNORABLE) { return "ignorable"; } else { return "none"; } } else if (name.equals(FeatureKeys.STYLE_PARSER_CLASS)) { return getStyleParserClass(); } else if (name.equals(FeatureKeys.TIMING)) { return Boolean.valueOf(isTiming()); } else if (name.equals(FeatureKeys.TRACE_LISTENER)) { return traceListener; } else if (name.equals(FeatureKeys.TRACE_LISTENER_CLASS)) { return traceListenerClass; } else if (name.equals(FeatureKeys.TRACE_EXTERNAL_FUNCTIONS)) { return Boolean.valueOf(isTraceExternalFunctions()); } else if (name.equals(FeatureKeys.TRACE_OPTIMIZER_DECISIONS)) { return Boolean.valueOf(isOptimizerTracing()); } else if (name.equals(FeatureKeys.TREE_MODEL)) { return new Integer(getTreeModel()); } else if (name.equals(FeatureKeys.TREE_MODEL_NAME)) { return getTreeModel() == Builder.TINY_TREE ? "tinyTree" : "linkedTree"; } else if (name.equals(FeatureKeys.USE_PI_DISABLE_OUTPUT_ESCAPING)) { return Boolean.valueOf(useDisableOutputEscaping); } else if (name.equals(FeatureKeys.USE_XSI_SCHEMA_LOCATION)) { return Boolean.valueOf(useXsiSchemaLocation); } else if (name.equals(FeatureKeys.VALIDATION_WARNINGS)) { return Boolean.valueOf(isValidationWarnings()); } else if (name.equals(FeatureKeys.VERSION_WARNING)) { return Boolean.valueOf(isVersionWarning()); } else if (name.equals(FeatureKeys.XINCLUDE)) { return Boolean.valueOf(isXIncludeAware()); } else if (name.equals(FeatureKeys.XML_VERSION)) { // Spelling mistake retained for backwards compatibility with 8.9 and earlier return (getXMLVersion() == XML10 ? "1.0" : "1.1"); } else if (name.equals(FeatureKeys.XSD_VERSION)) { return (xsdlVersion == XSD10 ? "1.0" : "1.1"); } else { throw new IllegalArgumentException("Unknown attribute " + name); } } // public static void main(String[] args) { // Configuration config = Configuration.makeConfiguration(null, null); // System.err.println(config.getClass() + ": " + config.isSchemaAware(XML_SCHEMA)); // } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. //saxonb-9.1.0.8/bj/net/sf/saxon/dom/0000755000175000017500000000000012216261745016171 5ustar eugeneeugenesaxonb-9.1.0.8/bj/net/sf/saxon/dom/DOMWriter.java0000644000175000017500000002045611062234422020645 0ustar eugeneeugenepackage net.sf.saxon.dom; import net.sf.saxon.event.PipelineConfiguration; import net.sf.saxon.event.Receiver; import net.sf.saxon.event.ReceiverOptions; import net.sf.saxon.om.NamePool; import net.sf.saxon.om.NamespaceConstant; import net.sf.saxon.om.StandardNames; import net.sf.saxon.trans.XPathException; import org.w3c.dom.*; /** * DOMWriter is a Receiver that attaches the result tree to a specified Node in a DOM Document */ public class DOMWriter implements Receiver { private PipelineConfiguration pipe; private NamePool namePool; private Node currentNode; private Document document; private Node nextSibling; private int level = 0; private boolean canNormalize = true; private String systemId; /** * Set the pipelineConfiguration */ public void setPipelineConfiguration(PipelineConfiguration pipe) { this.pipe = pipe; namePool = pipe.getConfiguration().getNamePool(); } /** * Get the pipeline configuration used for this document */ public PipelineConfiguration getPipelineConfiguration() { return pipe; } /** * Set the System ID of the destination tree */ public void setSystemId(String systemId) { this.systemId = systemId; } /** * Notify an unparsed entity URI. * * @param name The name of the unparsed entity * @param systemID The system identifier of the unparsed entity * @param publicID The public identifier of the unparsed entity */ public void setUnparsedEntity(String name, String systemID, String publicID) throws XPathException { // no-op } /** * Get the system identifier that was set with setSystemId. * * @return The system identifier that was set with setSystemId, * or null if setSystemId was not called. */ public String getSystemId() { return systemId; } /** * Start of the document. */ public void open () {} /** * End of the document. */ public void close () {} /** * Start of a document node. */ public void startDocument(int properties) throws XPathException {} /** * Notify the end of a document node */ public void endDocument() throws XPathException {} /** * Start of an element. */ public void startElement (int nameCode, int typeCode, int locationId, int properties) throws XPathException { String qname = namePool.getDisplayName(nameCode); String uri = namePool.getURI(nameCode); try { Element element = document.createElementNS(("".equals(uri) ? null : uri), qname); if (nextSibling != null && level == 0) { currentNode.insertBefore(element, nextSibling); } else { currentNode.appendChild(element); } currentNode = element; } catch (DOMException err) { throw new XPathException(err); } level++; } public void namespace (int namespaceCode, int properties) throws XPathException { try { String prefix = namePool.getPrefixFromNamespaceCode(namespaceCode); String uri = namePool.getURIFromNamespaceCode(namespaceCode); Element element = (Element)currentNode; if (!(uri.equals(NamespaceConstant.XML))) { if (prefix.length() == 0) { element.setAttributeNS(NamespaceConstant.XMLNS, "xmlns", uri); } else { element.setAttributeNS(NamespaceConstant.XMLNS, "xmlns:" + prefix, uri); } } } catch (DOMException err) { throw new XPathException(err); } } public void attribute (int nameCode, int typeCode, CharSequence value, int locationId, int properties) throws XPathException { String qname = namePool.getDisplayName(nameCode); String uri = namePool.getURI(nameCode); try { Element element = (Element)currentNode; element.setAttributeNS(("".equals(uri) ? null : uri), qname, value.toString()); // The following code assumes JDK 1.5 or JAXP 1.3 if ((nameCode & NamePool.FP_MASK) == StandardNames.XML_ID || (properties & ReceiverOptions.IS_ID) != 0) { String localName = namePool.getLocalName(nameCode); element.setIdAttributeNS(uri, localName, true); } } catch (DOMException err) { throw new XPathException(err); } } public void startContent() throws XPathException {} /** * End of an element. */ public void endElement () throws XPathException { if (canNormalize) { try { currentNode.normalize(); } catch (Throwable err) { canNormalize = false; } // in case it's a Level 1 DOM } currentNode = currentNode.getParentNode(); level--; } /** * Character data. */ public void characters (CharSequence chars, int locationId, int properties) throws XPathException { try { Text text = document.createTextNode(chars.toString()); if (nextSibling != null && level == 0) { currentNode.insertBefore(text, nextSibling); } else { currentNode.appendChild(text); } } catch (DOMException err) { throw new XPathException(err); } } /** * Handle a processing instruction. */ public void processingInstruction (String target, CharSequence data, int locationId, int properties) throws XPathException { try { ProcessingInstruction pi = document.createProcessingInstruction(target, data.toString()); if (nextSibling != null && level == 0) { currentNode.insertBefore(pi, nextSibling); } else { currentNode.appendChild(pi); } } catch (DOMException err) { throw new XPathException(err); } } /** * Handle a comment. */ public void comment (CharSequence chars, int locationId, int properties) throws XPathException { try { Comment comment = document.createComment(chars.toString()); if (nextSibling != null && level == 0) { currentNode.insertBefore(comment, nextSibling); } else { currentNode.appendChild(comment); } } catch (DOMException err) { throw new XPathException(err); } } /** * Set the attachment point for the new subtree * @param node the node to which the new subtree will be attached */ public void setNode (Node node) { if (node == null) { return; } currentNode = node; if (node.getNodeType() == Node.DOCUMENT_NODE) { document = (Document)node; } else { document = currentNode.getOwnerDocument(); } } /** * Set next sibling * @param nextSibling the node, which must be a child of the attachment point, before which the new subtree * will be created. If this is null the new subtree will be added after any existing children of the * attachment point. */ public void setNextSibling(Node nextSibling) { this.nextSibling = nextSibling; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/dom/DOMAttributeMap.java0000644000175000017500000001703011033112257021763 0ustar eugeneeugenepackage net.sf.saxon.dom; import net.sf.saxon.om.*; import org.w3c.dom.DOMException; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; /** * Implementation of DOM NamedNodeMap used to represent the attributes of an element, for use when * Saxon element and attribute nodes are accessed using the DOM API. * *

    Note that namespaces are treated as attributes.

    * */ class DOMAttributeMap implements NamedNodeMap { private NodeInfo parent; private int numberOfNamespaces = -1; /** * Construct an AttributeMap for a given element node */ public DOMAttributeMap(NodeInfo parent) { this.parent = parent; } /** * Get named attribute (DOM NamedNodeMap method) */ public Node getNamedItem(String name) { if (name.equals("xmlns")) { int[] nsarray = parent.getDeclaredNamespaces(null); for (int i=0; i>16) & 0xffff) == 0) { NamespaceIterator.NamespaceNodeImpl nn = new NamespaceIterator.NamespaceNodeImpl(parent, nsarray[i], i+1); return NodeOverNodeInfo.wrap(nn); } } return null; } else if (name.startsWith("xmlns:")) { String prefix = name.substring(6); if (prefix.equals("xml")) { NamespaceIterator.NamespaceNodeImpl nn = new NamespaceIterator.NamespaceNodeImpl(parent, NamespaceConstant.XML_CODE, 0); return NodeOverNodeInfo.wrap(nn); } int[] buffer = new int[8]; int[] nsarray = parent.getDeclaredNamespaces(buffer); for (int i=0; i * The class provides read-only access to the tree; methods that request updates all fail * with an UnsupportedOperationException. *

    * Note that contrary to the DOM specification, this implementation does not expose namespace * declarations as attributes. */ public class ElementOverNodeInfo extends NodeOverNodeInfo implements Element { /** * The name of the element (DOM interface). */ public String getTagName() { return node.getDisplayName(); } /** * Returns a NodeList of all descendant Elements * with a given tag name, in document order. * * @param name The name of the tag to match on. The special value "*" * matches all tags. * @return A list of matching Element nodes. */ public NodeList getElementsByTagName(String name) { return DocumentOverNodeInfo.getElementsByTagName(node, name); } /** * Returns a NodeList of all the descendant * Elements with a given local name and namespace URI in * document order. * * @param namespaceURI The namespace URI of the elements to match on. The * special value "*" matches all namespaces. * @param localName The local name of the elements to match on. The * special value "*" matches all local names. * @return A new NodeList object containing all the matched * Elements. * @throws org.w3c.dom.DOMException NOT_SUPPORTED_ERR: May be raised if the implementation does not * support the feature "XML" and the language exposed * through the Document does not support XML Namespaces (such as [HTML 4.01]). * @since DOM Level 2 */ public NodeList getElementsByTagNameNS(String namespaceURI, String localName) throws DOMException { return DocumentOverNodeInfo.getElementsByTagNameNS(node, namespaceURI, localName); } /** * Retrieves an attribute value by name. * This implementation does not expose namespace nodes as attributes. * @param name The QName of the attribute to retrieve. * @return The Attr value as a string, or the empty string if * that attribute does not have a specified or default value. */ public String getAttribute(String name) { AxisIterator atts = node.iterateAxis(Axis.ATTRIBUTE); while (true) { NodeInfo att = (NodeInfo)atts.next(); if (att == null) { return ""; } if (att.getDisplayName().equals(name)) { String val = att.getStringValue(); if (val==null) return ""; return val; } } } /** * Retrieves an attribute node by name. * This implementation does not expose namespace nodes as attributes. *
    To retrieve an attribute node by qualified name and namespace URI, * use the getAttributeNodeNS method. * @param name The name (nodeName ) of the attribute to * retrieve. * @return The Attr node with the specified name ( * nodeName ) or null if there is no such * attribute. */ public Attr getAttributeNode(String name) { AxisIterator atts = node.iterateAxis(Axis.ATTRIBUTE); while (true) { NodeInfo att = (NodeInfo)atts.next(); if (att == null) { return null; } if (att.getDisplayName().equals(name)) { return (Attr)att; } } } /** * Adds a new attribute node. Always fails * @exception org.w3c.dom.DOMException * NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly. */ public Attr setAttributeNode(Attr newAttr) throws DOMException { disallowUpdate(); return null; } /** * Removes the specified attribute. Always fails * @exception org.w3c.dom.DOMException * NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly. */ public void removeAttribute(String oldAttr) throws DOMException { disallowUpdate(); } /** * Removes the specified attribute node. Always fails * @exception org.w3c.dom.DOMException * NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly. */ public Attr removeAttributeNode(Attr oldAttr) throws DOMException { disallowUpdate(); return null; } /** * Retrieves an attribute value by local name and namespace URI. * This implementation does not expose namespace nodes as attributes. * @param namespaceURI The namespace URI of the attribute to retrieve. * @param localName The local name of the attribute to retrieve. * @return The Attr value as a string, or the empty string if * that attribute does not have a specified or default value. * @since DOM Level 2 */ public String getAttributeNS(String namespaceURI, String localName) { String val = Navigator.getAttributeValue(node, (namespaceURI==null ? "" : namespaceURI), localName); if (val==null) return ""; return val; } /** * Adds a new attribute. Always fails * * @param name The name of the attribute to create or alter. * @param value Value to set in string form. * @throws org.w3c.dom.DOMException INVALID_CHARACTER_ERR: Raised if the specified name is not an XML * name according to the XML version in use specified in the * Document.xmlVersion attribute. *
    NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly. */ public void setAttribute(String name, String value) throws DOMException { disallowUpdate(); } /** * Adds a new attribute. Always fails. * @param namespaceURI The namespace URI of the attribute to create or * alter. * @param qualifiedName The qualified name of the attribute to create or * alter. * @param value The value to set in string form. * @exception org.w3c.dom.DOMException * NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly. */ public void setAttributeNS(String namespaceURI, String qualifiedName, String value) throws DOMException { disallowUpdate(); } /** * Removes an attribute by local name and namespace URI. Always fails * @exception org.w3c.dom.DOMException * NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly. * @since DOM Level 2 */ public void removeAttributeNS(String namespaceURI, String localName) throws DOMException{ disallowUpdate(); } /** * Retrieves an Attr node by local name and namespace URI. * This implementation does not expose namespace nodes as attributes. * @param namespaceURI The namespace URI of the attribute to retrieve. * @param localName The local name of the attribute to retrieve. * @return The Attr node with the specified attribute local * name and namespace URI or null if there is no such * attribute. * @since DOM Level 2 */ public Attr getAttributeNodeNS(String namespaceURI, String localName) { NamePool pool = node.getNamePool(); int fingerprint = pool.getFingerprint((namespaceURI==null ? "" : namespaceURI), localName); if (fingerprint==-1) return null; NameTest test = new NameTest(Type.ATTRIBUTE, fingerprint, pool); AxisIterator atts = node.iterateAxis(Axis.ATTRIBUTE, test); return (Attr)wrap((NodeInfo)atts.next()); } /** * Add a new attribute. Always fails. * @param newAttr The Attr node to add to the attribute list. * @return If the newAttr attribute replaces an existing * attribute with the same local name and namespace URI , the * replaced Attr node is returned, otherwise * null is returned. * @exception org.w3c.dom.DOMException *
    NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly. * @since DOM Level 2 */ public Attr setAttributeNodeNS(Attr newAttr) throws DOMException{ disallowUpdate(); return null; } /** * Returns true when an attribute with a given name is * specified on this element or has a default value, false * otherwise. * This implementation does not expose namespace nodes as attributes. * @param name The name of the attribute to look for. * @return true if an attribute with the given name is * specified on this element or has a default value, false * otherwise. * @since DOM Level 2 */ public boolean hasAttribute(String name) { AxisIterator atts = node.iterateAxis(Axis.ATTRIBUTE); while (true) { NodeInfo att = (NodeInfo)atts.next(); if (att == null) { return false; } if (att.getDisplayName().equals(name)) { return true; } } } /** * Returns true when an attribute with a given local name * and namespace URI is specified on this element or has a default value, * false otherwise. * This implementation does not expose namespace nodes as attributes. * @param namespaceURI The namespace URI of the attribute to look for. * @param localName The local name of the attribute to look for. * @return true if an attribute with the given local name and * namespace URI is specified or has a default value on this element, * false otherwise. * @since DOM Level 2 */ public boolean hasAttributeNS(String namespaceURI, String localName) { return (Navigator.getAttributeValue(node, (namespaceURI==null ? "" : namespaceURI), localName) != null); } /** * Mark an attribute as an ID. Always fails. * @throws DOMException */ public void setIdAttribute(String name, boolean isId) throws DOMException{ disallowUpdate(); } /** * Mark an attribute as an ID. Always fails. * @throws DOMException */ public void setIdAttributeNS(String namespaceURI, String localName, boolean isId) throws DOMException{ disallowUpdate(); } /** * Mark an attribute as an ID. Always fails. * @throws DOMException */ public void setIdAttributeNode(Attr idAttr, boolean isId) throws DOMException{ disallowUpdate(); } /** * Get the schema type information for this node. * @return the type information. Returns null for an untyped node. */ public TypeInfo getSchemaTypeInfo() { int annotation = node.getTypeAnnotation(); if (annotation == -1) { return null; } final Configuration config = node.getConfiguration(); return new TypeInfoImpl(config, config.getSchemaType(annotation)); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. //saxonb-9.1.0.8/bj/net/sf/saxon/dom/DOMExceptionImpl.java0000644000175000017500000000551611033112257022150 0ustar eugeneeugenepackage net.sf.saxon.dom; import org.w3c.dom.DOMException; /** * DOM operations only raise exceptions in "exceptional" circumstances, * i.e., when an operation is impossible to perform (either for logical * reasons, because data is lost, or because the implementation has become * unstable). In general, DOM methods return specific error values in ordinary * processing situations, such as out-of-bound errors when using * NodeList . *

    Implementations may raise other exceptions under other circumstances. * For example, implementations may raise an implementation-dependent * exception if a null argument is passed. *

    See also the Document Object Model (DOM) Level 2 Specification. */ public class DOMExceptionImpl extends DOMException { public DOMExceptionImpl (short code, String message) { super(code, message); //this.code = code; } public short code; // ExceptionCode // public static final short INDEX_SIZE_ERR = 1; // public static final short DOMSTRING_SIZE_ERR = 2; // public static final short HIERARCHY_REQUEST_ERR = 3; // public static final short WRONG_DOCUMENT_ERR = 4; // public static final short INVALID_CHARACTER_ERR = 5; // public static final short NO_DATA_ALLOWED_ERR = 6; // public static final short NO_MODIFICATION_ALLOWED_ERR = 7; // public static final short NOT_FOUND_ERR = 8; // public static final short NOT_SUPPORTED_ERR = 9; // public static final short INUSE_ATTRIBUTE_ERR = 10; /** * @since DOM Level 2 */ public static final short INVALID_STATE_ERR = 11; /** * @since DOM Level 2 */ public static final short SYNTAX_ERR = 12; /** * @since DOM Level 2 */ public static final short INVALID_MODIFICATION_ERR = 13; /** * @since DOM Level 2 */ public static final short NAMESPACE_ERR = 14; /** * @since DOM Level 2 */ public static final short INVALID_ACCESS_ERR = 15; } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none //saxonb-9.1.0.8/bj/net/sf/saxon/dom/DOMObjectModel.java0000644000175000017500000005760011174043730021565 0ustar eugeneeugenepackage net.sf.saxon.dom; import net.sf.saxon.Configuration; import net.sf.saxon.event.PipelineConfiguration; import net.sf.saxon.event.Receiver; import net.sf.saxon.expr.JPConverter; import net.sf.saxon.expr.PJConverter; import net.sf.saxon.expr.StaticProperty; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.*; import net.sf.saxon.pattern.AnyNodeTest; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ItemType; import net.sf.saxon.value.SequenceExtent; import net.sf.saxon.value.Value; import net.sf.saxon.xpath.XPathEvaluator; import org.w3c.dom.Document; import org.w3c.dom.DocumentFragment; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import javax.xml.namespace.NamespaceContext; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.Result; import javax.xml.transform.Source; import javax.xml.transform.dom.DOMResult; import javax.xml.transform.dom.DOMSource; import javax.xml.xpath.XPathConstants; import java.io.Serializable; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.*; /** * This interface must be implemented by any third-party object model that can * be wrapped with a wrapper that implements the Saxon Object Model (the NodeInfo interface). * This implementation of the interface supports wrapping of DOM Documents. */ public class DOMObjectModel implements ExternalObjectModel, Serializable { private static DOMObjectModel THE_INSTANCE = new DOMObjectModel(); /** * Get a reusable instance instance of this class. *

    Note, this is not actually a singleton instance; the class also has a public constructor, * which is needed to support the automatic loading of object models into the Configuration.

    * @return the singleton instance */ public static DOMObjectModel getInstance() { return THE_INSTANCE; } /** * In JDK 1.5, the DOMResult object has a nextSibling property */ private static Method nextSiblingMethod; private static boolean nextSiblingMethodUnavailable = false; static { try { //noinspection RedundantArrayCreation nextSiblingMethod = DOMResult.class.getMethod("getNextSibling", new Class[]{}); } catch (NoSuchMethodException err) { nextSiblingMethodUnavailable = true; } } /** * Create an instance of the DOMObjectModel class. *

    When possible, use the getInstance() method in preference, as the instance is then reusable.

    */ public DOMObjectModel() {} /** * Get the URI of the external object model as used in the JAXP factory interfaces for obtaining * an XPath implementation */ public String getIdentifyingURI() { return XPathConstants.DOM_OBJECT_MODEL; } /** * Get a converter from XPath values to values in the external object model * @param targetClass the required class of the result of the conversion. If this class represents * a node or list of nodes in the external object model, the method should return a converter that takes * a native node or sequence of nodes as input and returns a node or sequence of nodes in the * external object model representation. Otherwise, it should return null. * @return a converter, if the targetClass is recognized as belonging to this object model; * otherwise null */ public PJConverter getPJConverter(Class targetClass) { if (Node.class.isAssignableFrom(targetClass) && !(NodeOverNodeInfo.class.isAssignableFrom(targetClass))) { return new PJConverter() { public Object convert(ValueRepresentation value, Class targetClass, XPathContext context) throws XPathException { return convertXPathValueToObject(Value.asValue(value), targetClass, context); } }; } else if (NodeList.class == targetClass) { return new PJConverter() { public Object convert(ValueRepresentation value, Class targetClass, XPathContext context) throws XPathException { return convertXPathValueToObject(Value.asValue(value), targetClass, context); } }; } else { return null; } } public JPConverter getJPConverter(Class targetClass) { if (Node.class.isAssignableFrom(targetClass) && !(NodeOverNodeInfo.class.isAssignableFrom(targetClass))) { return new JPConverter() { public ValueRepresentation convert(Object obj, XPathContext context) throws XPathException { return wrapOrUnwrapNode((Node)obj, context.getConfiguration()); } public ItemType getItemType() { return AnyNodeTest.getInstance(); } }; } else if (NodeList.class.isAssignableFrom(targetClass)) { return new JPConverter() { public ValueRepresentation convert(Object obj, XPathContext context) throws XPathException { Configuration config = context.getConfiguration(); NodeList list = ((NodeList)obj); final int len = list.getLength(); NodeInfo[] nodes = new NodeInfo[len]; for (int i=0; iunwrap it. * @param node a node (any node) in the third party document * @param baseURI the base URI of the node (supply "" if unknown) * @param config the Saxon configuration (which among other things provides access to the NamePool) * @return the wrapper, which must implement DocumentInfo */ private DocumentInfo wrapDocument(Object node, String baseURI, Configuration config) { if (node instanceof DocumentOverNodeInfo) { return (DocumentInfo)((DocumentOverNodeInfo)node).getUnderlyingNodeInfo(); } if (node instanceof NodeOverNodeInfo) { return ((NodeOverNodeInfo)node).getUnderlyingNodeInfo().getDocumentRoot(); } if (node instanceof org.w3c.dom.Node) { if (((Node)node).getNodeType() == Node.DOCUMENT_NODE) { Document doc = (org.w3c.dom.Document)node; return new DocumentWrapper(doc, baseURI, config); } else if (((Node)node).getNodeType() == Node.DOCUMENT_FRAGMENT_NODE) { DocumentFragment doc = (org.w3c.dom.DocumentFragment)node; return new DocumentWrapper(doc, baseURI, config); } else { Document doc = ((org.w3c.dom.Node)node).getOwnerDocument(); return new DocumentWrapper(doc, baseURI, config); } } throw new IllegalArgumentException("Unknown node class " + node.getClass()); } /** * Wrap a node within the external object model in a node wrapper that implements the Saxon * VirtualNode interface (which is an extension of NodeInfo) * @param document the document wrapper, as a DocumentInfo object * @param node the node to be wrapped. This must be a node within the document wrapped by the * DocumentInfo provided in the first argument * @return the wrapper for the node, as an instance of VirtualNode */ private NodeInfo wrapNode(DocumentInfo document, Object node) { return ((DocumentWrapper)document).wrap((Node)node); } /** * Test showing a DOM NodeList returned by an extension function */ public static void main (String[] args) throws Exception { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setNamespaceAware(true); DocumentBuilder db = factory.newDocumentBuilder(); Document doc = db.newDocument(); XPathEvaluator xpe = new XPathEvaluator(); String exp = "ext:sortArrayToNodeList(('fred', 'jane', 'anne', 'sue'))"; xpe.setNamespaceContext(new NamespaceContext() { public String getNamespaceURI(String prefix) { return (prefix.equals("ext") ? "java:net.sf.saxon.dom.DOMObjectModel" : null); } public String getPrefix(String namespaceURI) { return null; } public Iterator getPrefixes(String namespaceURI) { return null; } }); NodeList isList = (NodeList)xpe.evaluate(exp, doc, XPathConstants.NODESET); System.err.println("length " + isList.getLength()); } /** * Sample extension function * @param source * @return * @throws Exception */ public static NodeList sortArrayToNodeList(net.sf.saxon.value.Value source) throws Exception { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setNamespaceAware(true); DocumentBuilder db = factory.newDocumentBuilder(); Document doc = db.newDocument(); String[] items = new String[source.getLength()]; for (int i = 0; i < source.getLength(); i++) { items[i] = source.itemAt(i).getStringValue(); } Arrays.sort(items); List list = new ArrayList(); for (int i = 0; i < items.length; i++) { list.add(doc.createTextNode(items[i])); } DOMNodeList resultSet = new DOMNodeList(list); return resultSet; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): Gunther Schadow (changes to allow access to public fields; also wrapping // of extensions and mapping of null to empty sequence). // saxonb-9.1.0.8/bj/net/sf/saxon/dom/NodeOverNodeInfo.java0000644000175000017500000005770111033112257022176 0ustar eugeneeugenepackage net.sf.saxon.dom; import net.sf.saxon.functions.DeepEqual; import net.sf.saxon.om.*; import net.sf.saxon.sort.GenericAtomicComparer; import net.sf.saxon.sort.CodepointCollator; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.Type; import org.w3c.dom.*; import java.util.ArrayList; import java.util.List; /** * This class implements the DOM Node interface as a wrapper around a Saxon NodeInfo object. *

    * The class provides read-only access to the tree; methods that request updates all fail * with an UnsupportedOperationException. */ public abstract class NodeOverNodeInfo implements Node { protected NodeInfo node; /** * Get the Saxon NodeInfo object representing this node * @return the Saxon NodeInfo object */ public NodeInfo getUnderlyingNodeInfo() { return node; } /** * Factory method to construct a DOM node that wraps an underlying Saxon NodeInfo * @param node the Saxon NodeInfo object * @return the DOM wrapper node */ public static NodeOverNodeInfo wrap(NodeInfo node) { NodeOverNodeInfo n; if (node == null) { return null; } switch (node.getNodeKind()) { case Type.DOCUMENT: n = new DocumentOverNodeInfo(); break; case Type.ELEMENT: n = new ElementOverNodeInfo(); break; case Type.ATTRIBUTE: n = new AttrOverNodeInfo(); break; case Type.TEXT: case Type.COMMENT: n = new TextOverNodeInfo(); break; case Type.PROCESSING_INSTRUCTION: n = new PIOverNodeInfo(); break; case Type.NAMESPACE: n = new AttrOverNodeInfo(); break; default: return null; } n.node = node; return n; } /** * Determine whether this is the same node as another node. DOM Level 3 method. * @return true if this Node object and the supplied Node object represent the * same node in the tree. */ public final boolean isSameNode(Node other) { return other instanceof NodeOverNodeInfo && node.isSameNodeInfo(((NodeOverNodeInfo)other).node); } /** * Get the base URI for the node. Default implementation for child nodes gets * the base URI of the parent node. */ public String getBaseURI() { return node.getBaseURI(); } /** * Get the name of this node, following the DOM rules * @return The name of the node. For an element this is the element name, for an attribute * it is the attribute name, as a lexical QName. Other node types return conventional names such * as "#text" or "#comment" */ public String getNodeName() { switch (node.getNodeKind()) { case Type.DOCUMENT: return "#document"; case Type.ELEMENT: return node.getDisplayName(); case Type.ATTRIBUTE: return node.getDisplayName(); case Type.TEXT: return "#text"; case Type.COMMENT: return "#comment"; case Type.PROCESSING_INSTRUCTION: return node.getLocalPart(); case Type.NAMESPACE: if (node.getLocalPart().length() == 0) { return "xmlns"; } else { return "xmlns:" + node.getLocalPart(); } default: return "#unknown"; } } /** * Get the local name of this node, following the DOM rules * @return The local name of the node. For an element this is the local part of the element name, * for an attribute it is the local part of the attribute name. Other node types return null. */ public String getLocalName() { switch (node.getNodeKind()) { case Type.ELEMENT: case Type.ATTRIBUTE: return node.getLocalPart(); case Type.DOCUMENT: case Type.TEXT: case Type.COMMENT: case Type.PROCESSING_INSTRUCTION: return null; case Type.NAMESPACE: if (node.getLocalPart().length() == 0) { return "xmlns"; } else { return node.getLocalPart(); } default: return null; } } /** * Determine whether the node has any children. * @return true if this node has any attributes, * false otherwise. */ public boolean hasChildNodes() { return node.iterateAxis(Axis.CHILD).next() != null; } /** * Returns whether this node has any attributes. We treat the declaration of the XML namespace * as being present on every element, and since namespace declarations are treated as attributes, * every element has at least one attribute. This method therefore returns true. * @return true if this node has any attributes, * false otherwise. * @since DOM Level 2 */ public boolean hasAttributes() { return true; } /** * Get the type of this node (node kind, in XPath terminology). * Note, the numbers assigned to node kinds * in Saxon (see {@link Type}) are the same as those assigned in the DOM */ public short getNodeType() { short kind = (short)node.getNodeKind(); if (kind == Type.NAMESPACE) { return Type.ATTRIBUTE; } else { return kind; } } /** * Find the parent node of this node. * @return The Node object describing the containing element or root node. */ public Node getParentNode() { return wrap(node.getParent()); } /** * Get the previous sibling of the node * @return The previous sibling node. Returns null if the current node is the first * child of its parent. */ public Node getPreviousSibling() { return wrap((NodeInfo)node.iterateAxis(Axis.PRECEDING_SIBLING).next()); } /** * Get next sibling node * @return The next sibling node. Returns null if the current node is the last * child of its parent. */ public Node getNextSibling() { return wrap((NodeInfo)node.iterateAxis(Axis.FOLLOWING_SIBLING).next()); } /** * Get first child * @return the first child node of this node, or null if it has no children */ public Node getFirstChild() { return wrap((NodeInfo)node.iterateAxis(Axis.CHILD).next()); } /** * Get last child * @return last child of this node, or null if it has no children */ public Node getLastChild() { AxisIterator children = node.iterateAxis(Axis.CHILD); NodeInfo last = null; while (true) { NodeInfo next = (NodeInfo)children.next(); if (next == null) { return wrap(last); } else { last = next; } } } /** * Get the node value (as defined in the DOM). * This is not generally the same as the XPath string-value: in particular, the * node value of an element node is null. */ public String getNodeValue() { switch (node.getNodeKind()) { case Type.DOCUMENT: case Type.ELEMENT: return null; case Type.ATTRIBUTE: case Type.TEXT: case Type.COMMENT: case Type.PROCESSING_INSTRUCTION: case Type.NAMESPACE: return node.getStringValue(); default: return null; } } /** * Set the node value. Always fails */ public void setNodeValue(String nodeValue) throws DOMException { disallowUpdate(); } /** * Return a NodeList that contains all children of this node. If * there are no children, this is a NodeList containing no * nodes. */ public NodeList getChildNodes() { try { List nodes = new ArrayList(10); SequenceIterator iter = node.iterateAxis(Axis.CHILD); while (true) { NodeInfo node = (NodeInfo)iter.next(); if (node == null) break; nodes.add(NodeOverNodeInfo.wrap(node)); } return new DOMNodeList(nodes); } catch (XPathException err) { return null; // can't happen } } /** * Return a NamedNodeMap containing the attributes of this node (if * it is an Element) or null otherwise. Note that this * implementation changed in Saxon 8.8 to treat namespace declarations as attributes. */ public NamedNodeMap getAttributes() { if (node.getNodeKind()==Type.ELEMENT) { return new DOMAttributeMap(node); } else { return null; } } /** * Return the Document object associated with this node. */ public Document getOwnerDocument() { return (Document)wrap(node.getDocumentRoot()); } /** * Insert the node newChild before the existing child node * refChild. Always fails. * @param newChild The node to insert. * @param refChild The reference node, i.e., the node before which the * new node must be inserted. * @return The node being inserted. * @exception org.w3c.dom.DOMException * NO_MODIFICATION_ALLOWED_ERR: Always raised. */ public Node insertBefore(Node newChild, Node refChild) throws DOMException { disallowUpdate(); return null; } /** * Replace the child node oldChild with * newChild in the list of children, and returns the * oldChild node. Always fails. * @param newChild The new node to put in the child list. * @param oldChild The node being replaced in the list. * @return The node replaced. * @exception org.w3c.dom.DOMException * NO_MODIFICATION_ALLOWED_ERR: Always raised. */ public Node replaceChild(Node newChild, Node oldChild) throws DOMException{ disallowUpdate(); return null; } /** * Remove the child node indicated by oldChild from the * list of children, and returns it. Always fails. * @param oldChild The node being removed. * @return The node removed. * @exception org.w3c.dom.DOMException * NO_MODIFICATION_ALLOWED_ERR: Always raised. */ public Node removeChild(Node oldChild) throws DOMException { disallowUpdate(); return null; } /** * Adds the node newChild to the end of the list of children * of this node. Always fails. * @param newChild The node to add. * @return The node added. * @exception org.w3c.dom.DOMException *
    NO_MODIFICATION_ALLOWED_ERR: Always raised. */ public Node appendChild(Node newChild) throws DOMException { disallowUpdate(); return null; } /** * Returns a duplicate of this node, i.e., serves as a generic copy * constructor for nodes. Always fails. * @param deep If true , recursively clone the subtree under * the specified node; if false , clone only the node * itself (and its attributes, if it is an Element ). * @return The duplicate node. */ public Node cloneNode(boolean deep) { disallowUpdate(); return null; } /** * Puts all Text nodes in the full depth of the sub-tree * underneath this Node, including attribute nodes, into a * "normal" form where only structure (e.g., elements, comments, * processing instructions, CDATA sections, and entity references) * separates Text nodes, i.e., there are neither adjacent * Text nodes nor empty Text nodes. * @since DOM Level 2 */ public void normalize() { // null operation; nodes are always normalized } /** * Tests whether the DOM implementation implements a specific feature and * that feature is supported by this node. * @param feature The name of the feature to test. This is the same name * which can be passed to the method hasFeature on * DOMImplementation . * @param version This is the version number of the feature to test. In * Level 2, version 1, this is the string "2.0". If the version is not * specified, supporting any version of the feature will cause the * method to return true . * @return Returns true if the specified feature is supported * on this node, false otherwise. * @since DOM Level 2 */ public boolean isSupported(String feature, String version) { return (feature.equalsIgnoreCase("XML") || feature.equalsIgnoreCase("Core")) && (version == null || version.length() == 0 || version.equals("3.0") || version.equals("2.0") || version.equals("1.0")); } /** * The namespace URI of this node, or null if it is * unspecified. *
    This is not a computed value that is the result of a namespace * lookup based on an examination of the namespace declarations in scope. * It is merely the namespace URI given at creation time. *
    For nodes of any type other than ELEMENT_NODE and * ATTRIBUTE_NODE and nodes created with a DOM Level 1 * method, such as createElement from the * Document interface, this is always null . * Per the Namespaces in XML Specification an attribute does not * inherit its namespace from the element it is attached to. If an * attribute is not explicitly given a namespace, it simply has no * namespace. * @since DOM Level 2 */ public String getNamespaceURI() { if (node.getNodeKind() == Type.NAMESPACE) { if (node.getLocalPart().length() == 0) { return NamespaceConstant.XMLNS; //TODO: should be NamespaceConstant.XMLNS; } else { return NamespaceConstant.XMLNS; } } String uri = node.getURI(); return ("".equals(uri) ? null : uri); } /** * The namespace prefix of this node, or null if it is * unspecified. *
    For nodes of any type other than ELEMENT_NODE and * ATTRIBUTE_NODE and nodes created with a DOM Level 1 * method, such as createElement from the * Document interface, this is always null. * * @since DOM Level 2 */ public String getPrefix() { if (node.getNodeKind() == Type.NAMESPACE) { if (node.getLocalPart().length() == 0) { return null; } else { return "xmlns"; } } String p = node.getNamePool().getPrefix(node.getNameCode()); return ("".equals(p) ? null : p); } /** * Set the namespace prefix of this node. Always fails. */ public void setPrefix(String prefix) throws DOMException { disallowUpdate(); } /** * Compare the position of the (other) node in document order with the reference node (this node). * DOM Level 3 method. * @param other the other node. * @return Returns how the node is positioned relatively to the reference * node. * @throws org.w3c.dom.DOMException */ public short compareDocumentPosition(Node other) throws DOMException { final short DOCUMENT_POSITION_DISCONNECTED = 0x01; final short DOCUMENT_POSITION_PRECEDING = 0x02; final short DOCUMENT_POSITION_FOLLOWING = 0x04; final short DOCUMENT_POSITION_CONTAINS = 0x08; final short DOCUMENT_POSITION_CONTAINED_BY = 0x10; if (!(other instanceof NodeOverNodeInfo)) { return DOCUMENT_POSITION_DISCONNECTED; } int c = node.compareOrder(((NodeOverNodeInfo)other).node); if (c==0) { return (short)0; } else if (c==-1) { // TODO: This logic must be wrong: the value of "d" doesn't contribute to the result... short d = compareDocumentPosition(other.getParentNode()); short result = DOCUMENT_POSITION_FOLLOWING; if (d==0 || (d&DOCUMENT_POSITION_CONTAINED_BY) != 0) { d |= DOCUMENT_POSITION_CONTAINED_BY; } return result; } else if (c==+1) { short d = getParentNode().compareDocumentPosition(other); short result = DOCUMENT_POSITION_PRECEDING; if (d==0 || (d&DOCUMENT_POSITION_CONTAINS) != 0) { d |= DOCUMENT_POSITION_CONTAINS; } return result; } else { throw new AssertionError(); } } /** * Get the text content of a node. This is a DOM Level 3 method. The definition * is the same as the definition of the string value of a node in XPath, except * in the case of document nodes. * @return the string value of the node, or null in the case of document nodes. * @throws org.w3c.dom.DOMException */ public String getTextContent() throws DOMException { if (node.getNodeKind() == Type.DOCUMENT) { return null; } else { return node.getStringValue(); } } /** * Set the text content of a node. Always fails. * @param textContent the new text content of the node * @throws org.w3c.dom.DOMException */ public void setTextContent(String textContent) throws DOMException { disallowUpdate(); } /** * Get the (first) prefix assigned to a specified namespace URI, or null * if the namespace is not in scope. DOM Level 3 method. * @param namespaceURI the namespace whose prefix is required * @return the corresponding prefix, if there is one, or null if not. */ public String lookupPrefix(String namespaceURI){ if (node.getNodeKind() == Type.DOCUMENT) { return null; } else if (node.getNodeKind() == Type.ELEMENT) { AxisIterator iter = node.iterateAxis(Axis.NAMESPACE); while (true) { NodeInfo ns = (NodeInfo)iter.next(); if (ns==null) { return null; } if (ns.getStringValue().equals(namespaceURI)) { return ns.getLocalPart(); } } } else { return getParentNode().lookupPrefix(namespaceURI); } } /** * Test whether a particular namespace is the default namespace. * DOM Level 3 method. * @param namespaceURI the namespace to be tested * @return true if this is the default namespace */ public boolean isDefaultNamespace(String namespaceURI) { return namespaceURI.equals(lookupNamespaceURI("")); } /** * Find the URI corresponding to a given in-scope prefix * @param prefix The namespace prefix whose namespace URI is required. * @return the corresponding namespace URI, or null if the prefix is * not declared. */ public String lookupNamespaceURI(String prefix) { if (node.getNodeKind() == Type.DOCUMENT) { return null; } else if (node.getNodeKind() == Type.ELEMENT) { AxisIterator iter = node.iterateAxis(Axis.NAMESPACE); while (true) { NodeInfo ns = (NodeInfo)iter.next(); if (ns==null) { return null; } if (ns.getLocalPart().equals(prefix)) { return ns.getStringValue(); } } } else { return getParentNode().lookupNamespaceURI(prefix); } } /** * Compare whether two nodes have the same content. This is a DOM Level 3 method. * @param arg The node to be compared. This must wrap a Saxon NodeInfo. * @return true if the two nodes are deep-equal. */ public boolean isEqualNode(Node arg) { if (!(arg instanceof NodeOverNodeInfo)) { throw new IllegalArgumentException("Other Node must wrap a Saxon NodeInfo"); } return DeepEqual.deepEquals( SingletonIterator.makeIterator(node), SingletonIterator.makeIterator(((NodeOverNodeInfo)arg).node), new GenericAtomicComparer(CodepointCollator.getInstance(), node.getConfiguration().getConversionContext()), node.getConfiguration(), DeepEqual.INCLUDE_PREFIXES | DeepEqual.INCLUDE_COMMENTS | DeepEqual.COMPARE_STRING_VALUES | DeepEqual.INCLUDE_PROCESSING_INSTRUCTIONS); } /** * Get a feature of this node. DOM Level 3 method, always returns null. * @param feature the required feature * @param version the version of the required feature * @return the value of the feature. Always null in this implementation */ public Object getFeature(String feature, String version) { return null; } /** * Set user data. Always throws UnsupportedOperationException in this implementation * @param key name of the user data * @param data value of the user data * @param handler handler for the user data * @return This implementation always throws an exception */ public Object setUserData(String key, Object data, UserDataHandler handler) { disallowUpdate(); return null; } /** * Get user data associated with this node. DOM Level 3 method, always returns * null in this implementation * @param key identifies the user data required * @return always null in this implementation */ public Object getUserData(String key) { return null; } /** * Internal method used to indicate that update operations are not allowed */ protected static void disallowUpdate() throws DOMException { throw new UnsupportedOperationException("The Saxon DOM cannot be updated"); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/dom/PIOverNodeInfo.java0000644000175000017500000000404611033112257021613 0ustar eugeneeugenepackage net.sf.saxon.dom; import org.w3c.dom.DOMException; import org.w3c.dom.ProcessingInstruction; /** * This class is an implementation of the DOM ProcessingInstruction interface that wraps a Saxon NodeInfo * representation of a text or comment node. */ public class PIOverNodeInfo extends NodeOverNodeInfo implements ProcessingInstruction { /** * The target of this processing instruction. XML defines this as being * the first token following the markup that begins the processing * instruction. */ public String getTarget() { return node.getLocalPart(); } /** * The content of this processing instruction. This is from the first non * white space character after the target to the character immediately * preceding the ?>. */ public String getData() { return node.getStringValue(); } /** * The content of this processing instruction. This is from the first non * white space character after the target to the character immediately * preceding the ?>. * * @throws org.w3c.dom.DOMException NO_MODIFICATION_ALLOWED_ERR: Raised when the node is readonly. */ public void setData(String data) throws DOMException { disallowUpdate(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. //saxonb-9.1.0.8/bj/net/sf/saxon/dom/DOMTransform.java0000644000175000017500000000566111033112257021344 0ustar eugeneeugenepackage net.sf.saxon.dom; import net.sf.saxon.Transform; import net.sf.saxon.trans.XPathException; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.stream.StreamSource; import java.io.IOException; import java.util.ArrayList; import java.util.List; /** * Variant of command line net.sf.saxon.Transform do build the source document * in DOM and then proceed with the transformation. This class is provided largely for * testing purposes. */ public class DOMTransform extends Transform { public List preprocess(List sources) throws XPathException { try { ArrayList domSources = new ArrayList(sources.size()); for (int i=0; ioffset and * count exceeds the length , then all 16-bit * units to the end of the data are returned. * @exception org.w3c.dom.DOMException * INDEX_SIZE_ERR: Raised if the specified offset is * negative or greater than the number of 16-bit units in * data , or if the specified count is * negative. */ public String substringData(int offset, int count) throws DOMException { try { return node.getStringValue().substring(offset, offset+count); } catch (IndexOutOfBoundsException err2) { throw new DOMExceptionImpl(DOMException.INDEX_SIZE_ERR, "substringData: index out of bounds"); } } /** * Append the string to the end of the character data of the node. * DOM method: always fails. * @param arg The DOMString to append. * @exception org.w3c.dom.DOMException * NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly. */ public void appendData(String arg) throws DOMException { disallowUpdate(); } /** * Insert a string at the specified character offset. * DOM method: always fails. * @param offset The character offset at which to insert. * @param arg The DOMString to insert. * @exception org.w3c.dom.DOMException */ public void insertData(int offset, String arg) throws DOMException { disallowUpdate(); } /** * Remove a range of 16-bit units from the node. * DOM method: always fails. * @param offset The offset from which to start removing. * @param count The number of 16-bit units to delete. * @exception org.w3c.dom.DOMException */ public void deleteData(int offset, int count) throws DOMException { disallowUpdate(); } /** * Replace the characters starting at the specified 16-bit unit offset * with the specified string. DOM method: always fails. * @param offset The offset from which to start replacing. * @param count The number of 16-bit units to replace. * @param arg The DOMString with which the range must be * replaced. * @exception org.w3c.dom.DOMException * NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly. */ public void replaceData(int offset, int count, String arg) throws DOMException { disallowUpdate(); } /** * Break this node into two nodes at the specified offset, * keeping both in the tree as siblings. DOM method, always fails. * @param offset The 16-bit unit offset at which to split, starting from 0. * @return The new node, of the same type as this node. * @exception org.w3c.dom.DOMException */ public Text splitText(int offset) throws DOMException { disallowUpdate(); return null; } /** * Replaces the text of the current node and all logically-adjacent text * nodes with the specified text. All logically-adjacent text nodes are * removed including the current node unless it was the recipient of the * replacement text. *
    This method returns the node which received the replacement text. * The returned node is: *

      *
    • null, when the replacement text is * the empty string; *
    • *
    • the current node, except when the current node is * read-only; *
    • *
    • a new Text node of the same type ( * Text or CDATASection) as the current node * inserted at the location of the replacement. *
    • *
    *
    For instance, in the above example calling * replaceWholeText on the Text node that * contains "bar" with "yo" in argument results in the following: *
    Where the nodes to be removed are read-only descendants of an * EntityReference, the EntityReference must * be removed instead of the read-only nodes. If any * EntityReference to be removed has descendants that are * not EntityReference, Text, or * CDATASection nodes, the replaceWholeText * method must fail before performing any modification of the document, * raising a DOMException with the code * NO_MODIFICATION_ALLOWED_ERR. *
    For instance, in the example below calling * replaceWholeText on the Text node that * contains "bar" fails, because the EntityReference node * "ent" contains an Element node which cannot be removed. * * @param content The content of the replacing Text node. * @return The Text node created with the specified content. * @throws org.w3c.dom.DOMException NO_MODIFICATION_ALLOWED_ERR: Raised if one of the Text * nodes being replaced is readonly. * @since DOM Level 3 */ public Text replaceWholeText(String content) throws DOMException { disallowUpdate(); return null; } /** * Returns whether this text node contains * element content whitespace, often abusively called "ignorable whitespace". The text node is * determined to contain whitespace in element content during the load * of the document or if validation occurs while using * Document.normalizeDocument(). * * @since DOM Level 3 */ public boolean isElementContentWhitespace() { if (node.getNodeKind() != Type.TEXT) { throw new UnsupportedOperationException("Method is defined only on text nodes"); } int annotation = node.getParent().getTypeAnnotation(); if (annotation == -1) { return false; } if (!Whitespace.isWhite(node.getStringValue())) { return false; } SchemaType type = node.getConfiguration().getSchemaType(annotation); if (!type.isComplexType()) { return false; } if (((ComplexType)type).isMixedContent()) { return false; } return true; } /** * Returns all text of Text nodes logically-adjacent text * nodes to this node, concatenated in document order. *
    For instance, in the example below wholeText on the * Text node that contains "bar" returns "barfoo", while on * the Text node that contains "foo" it returns "barfoo". * * @since DOM Level 3 */ public String getWholeText() { if (node.getNodeKind() != Type.TEXT) { throw new UnsupportedOperationException("Method is defined only on text nodes"); } return node.getStringValue(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. //saxonb-9.1.0.8/bj/net/sf/saxon/dom/DocumentWrapper.java0000644000175000017500000001271511157707417022165 0ustar eugeneeugenepackage net.sf.saxon.dom; import net.sf.saxon.Configuration; import net.sf.saxon.om.DocumentInfo; import net.sf.saxon.om.NamePool; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.type.Type; import org.w3c.dom.Document; import org.w3c.dom.Node; import java.util.Collections; import java.util.Iterator; /** * The document node of a tree implemented as a wrapper around a DOM Document. */ public class DocumentWrapper extends NodeWrapper implements DocumentInfo { protected Configuration config; protected String baseURI; protected int documentNumber; protected boolean domLevel3; /** * Wrap a DOM Document or DocumentFragment node * @param doc a DOM Document or DocumentFragment node * @param baseURI the base URI of the document * @param config the Saxon configuration */ public DocumentWrapper(Node doc, String baseURI, Configuration config) { super(doc, null, 0); if (doc.getNodeType() != Node.DOCUMENT_NODE && doc.getNodeType() != Node.DOCUMENT_FRAGMENT_NODE) { throw new IllegalArgumentException("Node must be a DOM Document or DocumentFragment"); } node = doc; nodeKind = Type.DOCUMENT; this.baseURI = baseURI; docWrapper = this; domLevel3 = config.getDOMLevel() == 3; setConfiguration(config); } /** * Create a wrapper for a node in this document * * @param node the DOM node to be wrapped. This must be a node within the document wrapped by this * DocumentWrapper * @throws IllegalArgumentException if the node is not a descendant of the Document node wrapped by * this DocumentWrapper */ public NodeWrapper wrap(Node node) { if (node == this.node) { return this; } Document doc = node.getOwnerDocument(); if (doc == this.node || (domLevel3 && doc != null && doc.isSameNode(this.node))) { return makeWrapper(node, this); } else { throw new IllegalArgumentException( "DocumentWrapper#wrap: supplied node does not belong to the wrapped DOM document"); } } /** * Set the Configuration that contains this document */ public void setConfiguration(Configuration config) { this.config = config; documentNumber = config.getDocumentNumberAllocator().allocateDocumentNumber(); } /** * Get the configuration previously set using setConfiguration */ public Configuration getConfiguration() { return config; } /** * Get the name pool used for the names in this document */ public NamePool getNamePool() { return config.getNamePool(); } /** * Get the unique document number */ public int getDocumentNumber() { return documentNumber; } /** * Get the element with a given ID, if any * * @param id the required ID value * @return a NodeInfo representing the element with the given ID, or null if there * is no such element. This implementation does not necessarily conform to the * rule that if an invalid document contains two elements with the same ID, the one * that comes last should be returned. */ public NodeInfo selectID(String id) { if (node instanceof Document) { Node el = ((Document)node).getElementById(id); if (el == null) { return null; } return wrap(el); } else { return null; } } /** * Determine whether this is the same node as another node.
    * Note: a.isSameNode(b) if and only if generateId(a)==generateId(b) * * @return true if this Node object and the supplied Node object represent the * same node in the tree. */ public boolean isSameNodeInfo(NodeInfo other) { if (!(other instanceof DocumentWrapper)) { return false; } return node == ((DocumentWrapper)other).node; } /** * Get the list of unparsed entities defined in this document * @return an Iterator, whose items are of type String, containing the names of all * unparsed entities defined in this document. If there are no unparsed entities or if the * information is not available then an empty iterator is returned */ public Iterator getUnparsedEntityNames() { return Collections.EMPTY_LIST.iterator(); } /** * Get the unparsed entity with a given name * * @param name the name of the entity * @return null: JDOM does not provide access to unparsed entities */ public String[] getUnparsedEntity(String name) { return null; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/dom/AttrOverNodeInfo.java0000644000175000017500000001133311033112257022212 0ustar eugeneeugenepackage net.sf.saxon.dom; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.pattern.ContentTypeTest; import net.sf.saxon.type.BuiltInAtomicType; import net.sf.saxon.type.Type; import org.w3c.dom.*; import java.util.ArrayList; import java.util.List; /** * This class is an implementation of the DOM Attr class that wraps a Saxon NodeInfo * representation of an attribute or namespace node. */ public class AttrOverNodeInfo extends NodeOverNodeInfo implements Attr { /** * Get the name of an attribute node (the lexical QName) (DOM method) */ public String getName() { if (node.getNodeKind() == Type.NAMESPACE) { String local = node.getLocalPart(); if (local.equals("")) { return "xmlns"; } else { return "xmlns:" + local; } } return node.getDisplayName(); } /** * Return the character value of an attribute node (DOM method) * @return the attribute value */ public String getValue() { return node.getStringValue(); } /** * Determine whether the node has any children. * @return true: a DOM Attribute has a text node as a child. */ public boolean hasChildNodes() { return true; } /** * Get first child * @return the first child node of this node. In this model an attribute node always has a single text * node as its child. */ public Node getFirstChild() { return new TextOverAttrInfo(this); } /** * Get last child * * @return last child of this node, or null if it has no children */ public Node getLastChild() { return getFirstChild(); } /** * Return a NodeList that contains all children of this node. If * there are no children, this is a NodeList containing no * nodes. */ public NodeList getChildNodes() { List list = new ArrayList(1); list.add(getFirstChild()); return new DOMNodeList(list); } /** * If this attribute was explicitly given a value in the original * document, this is true ; otherwise, it is * false. (DOM method) * @return Always true in this implementation. */ public boolean getSpecified() { return true; } /** * Set the value of an attribute node. (DOM method). * Always fails (because tree is readonly) */ public void setValue(String value) throws DOMException { disallowUpdate(); } /** * Determine whether this (attribute) node is an ID. This method is introduced * in DOM Level 3. */ public boolean isId() { ContentTypeTest idTest = new ContentTypeTest(Type.ATTRIBUTE, BuiltInAtomicType.ID, node.getConfiguration()); idTest.setMatchDTDTypes(true); return idTest.matches(node); } /** * The Element node this attribute is attached to or * null if this attribute is not in use. * @since DOM Level 2 */ public Element getOwnerElement() { if (node.getNodeKind() == Type.ATTRIBUTE || node.getNodeKind() == Type.NAMESPACE) { return (Element)wrap(node.getParent()); } else { throw new UnsupportedOperationException( "This method is defined only on attribute and namespace nodes"); } } /** * Get the schema type information for this node. Returns null for an untyped node. */ public TypeInfo getSchemaTypeInfo() { int annotation = node.getTypeAnnotation(); if (annotation == -1 || ((annotation & NodeInfo.IS_DTD_TYPE) != 0)) { return null; } return new TypeInfoImpl(node.getConfiguration(), node.getConfiguration().getSchemaType(annotation)); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. //saxonb-9.1.0.8/bj/net/sf/saxon/dom/DOMSender.java0000644000175000017500000003361111227425355020620 0ustar eugeneeugenepackage net.sf.saxon.dom; import net.sf.saxon.Configuration; import net.sf.saxon.event.PipelineConfiguration; import net.sf.saxon.event.Receiver; import net.sf.saxon.event.SaxonLocator; import net.sf.saxon.event.SourceLocationProvider; import net.sf.saxon.om.NameChecker; import net.sf.saxon.om.NamePool; import net.sf.saxon.om.StandardNames; import net.sf.saxon.trans.XPathException; import org.w3c.dom.*; import org.xml.sax.helpers.AttributesImpl; import org.xml.sax.helpers.NamespaceSupport; import java.util.HashMap; import java.util.Iterator; /** * DOMSender.java: pseudo-SAX driver for a DOM source document. * This class takes an existing * DOM Document and walks around it in a depth-first traversal, * calling a Receiver to process the nodes as it does so */ public class DOMSender implements SaxonLocator, SourceLocationProvider { private Receiver receiver; private PipelineConfiguration pipe; private NamespaceSupport nsSupport = new NamespaceSupport(); private AttributesImpl attlist = new AttributesImpl(); private String[] parts = new String[3]; private String[] elparts = new String[3]; private HashMap nsDeclarations = new HashMap(10); protected Node root = null; protected String systemId; /** * Set the pipeline configuration * @param pipe the pipeline configuration */ public void setPipelineConfiguration(PipelineConfiguration pipe) { this.pipe = pipe; } /** * Set the receiver. * @param receiver The object to receive content events. */ public void setReceiver (Receiver receiver) { this.receiver = receiver; } /** * Set the DOM Document that will be walked * @param start the root node from which the tree walk will start */ public void setStartNode(Node start) { root = start; } /** * Set the systemId of the source document (which will also be * used for the destination) * @param systemId the systemId of the source document */ public void setSystemId(String systemId) { this.systemId = systemId; } /** * Walk a document (traversing the nodes depth first) * @exception net.sf.saxon.trans.XPathException On any error in the document */ public void send() throws XPathException { if (root==null) { throw new XPathException("DOMSender: no start node defined"); } if (receiver==null) { throw new XPathException("DOMSender: no receiver defined"); } receiver.setSystemId(systemId); pipe.setLocationProvider(this); receiver.setPipelineConfiguration(pipe); receiver.open(); if (root.getNodeType() == Node.ELEMENT_NODE) { sendElement((Element)root); } else { // walk the root node receiver.startDocument(0); walkNode(root); receiver.endDocument(); } receiver.close(); } /** * Walk a document starting from a particular element node. This has to make * sure that all the namespace declarations in scope for the element are * treated as if they were namespace declarations on the element itself. * @param startNode the start element node from which the walk will start */ private void sendElement(Element startNode) throws XPathException { Element node = startNode; NamedNodeMap topAtts = gatherNamespaces(node, false); while (true) { gatherNamespaces(node, true); Node parent = node.getParentNode(); if (parent != null && parent.getNodeType() == Node.ELEMENT_NODE) { node = (Element)parent; } else { break; } } outputElement(startNode, topAtts); } /** * Walk an element of a document (traversing the children depth first) * @param node The DOM Element object to walk * @exception net.sf.saxon.trans.XPathException On any error in the document * */ private void walkNode (Node node) throws XPathException { if (node.hasChildNodes()) { NodeList nit = node.getChildNodes(); final int len = nit.getLength(); for (int i=0; i * This is the implementation of the NodeInfo interface used as a wrapper for DOM nodes. */ public class NodeWrapper implements NodeInfo, VirtualNode, SiblingCountingNode { protected Node node; private int namecode = -1; protected short nodeKind; private NodeWrapper parent; // null means unknown protected DocumentWrapper docWrapper; protected int index; // -1 means unknown protected int span = 1; // the number of adjacent text nodes wrapped by this NodeWrapper. // If span>1, node will always be the first of a sequence of adjacent text nodes /** * This constructor is protected: nodes should be created using the makeWrapper * factory method * @param node The DOM node to be wrapped * @param parent The NodeWrapper that wraps the parent of this node * @param index Position of this node among its siblings */ protected NodeWrapper(Node node, NodeWrapper parent, int index) { this.node = node; this.parent = parent; this.index = index; } /** * Factory method to wrap a DOM node with a wrapper that implements the Saxon * NodeInfo interface. * @param node The DOM node * @param docWrapper The wrapper for the containing Document node * @return The new wrapper for the supplied node * @throws NullPointerException if the node or the document wrapper are null */ protected NodeWrapper makeWrapper(Node node, DocumentWrapper docWrapper) { if (node == null) { throw new NullPointerException("NodeWrapper#makeWrapper: Node must not be null"); } if (docWrapper == null) { throw new NullPointerException("NodeWrapper#makeWrapper: DocumentWrapper must not be null"); } return makeWrapper(node, docWrapper, null, -1); } /** * Factory method to wrap a DOM node with a wrapper that implements the Saxon * NodeInfo interface. * @param node The DOM node * @param docWrapper The wrapper for the containing Document node * * @param parent The wrapper for the parent of the JDOM node * @param index The position of this node relative to its siblings * @return The new wrapper for the supplied node */ protected NodeWrapper makeWrapper(Node node, DocumentWrapper docWrapper, NodeWrapper parent, int index) { NodeWrapper wrapper; switch (node.getNodeType()) { case Node.DOCUMENT_NODE: case Node.DOCUMENT_FRAGMENT_NODE: return docWrapper; case Node.ELEMENT_NODE: wrapper = new NodeWrapper(node, parent, index); wrapper.nodeKind = Type.ELEMENT; break; case Node.ATTRIBUTE_NODE: wrapper = new NodeWrapper(node, parent, index); wrapper.nodeKind = Type.ATTRIBUTE; break; case Node.TEXT_NODE: wrapper = new NodeWrapper(node, parent, index); wrapper.nodeKind = Type.TEXT; break; case Node.CDATA_SECTION_NODE: wrapper = new NodeWrapper(node, parent, index); wrapper.nodeKind = Type.TEXT; break; case Node.COMMENT_NODE: wrapper = new NodeWrapper(node, parent, index); wrapper.nodeKind = Type.COMMENT; break; case Node.PROCESSING_INSTRUCTION_NODE: wrapper = new NodeWrapper(node, parent, index); wrapper.nodeKind = Type.PROCESSING_INSTRUCTION; break; default: throw new IllegalArgumentException("Unsupported node type in DOM! " + node.getNodeType() + " instance " + node.toString()); } wrapper.docWrapper = docWrapper; return wrapper; } /** * Get the underlying DOM node, to implement the VirtualNode interface */ public Object getUnderlyingNode() { return node; } /** * Get the configuration */ public Configuration getConfiguration() { return docWrapper.getConfiguration(); } /** * Get the name pool for this node * @return the NamePool */ public NamePool getNamePool() { return docWrapper.getNamePool(); } /** * Return the type of node. * @return one of the values Node.ELEMENT, Node.TEXT, Node.ATTRIBUTE, etc. */ public int getNodeKind() { return nodeKind; } /** * Get the typed value of the item */ public SequenceIterator getTypedValue() { return SingletonIterator.makeIterator((AtomicValue)atomize()); } /** * Get the typed value. The result of this method will always be consistent with the method * {@link net.sf.saxon.om.Item#getTypedValue()}. However, this method is often more convenient and may be * more efficient, especially in the common case where the value is expected to be a singleton. * * @return the typed value. If requireSingleton is set to true, the result will always be an * AtomicValue. In other cases it may be a Value representing a sequence whose items are atomic * values. * @since 8.5 */ public Value atomize() { switch (getNodeKind()) { case Type.COMMENT: case Type.PROCESSING_INSTRUCTION: return new StringValue(getStringValueCS()); default: return new UntypedAtomicValue(getStringValueCS()); } } /** * Get the type annotation */ public int getTypeAnnotation() { if (getNodeKind() == Type.ATTRIBUTE) { return StandardNames.XS_UNTYPED_ATOMIC; } return StandardNames.XS_UNTYPED; } /** * Determine whether this is the same node as another node.
    * Note: a.isSameNodeInfo(b) if and only if generateId(a)==generateId(b) * @return true if this Node object and the supplied Node object represent the * same node in the tree. */ public boolean isSameNodeInfo(NodeInfo other) { if (!(other instanceof NodeWrapper)) { return false; } if (docWrapper.domLevel3) { return node.isSameNode(((NodeWrapper)other).node); } else { NodeWrapper ow = (NodeWrapper)other; return getNodeKind()==ow.getNodeKind() && getNameCode()==ow.getNameCode() && // redundant, but gives a quick exit getSiblingPosition()==ow.getSiblingPosition() && getParent().isSameNodeInfo(ow.getParent()); } } /** * The equals() method compares nodes for identity. It is defined to give the same result * as isSameNodeInfo(). * @param other the node to be compared with this node * @return true if this NodeInfo object and the supplied NodeInfo object represent * the same node in the tree. * @since 8.7 Previously, the effect of the equals() method was not defined. Callers * should therefore be aware that third party implementations of the NodeInfo interface may * not implement the correct semantics. It is safer to use isSameNodeInfo() for this reason. * The equals() method has been defined because it is useful in contexts such as a Java Set or HashMap. */ public boolean equals(Object other) { return other instanceof NodeInfo && isSameNodeInfo((NodeInfo)other); } /** * The hashCode() method obeys the contract for hashCode(): that is, if two objects are equal * (represent the same node) then they must have the same hashCode() * @since 8.7 Previously, the effect of the equals() and hashCode() methods was not defined. Callers * should therefore be aware that third party implementations of the NodeInfo interface may * not implement the correct semantics. */ public int hashCode() { FastStringBuffer buffer = new FastStringBuffer(20); generateId(buffer); return buffer.toString().hashCode(); } /** * Get the System ID for the node. * @return the System Identifier of the entity in the source document containing the node, * or null if not known. Note this is not the same as the base URI: the base URI can be * modified by xml:base, but the system ID cannot. */ public String getSystemId() { return docWrapper.baseURI; } public void setSystemId(String uri) { docWrapper.baseURI = uri; } /** * Get the Base URI for the node, that is, the URI used for resolving a relative URI contained * in the node. In the DOM model, base URIs are held only an the document level. */ public String getBaseURI() { NodeInfo n = this; if (getNodeKind() != Type.ELEMENT) { n = getParent(); } // Look for an xml:base attribute while (n != null) { String xmlbase = n.getAttributeValue(StandardNames.XML_BASE); if (xmlbase != null) { return xmlbase; } n = n.getParent(); } // if not found, return the base URI of the document node return docWrapper.baseURI; } /** * Get line number * @return the line number of the node in its original source document; or -1 if not available */ public int getLineNumber() { return -1; } /** * Get column number * @return the column number of the node in its original source document; or -1 if not available */ public int getColumnNumber() { return -1; } /** * Determine the relative position of this node and another node, in document order. * The other node will always be in the same document. * @param other The other node, whose position is to be compared with this node * @return -1 if this node precedes the other node, +1 if it follows the other * node, or 0 if they are the same node. (In this case, isSameNode() will always * return true, and the two nodes will produce the same result for generateId()) */ public int compareOrder(NodeInfo other) { // Use the DOM Level-3 compareDocumentPosition() method if (other instanceof NodeWrapper && docWrapper.domLevel3) { if (isSameNodeInfo(other)) { return 0; } try { short relationship = node.compareDocumentPosition(((NodeWrapper)other).node); if ((relationship & (Node.DOCUMENT_POSITION_PRECEDING | Node.DOCUMENT_POSITION_CONTAINS)) != 0) { return +1; } else if ((relationship & (Node.DOCUMENT_POSITION_FOLLOWING | Node.DOCUMENT_POSITION_CONTAINED_BY)) != 0) { return -1; } // otherwise use fallback implementation (e.g. nodes in different documents) } catch (DOMException e) { // can happen if nodes are from different DOM implementations. // use fallback implementation } } if (other instanceof SiblingCountingNode) { return Navigator.compareOrder(this, (SiblingCountingNode)other); } else { // it's presumably a Namespace Node return -other.compareOrder(this); } } /** * Return the string value of the node. The interpretation of this depends on the type * of node. For an element it is the accumulated character content of the element, * including descendant elements. * @return the string value of the node */ public String getStringValue() { return getStringValueCS().toString(); } /** * Get the value of the item as a CharSequence. This is in some cases more efficient than * the version of the method that returns a String. */ public CharSequence getStringValueCS() { switch (nodeKind) { case Type.DOCUMENT: case Type.ELEMENT: NodeList children1 = node.getChildNodes(); StringBuffer sb1 = new StringBuffer(16); expandStringValue(children1, sb1); return sb1; case Type.ATTRIBUTE: return emptyIfNull(((Attr)node).getValue()); case Type.TEXT: if (span == 1) { return emptyIfNull(node.getNodeValue()); } else { FastStringBuffer fsb = new FastStringBuffer(100); Node textNode = node; for (int i=0; i= 0) { return n.substring(colon+1); } return n; } else { return s; } case Type.PROCESSING_INSTRUCTION: return node.getNodeName(); default: return null; } } /** * Get the URI part of the name of this node. This is the URI corresponding to the * prefix, or the URI of the default namespace if appropriate. * @return The URI of the namespace of this node. For an unnamed node, * or for a node with an empty prefix, return an empty * string. */ public String getURI() { NodeInfo element; if (nodeKind == Type.ELEMENT) { element = this; } else if (nodeKind == Type.ATTRIBUTE) { element = parent; } else { return ""; } // The DOM methods getPrefix() and getNamespaceURI() do not always // return the prefix and the URI; they both return null, unless the // prefix and URI have been explicitly set in the node by using DOM // level 2 interfaces. There's no obvious way of deciding whether // an element whose name has no prefix is in the default namespace, // other than searching for a default namespace declaration. So we have to // be prepared to search. // If getPrefix() and getNamespaceURI() are non-null, however, // we can use the values. String uri = node.getNamespaceURI(); if (uri != null) { return uri; } // Otherwise we have to work it out the hard way... if (node.getNodeName().startsWith("xml:")) { return NamespaceConstant.XML; } String[] parts; try { parts = Name11Checker.getInstance().getQNameParts(node.getNodeName()); // use the XML 1.1 rules: these will do because it should already have been checked } catch (QNameException e) { throw new IllegalStateException("Invalid QName in DOM node. " + e); } if (nodeKind == Type.ATTRIBUTE && parts[0].length() == 0) { // for an attribute, no prefix means no namespace uri = ""; } else { AxisIterator nsiter = element.iterateAxis(Axis.NAMESPACE); while (true) { NodeInfo ns = (NodeInfo)nsiter.next(); if (ns == null) break; if (ns.getLocalPart().equals(parts[0])) { uri = ns.getStringValue(); break; } } if (uri == null) { if (parts[0].length() == 0) { uri = ""; } else { throw new IllegalStateException("Undeclared namespace prefix in DOM input: " + parts[0]); } } } return uri; } /** * Get the prefix of the name of the node. This is defined only for elements and attributes. * If the node has no prefix, or for other kinds of node, return a zero-length string. * @return The prefix of the name of the node. */ public String getPrefix() { int kind = getNodeKind(); if (kind == Type.ELEMENT || kind == Type.ATTRIBUTE) { String name = node.getNodeName(); int colon = name.indexOf(':'); if (colon < 0) { return ""; } else { return name.substring(0, colon); } } return ""; } /** * Get the display name of this node. For elements and attributes this is [prefix:]localname. * For unnamed nodes, it is an empty string. * @return The display name of this node. * For a node with no name, return an empty string. */ public String getDisplayName() { switch (nodeKind) { case Type.ELEMENT: case Type.ATTRIBUTE: case Type.PROCESSING_INSTRUCTION: return node.getNodeName(); default: return ""; } } /** * Get the NodeInfo object representing the parent of this node */ public NodeInfo getParent() { if (parent==null) { switch (getNodeKind()) { case Type.ATTRIBUTE: parent = makeWrapper(((Attr)node).getOwnerElement(), docWrapper); break; default: Node p = node.getParentNode(); if (p==null) { return null; } else { parent = makeWrapper(p, docWrapper); } } } return parent; } /** * Get the index position of this node among its siblings (starting from 0). * In the case of a text node that maps to several adjacent siblings in the DOM, * the numbering actually refers to the position of the underlying DOM nodes; * thus the sibling position for the text node is that of the first DOM node * to which it relates, and the numbering of subsequent XPath nodes is not necessarily * consecutive. */ public int getSiblingPosition() { if (index == -1) { switch (nodeKind) { case Type.ELEMENT: case Type.TEXT: case Type.COMMENT: case Type.PROCESSING_INSTRUCTION: int ix = 0; Node start = node; while (true) { start = start.getPreviousSibling(); if (start == null) { index = ix; return ix; } ix++; } case Type.ATTRIBUTE: ix = 0; int fp = getFingerprint(); AxisIterator iter = parent.iterateAxis(Axis.ATTRIBUTE); while (true) { NodeInfo n = (NodeInfo)iter.next(); if (n==null || n.getFingerprint()==fp) { index = ix; return ix; } ix++; } case Type.NAMESPACE: ix = 0; fp = getFingerprint(); iter = parent.iterateAxis(Axis.NAMESPACE); while (true) { NodeInfo n = (NodeInfo)iter.next(); if (n==null || n.getFingerprint()==fp) { index = ix; return ix; } ix++; } default: index = 0; return index; } } return index; } /** * Return an iteration over the nodes reached by the given axis from this node * @param axisNumber the axis to be used * @return a SequenceIterator that scans the nodes reached by the axis in turn. */ public AxisIterator iterateAxis(byte axisNumber) { switch (axisNumber) { case Axis.ANCESTOR: if (nodeKind==Type.DOCUMENT) return EmptyIterator.getInstance(); return new Navigator.AncestorEnumeration(this, false); case Axis.ANCESTOR_OR_SELF: if (nodeKind==Type.DOCUMENT) return SingleNodeIterator.makeIterator(this); return new Navigator.AncestorEnumeration(this, true); case Axis.ATTRIBUTE: if (nodeKind!=Type.ELEMENT) return EmptyIterator.getInstance(); return new AttributeEnumeration(this); case Axis.CHILD: if (hasChildNodes()) { return new ChildEnumeration(this, true, true, false); } else { return EmptyIterator.getInstance(); } case Axis.DESCENDANT: if (hasChildNodes()) { return new Navigator.DescendantEnumeration(this, false, true); } else { return EmptyIterator.getInstance(); } case Axis.DESCENDANT_OR_SELF: return new Navigator.DescendantEnumeration(this, true, true); case Axis.FOLLOWING: return new Navigator.FollowingEnumeration(this); case Axis.FOLLOWING_SIBLING: switch (nodeKind) { case Type.DOCUMENT: case Type.ATTRIBUTE: case Type.NAMESPACE: return EmptyIterator.getInstance(); default: return new ChildEnumeration(this, false, true, false); } case Axis.NAMESPACE: if (nodeKind!=Type.ELEMENT) { return EmptyIterator.getInstance(); } return NamespaceIterator.makeIterator(this, null); case Axis.PARENT: getParent(); return SingleNodeIterator.makeIterator(parent); case Axis.PRECEDING: return new Navigator.PrecedingEnumeration(this, false); case Axis.PRECEDING_SIBLING: switch (nodeKind) { case Type.DOCUMENT: case Type.ATTRIBUTE: case Type.NAMESPACE: return EmptyIterator.getInstance(); default: return new ChildEnumeration(this, false, false, false); } case Axis.SELF: return SingleNodeIterator.makeIterator(this); case Axis.PRECEDING_OR_ANCESTOR: return new Navigator.PrecedingEnumeration(this, true); default: throw new IllegalArgumentException("Unknown axis number " + axisNumber); } } /** * Return an iteration over the nodes reached by the given axis from this node * @param axisNumber the axis to be used * @param nodeTest A pattern to be matched by the returned nodes * @return a SequenceIterator that scans the nodes reached by the axis in turn. */ public AxisIterator iterateAxis(byte axisNumber, NodeTest nodeTest) { if (axisNumber == Axis.CHILD && nodeTest.getPrimitiveType() == Type.ELEMENT) { // common case: avoid creating wrappers for the text nodes if (hasChildNodes()) { return new Navigator.AxisFilter( new ChildEnumeration(this, true, true, true), nodeTest); } else { return EmptyIterator.getInstance(); } } return new Navigator.AxisFilter(iterateAxis(axisNumber), nodeTest); } /** * Get the value of a given attribute of this node * @param fingerprint The fingerprint of the attribute name * @return the attribute value if it exists or null if not */ public String getAttributeValue(int fingerprint) { NameTest test = new NameTest(Type.ATTRIBUTE, fingerprint, getNamePool()); AxisIterator iterator = iterateAxis(Axis.ATTRIBUTE, test); NodeInfo attribute = (NodeInfo)iterator.next(); if (attribute == null) { return null; } else { return attribute.getStringValue(); } } /** * Get the root node - always a document node with this tree implementation * @return the NodeInfo representing the containing document */ public NodeInfo getRoot() { return docWrapper; } /** * Get the root (document) node * @return the DocumentInfo representing the containing document */ public DocumentInfo getDocumentRoot() { return docWrapper; } /** * Determine whether the node has any children.
    * Note: the result is equivalent to
    * getEnumeration(Axis.CHILD, AnyNodeTest.getInstance()).hasNext() */ public boolean hasChildNodes() { // An attribute node has child text nodes return node.getNodeType() != Node.ATTRIBUTE_NODE && node.hasChildNodes(); } /** * Get a character string that uniquely identifies this node. * Note: a.isSameNode(b) if and only if generateId(a)==generateId(b) * @param buffer a buffer to contain a string that uniquely identifies this node, across all * documents * */ public void generateId(FastStringBuffer buffer) { Navigator.appendSequentialKey(this, buffer, true); //buffer.append(Navigator.getSequentialKey(this)); } /** * Get the document number of the document containing this node. For a free-standing * orphan node, just return the hashcode. */ public int getDocumentNumber() { return getDocumentRoot().getDocumentNumber(); } /** * Copy this node to a given outputter (deep copy) */ public void copy(Receiver out, int whichNamespaces, boolean copyAnnotations, int locationId) throws XPathException { Navigator.copy(this, out, docWrapper.getNamePool(), whichNamespaces, copyAnnotations, locationId); } /** * Get all namespace undeclarations and undeclarations defined on this element. * * @param buffer If this is non-null, and the result array fits in this buffer, then the result * may overwrite the contents of this array, to avoid the cost of allocating a new array on the heap. * @return An array of integers representing the namespace declarations and undeclarations present on * this element. For a node other than an element, return null. Otherwise, the returned array is a * sequence of namespace codes, whose meaning may be interpreted by reference to the name pool. The * top half word of each namespace code represents the prefix, the bottom half represents the URI. * If the bottom half is zero, then this is a namespace undeclaration rather than a declaration. * The XML namespace is never included in the list. If the supplied array is larger than required, * then the first unused entry will be set to -1. *

    *

    For a node other than an element, the method returns null.

    */ public int[] getDeclaredNamespaces(int[] buffer) { if (node.getNodeType() == Node.ELEMENT_NODE) { Element elem = (Element)node; NamedNodeMap atts = elem.getAttributes(); if (atts == null) { return EMPTY_NAMESPACE_LIST; } int count = 0; final int attsLen = atts.getLength(); for (int i=0; i buffer.length ? new int[count] : buffer); NamePool pool = getNamePool(); int n = 0; for (int i=0; i= attList.size()) { return null; } current = start.makeWrapper( (Attr)attList.get(ix), docWrapper, start, ix); ix++; return current; } public Item current() { return current; } public int position() { return ix+1; } public void close() { } /** * Return an iterator over an axis, starting at the current node. * * @param axis the axis to iterate over, using a constant such as * {@link Axis#CHILD} * @param test a predicate to apply to the nodes before returning them. */ public AxisIterator iterateAxis(byte axis, NodeTest test) { return current.iterateAxis(axis, test); } /** * Return the atomized value of the current node. * * @return the atomized value. * @throws NullPointerException if there is no current node */ public Value atomize() throws XPathException { return current.atomize(); } /** * Return the string value of the current node. * * @return the string value, as an instance of CharSequence. * @throws NullPointerException if there is no current node */ public CharSequence getStringValue() { return current.getStringValueCS(); } public SequenceIterator getAnother() { return new AttributeEnumeration(start); } /** * Get properties of this iterator, as a bit-significant integer. * * @return the properties of this iterator. This will be some combination of * properties such as {@link #GROUNDED}, {@link #LAST_POSITION_FINDER}, * and {@link #LOOKAHEAD}. It is always * acceptable to return the value zero, indicating that there are no known special properties. * It is acceptable for the properties of the iterator to change depending on its state. */ public int getProperties() { return LOOKAHEAD; } } /** * The class ChildEnumeration handles not only the child axis, but also the * following-sibling and preceding-sibling axes. It can also iterate the children * of the start node in reverse order, something that is needed to support the * preceding and preceding-or-ancestor axes (the latter being used by xsl:number) */ private final class ChildEnumeration extends AxisIteratorImpl implements LookaheadIterator{ private NodeWrapper start; private NodeWrapper commonParent; private boolean downwards; // iterate children of start node (not siblings) private boolean forwards; // iterate in document order (not reverse order) private boolean elementsOnly; NodeList childNodes; private int childNodesLength; private int ix; // index of the current DOM node within childNodes; // in the case of adjacent text nodes, index of the first in the group private int currentSpan; // number of DOM nodes mapping to the current XPath node public ChildEnumeration(NodeWrapper start, boolean downwards, boolean forwards, boolean elementsOnly) { this.start = start; this.downwards = downwards; this.forwards = forwards; this.elementsOnly = elementsOnly; position = 0; currentSpan = 1; if (downwards) { commonParent = start; } else { commonParent = (NodeWrapper)start.getParent(); } childNodes = commonParent.node.getChildNodes(); childNodesLength = childNodes.getLength(); if (downwards) { currentSpan = 1; if (forwards) { ix = -1; // just before first } else { ix = childNodesLength; // just after last } } else { ix = start.getSiblingPosition(); // at current node currentSpan = start.span; } } /** * Starting with ix positioned at a node, which in the last in a span, calculate the length * of the span, that is the number of DOM nodes mapped to this XPath node. * @return the number of nodes spanned */ private int skipPrecedingTextNodes() { int count = 0; while (ix >= count) { Node node = childNodes.item(ix - count); short kind = node.getNodeType(); if (kind == Node.TEXT_NODE || kind == Node.CDATA_SECTION_NODE) { count++; } else { break; } } return (count == 0 ? 1 : count); } /** * Starting with ix positioned at a node, which in the first in a span, calculate the length * of the span, that is the number of DOM nodes mapped to this XPath node. * @return the number of nodes spanned */ private int skipFollowingTextNodes() { int count = 0; int pos = ix; final int len = childNodesLength; while (pos < len) { Node node = childNodes.item(pos); short kind = node.getNodeType(); if (kind == Node.TEXT_NODE || kind == Node.CDATA_SECTION_NODE) { pos++; count++; } else { break; } } return (count == 0 ? 1 : count); } public boolean hasNext() { if (forwards) { return ix + currentSpan < childNodesLength; } else { return ix > 0; } } public Item next() { while (true) { if (forwards) { ix += currentSpan; if (ix >= childNodesLength) { position = -1; return null; } else { currentSpan = skipFollowingTextNodes(); Node currentDomNode = childNodes.item(ix); switch (currentDomNode.getNodeType()) { case Node.DOCUMENT_TYPE_NODE: continue; case Node.ELEMENT_NODE: break; default: if (elementsOnly) { continue; } else { break; } } NodeWrapper wrapper = makeWrapper(currentDomNode, docWrapper, commonParent, ix); wrapper.span = currentSpan; position++; return current = wrapper; } } else { ix--; if (ix < 0) { position = -1; return null; } else { currentSpan = skipPrecedingTextNodes(); ix -= (currentSpan - 1); Node currentDomNode = childNodes.item(ix); switch (currentDomNode.getNodeType()) { case Node.DOCUMENT_TYPE_NODE: continue; case Node.ELEMENT_NODE: break; default: if (elementsOnly) { continue; } else { break; } } NodeWrapper wrapper = makeWrapper(currentDomNode, docWrapper, commonParent, ix); wrapper.span = currentSpan; position++; return current = wrapper; } } } } public SequenceIterator getAnother() { return new ChildEnumeration(start, downwards, forwards, elementsOnly); } /** * Get properties of this iterator, as a bit-significant integer. * * @return the properties of this iterator. This will be some combination of * properties such as {@link #GROUNDED}, {@link #LAST_POSITION_FINDER}, * and {@link #LOOKAHEAD}. It is always * acceptable to return the value zero, indicating that there are no known special properties. * It is acceptable for the properties of the iterator to change depending on its state. */ public int getProperties() { return LOOKAHEAD; } } // end of class ChildEnumeration } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/dom/DOMImplementationImpl.java0000644000175000017500000001001111033112257023161 0ustar eugeneeugenepackage net.sf.saxon.dom; import org.w3c.dom.DOMException; import org.w3c.dom.DOMImplementation; import org.w3c.dom.Document; import org.w3c.dom.DocumentType; /** * A simple implementation of the DOMImplementation interface, for use when accessing * Saxon tree structure using the DOM API. */ class DOMImplementationImpl implements DOMImplementation { /** * Test if the DOM implementation implements a specific feature. * @param feature The name of the feature to test (case-insensitive). * @param version This is the version number of the feature to test. * @return true if the feature is implemented in the * specified version, false otherwise. This implementation * returns true if the feature is "XML" or "Core" and the version is null, * "", "3.0", "2.0", or "1.0". */ public boolean hasFeature(String feature, String version) { return (feature.equalsIgnoreCase("XML") || feature.equalsIgnoreCase("Core")) && (version == null || version.length() == 0 || version.equals("3.0") || version.equals("2.0") || version.equals("1.0")); } /** * This method returns a specialized object which implements the * specialized APIs of the specified feature and version, as specified * in . * @param feature The name of the feature requested. * @param version This is the version number of the feature to test. * @return Always returns null in this implementation * @since DOM Level 3 */ public Object getFeature(String feature, String version) { return null; } /** * Creates an empty DocumentType node. * @param qualifiedName The qualified name of the document type to be * created. * @param publicId The external subset public identifier. * @param systemId The external subset system identifier. * @return A new DocumentType node with * Node.ownerDocument set to null . * @exception org.w3c.dom.DOMException * INVALID_CHARACTER_ERR: Raised if the specified qualified name * contains an illegal character. *
    NAMESPACE_ERR: Raised if the qualifiedName is * malformed. * @since DOM Level 2 */ public DocumentType createDocumentType(String qualifiedName, String publicId, String systemId) throws DOMException { NodeOverNodeInfo.disallowUpdate(); return null; } /** * Creates an XML Document object of the specified type with * its document element. * @param namespaceURI The namespace URI of the document element to * create. * @param qualifiedName The qualified name of the document element to be * created. * @param doctype The type of document to be created or null. * @return A new Document object. * @exception org.w3c.dom.DOMException * @since DOM Level 2 */ public Document createDocument(String namespaceURI, String qualifiedName, DocumentType doctype) throws DOMException { NodeOverNodeInfo.disallowUpdate(); return null; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/dom/TypeInfoImpl.java0000644000175000017500000000724411033112257021407 0ustar eugeneeugenepackage net.sf.saxon.dom; import net.sf.saxon.type.SchemaType; import net.sf.saxon.type.AnyType; import net.sf.saxon.Configuration; import org.w3c.dom.TypeInfo; /** * This class implements the DOM TypeInfo interface as a wrapper over the Saxon SchemaType * interface. */ public class TypeInfoImpl implements TypeInfo { private Configuration config; private SchemaType schemaType; /** * Construct a TypeInfo based on a SchemaType */ public TypeInfoImpl(Configuration config, SchemaType type) { this.config = config; this.schemaType = type; } /** * Get the local name of the type (a system-allocated name if anonymous). Needed to implement the * DOM level 3 TypeInfo interface. */ public String getTypeName() { return config.getNamePool().getLocalName(schemaType.getNameCode()); } /** * Get the namespace name of the type (a system-allocated name if anonymous). Needed to implement the * DOM level 3 TypeInfo interface. */ public String getTypeNamespace() { return config.getNamePool().getURI(schemaType.getNameCode()); } /** * This method returns true if there is a derivation between the reference type definition, that is the TypeInfo * on which the method is being called, and the other type definition, that is the one passed as parameters. * This method implements the DOM Level 3 TypeInfo interface. It must be called only on a valid type. * @param typeNamespaceArg the namespace of the "other" type * @param typeNameArg the local name of the "other" type * @param derivationMethod the derivation method: zero or more of {@link SchemaType#DERIVATION_RESTRICTION}, * {@link SchemaType#DERIVATION_EXTENSION}, {@link SchemaType#DERIVATION_LIST}, or {@link SchemaType#DERIVATION_UNION}. * Zero means derived by any possible route. */ public boolean isDerivedFrom(String typeNamespaceArg, String typeNameArg, int derivationMethod) throws IllegalStateException { SchemaType base = schemaType.getBaseType(); int fingerprint = config.getNamePool().allocate("", typeNamespaceArg, typeNameArg); if (derivationMethod==0 || (derivationMethod & schemaType.getDerivationMethod()) != 0) { if (base.getFingerprint() == fingerprint) { return true; } else if (base instanceof AnyType) { return false; } else { return new TypeInfoImpl(config, base).isDerivedFrom(typeNamespaceArg, typeNameArg, derivationMethod); } } return false; // Note: if derivationMethod is RESTRICTION, this interpretation requires every step to be derived // by restriction. An alternative interpretation is that at least one step must be derived by restriction. } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Saxonica Limited // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none // saxonb-9.1.0.8/bj/net/sf/saxon/dom/TextOverAttrInfo.java0000644000175000017500000000634611033112257022261 0ustar eugeneeugenepackage net.sf.saxon.dom; import org.w3c.dom.Node; import org.w3c.dom.DOMException; import net.sf.saxon.type.Type; /** * This class represents a DOM text node that is the child of a DOM attribute node. The DOM attribute node * will be a wrapper over a Saxon attribute node or namespace node. */ public class TextOverAttrInfo extends TextOverNodeInfo { private AttrOverNodeInfo attr; public TextOverAttrInfo(AttrOverNodeInfo attr) { this.attr = attr; this.node = attr.getUnderlyingNodeInfo(); } /** * Returns whether this text node contains * element content whitespace, often abusively called "ignorable whitespace". The text node is * determined to contain whitespace in element content during the load * of the document or if validation occurs while using * Document.normalizeDocument(). * * @since DOM Level 3 */ public boolean isElementContentWhitespace() { return false; } /** * Get the type of this node (node kind, in XPath terminology). * Note, the numbers assigned to node kinds * in Saxon (see {@link net.sf.saxon.type.Type}) are the same as those assigned in the DOM */ public short getNodeType() { return Type.TEXT; } /** * Compare the position of the (other) node in document order with the reference node (this node). * DOM Level 3 method. * * @param other the other node. * @return Returns how the node is positioned relatively to the reference * node. * @throws org.w3c.dom.DOMException */ public short compareDocumentPosition(Node other) throws DOMException { final short DOCUMENT_POSITION_FOLLOWING = 0x04; if (other instanceof TextOverAttrInfo) { if (node.isSameNodeInfo(((TextOverAttrInfo)other).node)) { return 0; } else { return attr.compareDocumentPosition(((TextOverAttrInfo)other).attr); } } else if (other instanceof AttrOverNodeInfo) { if (node.isSameNodeInfo(((AttrOverNodeInfo)other).getUnderlyingNodeInfo())) { return DOCUMENT_POSITION_FOLLOWING; } } return attr.compareDocumentPosition(other); } /** * Find the parent node of this node. * * @return The Node object describing the containing element or root node. */ public Node getParentNode() { return attr; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/dom/DocumentOverNodeInfo.java0000644000175000017500000007041111033112257023060 0ustar eugeneeugenepackage net.sf.saxon.dom; import net.sf.saxon.om.Axis; import net.sf.saxon.om.AxisIterator; import net.sf.saxon.om.DocumentInfo; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.type.Type; import net.sf.saxon.pattern.NodeKindTest; import org.w3c.dom.*; import java.util.ArrayList; /** * This class is an implementation of the DOM Document class that wraps a Saxon DocumentInfo * representation of a document node. */ public class DocumentOverNodeInfo extends NodeOverNodeInfo implements Document { /** * Get the Document Type Declaration (see DocumentType ) * associated with this document. For HTML documents as well as XML * documents without a document type declaration this returns * null. DOM method. * @return null: The Saxon tree model does not include the document type * information. */ public DocumentType getDoctype() { return null; } /** * Get a DOMImplementation object that handles this document. * A DOM application may use objects from multiple implementations. * DOM method. */ public DOMImplementation getImplementation() { return new DOMImplementationImpl(); } /** * Creates an element of the type specified. DOM method: always fails, * because the Saxon tree is not updateable. */ public Element createElement(String tagName) throws DOMException { disallowUpdate(); return null; } /** * Creates an empty DocumentFragment object. * @return A new DocumentFragment . * DOM method: returns null, because the Saxon tree is not updateable. */ public DocumentFragment createDocumentFragment() { return null; } /** * Create a Text node given the specified string. * DOM method: returns null, because the Saxon tree is not updateable. * @param data The data for the node. * @return The new Text object. */ public Text createTextNode(String data) { return null; } /** * Create a Comment node given the specified string. * DOM method: returns null, because the Saxon tree is not updateable. * @param data The data for the node. * @return The new Comment object. */ public Comment createComment(String data) { return null; } /** * Create a CDATASection node whose value is the specified * string. * DOM method: always fails, because the Saxon tree is not updateable. * @param data The data for the CDATASection contents. * @return The new CDATASection object. * @exception org.w3c.dom.DOMException * NOT_SUPPORTED_ERR: Raised if this document is an HTML document. */ public CDATASection createCDATASection(String data) throws DOMException { disallowUpdate(); return null; } /** * Create a ProcessingInstruction node given the specified * name and data strings. * DOM method: returns null, because the Saxon tree is not updateable. * @param target The target part of the processing instruction. * @param data The data for the node. * @return The new ProcessingInstruction object. * @exception org.w3c.dom.DOMException * INVALID_CHARACTER_ERR: Raised if the specified target contains an * illegal character. *
    NOT_SUPPORTED_ERR: Raised if this document is an HTML document. */ public ProcessingInstruction createProcessingInstruction(String target, String data) throws DOMException { disallowUpdate(); return null; } /** * Create an Attr of the given name. * DOM method: always fails, because the Saxon tree is not updateable. * @param name The name of the attribute. * @return A new Attr object with the nodeName * attribute set to name , and localName , * prefix , and namespaceURI set to * null . * @exception org.w3c.dom.DOMException * INVALID_CHARACTER_ERR: Raised if the specified name contains an * illegal character. */ public Attr createAttribute(String name) throws DOMException { disallowUpdate(); return null; } /** * Create an EntityReference object. * DOM method: returns null, because the Saxon tree is not updateable. * @param name The name of the entity to reference. * @return The new EntityReference object. * @exception org.w3c.dom.DOMException * INVALID_CHARACTER_ERR: Raised if the specified name contains an * illegal character. *
    NOT_SUPPORTED_ERR: Raised if this document is an HTML document. */ public EntityReference createEntityReference(String name) throws DOMException { disallowUpdate(); return null; } /** * Return a NodeList of all the Elements with * a given tag name in the order in which they are encountered in a * preorder traversal of the Document tree. * @param tagname The name of the tag to match on. The special value "*" * matches all tags. * @return A new NodeList object containing all the matched * Elements . */ public NodeList getElementsByTagName(String tagname) { return getElementsByTagName(node, tagname); } /** * Get the outermost element of a document. * @return the Element for the outermost element of the document. If the document is * not well-formed, this returns the first element child of the root if there is one, otherwise * null. */ public Element getDocumentElement() { NodeInfo root = node.getDocumentRoot(); if (root==null) { return null; } AxisIterator children = root.iterateAxis(Axis.CHILD, NodeKindTest.ELEMENT); return (Element)wrap((NodeInfo)children.next()); } protected static NodeList getElementsByTagName(NodeInfo node, String tagname) { AxisIterator allElements = node.iterateAxis(Axis.DESCENDANT); ArrayList nodes = new ArrayList(100); while(true) { NodeInfo next = (NodeInfo)allElements.next(); if (next == null) { break; } if (next.getNodeKind()==Type.ELEMENT) { if (tagname.equals("*") || tagname.equals(next.getDisplayName())) { nodes.add(NodeOverNodeInfo.wrap(next)); } } } return new DOMNodeList(nodes); } /** * Import a node from another document to this document. * DOM method: always fails, because the Saxon tree is not updateable. * @exception org.w3c.dom.DOMException * @since DOM Level 2 */ public Node importNode(Node importedNode, boolean deep) throws DOMException { disallowUpdate(); return null; } /** * Create an element of the given qualified name and namespace URI. * HTML-only DOM implementations do not need to implement this method. * DOM method: always fails, because the Saxon tree is not updateable. * @param namespaceURI The namespace URI of the element to create. * @param qualifiedName The qualified name of the element type to * instantiate. * @return A new Element object * @exception org.w3c.dom.DOMException */ public Element createElementNS(String namespaceURI, String qualifiedName) throws DOMException { disallowUpdate(); return null; } /** * Create an attribute of the given qualified name and namespace URI. * HTML-only DOM implementations do not need to implement this method. * DOM method: returns null, because the Saxon tree is not updateable. * @param namespaceURI The namespace URI of the attribute to create. * @param qualifiedName The qualified name of the attribute to * instantiate. * @return A new Attr object. * @exception org.w3c.dom.DOMException */ public Attr createAttributeNS(String namespaceURI, String qualifiedName) throws DOMException { disallowUpdate(); return null; } /** * Return a NodeList of all the Elements with * a given local name and namespace URI in the order in which they are * encountered in a preorder traversal of the Document tree. * DOM method. * @param namespaceURI The namespace URI of the elements to match on. * The special value "*" matches all namespaces. The value null matches * elements not in any namespace * @param localName The local name of the elements to match on. The * special value "*" matches all local names. * @return A new NodeList object containing all the matched * Elements . * @since DOM Level 2 */ public NodeList getElementsByTagNameNS(String namespaceURI, String localName) { return getElementsByTagNameNS(node, namespaceURI, localName); } public static NodeList getElementsByTagNameNS(NodeInfo node, String namespaceURI, String localName) { String ns = (namespaceURI==null ? "" : namespaceURI); AxisIterator allElements = node.iterateAxis(Axis.DESCENDANT); ArrayList nodes = new ArrayList(100); while(true) { NodeInfo next = (NodeInfo)allElements.next(); if (next == null) { break; } if (next.getNodeKind()==Type.ELEMENT) { if ((ns.equals("*") || ns.equals(next.getURI())) && (localName.equals("*") || localName.equals(next.getLocalPart()))) { nodes.add(NodeOverNodeInfo.wrap(next)); } } } return new DOMNodeList(nodes); } /** * Return the Element whose ID is given by * elementId . If no such element exists, returns * null . Behavior is not defined if more than one element * has this ID . The DOM implementation must have * information that says which attributes are of type ID. Attributes with * the name "ID" are not of type ID unless so defined. Implementations * that do not know whether attributes are of type ID or not are expected * to return null . * @param elementId The unique id value for an element. * @return The matching element, or null if there is none. * @since DOM Level 2 */ public Element getElementById(String elementId) { // Defined on Document node; but we support it on any node. DocumentInfo doc = node.getDocumentRoot(); if (doc == null) { return null; } return (Element)wrap(doc.selectID(elementId)); } /** * An attribute specifying the encoding used for this document at the time * of the parsing. This is null when it is not known, such * as when the Document was created in memory. * * @since DOM Level 3 */ public String getInputEncoding() { return null; } /** * An attribute specifying, as part of the * XML declaration, * the encoding of this document. This is null when * unspecified or when it is not known, such as when the * Document was created in memory. * * @since DOM Level 3 */ public String getXmlEncoding() { return null; } /** * An attribute specifying, as part of the * XML declaration, * whether this document is standalone. This is false when * unspecified. *

    Note: No verification is done on the value when setting * this attribute. Applications should use * Document.normalizeDocument() with the "validate" * parameter to verify if the value matches the validity * constraint for standalone document declaration as defined in [XML 1.0]. * * @since DOM Level 3 */ public boolean getXmlStandalone() { return false; } /** * An attribute specifying, as part of the XML declaration, whether this document is standalone. This is false when * unspecified. *

    Note: No verification is done on the value when setting * this attribute. Applications should use * Document.normalizeDocument() with the "validate" * parameter to verify if the value matches the validity * constraint for standalone document declaration as defined in [XML 1.0]. * * @throws org.w3c.dom.DOMException NOT_SUPPORTED_ERR: Raised if this document does not support the * "XML" feature. * @since DOM Level 3 */ public void setXmlStandalone(boolean xmlStandalone) throws DOMException { disallowUpdate(); } /** * An attribute specifying, as part of the XML declaration, the version number of this document. If there is no declaration and if * this document supports the "XML" feature, the value is * "1.0". If this document does not support the "XML" * feature, the value is always null. Changing this * attribute will affect methods that check for invalid characters in * XML names. Application should invoke * Document.normalizeDocument() in order to check for * invalid characters in the Nodes that are already part of * this Document. *
    DOM applications may use the * DOMImplementation.hasFeature(feature, version) method * with parameter values "XMLVersion" and "1.0" (respectively) to * determine if an implementation supports [XML 1.0]. DOM * applications may use the same method with parameter values * "XMLVersion" and "1.1" (respectively) to determine if an * implementation supports [XML 1.1]. In both * cases, in order to support XML, an implementation must also support * the "XML" feature defined in this specification. Document * objects supporting a version of the "XMLVersion" feature must not * raise a NOT_SUPPORTED_ERR exception for the same version * number when using Document.xmlVersion. * * @since DOM Level 3 */ public String getXmlVersion() { return "1.0"; } /** * An attribute specifying, as part of the XML declaration, the version number of this document. If there is no declaration and if * this document supports the "XML" feature, the value is * "1.0". If this document does not support the "XML" * feature, the value is always null. Changing this * attribute will affect methods that check for invalid characters in * XML names. Application should invoke * Document.normalizeDocument() in order to check for * invalid characters in the Nodes that are already part of * this Document. *
    DOM applications may use the * DOMImplementation.hasFeature(feature, version) method * with parameter values "XMLVersion" and "1.0" (respectively) to * determine if an implementation supports [XML 1.0]. DOM * applications may use the same method with parameter values * "XMLVersion" and "1.1" (respectively) to determine if an * implementation supports [XML 1.1]. In both * cases, in order to support XML, an implementation must also support * the "XML" feature defined in this specification. Document * objects supporting a version of the "XMLVersion" feature must not * raise a NOT_SUPPORTED_ERR exception for the same version * number when using Document.xmlVersion. * * @throws org.w3c.dom.DOMException NOT_SUPPORTED_ERR: Raised if the version is set to a value that is * not supported by this Document or if this document * does not support the "XML" feature. * @since DOM Level 3 */ public void setXmlVersion(String xmlVersion) throws DOMException { disallowUpdate(); } /** * An attribute specifying whether error checking is enforced or not. When * set to false, the implementation is free to not test * every possible error case normally defined on DOM operations, and not * raise any DOMException on DOM operations or report * errors while using Document.normalizeDocument(). In case * of error, the behavior is undefined. This attribute is * true by default. * * @since DOM Level 3 */ public boolean getStrictErrorChecking() { return false; } /** * An attribute specifying whether error checking is enforced or not. When * set to false, the implementation is free to not test * every possible error case normally defined on DOM operations, and not * raise any DOMException on DOM operations or report * errors while using Document.normalizeDocument(). In case * of error, the behavior is undefined. This attribute is * true by default. * * @since DOM Level 3 */ public void setStrictErrorChecking(boolean strictErrorChecking) { //no-op } /** * The location of the document or null if undefined or if * the Document was created using * DOMImplementation.createDocument. No lexical checking is * performed when setting this attribute; this could result in a * null value returned when using Node.baseURI * . *
    Beware that when the Document supports the feature * "HTML" [DOM Level 2 HTML] * , the href attribute of the HTML BASE element takes precedence over * this attribute when computing Node.baseURI. * * @since DOM Level 3 */ public String getDocumentURI() { return node.getSystemId(); } /** * The location of the document or null if undefined or if * the Document was created using * DOMImplementation.createDocument. No lexical checking is * performed when setting this attribute; this could result in a * null value returned when using Node.baseURI * . *
    Beware that when the Document supports the feature * "HTML" [DOM Level 2 HTML] * , the href attribute of the HTML BASE element takes precedence over * this attribute when computing Node.baseURI. * * @since DOM Level 3 */ public void setDocumentURI(String documentURI) { disallowUpdate(); } /** * Attempts to adopt a node from another document to this document. If * supported, it changes the ownerDocument of the source * node, its children, as well as the attached attribute nodes if there * are any. If the source node has a parent it is first removed from the * child list of its parent. This effectively allows moving a subtree * from one document to another (unlike importNode() which * create a copy of the source node instead of moving it). When it * fails, applications should use Document.importNode() * instead. Note that if the adopted node is already part of this * document (i.e. the source and target document are the same), this * method still has the effect of removing the source node from the * child list of its parent, if any. The following list describes the * specifics for each type of node. *

    *
    ATTRIBUTE_NODE
    *
    The * ownerElement attribute is set to null and * the specified flag is set to true on the * adopted Attr. The descendants of the source * Attr are recursively adopted.
    *
    DOCUMENT_FRAGMENT_NODE
    *
    The * descendants of the source node are recursively adopted.
    *
    DOCUMENT_NODE
    *
    * Document nodes cannot be adopted.
    *
    DOCUMENT_TYPE_NODE
    *
    * DocumentType nodes cannot be adopted.
    *
    ELEMENT_NODE
    *
    Specified attribute nodes of the source element are adopted. Default attributes * are discarded, though if the document being adopted into defines * default attributes for this element name, those are assigned. The * descendants of the source element are recursively adopted.
    *
    ENTITY_NODE
    *
    * Entity nodes cannot be adopted.
    *
    ENTITY_REFERENCE_NODE
    *
    Only * the EntityReference node itself is adopted, the * descendants are discarded, since the source and destination documents * might have defined the entity differently. If the document being * imported into provides a definition for this entity name, its value * is assigned.
    *
    NOTATION_NODE
    *
    Notation nodes cannot be * adopted.
    *
    PROCESSING_INSTRUCTION_NODE, TEXT_NODE, CDATA_SECTION_NODE, * COMMENT_NODE
    *
    These nodes can all be adopted. No specifics.
    *
    *

    Note: Since it does not create new nodes unlike the * Document.importNode() method, this method does not raise * an INVALID_CHARACTER_ERR exception, and applications * should use the Document.normalizeDocument() method to * check if an imported name is not an XML name according to the XML * version in use. * * @param source The node to move into this document. * @return The adopted node, or null if this operation * fails, such as when the source node comes from a different * implementation. * @throws org.w3c.dom.DOMException NOT_SUPPORTED_ERR: Raised if the source node is of type * DOCUMENT, DOCUMENT_TYPE. *
    NO_MODIFICATION_ALLOWED_ERR: Raised when the source node is * readonly. * @since DOM Level 3 */ public Node adoptNode(Node source) throws DOMException { disallowUpdate(); return null; } /** * The configuration used when Document.normalizeDocument() * is invoked. * * @since DOM Level 3 */ public DOMConfiguration getDomConfig() { return null; } /** * This method acts as if the document was going through a save and load * cycle, putting the document in a "normal" form. As a consequence, * this method updates the replacement tree of * EntityReference nodes and normalizes Text * nodes, as defined in the method Node.normalize(). *
    Otherwise, the actual result depends on the features being set on * the Document.domConfig object and governing what * operations actually take place. Noticeably this method could also * make the document namespace well-formed according to the algorithm * described in , check the character normalization, remove the * CDATASection nodes, etc. See * DOMConfiguration for details. *

    // Keep in the document
         * the information defined // in the XML Information Set (Java example)
         * DOMConfiguration docConfig = myDocument.getDomConfig();
         * docConfig.setParameter("infoset", Boolean.TRUE);
         * myDocument.normalizeDocument();
    *

    *
    Mutation events, when supported, are generated to reflect the * changes occurring on the document. *
    If errors occur during the invocation of this method, such as an * attempt to update a read-only node or a Node.nodeName * contains an invalid character according to the XML version in use, * errors or warnings (DOMError.SEVERITY_ERROR or * DOMError.SEVERITY_WARNING) will be reported using the * DOMErrorHandler object associated with the "error-handler * " parameter. Note this method might also report fatal errors ( * DOMError.SEVERITY_FATAL_ERROR) if an implementation * cannot recover from an error. * * @since DOM Level 3 */ public void normalizeDocument() { disallowUpdate(); } /** * Rename an existing node of type ELEMENT_NODE or * ATTRIBUTE_NODE. Not supported in this implementation * * @param n The node to rename. * @param namespaceURI The new namespace URI. * @param qualifiedName The new qualified name. * @return The renamed node. This is either the specified node or the new * node that was created to replace the specified node. * @throws org.w3c.dom.DOMException */ public Node renameNode(Node n, String namespaceURI, String qualifiedName) throws DOMException { disallowUpdate(); return null; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. //saxonb-9.1.0.8/bj/net/sf/saxon/dom/DocumentBuilderImpl.java0000644000175000017500000002760411033112257022741 0ustar eugeneeugenepackage net.sf.saxon.dom; import net.sf.saxon.Configuration; import net.sf.saxon.AugmentedSource; import net.sf.saxon.value.Whitespace; import net.sf.saxon.om.Validation; import net.sf.saxon.event.Builder; import net.sf.saxon.event.PipelineConfiguration; import net.sf.saxon.event.Sender; import net.sf.saxon.tinytree.TinyBuilder; import net.sf.saxon.tinytree.TinyDocumentImpl; import net.sf.saxon.trans.XPathException; import org.w3c.dom.DOMImplementation; import org.w3c.dom.Document; import org.xml.sax.*; import javax.xml.parsers.DocumentBuilder; import javax.xml.transform.sax.SAXSource; import javax.xml.transform.Source; import java.io.File; import java.io.IOException; /** * This class implements the JAXP DocumentBuilder interface, allowing a Saxon TinyTree to be * constructed using standard JAXP parsing interfaces. The returned DOM document node is a wrapper * over the Saxon TinyTree structure. Note that although this wrapper * implements the DOM interfaces, it is read-only, and all attempts to update it will throw * an exception. No schema or DTD validation is carried out on the document. */ public class DocumentBuilderImpl extends DocumentBuilder { private Configuration config; private EntityResolver entityResolver; private ErrorHandler errorHandler; private boolean xIncludeAware; private boolean validating; private int stripSpace = Whitespace.UNSPECIFIED; /** * Set the Saxon Configuration to be used by the document builder. * This non-JAXP method must be called if the resulting document is to be used * within a Saxon query or transformation. If no Configuration is supplied, * Saxon creates a Configuration on the first call to the {@link #parse} method, * and subsequent calls reuse the same Configuration. * *

    As an alternative to calling this method, a Configuration can be supplied by calling * setAttribute(FeatureKeys.CONFIGURATION, config) on the DocumentBuilderFactory * object, where config can be obtained by calling * getAttribute(FeatureKeys.CONFIGURATION) on the TransformerFactory.

    * * @since Saxon 8.8 */ public void setConfiguration(Configuration config) { this.config = config; } /** * Get the Saxon Configuration to be used by the document builder. This is * a non-JAXP method. * @return the Configuration previously supplied to {@link #setConfiguration}, * or the Configuration created automatically by Saxon on the first call to the * {@link #parse} method, or null if no Configuration has been supplied and * the {@link #parse} method has not been called. * * @since Saxon 8.8 */ public Configuration getConfiguration() { return config; } /** * Indicates whether or not this document builder is configured to * understand namespaces. * * @return true if this document builder is configured to understand * namespaces. This implementation always returns true. */ public boolean isNamespaceAware() { return true; } /** * Determine whether the document builder should perform DTD validation * @param state set to true to request DTD validation */ public void setValidating(boolean state) { validating = state; } /** * Indicates whether or not this document builder is configured to * validate XML documents against a DTD. * * @return true if this parser is configured to validate * XML documents against a DTD; false otherwise. */ public boolean isValidating() { return validating; } /** * Create a new Document Node. * @throws UnsupportedOperationException (always). The only way to build a document using this DocumentBuilder * implementation is by using the parse() method. */ public Document newDocument() { throw new UnsupportedOperationException("The only way to build a document using this DocumentBuilder is with the parse() method"); } /** * Parse the content of the given input source as an XML document * and return a new DOM {@link Document} object. * *

    Note: for this document to be usable as part of a Saxon query or transformation, * the document should be built within the {@link Configuration} in which that query * or transformation is running. This can be achieved using the non-JAXP * {@link #setConfiguration} method. * * @param in InputSource containing the content to be parsed. Note that if * an EntityResolver or ErrorHandler has been supplied, then the XMLReader contained * in this InputSource will be modified to register this EntityResolver or ErrorHandler, * replacing any that was previously registered. * * @exception SAXException If any parse errors occur. * @return A new DOM Document object. */ public Document parse(InputSource in) throws SAXException { try { Builder builder = new TinyBuilder(); if (config == null) { config = new Configuration(); } PipelineConfiguration pipe = config.makePipelineConfiguration(); builder.setPipelineConfiguration(pipe); SAXSource source = new SAXSource(in); if (entityResolver != null) { XMLReader reader = source.getXMLReader(); if (reader == null) { reader = config.getSourceParser(); } reader.setEntityResolver(entityResolver); } if (errorHandler != null) { XMLReader reader = source.getXMLReader(); if (reader == null) { reader = config.getSourceParser(); } reader.setErrorHandler(errorHandler); } source.setSystemId(in.getSystemId()); Source ss = source; if (xIncludeAware) { ss = AugmentedSource.makeAugmentedSource(ss); ((AugmentedSource)ss).setXIncludeAware(true); } if (validating) { ss = AugmentedSource.makeAugmentedSource(ss); ((AugmentedSource)ss).setDTDValidationMode(Validation.STRICT); } if (stripSpace != Whitespace.UNSPECIFIED) { ss = AugmentedSource.makeAugmentedSource(ss); ((AugmentedSource)ss).setStripSpace(stripSpace); } new Sender(pipe).send(source, builder); TinyDocumentImpl doc = (TinyDocumentImpl)builder.getCurrentRoot(); builder.reset(); return (Document)DocumentOverNodeInfo.wrap(doc); } catch (XPathException err) { throw new SAXException(err); } } /** * Parse the content of the given file as an XML document * and return a new DOM {@link Document} object. * An IllegalArgumentException is thrown if the * File is null null. * *

    This implementation differs from the parent implementation * by using a correct algorithm for filename-to-uri conversion.

    * * @param f The file containing the XML to parse. * @exception java.io.IOException If any IO errors occur. * @exception SAXException If any parse errors occur. * @return A new DOM Document object. */ public Document parse(File f) throws SAXException, IOException { if (f == null) { throw new IllegalArgumentException("File cannot be null"); } String uri = f.toURI().toString(); InputSource in = new InputSource(uri); return parse(in); } /** * Specify the {@link EntityResolver} to be used to resolve * entities present in the XML document to be parsed. Setting * this to null will result in the underlying * implementation using the EntityResolver registered with the * XMLReader contained in the InputSource. * * @param er The EntityResolver to be used to resolve entities * present in the XML document to be parsed. */ public void setEntityResolver(EntityResolver er) { entityResolver = er; } /** * Specify the {@link ErrorHandler} to be used by the parser. * Setting this to null will result in the underlying * implementation using using the ErrorHandler registered with the * XMLReader contained in the InputSource. * * @param eh The ErrorHandler to be used by the parser. */ public void setErrorHandler(ErrorHandler eh) { errorHandler = eh; } /** * Obtain an instance of a {@link DOMImplementation} object. * * @return A new instance of a DOMImplementation. */ public DOMImplementation getDOMImplementation() { return newDocument().getImplementation(); } /** *

    Set state of XInclude processing.

    *

    *

    If XInclude markup is found in the document instance, should it be * processed as specified in * XML Inclusions (XInclude) Version 1.0.

    *

    *

    XInclude processing defaults to false.

    * * @param state Set XInclude processing to true or * false */ public void setXIncludeAware(boolean state) { xIncludeAware = state; } /** *

    Get the XInclude processing mode for this parser.

    * * @return the return value of * the {@link javax.xml.parsers.DocumentBuilderFactory#isXIncludeAware()} * when this parser was created from factory. * @throws UnsupportedOperationException For backward compatibility, when implementations for * earlier versions of JAXP is used, this exception will be * thrown. * @see javax.xml.parsers.DocumentBuilderFactory#setXIncludeAware(boolean) * @since JAXP 1.5, Saxon 8.9 */ public boolean isXIncludeAware() { return xIncludeAware; } /** * Set the space-stripping action to be applied to the source document * @param stripAction one of {@link net.sf.saxon.value.Whitespace#IGNORABLE}, * {@link net.sf.saxon.value.Whitespace#ALL}, or {@link net.sf.saxon.value.Whitespace#NONE} * @since 8.9 */ public void setStripSpace(int stripAction) { stripSpace = stripAction; } /** * Get the space-stripping action to be applied to the source document * @return one of {@link net.sf.saxon.value.Whitespace#IGNORABLE}, * {@link net.sf.saxon.value.Whitespace#ALL}, or {@link net.sf.saxon.value.Whitespace#NONE} * @since 8.9 */ public int getStripSpace() { return stripSpace; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none //saxonb-9.1.0.8/bj/net/sf/saxon/dom/DOMEnvelope.java0000644000175000017500000003771211055011061021143 0ustar eugeneeugenepackage net.sf.saxon.dom; import net.sf.saxon.Configuration; import net.sf.saxon.event.PipelineConfiguration; import net.sf.saxon.event.Receiver; import net.sf.saxon.event.Sender; import net.sf.saxon.expr.JPConverter; import net.sf.saxon.expr.PJConverter; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.*; import net.sf.saxon.pattern.AnyNodeTest; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ItemType; import net.sf.saxon.value.SequenceExtent; import net.sf.saxon.value.Value; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import javax.xml.transform.Result; import javax.xml.transform.Source; import javax.xml.transform.dom.DOMSource; import javax.xml.xpath.XPathConstants; import java.io.Serializable; import java.util.ArrayList; import java.util.HashSet; import java.util.List; /** * DOMEnvelope is an object model representation in which DOM interfaces are wrapped around * Saxon NodeInfo nodes: that is, it implements the DOM on top of a Saxon tree implementation * such as the tiny tree or linked tree. */ public class DOMEnvelope implements ExternalObjectModel, Serializable { public DOMEnvelope() {} /** * Get the URI of the external object model as used in the JAXP factory interfaces for obtaining * an XPath implementation */ public String getIdentifyingURI() { return XPathConstants.DOM_OBJECT_MODEL; } public PJConverter getPJConverter(Class targetClass) { if (NodeOverNodeInfo.class.isAssignableFrom(targetClass)) { return new PJConverter() { public Object convert(ValueRepresentation value, Class targetClass, XPathContext context) throws XPathException { return convertXPathValueToObject(value, targetClass, context); } }; } else if (NodeList.class.isAssignableFrom(targetClass)) { return new PJConverter() { public Object convert(ValueRepresentation value, Class targetClass, XPathContext context) throws XPathException { return convertXPathValueToObject(value, targetClass, context); } }; } else { return null; } } public JPConverter getJPConverter(Class targetClass) { if (NodeOverNodeInfo.class.isAssignableFrom(targetClass)) { return new JPConverter() { public ValueRepresentation convert(Object object, XPathContext context) throws XPathException { return convertObjectToXPathValue(object, context.getConfiguration()); } public ItemType getItemType() { return AnyNodeTest.getInstance(); } }; } else { return null; } } /** * Get a converter that converts a sequence of XPath nodes to this model's representation * of a node list. * @param node an example of the kind of node used in this model * @return if the model does not recognize this node as one of its own, return null. Otherwise * return a PJConverter that takes a list of XPath nodes (represented as NodeInfo objects) and * returns a collection of nodes in this object model */ public PJConverter getNodeListCreator(Object node) { //return getPJConverter(NodeList.class); return null; } /** * Test whether this object model recognizes a given node as one of its own */ public boolean isRecognizedNode(Object object) { return object instanceof NodeOverNodeInfo; } /** * Test whether this object model recognizes a given class as representing a * node in that object model. This method will generally be called at compile time. * * @param nodeClass A class that possibly represents nodes * @return true if the class is used to represent nodes in this object model */ public boolean isRecognizedNodeClass(Class nodeClass) { return NodeOverNodeInfo.class.isAssignableFrom(nodeClass); } /** * Test whether this object model recognizes a given class as representing a * list of nodes in that object model. This method will generally be called at compile time. * * @param nodeClass A class that possibly represents nodes * @return true if the class is used to represent nodes in this object model */ private boolean isRecognizedNodeListClass(Class nodeClass) { return NodeList.class.isAssignableFrom(nodeClass); } /** * Test whether this object model recognizes a particular kind of JAXP Result object, * and if it does, return a Receiver that builds an instance of this data model from * a sequence of events. If the Result is not recognised, return null. *

    * This implementation always returns null: it is not possible to construct an instance * of this object model implementation directly as the result of a JAXP transformation. */ public Receiver getDocumentBuilder(Result result) throws XPathException { return null; } /** * Test whether this object model recognizes a particular kind of JAXP Source object, * and if it does, send the contents of the document to a supplied Receiver, and return true. * Otherwise, return false. *

    * This implementation returns true only if the source is a DOMSource whose contained node is a * a "NodeOverNodeInfo". */ public boolean sendSource(Source source, Receiver receiver, PipelineConfiguration pipe) throws XPathException { if (source instanceof DOMSource) { Node startNode = ((DOMSource)source).getNode(); if (startNode instanceof NodeOverNodeInfo) { NodeInfo base = ((NodeOverNodeInfo)startNode).getUnderlyingNodeInfo(); Sender driver = new Sender(pipe); driver.send(base, receiver); return true; } } return false; } /** * Wrap or unwrap a node using this object model to return the corresponding Saxon node. If the supplied * source does not belong to this object model, return null */ public NodeInfo unravel(Source source, Configuration config) { if (source instanceof DOMSource) { Node dsnode = ((DOMSource)source).getNode(); if (dsnode instanceof NodeOverNodeInfo) { // Supplied source is a DOM Node wrapping a Saxon node: unwrap it return ((NodeOverNodeInfo)dsnode).getUnderlyingNodeInfo(); } } return null; } /** * Convert a Java object to an XPath value. If the supplied object is recognized as a representation * of a value using this object model, the object model should convert the value to an XPath value * and return this as the result. If not, it should return null. If the object is recognized but cannot * be converted, an exception should be thrown */ public ValueRepresentation convertObjectToXPathValue(Object object, Configuration config) throws XPathException { if (object instanceof NodeList) { // NodeList needs great care, because Xerces element nodes implement the NodeList interface, // with the actual list being the children of the node in question. So we only recognize a // NodeList here if it is non-empty, and if all the nodes within it are NodeOverNodeInfo objects. NodeList list = ((NodeList)object); final int len = list.getLength(); if (len == 0) { return null; } NodeInfo[] nodes = new NodeInfo[len]; for (int i=0; iunwrap it). * @param node a node (any node) in the third party document * @param baseURI the base URI of the node (supply "" if unknown) * @param config the Saxon configuration (which among other things provides access to the NamePool) * @return the wrapper, which must implement DocumentInfo */ public DocumentInfo wrapDocument(Object node, String baseURI, Configuration config) { DocumentInfo doc = null; if (node instanceof DocumentOverNodeInfo) { doc = (DocumentInfo)((DocumentOverNodeInfo)node).getUnderlyingNodeInfo(); } else if (node instanceof NodeOverNodeInfo) { doc = ((NodeOverNodeInfo)node).getUnderlyingNodeInfo().getDocumentRoot(); } if (doc == null) { throw new IllegalArgumentException("Unknown node class " + node.getClass()); } else if (doc.getConfiguration() != config) { throw new IllegalArgumentException("Externally-supplied DOM envelope belong to the wrong Configuration"); } else { return doc; } } /** * Wrap a node in the external object model in a wrapper that implements * the Saxon NodeInfo interface. (However, if the supplied object is a wrapper for a Saxon * NodeInfo object, which is the case for this object model, then we unwrap it). * @param document the document wrapper, as a DocumentInfo object * @param node the node to be wrapped. This must be a node within the document wrapped by the * DocumentInfo provided in the first argument * @return the wrapper for the node, as an instance of VirtualNode */ public NodeInfo wrapNode(DocumentInfo document, Object node) { if (node instanceof NodeOverNodeInfo) { return ((NodeOverNodeInfo)node).getUnderlyingNodeInfo(); } throw new IllegalArgumentException("Unknown node class " + node.getClass()); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): Gunther Schadow (changes to allow access to public fields; also wrapping // of extensions and mapping of null to empty sequence). // saxonb-9.1.0.8/bj/net/sf/saxon/dom/DOMNodeList.java0000644000175000017500000000615611055506270021120 0ustar eugeneeugenepackage net.sf.saxon.dom; import net.sf.saxon.om.Item; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.om.VirtualNode; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.SequenceExtent; import org.w3c.dom.Node; import java.util.ArrayList; import java.util.List; /** * This class wraps a list of nodes as a DOM NodeList */ public final class DOMNodeList implements org.w3c.dom.NodeList { private List sequence; /** * Construct an node list that wraps a supplied SequenceExtent. This constructor does * not check that the items in the supplied SequenceExtent are indeed DOM Nodes. */ public DOMNodeList(List extent) { sequence = extent; } /** * Construct an node list that wraps a supplied SequenceExtent, checking that all the * items in the sequence are wrappers around DOM Nodes */ public static DOMNodeList checkAndMake(SequenceExtent extent) throws XPathException { SequenceIterator it = extent.iterate(); List list = new ArrayList(extent.getLength()); while (true) { Item next = it.next(); if (next==null) break; Object o = next; if (!(o instanceof NodeInfo)) { throw new XPathException("Supplied sequence contains an item that is not a Saxon NodeInfo"); } if (o instanceof VirtualNode) { o = ((VirtualNode)o).getUnderlyingNode(); if (!(o instanceof Node)) { throw new XPathException("Supplied sequence contains an item that is not a wrapper around a DOM Node"); } list.add(o); } } return new DOMNodeList(list); } /** * return the number of nodes in the list (DOM method) */ public int getLength() { return sequence.size(); } /** * Return the n'th item in the list (DOM method) * @return the n'th node in the node list, counting from zero; or null if the index is out of range * @throws java.lang.ClassCastException if the item is not a DOM Node */ public Node item(int index) { if (index < 0 || index >= sequence.size()) { return null; } else { return (Node)sequence.get(index); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/dom/DocumentBuilderFactoryImpl.java0000644000175000017500000002346211033112257024267 0ustar eugeneeugenepackage net.sf.saxon.dom; import net.sf.saxon.Configuration; import net.sf.saxon.FeatureKeys; import net.sf.saxon.value.Whitespace; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; /** * Implementation of JAXP 1.1 DocumentBuilderFactory. To build a Document using * Saxon, set the system property javax.xml.parsers.DocumentBuilderFactory to * "net.sf.saxon.om.DocumentBuilderFactoryImpl" and then call * DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(InputSource); */ public class DocumentBuilderFactoryImpl extends DocumentBuilderFactory { Configuration config = null; boolean xIncludeAware = false; public DocumentBuilderFactoryImpl() { setCoalescing(true); setExpandEntityReferences(true); setIgnoringComments(false); setIgnoringElementContentWhitespace(false); setNamespaceAware(true); setValidating(false); } /** * Allows the user to set specific attributes on the underlying * implementation. * @param name The name of the attribute. For Saxon this must be one of the * names defined in {@link FeatureKeys} * @param value The value of the attribute. * @exception IllegalArgumentException thrown if the underlying * implementation doesn't recognize the attribute. */ public void setAttribute(String name, Object value) { if (name.equals(FeatureKeys.CONFIGURATION)) { config = (Configuration)value; } else { if (config == null) { config = new Configuration(); } config.setConfigurationProperty(name, value); } } /** * Allows the user to retrieve specific attributes on the underlying * implementation. * @param name The name of the attribute. For Saxon this must be one of the * names defined in {@link FeatureKeys} * @return value The value of the attribute. * @exception IllegalArgumentException thrown if the underlying * implementation doesn't recognize the attribute. */ public Object getAttribute(String name) { if (name.equals(FeatureKeys.CONFIGURATION)) { return config; } else { if (config == null) { config = new Configuration(); } return config.getConfigurationProperty(name); } } /** * Creates a new instance of a {@link javax.xml.parsers.DocumentBuilder} * using the currently configured parameters. * * @exception ParserConfigurationException if a DocumentBuilder * cannot be created which satisfies the configuration requested. * @return A new instance of a DocumentBuilder. For Saxon the returned DocumentBuilder * will be an instance of {@link DocumentBuilderImpl} */ public DocumentBuilder newDocumentBuilder() throws ParserConfigurationException { // Check that configuration options are all available if (!isExpandEntityReferences()) { throw new ParserConfigurationException( "Saxon parser always expands entity references"); } if (isIgnoringComments()) { throw new ParserConfigurationException( "Saxon parser does not allow comments to be ignored"); } if (isIgnoringElementContentWhitespace()) { throw new ParserConfigurationException( "Saxon parser does not allow whitespace in element content to be ignored"); } if (!isNamespaceAware()) { throw new ParserConfigurationException( "Saxon parser is always namespace aware"); } DocumentBuilderImpl builder = new DocumentBuilderImpl(); builder.setValidating(isValidating()); builder.setXIncludeAware(xIncludeAware); if (isIgnoringElementContentWhitespace()) { builder.setStripSpace(Whitespace.IGNORABLE); } builder.setConfiguration(config); return builder; } /** *

    Set a feature for this DocumentBuilderFactory and DocumentBuilders created by this factory.

    *

    *

    * Feature names are fully qualified {@link java.net.URI}s. * Implementations may define their own features. * An {@link javax.xml.parsers.ParserConfigurationException} is thrown if this DocumentBuilderFactory or the * DocumentBuilders it creates cannot support the feature. * It is possible for an DocumentBuilderFactory to expose a feature value but be unable to change its state. *

    *

    *

    * All implementations are required to support the {@link javax.xml.XMLConstants#FEATURE_SECURE_PROCESSING} feature. * When the feature is:

    *
      *
    • * true: the implementation will limit XML processing to conform to implementation limits. * Examples include entity expansion limits and XML Schema constructs that would consume large amounts of resources. * If XML processing is limited for security reasons, it will be reported via a call to the registered * {@link org.xml.sax.ErrorHandler#fatalError(org.xml.sax.SAXParseException exception)}. * See {@link javax.xml.parsers.DocumentBuilder#setErrorHandler(org.xml.sax.ErrorHandler errorHandler)}. *
    • *
    • * false: the implementation will processing XML according to the XML specifications without * regard to possible implementation limits. *
    • *
    * * @param name Feature name. * @param value Is feature state true or false. * @throws javax.xml.parsers.ParserConfigurationException * if this DocumentBuilderFactory or the DocumentBuilders * it creates cannot support this feature. * @throws NullPointerException If the name parameter is null. */ public void setFeature(String name, boolean value) throws ParserConfigurationException { if (name.equals(FEATURE_SECURE_PROCESSING) && !value) { // no action } else { throw new ParserConfigurationException("Unsupported feature or value: " + name); } } /** *

    Get the state of the named feature.

    *

    *

    * Feature names are fully qualified {@link java.net.URI}s. * Implementations may define their own features. * An {@link javax.xml.parsers.ParserConfigurationException} is thrown if this DocumentBuilderFactory or the * DocumentBuilders it creates cannot support the feature. * It is possible for an DocumentBuilderFactory to expose a feature value but be unable to change its state. *

    * * @param name Feature name. * @return State of the named feature. * @throws javax.xml.parsers.ParserConfigurationException * if this DocumentBuilderFactory * or the DocumentBuilders it creates cannot support this feature. */ public boolean getFeature(String name) throws ParserConfigurationException { if (name.equals(FEATURE_SECURE_PROCESSING)) { return false; } else { throw new ParserConfigurationException("Unsupported feature: " + name); } } /** *

    Get state of XInclude processing.

    * * @return current state of XInclude processing * @throws UnsupportedOperationException For backward compatibility, when implementations for * earlier versions of JAXP is used, this exception will be * thrown. * @since 1.5 */ public boolean isXIncludeAware() { return xIncludeAware; } /** *

    Set state of XInclude processing.

    *

    *

    If XInclude markup is found in the document instance, should it be * processed as specified in * XML Inclusions (XInclude) Version 1.0.

    *

    *

    XInclude processing defaults to false.

    * * @param state Set XInclude processing to true or * false * @throws UnsupportedOperationException For backward compatibility, when implementations for * earlier versions of JAXP is used, this exception will be * thrown. * @since 1.5 */ public void setXIncludeAware(boolean state) { xIncludeAware = state; } private static String FEATURE_SECURE_PROCESSING = "http://javax.xml.XMLConstants/feature/secure-processing"; // XMLConstants.FEATURE_SECURE_PROCESSING in JDK 1.5 } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none //saxonb-9.1.0.8/bj/net/sf/saxon/dom/package.html0000644000175000017500000000517311033112257020445 0ustar eugeneeugene Package overview for net.sf.saxon.dom

    This package provides glue classes that enable Saxon to process a source document supplied as a DOM tree in the form of a DOMSource object; it also provides classes that present a DOM view of Saxon's native tree structures.

    Because of incompatibilities between the DOM interfaces in JDK 1.4 and JDK 1.5, the native Saxon tree structures (the standard tree and tiny tree) no longer implements DOM interfaces directly. In addition, to reduce installation problems for users who dont require DOM interfaces, this package is delivered in a JAR file of its own, saxon8-dom.jar, and not with the main saxon8.jar JAR file. However, Saxon continues to support the DOM at two levels:

    • The input to a transformation or query may be supplied in the form of a DOMSource (which contains a DOM document). Saxon performs the query or transformation on the DOM in situ, by wrapping the DOM nodes in a layer that make them appear to be Saxon nodes.

    • It is possible for a transformation or query to call extension functions that use DOM interfaces to access a Saxon tree. If the Saxon tree is in fact a wrapper around the DOM, then extension functions will be presented with the underlying DOM nodes. In other cases, Saxon adds a wrapper to the native Saxon nodes to make them implement the DOM interfaces.

      Note, however, that Saxon's tree structures are immutable. Updating interfaces in the DOM API are therefore not supported.

    The classes NodeWrapper and DocumentWrapper implement the Saxon interfaces NodeInfo and DocumentInfo on top of an underlying DOM Node or Document object respectively. This enables XPath expressions to be executed directly against the DOM.

    The classes NodeOverNodeInfo, DocumentOverNodeInfo, and the like do the converse: they provide a DOM wrapper over a native Saxon node.

    Note that using the DOM with Saxon is considerably less efficient than using Saxon's native tree implementations, the Tiny Tree and the (so-called) Standard Tree. The DOM should be used only where there is some good reason, e.g. where other parts of the application have to use DOM interfaces.

    Saxon doesn't stop you modifying the contents of the DOM in the course of a transformation (for example, from an extension function, or in a different thread) but the consequences of doing so are unpredictable.


    Michael H. Kay
    Saxonica Limited
    9 February 2005

    saxonb-9.1.0.8/bj/net/sf/saxon/charcode/0000755000175000017500000000000012216261747017164 5ustar eugeneeugenesaxonb-9.1.0.8/bj/net/sf/saxon/charcode/CP1250CharacterSet.java0000644000175000017500000001142211033112257023115 0ustar eugeneeugenepackage net.sf.saxon.charcode; import java.util.Arrays; /** * This class defines properties of the cp1250 Central Europe character set, * as defined at http://www.microsoft.com/globaldev/reference/sbcs/1250.htm. * @author Michael Kay, with advice from Jirka Kocek */ public class CP1250CharacterSet implements CharacterSet{ public static CP1250CharacterSet theInstance = null; private CP1250CharacterSet() {} public static CP1250CharacterSet getInstance() { if (theInstance == null) { init(); theInstance = new CP1250CharacterSet(); } return theInstance; } private static boolean[] c = null; private static void init() { c = new boolean[740]; // for (int i=0; i<127; i++) { // c[i] = true; // } Arrays.fill(c, 0, 127, true); // for (int i=128; i<740; i++) { // c[i] = false; // } Arrays.fill(c, 127, 740, false); c[160] = true; c[164] = true; c[166] = true; c[167] = true; c[168] = true; c[169] = true; c[171] = true; c[172] = true; c[173] = true; c[174] = true; c[176] = true; c[177] = true; c[180] = true; c[181] = true; c[182] = true; c[183] = true; c[184] = true; c[187] = true; c[193] = true; c[194] = true; c[196] = true; c[199] = true; c[201] = true; c[203] = true; c[205] = true; c[206] = true; c[211] = true; c[212] = true; c[214] = true; c[215] = true; c[218] = true; c[220] = true; c[221] = true; c[223] = true; c[225] = true; c[226] = true; c[228] = true; c[231] = true; c[233] = true; c[235] = true; c[237] = true; c[238] = true; c[243] = true; c[244] = true; c[246] = true; c[247] = true; c[250] = true; c[252] = true; c[253] = true; c[258] = true; c[259] = true; c[260] = true; c[261] = true; c[262] = true; c[263] = true; c[268] = true; c[269] = true; c[270] = true; c[271] = true; c[272] = true; c[273] = true; c[280] = true; c[281] = true; c[282] = true; c[283] = true; c[313] = true; c[314] = true; c[317] = true; c[318] = true; c[321] = true; c[322] = true; c[323] = true; c[324] = true; c[327] = true; c[328] = true; c[336] = true; c[337] = true; c[340] = true; c[341] = true; c[344] = true; c[345] = true; c[346] = true; c[347] = true; c[350] = true; c[351] = true; c[352] = true; c[353] = true; c[354] = true; c[355] = true; c[356] = true; c[357] = true; c[366] = true; c[367] = true; c[368] = true; c[369] = true; c[377] = true; c[378] = true; c[379] = true; c[380] = true; c[381] = true; c[382] = true; c[711] = true; c[728] = true; c[729] = true; c[731] = true; c[733] = true; } public final boolean inCharset(int ch) { return (ch < 740 && c[ch]) || (ch > 8210 && ( ch==8211 || ch==8212 || ch==8216 || ch==8217 || ch==8218 || ch==8220 || ch==8221 || ch==8222 || ch==8224 || ch==8225 || ch==8226 || ch==8230 || ch==8240 || ch==8249 || ch==8250 || ch==8364 || ch==8482 )); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/charcode/KOI8RCharacterSet.java0000644000175000017500000000246211033112257023143 0ustar eugeneeugenepackage net.sf.saxon.charcode; /** * This class defines properties of the KO18R Cyrillic character set */ public class KOI8RCharacterSet implements CharacterSet { private static KOI8RCharacterSet theInstance = new KOI8RCharacterSet(); private KOI8RCharacterSet() {} public static KOI8RCharacterSet getInstance() { return theInstance; } public final boolean inCharset(int c) { return ( c <= 0x7f ) || ( (0x0410 <= c) && (c <= 0x044f) ) || c == 0x0451 || c == 0x0401; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is // Aleksei Makarov [makarov@iitam.omsk.net.ru] // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/charcode/ISO88599CharacterSet.java0000644000175000017500000000550011033112257023364 0ustar eugeneeugenepackage net.sf.saxon.charcode; import java.util.Arrays; /* Copyright (C) 2006 Hewlett-Packard Development Company, L.P. The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. The Original Code is: all this file The Initial Developer of the Original Code is Lauren Ward. All Rights Reserved. Contributor(s): Integrated into Saxon by Michael Kay ************************* Author: Lauren Ward Date: February 01, 2006 Address: Hewlett-Packard Company 3404 East Harmony Road Fort Collins, CO 80528-9599 Revision: 1.0 - Initial creation Description: This class implements the PluggableCharacterSet to support iso-8859-9 encoding. The character mapping was obtained by extracting the Unicode values from an iconv character table (iso89=ucs2) available on HP-UX 11.23. The class was tested by transforming a document with ISO-8859-9 set as the output encoding, converting ISO-8859-9 output to utf-8 using iconv, and then comparing converted content to the same transformed document with utf-8 set as the output encoding. */ public class ISO88599CharacterSet implements CharacterSet { private static ISO88599CharacterSet THE_INSTANCE = new ISO88599CharacterSet(); public static ISO88599CharacterSet getInstance() { return THE_INSTANCE; } private static boolean c[]; static { c = new boolean[360]; // for (int i=0; i<=25; ++i) { c[i] = true; } // for (int i=27; i<=207; ++i) { c[i] = true; } // for (int i=209; i<=220; ++i) { c[i] = true; } // for (int i=223; i<=239; ++i) { c[i] = true; } // for (int i=241; i<=252; ++i) { c[i] = true; } // c[255] = true; // for (int i=286; i<=287; ++i) { c[i] = true; } // for (int i=304; i<=305; ++i) { c[i] = true; } // for (int i=350; i<=351; ++i) { c[i] = true; } Arrays.fill(c, 0, 256, true); c[26] = false; c[208] = false; c[221] = false; c[222] = false; c[240] = false; c[253] = false; c[254] = false; c[286] = true; c[287] = true; c[304] = true; c[305] = true; c[350] = true; c[351] = true; } public ISO88599CharacterSet() { } // Determine if it is a valid character public final boolean inCharset(int ch) { return ch < 360 && c[ch]; } public final String getEncodingName() { // Canonical Name for java.io and java.lang API return "ISO8859_9"; } } saxonb-9.1.0.8/bj/net/sf/saxon/charcode/CP1251CharacterSet.java0000644000175000017500000001706011033112257023122 0ustar eugeneeugenepackage net.sf.saxon.charcode; /** * This class defines properties of the CP1251 Cyrillic character set, * as defined at http://www.microsoft.com/globaldev/reference/sbcs/1251.htm. */ public class CP1251CharacterSet implements CharacterSet { public static CP1251CharacterSet theInstance = new CP1251CharacterSet(); private CP1251CharacterSet() {} public static CP1251CharacterSet getInstance() { return theInstance; } public final boolean inCharset(int c) { return ( c <= 0x7f ) || (c >= 0x0401 && c <= 0x044F) || (c >= 0x0451 && c <= 0x045f) || (c == 0x0490) || (c == 0x0491) || (c > 0x2012 && c <= 0x2122 && ( (c == 0x2013) || (c == 0x2014) || (c == 0x2018) || (c == 0x2019) || (c == 0x201A) || (c == 0x201C) || (c == 0x201D) || (c == 0x201E) || (c == 0x2020) || (c == 0x2021) || (c == 0x2022) || (c == 0x2026) || (c == 0x2030) || (c == 0x2039) || (c == 0x203A) || (c == 0x20AC) || (c == 0x2116) || (c == 0x2122))); } } // 80 = U+0402 : CYRILLIC CAPITAL LETTER DJE // 81 = U+0403 : CYRILLIC CAPITAL LETTER GJE // 82 = U+201A : SINGLE LOW-9 QUOTATION MARK // 83 = U+0453 : CYRILLIC SMALL LETTER GJE // 84 = U+201E : DOUBLE LOW-9 QUOTATION MARK // 85 = U+2026 : HORIZONTAL ELLIPSIS // 86 = U+2020 : DAGGER // 87 = U+2021 : DOUBLE DAGGER // 88 = U+20AC : EURO SIGN // 89 = U+2030 : PER MILLE SIGN // 8A = U+0409 : CYRILLIC CAPITAL LETTER LJE // 8B = U+2039 : SINGLE LEFT-POINTING ANGLE QUOTATION MARK // 8C = U+040A : CYRILLIC CAPITAL LETTER NJE // 8D = U+040C : CYRILLIC CAPITAL LETTER KJE // 8E = U+040B : CYRILLIC CAPITAL LETTER TSHE // 8F = U+040F : CYRILLIC CAPITAL LETTER DZHE // 90 = U+0452 : CYRILLIC SMALL LETTER DJE // 91 = U+2018 : LEFT SINGLE QUOTATION MARK // 92 = U+2019 : RIGHT SINGLE QUOTATION MARK // 93 = U+201C : LEFT DOUBLE QUOTATION MARK // 94 = U+201D : RIGHT DOUBLE QUOTATION MARK // 95 = U+2022 : BULLET // 96 = U+2013 : EN DASH // 97 = U+2014 : EM DASH // 99 = U+2122 : TRADE MARK SIGN // 9A = U+0459 : CYRILLIC SMALL LETTER LJE // 9B = U+203A : SINGLE RIGHT-POINTING ANGLE QUOTATION MARK // 9C = U+045A : CYRILLIC SMALL LETTER NJE // 9D = U+045C : CYRILLIC SMALL LETTER KJE // 9E = U+045B : CYRILLIC SMALL LETTER TSHE // 9F = U+045F : CYRILLIC SMALL LETTER DZHE // A0 = U+00A0 : NO-BREAK SPACE // A1 = U+040E : CYRILLIC CAPITAL LETTER SHORT U // A2 = U+045E : CYRILLIC SMALL LETTER SHORT U // A3 = U+0408 : CYRILLIC CAPITAL LETTER JE // A4 = U+00A4 : CURRENCY SIGN // A5 = U+0490 : CYRILLIC CAPITAL LETTER GHE WITH UPTURN // A6 = U+00A6 : BROKEN BAR // A7 = U+00A7 : SECTION SIGN // A8 = U+0401 : CYRILLIC CAPITAL LETTER IO // A9 = U+00A9 : COPYRIGHT SIGN // AA = U+0404 : CYRILLIC CAPITAL LETTER UKRAINIAN IE // AB = U+00AB : LEFT-POINTING DOUBLE ANGLE QUOTATION MARK // AC = U+00AC : NOT SIGN // AD = U+00AD : SOFT HYPHEN // AE = U+00AE : REGISTERED SIGN // AF = U+0407 : CYRILLIC CAPITAL LETTER YI // B0 = U+00B0 : DEGREE SIGN // B1 = U+00B1 : PLUS-MINUS SIGN // B2 = U+0406 : CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I // B3 = U+0456 : CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I // B4 = U+0491 : CYRILLIC SMALL LETTER GHE WITH UPTURN // B5 = U+00B5 : MICRO SIGN // B6 = U+00B6 : PILCROW SIGN // B7 = U+00B7 : MIDDLE DOT // B8 = U+0451 : CYRILLIC SMALL LETTER IO // B9 = U+2116 : NUMERO SIGN // BA = U+0454 : CYRILLIC SMALL LETTER UKRAINIAN IE // BB = U+00BB : RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK // BC = U+0458 : CYRILLIC SMALL LETTER JE // BD = U+0405 : CYRILLIC CAPITAL LETTER DZE // BE = U+0455 : CYRILLIC SMALL LETTER DZE // BF = U+0457 : CYRILLIC SMALL LETTER YI // C0 = U+0410 : CYRILLIC CAPITAL LETTER A // C1 = U+0411 : CYRILLIC CAPITAL LETTER BE // C2 = U+0412 : CYRILLIC CAPITAL LETTER VE // C3 = U+0413 : CYRILLIC CAPITAL LETTER GHE // C4 = U+0414 : CYRILLIC CAPITAL LETTER DE // C5 = U+0415 : CYRILLIC CAPITAL LETTER IE // C6 = U+0416 : CYRILLIC CAPITAL LETTER ZHE // C7 = U+0417 : CYRILLIC CAPITAL LETTER ZE // C8 = U+0418 : CYRILLIC CAPITAL LETTER I // C9 = U+0419 : CYRILLIC CAPITAL LETTER SHORT I // CA = U+041A : CYRILLIC CAPITAL LETTER KA // CB = U+041B : CYRILLIC CAPITAL LETTER EL // CC = U+041C : CYRILLIC CAPITAL LETTER EM // CD = U+041D : CYRILLIC CAPITAL LETTER EN // CE = U+041E : CYRILLIC CAPITAL LETTER O // CF = U+041F : CYRILLIC CAPITAL LETTER PE // D0 = U+0420 : CYRILLIC CAPITAL LETTER ER // D1 = U+0421 : CYRILLIC CAPITAL LETTER ES // D2 = U+0422 : CYRILLIC CAPITAL LETTER TE // D3 = U+0423 : CYRILLIC CAPITAL LETTER U // D4 = U+0424 : CYRILLIC CAPITAL LETTER EF // D5 = U+0425 : CYRILLIC CAPITAL LETTER HA // D6 = U+0426 : CYRILLIC CAPITAL LETTER TSE // D7 = U+0427 : CYRILLIC CAPITAL LETTER CHE // D8 = U+0428 : CYRILLIC CAPITAL LETTER SHA // D9 = U+0429 : CYRILLIC CAPITAL LETTER SHCHA // DA = U+042A : CYRILLIC CAPITAL LETTER HARD SIGN // DB = U+042B : CYRILLIC CAPITAL LETTER YERU // DC = U+042C : CYRILLIC CAPITAL LETTER SOFT SIGN // DD = U+042D : CYRILLIC CAPITAL LETTER E // DE = U+042E : CYRILLIC CAPITAL LETTER YU // DF = U+042F : CYRILLIC CAPITAL LETTER YA // E0 = U+0430 : CYRILLIC SMALL LETTER A // E1 = U+0431 : CYRILLIC SMALL LETTER BE // E2 = U+0432 : CYRILLIC SMALL LETTER VE // E3 = U+0433 : CYRILLIC SMALL LETTER GHE // E4 = U+0434 : CYRILLIC SMALL LETTER DE // E5 = U+0435 : CYRILLIC SMALL LETTER IE // E6 = U+0436 : CYRILLIC SMALL LETTER ZHE // E7 = U+0437 : CYRILLIC SMALL LETTER ZE // E8 = U+0438 : CYRILLIC SMALL LETTER I // E9 = U+0439 : CYRILLIC SMALL LETTER SHORT I // EA = U+043A : CYRILLIC SMALL LETTER KA // EB = U+043B : CYRILLIC SMALL LETTER EL // EC = U+043C : CYRILLIC SMALL LETTER EM // ED = U+043D : CYRILLIC SMALL LETTER EN // EE = U+043E : CYRILLIC SMALL LETTER O // EF = U+043F : CYRILLIC SMALL LETTER PE // F0 = U+0440 : CYRILLIC SMALL LETTER ER // F1 = U+0441 : CYRILLIC SMALL LETTER ES // F2 = U+0442 : CYRILLIC SMALL LETTER TE // F3 = U+0443 : CYRILLIC SMALL LETTER U // F4 = U+0444 : CYRILLIC SMALL LETTER EF // F5 = U+0445 : CYRILLIC SMALL LETTER HA // F6 = U+0446 : CYRILLIC SMALL LETTER TSE // F7 = U+0447 : CYRILLIC SMALL LETTER CHE // F8 = U+0448 : CYRILLIC SMALL LETTER SHA // F9 = U+0449 : CYRILLIC SMALL LETTER SHCHA // FA = U+044A : CYRILLIC SMALL LETTER HARD SIGN // FB = U+044B : CYRILLIC SMALL LETTER YERU // FC = U+044C : CYRILLIC SMALL LETTER SOFT SIGN // FD = U+044D : CYRILLIC SMALL LETTER E // FE = U+044E : CYRILLIC SMALL LETTER YU // FF = U+044F : CYRILLIC SMALL LETTER YA // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is // Aleksei Makarov [makarov@iitam.omsk.net.ru] // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/charcode/UnknownCharacterSet.java0000644000175000017500000000573211033112257023751 0ustar eugeneeugenepackage net.sf.saxon.charcode; import java.nio.charset.Charset; import java.nio.charset.CharsetEncoder; import java.util.HashMap; /** * This class establishes properties of a character set that is * known to the Java VM but not specifically known to Saxon */ public class UnknownCharacterSet implements CharacterSet { public static HashMap map; private CharsetEncoder encoder; // This class is written on the assumption that the CharsetEncoder.canEncode() // method may be expensive. For BMP characters, it therefore remembers the results // so each character is only looked up the first time it is encountered. private byte[] charinfo = new byte[65536]; // rely on initialization to zeroes private StringBuffer supplementary = new StringBuffer(2); //private final static byte UNKNOWN = 0; private static final byte GOOD = 1; private static final byte BAD = 2; private UnknownCharacterSet(Charset charset) { encoder = charset.newEncoder(); } public static synchronized UnknownCharacterSet makeCharSet(Charset charset) { if (map == null) { map = new HashMap(10); } UnknownCharacterSet c = (UnknownCharacterSet)map.get(charset); if (c == null) { c = new UnknownCharacterSet(charset); map.put(charset, c); } return c; } public final boolean inCharset(int c) { // Assume ASCII chars are always OK if (c <= 127) { return true; } if (c <= 65535) { if (charinfo[c] == GOOD) { return true; } else if (charinfo[c] == BAD) { return false; } else { if (encoder.canEncode((char)c)) { charinfo[c] = GOOD; return true; } else { charinfo[c] = BAD; return false; } } } else { supplementary.setCharAt(0, UTF16.highSurrogate(c)); supplementary.setCharAt(1, UTF16.lowSurrogate(c)); return encoder.canEncode(supplementary); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is // Aleksei Makarov [makarov@iitam.omsk.net.ru] // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/charcode/ISO88592CharacterSet.java0000644000175000017500000001572211033112257023364 0ustar eugeneeugenepackage net.sf.saxon.charcode; import java.util.Arrays; /** * This class defines properties of the ISO-8859-2 character set */ public class ISO88592CharacterSet implements CharacterSet { private static ISO88592CharacterSet theInstance = null; private ISO88592CharacterSet() {} public static ISO88592CharacterSet getInstance() { if (theInstance == null) { theInstance = new ISO88592CharacterSet(); } return theInstance; } private static boolean[] c = null; static { c = new boolean[750]; // for (int i=0; i<127; i++) { // c[i] = true; // } Arrays.fill(c, 0, 127, true); // for (int i=128; i<750; i++) { // c[i] = false; // } Arrays.fill(c, 127, 750, false); c[ 160 ] = true; c[ 164 ] = true; c[ 167 ] = true; c[ 168 ] = true; c[ 173 ] = true; c[ 176 ] = true; c[ 180 ] = true; c[ 184 ] = true; c[ 193 ] = true; c[ 194 ] = true; c[ 196 ] = true; c[ 199 ] = true; c[ 201 ] = true; c[ 203 ] = true; c[ 205 ] = true; c[ 206 ] = true; c[ 211 ] = true; c[ 212 ] = true; c[ 214 ] = true; c[ 215 ] = true; c[ 218 ] = true; c[ 220 ] = true; c[ 221 ] = true; c[ 223 ] = true; c[ 225 ] = true; c[ 226 ] = true; c[ 228 ] = true; c[ 231 ] = true; c[ 233 ] = true; c[ 235 ] = true; c[ 237 ] = true; c[ 238 ] = true; c[ 243 ] = true; c[ 244 ] = true; c[ 246 ] = true; c[ 247 ] = true; c[ 250 ] = true; c[ 252 ] = true; c[ 253 ] = true; c[ 258 ] = true; c[ 259 ] = true; c[ 260 ] = true; c[ 261 ] = true; c[ 262 ] = true; c[ 263 ] = true; c[ 268 ] = true; c[ 269 ] = true; c[ 270 ] = true; c[ 271 ] = true; c[ 272 ] = true; c[ 273 ] = true; c[ 280 ] = true; c[ 281 ] = true; c[ 282 ] = true; c[ 283 ] = true; c[ 313 ] = true; c[ 314 ] = true; c[ 317 ] = true; c[ 318 ] = true; c[ 321 ] = true; c[ 322 ] = true; c[ 323 ] = true; c[ 324 ] = true; c[ 327 ] = true; c[ 328 ] = true; c[ 336 ] = true; c[ 337 ] = true; c[ 340 ] = true; c[ 341 ] = true; c[ 344 ] = true; c[ 345 ] = true; c[ 346 ] = true; c[ 347 ] = true; c[ 350 ] = true; c[ 351 ] = true; c[ 352 ] = true; c[ 353 ] = true; c[ 354 ] = true; c[ 355 ] = true; c[ 356 ] = true; c[ 357 ] = true; c[ 366 ] = true; c[ 367 ] = true; c[ 368 ] = true; c[ 369 ] = true; c[ 377 ] = true; c[ 378 ] = true; c[ 379 ] = true; c[ 380 ] = true; c[ 381 ] = true; c[ 382 ] = true; c[ 711 ] = true; c[ 728 ] = true; c[ 729 ] = true; c[ 731 ] = true; c[ 733 ] = true; } public final boolean inCharset(int ch) { return (ch < 750 && c[ch]); } } // Data from Han The Thanh [thanh@informatics.muni.cz] // Latin2 UTF8-1 UTF8-2 Name Unicode // 160 194 160 nobreakspace 160 // 164 194 164 currency 164 // 167 194 167 section 167 // 168 194 168 diaeresis 168 // 173 194 173 hyphen 173 // 176 194 176 degree 176 // 180 194 180 acute 180 // 184 194 184 cedilla 184 // 193 195 129 Aacute 193 // 194 195 130 Acircumflex 194 // 196 195 132 Adiaeresis 196 // 199 195 135 Ccedilla 199 // 201 195 137 Eacute 201 // 203 195 139 Ediaeresis 203 // 205 195 141 Iacute 205 // 206 195 142 Icircumflex 206 // 211 195 147 Oacute 211 // 212 195 148 Ocircumflex 212 // 214 195 150 Odiaeresis 214 // 215 195 151 multiply 215 // 218 195 154 Uacute 218 // 220 195 156 Udiaeresis 220 // 221 195 157 Yacute 221 // 223 195 159 ssharp 223 // 225 195 161 aacute 225 // 226 195 162 acircumflex 226 // 228 195 164 adiaeresis 228 // 231 195 167 ccedilla 231 // 233 195 169 eacute 233 // 235 195 171 ediaeresis 235 // 237 195 173 iacute 237 // 238 195 174 icircumflex 238 // 243 195 179 oacute 243 // 244 195 180 ocircumflex 244 // 246 195 182 odiaeresis 246 // 247 195 183 division 247 // 250 195 186 uacute 250 // 252 195 188 udiaeresis 252 // 253 195 189 yacute 253 // 195 196 130 Abreve 258 // 227 196 131 abreve 259 // 161 196 132 Aogonek 260 // 177 196 133 aogonek 261 // 198 196 134 Cacute 262 // 230 196 135 cacute 263 // 200 196 140 Ccaron 268 // 232 196 141 ccaron 269 // 207 196 142 Dcaron 270 // 239 196 143 dcaron 271 // 208 196 144 Eth 272 // 240 196 145 eth 273 // 202 196 152 Eogonek 280 // 234 196 153 eogonek 281 // 204 196 154 Ecaron 282 // 236 196 155 ecaron 283 // 197 196 185 Lacute 313 // 229 196 186 lacute 314 // 165 196 189 Lcaron 317 // 181 196 190 lcaron 318 // 163 197 129 Lstroke 321 // 179 197 130 lstroke 322 // 209 197 131 Nacute 323 // 241 197 132 nacute 324 // 210 197 135 Ncaron 327 // 242 197 136 ncaron 328 // 213 197 144 Odoubleacute 336 // 245 197 145 odoubleacute 337 // 192 197 148 Racute 340 // 224 197 149 racute 341 // 216 197 152 Rcaron 344 // 248 197 153 rcaron 345 // 166 197 154 Sacute 346 // 182 197 155 sacute 347 // 170 197 158 Scedilla 350 // 186 197 159 scedilla 351 // 169 197 160 Scaron 352 // 185 197 161 scaron 353 // 222 197 162 Tcedilla 354 // 254 197 163 tcedilla 355 // 171 197 164 Tcaron 356 // 187 197 165 tcaron 357 // 217 197 174 Uring 366 // 249 197 175 uring 367 // 219 197 176 Udoubleacute 368 // 251 197 177 udoubleacute 369 // 172 197 185 Zacute 377 // 188 197 186 zacute 378 // 175 197 187 Zabovedot 379 // 191 197 188 zabovedot 380 // 174 197 189 Zcaron 381 // 190 197 190 zcaron 382 // 183 203 135 caron 711 // 162 203 152 breve 728 // 255 203 153 abovedot 729 // 178 203 155 ogonek 731 // 189 203 157 doubleacute 733 // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay using data supplied by Han The Thanh [thanh@informatics.muni.cz] // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/charcode/CP852CharacterSet.java0000644000175000017500000001057511033112257023054 0ustar eugeneeugenepackage net.sf.saxon.charcode; import java.util.Arrays; /** * This package defines character set CP852 */ public class CP852CharacterSet implements CharacterSet { public static CP852CharacterSet theInstance = null; private CP852CharacterSet() { } public static CP852CharacterSet getInstance() { if (theInstance == null) { init(); theInstance = new CP852CharacterSet(); } return theInstance; } private static boolean c[] = null; private static void init() { c = new boolean[400]; // for (int i=0; i<127; i++) { // c[i] = true; // } Arrays.fill(c, 0, 127, true); // for (int i=127; i<400; i++) { // c[i] = false; // } Arrays.fill(c, 127, 400, false); c[167] = true; c[171] = true; c[172] = true; c[187] = true; c[193] = true; c[194] = true; c[196] = true; c[199] = true; c[201] = true; c[203] = true; c[205] = true; c[206] = true; c[211] = true; c[212] = true; c[214] = true; c[218] = true; c[220] = true; c[221] = true; c[223] = true; c[225] = true; c[226] = true; c[228] = true; c[231] = true; c[233] = true; c[235] = true; c[237] = true; c[238] = true; c[243] = true; c[244] = true; c[246] = true; c[250] = true; c[252] = true; c[253] = true; c[258] = true; c[259] = true; c[260] = true; c[261] = true; c[262] = true; c[263] = true; c[268] = true; c[269] = true; c[270] = true; c[271] = true; c[272] = true; c[273] = true; c[280] = true; c[281] = true; c[282] = true; c[283] = true; c[313] = true; c[314] = true; c[317] = true; c[318] = true; c[321] = true; c[322] = true; c[323] = true; c[324] = true; c[327] = true; c[328] = true; c[336] = true; c[337] = true; c[340] = true; c[341] = true; c[344] = true; c[345] = true; c[346] = true; c[347] = true; c[350] = true; c[351] = true; c[352] = true; c[353] = true; c[355] = true; c[356] = true; c[357] = true; c[366] = true; c[367] = true; c[368] = true; c[369] = true; c[377] = true; c[378] = true; c[379] = true; c[380] = true; c[381] = true; c[382] = true; } public final boolean inCharset(int ch) { return ch < 400 && c[ch]; } public final String getEncodingName() { return "cp852"; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Zdenek Wagner [zdenek.wagner@gmail.com]. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // /** Originally contributed in 2001. In releases prior to Saxon 9.0, this code was present under a different license. It has been recontributed under the Mozilla license by the original author on 2007-10-21. The character mapping was obtained by conversion a character table of all non-US characters from CP852 into UNICODE entities using a simple stylesheet and saxon with the following attribute in xsl:output saxon:character-representation="dec;dec" The class was tested by reverse conversion of the generated table to native representation as well as by transformation of several texts which use Czech and Slovak accented characters. */ saxonb-9.1.0.8/bj/net/sf/saxon/charcode/BuggyCharacterSet.java0000644000175000017500000000663411033112257023371 0ustar eugeneeugenepackage net.sf.saxon.charcode; import java.nio.CharBuffer; import java.nio.charset.CharacterCodingException; import java.nio.charset.Charset; import java.nio.charset.CharsetEncoder; import java.util.HashMap; /** * This class establishes properties of a character set that is * known to the Java VM but not specifically known to Saxon. It avoids * using the encoder.canEncode() method because there is a known bug * (in JDK 1.4.2) that for some encodings, this returns true for * every character. So this version of the class actually attempts * to encode the characters, and catches the exception when it fails. */ public class BuggyCharacterSet implements CharacterSet { private static HashMap map; private CharsetEncoder encoder; // This class is written on the assumption that the CharsetEncoder.canEncode() // method may be expensive. For BMP characters, it therefore remembers the results // so each character is only looked up the first time it is encountered. private byte[] charinfo = new byte[65536]; // rely on initialization to zeroes //private final static byte UNKNOWN = 0; private static final byte GOOD = 1; private static final byte BAD = 2; private BuggyCharacterSet(Charset charset) { encoder = charset.newEncoder(); } public static synchronized BuggyCharacterSet makeCharSet(Charset charset) { if (map == null) { map = new HashMap(10); } BuggyCharacterSet c = (BuggyCharacterSet)map.get(charset); if (c == null) { c = new BuggyCharacterSet(charset); map.put(charset, c); } return c; } public final boolean inCharset(int c) { // Assume ASCII chars are always OK if (c <= 127) { return true; } try { if (c <= 65535) { if (charinfo[c] == GOOD) { return true; } else if (charinfo[c] == BAD) { return false; } else { charinfo[c] = BAD; // guilty until proved innocent char[] cc = {(char)c}; encoder.encode(CharBuffer.wrap(cc)); charinfo[c] = GOOD; return true; } } else { char[] ss = { UTF16.highSurrogate(c), UTF16.lowSurrogate(c) }; encoder.encode(CharBuffer.wrap(ss)); return true; } } catch (CharacterCodingException ex) { return false; } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is // Aleksei Makarov [makarov@iitam.omsk.net.ru] // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/charcode/UnicodeCharacterSet.java0000644000175000017500000001242411033112257023674 0ustar eugeneeugenepackage net.sf.saxon.charcode; /** * This class defines properties of the Unicode character set */ public final class UnicodeCharacterSet implements CharacterSet { private static UnicodeCharacterSet theInstance = new UnicodeCharacterSet(); /** * Private constructor to force the singular instance to be used */ private UnicodeCharacterSet() {} /** * Get the singular instance of this class * @return the singular instance of this classthe singular instance of this class */ public static UnicodeCharacterSet getInstance() { return theInstance; } public boolean inCharset(int c) { return true; } /** * Static method to generate the UTF-8 representation of a Unicode character * @param in the Unicode character, or the high half of a surrogate pair * @param in2 the low half of a surrogate pair (ignored unless the first argument is in the * range for a surrogate pair) * @param out an array of at least 4 bytes to hold the UTF-8 representation. * @return the number of bytes in the UTF-8 representation */ public static int getUTF8Encoding(char in, char in2, byte[] out) { // See Tony Graham, "Unicode, a Primer", page 92 int i = (int)in; if (i<=0x7f) { out[0] = (byte)i; return 1; } else if (i<=0x7ff) { out[0] = (byte)(0xc0 | ((in >> 6) & 0x1f)); out[1] = (byte)(0x80 | (in & 0x3f)); return 2; } else if (i>=0xd800 && i<=0xdbff) { // surrogate pair int j = (int)in2; if (!(j>=0xdc00 && j<=0xdfff)) { throw new IllegalArgumentException("Malformed Unicode Surrogate Pair (" + i + ',' + j + ')'); } byte xxxxxx = (byte)(j & 0x3f); byte yyyyyy = (byte)(((i & 0x03) << 4) | ((j >> 6) & 0x0f)); byte zzzz = (byte)((i >> 2) & 0x0f); byte uuuuu = (byte)(((i >> 6) & 0x0f) + 1); out[0] = (byte)(0xf0 | ((uuuuu >> 2) & 0x07)); out[1] = (byte)(0x80 | ((uuuuu & 0x03) << 4) | zzzz); out[2] = (byte)(0x80 | yyyyyy); out[3] = (byte)(0x80 | xxxxxx); return 4; } else if (i>=0xdc00 && i<=0xdfff) { // second half of surrogate pair - ignore it return 0; } else { out[0] = (byte)(0xe0 | ((in >> 12) & 0x0f)); out[1] = (byte)(0x80 | ((in >> 6) & 0x3f)); out[2] = (byte)(0x80 | (in & 0x3f)); return 3; } } /** * Decode a UTF8 character * @param in array of bytes representing a single UTF-8 encoded character * @param used number of bytes in the array that are actually used * @return the Unicode codepoint of this character * @throws IllegalArgumentException if the byte sequence is not a valid UTF-8 representation */ public static int decodeUTF8(byte[] in, int used) throws IllegalArgumentException { int bottom = 0; for (int i=1; i> 10) + SURROGATE1_MIN); } /** * Return the low surrogate of a non-BMP character * @param ch The Unicode codepoint of the non-BMP character to be divided. * @return the second character in the surrogate pair */ public static char lowSurrogate(int ch) { return (char) (((ch - NONBMP_MIN) & 0x3FF) + SURROGATE2_MIN); } /** * Test whether a given character is a surrogate (high or low) * @param c the character to test * @return true if the character is the high or low half of a surrogate pair */ public static boolean isSurrogate(int c) { return (c & 0xF800) == 0xD800; } /** * Test whether the given character is a high surrogate * @param ch The character to test. * @return true if the character is the first character in a surrogate pair */ public static boolean isHighSurrogate(int ch) { return (SURROGATE1_MIN <= ch && ch <= SURROGATE1_MAX); } /** * Test whether the given character is a low surrogate * @param ch The character to test. * @return true if the character is the second character in a surrogate pair */ public static boolean isLowSurrogate(int ch) { return (SURROGATE2_MIN <= ch && ch <= SURROGATE2_MAX); } // public static void main(String[] args) { // System.err.println(Integer.toHexString(highSurrogate(0x1018a))); // System.err.println(Integer.toHexString(lowSurrogate(0x1018a))); // } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/charcode/EucJPCharacterSet.java0000644000175000017500000003720711033112257023262 0ustar eugeneeugenepackage net.sf.saxon.charcode; /* Copyright (C) 2006 Hewlett-Packard Development Company, L.P. The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. The Original Code is: all this file The Initial Developer of the Original Code is Lauren Ward. All Rights Reserved. Contributor(s): Integrated into Saxon by Michael Kay. Removed code to perform dynamic initialization of the boolean array, replaced it with generated static data. ************************* Author: Lauren Ward Date: February 01, 2006 Address: Hewlett-Packard Company 3404 East Harmony Road Fort Collins, CO 80528-9599 Revision: 1.0 - Initial creation Description: This class implements the PluggableCharacterSet to support EUC-JP encoding. The character mapping was obtained by extracting the Unicode values from an iconv character table (eucJP=ucs2) available on HP-UX 11.23. The class was tested by transforming numerous manuals and having localization engineers review the output. The class was also tested by transforming a document with EUC-JP set as the output encoding, converting EUC-JP output to utf-8 using iconv, and then comparing converted content to the same transformed document with utf-8 set as the output encoding. */ public class EucJPCharacterSet implements CharacterSet { private static EucJPCharacterSet THE_INSTANCE = new EucJPCharacterSet(); public static EucJPCharacterSet getInstance() { return THE_INSTANCE; } private static long[] flags = { 0xffffffffffffffffL, 0xffffffffffffffffL, 0x7febcaa1L, 0xffff7fffffffffffL, 0xfffff3ffeff3ffffL, 0xfffcfffffffffffeL, 0x0L, 0x7fff800000400L, 0x0L, 0x0L, 0x0L, 0x10000f400000000L, 0x0L, 0x0L, 0xeebffffdfffffffL, 0xfffe000000000000L, 0x7ffbffffffffffffL, 0xffff7ffb00000000L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x8accc600b012L, 0x0L, 0x0L, 0x0L, 0x1000020020100000L, 0x0L, 0xf00000000000L, 0x280000000000L, 0xb190202681f80c04L, 0x2000c3300000L, 0x3300000004000000L, 0x0L, 0x200000000000L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0xf009999c9c999999L, 0x2010000000000000L, 0xc000300cL, 0x313000000010000L, 0x600000000000000L, 0xa000000000250000L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0xf7fffc0800000000L, 0x7fffffffffffffffL, 0xfffff01e7fffffffL, 0xfffffffffffffe1eL, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0xfdfeefc35ab7e6d9L, 0xfd1747ef30c05c43L, 0xa6fe6fdfee9f9260L, 0xfb378ff7fc87f717L, 0xf0ffe76c0003dffeL, 0xb3dfffff906bd7ffL, 0x7efffbf7c017275fL, 0xfeffe9bdfc03b6afL, 0xcf7ffbff7ffeb650L, 0xf7ebf769b72cee84L, 0xde27fafbe02dbd66L, 0xbd6fdeaf3fc76672L, 0xfbdeafff51ad7df9L, 0xffffbda92efe478aL, 0xbe7ff7c4fefcffafL, 0x2edd769ee766ffe6L, 0xffb27f842de2f7f8L, 0x1d7d0fbbde63fdc5L, 0xb5ec7fb99f7dcffeL, 0xdfcd6fdfffe8ffe3L, 0xf6bdd7ffd5fdf4ffL, 0xf7fc79fad64ffdd3L, 0x39821ae5cef7bfb4L, 0xb4ff3f77fffff7a0L, 0x78ffd035c3ff4edeL, 0xbbe740032bf6df1dL, 0xdedfe6096fff71ffL, 0xebe60080e6ef222fL, 0xcfcf8e00003376deL, 0xcf6dd3beda00001bL, 0xfbf379ef19fea201L, 0x5f5a79bb38400347L, 0x6e7ebd00049ffddL, 0xfa5f8812fafd6ca0L, 0x8fb90c67a7de5b0aL, 0xf4ffd1ffdf96f365L, 0xf9fd76bdbfef9997L, 0xa72fe0006ff7dd7bL, 0x70d81d6ff9e89084L, 0x939b3e0fdb448fefL, 0xbefc0457cb25ec65L, 0xc07dede369d0a4cbL, 0xd5ed9b0de2d270faL, 0x6daeffef6c5bf17cL, 0x2679befc7dfff783L, 0x1bc3fdf7f5ff3edcL, 0x783e37551d8fb17aL, 0x5af4f86f1fb36b11L, 0xd84e70ab9de58608L, 0xcfc88422372c0133L, 0x10b27ba10874bfL, 0x6ad98328d6620634L, 0xc0d80354642caa82L, 0xd418efbf1ed3d4afL, 0xdfffdffd3ecfffe9L, 0xff4dbbf7efd3dea7L, 0x6fff5323badee6ffL, 0xc6b7d46afdcfce7cL, 0x1a9e805f2f87fbaL, 0x5502144c0e7ea34L, 0x43166ff13b504845L, 0x32bae449e86d9263L, 0x79b8bc55a11aa9ecL, 0x115eb2d6dfd27dd6L, 0xb31c6ef58497b786L, 0x9d5acf9b78bebeffL, 0xd9330728afbc5787L, 0x72fbfe3ff4d8dbbbL, 0x7bffdfdd7fdfcf9fL, 0xcdaedbdcfb7dfdefL, 0xfdfdf3cee9ffd8ccL, 0x1ddcfbcee8fff6bdL, 0x127bffdcff55420L, 0xf3fcef65fdfdc503L, 0x7afe7fb7bfe0ff9eL, 0x2ff35cfff580fffcL, 0xf3efff7b61b8cf4fL, 0x6ffe14e7b59bff9bL, 0xf936fbed8dfe22eaL, 0xf3ff840f774d2bafL, 0xd9eefe3ff373b8d5L, 0xfbdefeba9887526fL, 0xb867ff9a0298577fL, 0x2feffffcc02f7f0fL, 0x79fcd2c101f5066fL, 0x7a7fbd9807de6fbdL, 0xb9ebaef3ffff2c16L, 0xdec3fe38d46a3ee0L, 0x265bb8aaeed8e27L, 0x201378bdd1451ab4L, 0x1581f4f75edeb05fL, 0x6d7eeda0ff6def37L, 0xcce11adf3a7b4fffL, 0x15c5efc7b318ada4L, 0x75eae5dddf1fb94dL, 0x7edbabd1e7ccec73L, 0xbbef7e0fffffdf49L, 0xfe7b61dfebfb9ffbL, 0xd9dee3fdaa166cdbL, 0xf9cb0a7d82dabdffL, 0x95d71f5fa3be5ba7L, 0x47cbde4ffe2fff1bL, 0x4d5bd7fce241ffdcL, 0xfee3f9ee6b4bff53L, 0x38001b4761fdf8ddL, 0xfeaefddd1113ef7bL, 0x7e851bbdf7e7f678L, 0xefdffedd5bfe67cL, 0xcefff37876a0ded5L, 0x24621d7efefffdffL, 0xe0266e98c79769bbL, 0x55bed3c625977457L, 0xf4397d77f8f2aff7L, 0xff2e6d16b207083L, 0xdb56c11fb43bd897L, 0x72c8de3f09a8e03cL, 0x3f61e317d99927f7L, 0x136ebad5fb739cd7L, 0xbe740793b8fffdffL, 0x9e5e3ab1531b5141L, 0x2cc7f9511b8a1fb3L, 0xe037ad7fa1b5baf6L, 0x77ccbff96012f8ffL, 0x6e6dff7cf5fbf800L, 0x93b717307f376dfL, 0x4c00016b5f6b89c8L, 0x258a7fd800292dcdL, 0x8fbb66d7eefbdf78L, 0x8df01477ff5f22faL, 0x1cf77b9f31933217L, 0xa00d92cda5277335L, 0xfdff5c06001f29d7L, 0x6aed5eb0b27df29bL, 0x440179ff6a8f88aeL, 0xfb9efb21dfa3d648L, 0xf7a00cb3c8dbd66eL, 0xc75545b79309a94aL, 0x18fa4c861c1b868eL, 0x46622fd0081fd9e0L, 0xb15ecd08004064L, 0x1f59086ac215c288L, 0x477aa76aafca0044L, 0x8da92c71a089f063L, 0xd8dabf69870e04dbL, 0x83c4913508bdaeffL, 0xf79bb6fff1d369dfL, 0xe9463210a18f6a42L, 0x7b4aa7d1e44c19feL, 0x2d3433df2dfb6f37L, 0x1c07a38793fbe5f8L, 0xdf52978ba674355dL, 0xa6ff3246d7664df7L, 0xdf6040302efffe61L, 0xdb14657fbbf7f202L, 0xd751e0ebf3f3e455L, 0xe998bbbbf3ebb9L, 0x1e0e77abdff9f3ffL, 0x9bffe97fef75dbffL, 0x6773fc6c3c107cefL, 0xff2f2ddbf94bf86bL, 0xf9fd365fff44bcf8L, 0xfff826c96defeabeL, 0xdf9e967dbfa689e5L, 0x76fe2b5bdfaaeadaL, 0xcbfa2d7baec70feeL, 0xa727233bffb8b867L, 0x881e4e23a52fd65fL, 0x1144657bbf6fd898L, 0x264e6c04f706ad21L, 0x1d8a200ed8bb282aL, 0x432f5da759edf43fL, 0x47fafe31cba93b35L, 0xc30ae06b877c4c3fL, 0xcff1dfbfa5d4217bL, 0xcc3f5e9c43f3d8f7L, 0xe9f16ea7ff7cc098L, 0xb1fe4dfbc117edffL, 0xbfcf874df5748ee7L, 0xfeb0ff83906b9679L, 0x1fff747df6fdcaf7L, 0x2bb148d397ffde45L, 0xc7dfee048f6ffd20L, 0xb57efffc42deebcL, 0xeff90b748ee43feaL, 0xfb5f7951d7b85be7L, 0x922dfeffdd4eb44eL, 0x7355ad93ef96f37fL, 0xade73fefa3512eb2L, 0xbff5fffef23ff46fL, 0xff9fd37e77a2f6f5L, 0x76dd537f333ffff7L, 0x3f3f65eeeefd6e70L, 0xccf0e51ff39f7777L, 0x5f36aee7677790dfL, 0x73effebe00000000L, 0x0L, 0x2bfL, 0x1d0ffc9ddff6e5c7L, 0xb7bfcb2e7ae72acdL, 0xd6ab2c11d6dbb07fL, 0xdfbfffcfca8a9f7fL, 0x8a2022a3ea85ff47L, 0x4fda12be677d68e0L, 0x1a8f2ff6cc07faeeL, 0x37f003ba9949d46aL, 0x73afd01c7d7c9e1L, 0xfeb396beb8c2bcb7L, 0xb6f755f7ddbcfeffL, 0xf5efbbff60fa3fe0L, 0x9f1342edbbb76b97L, 0xd9766af5dffff9ffL, 0x600fd7bffb55b76L, 0xfff2039f709fffecL, 0xbd67ff800000959dL, 0xaf663effa3fc4407L, 0xc56bda8d80f1ebdcL, 0x5b3f5440a06944ccL, 0x7e763f8ff7fdfecL, 0x6c10bc4b42e568ffL, 0xebfdd268012be93dL, 0xb30addab7f3d3e05L, 0xd2f3f7eff8f50177L, 0xcff9d9ddafff0befL, 0x617784ad8ee4137bL, 0xaf36f3f2614582adL, 0xe206bfeff9594770L, 0xbc56a85bf5dfc1L, 0xdf566d7b9d4f00feL, 0xbff7f8eb54c3697fL, 0x945e15c5dea36a91L, 0x3fdc95c3b11f5437L, 0xcbf2a669b83573f3L, 0x5677fefb7186e678L, 0xfefe77fff8d0e557L, 0xe09423fba8b2cd27L, 0xfc3f7cdf4181fdceL, 0x6b2fb6ee87b0e6f2L, 0xfe4d233bfa37bd3fL, 0x53f59fb9c769bf2dL, 0x80002fac17545ac5L, 0xbdabff97be3d5f3eL, 0xd7c6ff9ef75ef77bL, 0xbf5df7e3dfcfb35bL, 0x3bfd7f3feb1edfabL, 0xef3acb7fc29c914aL, 0x7ecf3afb121debceL, 0xdc3fbe6b00000000L, 0x0L, 0x1e7L, 0x47fbddf47afc16faL, 0x277eb8dee9ffbbfdL, 0xfff7567efaada5bfL, 0x5df5bb1000000000L, 0xf5ed901L, 0x6ca4c4439299357aL, 0xa7bb4f755db9fc0dL, 0x4ef1ca07f320dfc4L, 0xe9ff8c5ff84dea78L, 0x7d74fc76617fd432L, 0xdfbd68193096c1feL, 0xb5e9bfdfd7ef1ff3L, 0xff4f7d8f7c000000L, 0x1fdf87e7bbL, 0xee36fc20bef7cff6L, 0xfe9fdff7f1ef7fcbL, 0x7d7ffedef7cfafedL, 0xfdfbc5d0f6a1fe86L, 0x5daa25dd6c958f07L, 0xae84abeab547eb6cL, 0x11ff3bf07d6c3df0L, 0x7776fd8a6abffebdL, 0xf7dfdbff5f6fc75dL, 0xcf6efe8e1ecb9febL, 0xbff7c1feefc3c7dfL, 0x94e677f98d9523fdL, 0xf79fb5cdddeeb0f9L, 0xa285cceffffb3f30L, 0x9d4efba8d6fde2fL, 0xe0bd2fb25bde8e60L, 0x5ffcd3cf6f8001f4L, 0x79c79fe140137eb5L, 0x5ca8747bf0b7e50fL, 0x5800000000000000L, 0x0L, 0x0L, 0x1c2L, 0xb9ff5ac7ffdc2a7fL, 0x13fcfeefee000000L, 0xe6eab71fdL, 0xe81dab9f7e2abfbfL, 0x7ef74ffd9fe3fbf8L, 0xcf7e66ff30f1e370L, 0xbfe7527e79a0f0c6L, 0x7ae327fafbf65bfdL, 0xce5587ebb29e7eebL, 0x5ffed9dec8077fb1L, 0x77affbeade1fbd9eL, 0xb3f7ff23739d800L, 0xb7cbb1L, 0x3e88001977773a0eL, 0x35e8ffbfeb9a7c7eL, 0xe7deeddb80000000L, 0x3d5068efc6dL, 0x5ec0fcff213eecd7L, 0x7c1bf242b9969782L, 0xfd3e4f352c700000L, 0xafaedbL, 0xda83ff9bbf7f7d75L, 0xfedea2f9b7f77d7cL, 0x7c9f4fb256bf1dc1L, 0x9f77fb2783fee9dbL, 0xc3e3eb957db1f5e5L, 0xaafdfefa7fe7e776L, 0x5fe3bbbf91f2a790L, 0x0L, 0x758bb40L, 0x33d2659f12b9b83fL, 0x7fa0d84ffc79a33aL, 0x1b6737a0487b6cf9L, 0x7b611f638757b8e6L, 0x2122e67e00000000L, 0x4fdL, 0xfd9b77970eef9cfbL, 0xa9facdf8d8fefddL, 0x31c3ff71e239697fL, 0x5f333fa7f3eff724L, 0x5ef0ef4000000L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x5efbffffffffffffL, 0xfffffffe7fffffffL, 0xffffffff00000000L, 0x0L, }; public EucJPCharacterSet() { } // Determine if it is a valid character public final boolean inCharset(int ch) { if (ch > 65535) { return false; } long g = flags[ch >> 6]; long h = (g >> (63 - (ch & 0x3f))) & 1L; return h == 1L; } public final String getEncodingName() { // Canonical Name for java.io and java.lang API return "EUC_JP"; } } saxonb-9.1.0.8/bj/net/sf/saxon/charcode/CharacterSet.java0000644000175000017500000000230711033112257022364 0ustar eugeneeugenepackage net.sf.saxon.charcode; /** * This interface defines properties of a character set, built in to the Saxon product. * This is selected in xsl:output using encoding="encoding-name", where * the mapping from an encoding-name to a class is defined in CharacterSetFactory. */ public interface CharacterSet { /** * Determine if a character is present in the character set */ public boolean inCharset(int ch); } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is // Aleksei Makarov [makarov@iitam.omsk.net.ru] // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/charcode/PluggableCharacterSet.java0000644000175000017500000000250311033112257024205 0ustar eugeneeugenepackage net.sf.saxon.charcode; /** * This interface defines properties of a pluggable character set, that is, a user-supplied * character set. This is selected in xsl:output using encoding.XXX="class-name", where * XXX is the name of the encoding as used in the encoding property, and * class-name is the full name of an implementation of PluggableCharacterSet */ public interface PluggableCharacterSet extends CharacterSet { /** * Determine the name of the Java character set encoding to be used */ public String getEncodingName(); } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is // Aleksei Makarov [makarov@iitam.omsk.net.ru] // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/charcode/ISO88595CharacterSet.java0000644000175000017500000000502111033112257023356 0ustar eugeneeugenepackage net.sf.saxon.charcode; import java.util.Arrays; /* Copyright (C) 2006 Hewlett-Packard Development Company, L.P. The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. The Original Code is: all this file The Initial Developer of the Original Code is Lauren Ward. All Rights Reserved. Contributor(s): Integrated into Saxon by Michael Kay ************************* Author: Lauren Ward Date: February 01, 2006 Address: Hewlett-Packard Company 3404 East Harmony Road Fort Collins, CO 80528-9599 Revision: 1.0 - Initial creation */ /** * Description: This class implements the CharacterSet to support ISO-8859-5 (Latin/Cyrillic) * encoding. The character mapping was obtained by extracting the * Unicode values from an iconv character table (iso85=ucs2) available on HP-UX 11.23. *

    * The class was tested by transforming a document with ISO-8859-5 * set as the output encoding, converting Shif_JIS output to utf-8 using iconv, * and then comparing converted content to the same transformed document with utf-8 set * as the output encoding. *

    * Checked by MHK against http://www.unicode.org/Public/MAPPINGS/ISO8859/8859-5.TXT * */ public class ISO88595CharacterSet implements CharacterSet { private static ISO88595CharacterSet THE_INSTANCE = new ISO88595CharacterSet(); public static ISO88595CharacterSet getInstance() { return THE_INSTANCE; } private static boolean c[] = null; static { c = new boolean[1120]; Arrays.fill(c, 0, 161, true); c[26] = false; c[167] = true; // xA7 section sign c[173] = true; // xAD soft hyphen Arrays.fill(c, 1025, 1120, true); c[1037] = false; // x040D c[1104] = false; // x0450 c[1117] = false; // x045D //c[8470] = true; } public ISO88595CharacterSet() { } // Determine if it is a valid character public final boolean inCharset(int ch) { return (ch < 1120 && c[ch]) || (ch==8470); } public final String getEncodingName() { // Canonical Name for java.io and java.lang API return "ISO8859_5"; } } saxonb-9.1.0.8/bj/net/sf/saxon/charcode/XMLCharacterData.java0000644000175000017500000010024411033112257023062 0ustar eugeneeugenepackage net.sf.saxon.charcode; import net.sf.saxon.sort.IntRangeSet; import java.util.Arrays; /** * This module contains data regarding the classification of characters in XML 1.0 and XML 1.1, and a number * of interrogative methods to support queries on this data. * * For characters in the BMP, the information is tabulated by means of an array of one-byte entries, * one for each character, with bit-significant property settings. For characters outside the BMP, the * rules are built in to the interrogative methods. */ public class XMLCharacterData { private final static byte[] data = new byte[65536]; /** * Bit setting to indicate that a character is valid in XML 1.0 */ public final static byte VALID_10_MASK = 1; /** * Bit setting to indicate that a character is valid in an XML 1.0 name */ public final static byte NAME_10_MASK = 2; /** * Bit setting to indicate that a character is valid at the start of an XML 1.0 name */ public final static byte NAME_START_10_MASK = 4; /** * Bit setting to indicate that a character is valid in XML 1.1 */ public final static byte VALID_11_MASK = 8; /** * Bit setting to indicate that a character is valid in an XML 1.1 name */ public final static byte NAME_11_MASK = 16; /** * Bit setting to indicate that a character is valid at the start of an XML 1.1 name */ public final static byte NAME_START_11_MASK = 32; /** * Maximum code point for a character permitted in an XML 1.1 name */ public final static int MAX_XML11_NAME_CHAR = 0xEFFFF; /** * Determine whether a character is valid in XML 1.0 * @param i the character * @return true if the character is valid in XML 1.0 */ public static boolean isValid10(int i) { return i < 65536 ? (data[i]&VALID_10_MASK) != 0 : (UTF16.NONBMP_MIN <= i && i <= UTF16.NONBMP_MAX); } /** * Determine whether a character is valid in an NCName in XML 1.0 * @param i the character * @return true if the character is valid in an NCName in XML 1.0 */ public static boolean isNCName10(int i) { return i < 65536 && (data[i]&NAME_10_MASK) != 0; } /** * Determine whether a character is valid at the start of an NCName in XML 1.0 * @param i the character * @return true if the character is valid at the start of an NCName in XML 1.0 */ public static boolean isNCNameStart10(int i) { return i < 65536 && (data[i]&NAME_START_10_MASK) != 0; } /** * Determine whether a character is valid in XML 1.1 * @param i the character * @return true if the character is valid in XML 1.1 */ public static boolean isValid11(int i) { return i < 65536 ? (data[i]&VALID_11_MASK) != 0 : (UTF16.NONBMP_MIN <= i && i <= UTF16.NONBMP_MAX); } /** * Determine whether a character is valid in an NCName in XML 1.1 * @param i the character * @return true if the character is valid in an NCName in XML 1.1 */ public static boolean isNCName11(int i) { return i < 65536 ? (data[i]&NAME_11_MASK) != 0 : (UTF16.NONBMP_MIN <= i && i <= MAX_XML11_NAME_CHAR); } /** * Determine whether a character is valid at the start of an NCName in XML 1.1 * @param i the character * @return true if the character is valid at the start of an NCName in XML 1.1 */ public static boolean isNCNameStart11(int i) { return i < 65536 ? (data[i]&NAME_START_11_MASK) != 0 : (UTF16.NONBMP_MIN <= i && i <= MAX_XML11_NAME_CHAR); } /** * Static code to initialize the data table */ static { data[0] = (byte)0; Arrays.fill(data, 1, 9, (byte)8); Arrays.fill(data, 9, 11, (byte)9); Arrays.fill(data, 11, 13, (byte)8); data[13] = (byte)9; Arrays.fill(data, 14, 32, (byte)8); Arrays.fill(data, 32, 45, (byte)9); Arrays.fill(data, 45, 47, (byte)27); data[47] = (byte)9; Arrays.fill(data, 48, 58, (byte)27); data[58] = (byte)9; // colon Arrays.fill(data, 59, 65, (byte)9); Arrays.fill(data, 65, 91, (byte)63); Arrays.fill(data, 91, 95, (byte)9); data[95] = (byte)63; data[96] = (byte)9; Arrays.fill(data, 97, 123, (byte)63); Arrays.fill(data, 123, 183, (byte)9); data[183] = (byte)27; Arrays.fill(data, 184, 192, (byte)9); Arrays.fill(data, 192, 215, (byte)63); data[215] = (byte)9; Arrays.fill(data, 216, 247, (byte)63); data[247] = (byte)9; Arrays.fill(data, 248, 306, (byte)63); Arrays.fill(data, 306, 308, (byte)57); Arrays.fill(data, 308, 319, (byte)63); Arrays.fill(data, 319, 321, (byte)57); Arrays.fill(data, 321, 329, (byte)63); data[329] = (byte)57; Arrays.fill(data, 330, 383, (byte)63); data[383] = (byte)57; Arrays.fill(data, 384, 452, (byte)63); Arrays.fill(data, 452, 461, (byte)57); Arrays.fill(data, 461, 497, (byte)63); Arrays.fill(data, 497, 500, (byte)57); Arrays.fill(data, 500, 502, (byte)63); Arrays.fill(data, 502, 506, (byte)57); Arrays.fill(data, 506, 536, (byte)63); Arrays.fill(data, 536, 592, (byte)57); Arrays.fill(data, 592, 681, (byte)63); Arrays.fill(data, 681, 699, (byte)57); Arrays.fill(data, 699, 706, (byte)63); Arrays.fill(data, 706, 720, (byte)57); Arrays.fill(data, 720, 722, (byte)59); Arrays.fill(data, 722, 768, (byte)57); Arrays.fill(data, 768, 838, (byte)27); Arrays.fill(data, 838, 864, (byte)25); Arrays.fill(data, 864, 866, (byte)27); Arrays.fill(data, 866, 880, (byte)25); Arrays.fill(data, 880, 894, (byte)57); data[894] = (byte)9; Arrays.fill(data, 895, 902, (byte)57); data[902] = (byte)63; data[903] = (byte)59; Arrays.fill(data, 904, 907, (byte)63); data[907] = (byte)57; data[908] = (byte)63; data[909] = (byte)57; Arrays.fill(data, 910, 930, (byte)63); data[930] = (byte)57; Arrays.fill(data, 931, 975, (byte)63); data[975] = (byte)57; Arrays.fill(data, 976, 983, (byte)63); Arrays.fill(data, 983, 986, (byte)57); data[986] = (byte)63; data[987] = (byte)57; data[988] = (byte)63; data[989] = (byte)57; data[990] = (byte)63; data[991] = (byte)57; data[992] = (byte)63; data[993] = (byte)57; Arrays.fill(data, 994, 1012, (byte)63); Arrays.fill(data, 1012, 1025, (byte)57); Arrays.fill(data, 1025, 1037, (byte)63); data[1037] = (byte)57; Arrays.fill(data, 1038, 1104, (byte)63); data[1104] = (byte)57; Arrays.fill(data, 1105, 1117, (byte)63); data[1117] = (byte)57; Arrays.fill(data, 1118, 1154, (byte)63); data[1154] = (byte)57; Arrays.fill(data, 1155, 1159, (byte)59); Arrays.fill(data, 1159, 1168, (byte)57); Arrays.fill(data, 1168, 1221, (byte)63); Arrays.fill(data, 1221, 1223, (byte)57); Arrays.fill(data, 1223, 1225, (byte)63); Arrays.fill(data, 1225, 1227, (byte)57); Arrays.fill(data, 1227, 1229, (byte)63); Arrays.fill(data, 1229, 1232, (byte)57); Arrays.fill(data, 1232, 1260, (byte)63); Arrays.fill(data, 1260, 1262, (byte)57); Arrays.fill(data, 1262, 1270, (byte)63); Arrays.fill(data, 1270, 1272, (byte)57); Arrays.fill(data, 1272, 1274, (byte)63); Arrays.fill(data, 1274, 1329, (byte)57); Arrays.fill(data, 1329, 1367, (byte)63); Arrays.fill(data, 1367, 1369, (byte)57); data[1369] = (byte)63; Arrays.fill(data, 1370, 1377, (byte)57); Arrays.fill(data, 1377, 1415, (byte)63); Arrays.fill(data, 1415, 1425, (byte)57); Arrays.fill(data, 1425, 1442, (byte)59); data[1442] = (byte)57; Arrays.fill(data, 1443, 1466, (byte)59); data[1466] = (byte)57; Arrays.fill(data, 1467, 1470, (byte)59); data[1470] = (byte)57; data[1471] = (byte)59; data[1472] = (byte)57; Arrays.fill(data, 1473, 1475, (byte)59); data[1475] = (byte)57; data[1476] = (byte)59; Arrays.fill(data, 1477, 1488, (byte)57); Arrays.fill(data, 1488, 1515, (byte)63); Arrays.fill(data, 1515, 1520, (byte)57); Arrays.fill(data, 1520, 1523, (byte)63); Arrays.fill(data, 1523, 1569, (byte)57); Arrays.fill(data, 1569, 1595, (byte)63); Arrays.fill(data, 1595, 1600, (byte)57); data[1600] = (byte)59; Arrays.fill(data, 1601, 1611, (byte)63); Arrays.fill(data, 1611, 1619, (byte)59); Arrays.fill(data, 1619, 1632, (byte)57); Arrays.fill(data, 1632, 1642, (byte)59); Arrays.fill(data, 1642, 1648, (byte)57); data[1648] = (byte)59; Arrays.fill(data, 1649, 1720, (byte)63); Arrays.fill(data, 1720, 1722, (byte)57); Arrays.fill(data, 1722, 1727, (byte)63); data[1727] = (byte)57; Arrays.fill(data, 1728, 1743, (byte)63); data[1743] = (byte)57; Arrays.fill(data, 1744, 1748, (byte)63); data[1748] = (byte)57; data[1749] = (byte)63; Arrays.fill(data, 1750, 1765, (byte)59); Arrays.fill(data, 1765, 1767, (byte)63); Arrays.fill(data, 1767, 1769, (byte)59); data[1769] = (byte)57; Arrays.fill(data, 1770, 1774, (byte)59); Arrays.fill(data, 1774, 1776, (byte)57); Arrays.fill(data, 1776, 1786, (byte)59); Arrays.fill(data, 1786, 2305, (byte)57); Arrays.fill(data, 2305, 2308, (byte)59); data[2308] = (byte)57; Arrays.fill(data, 2309, 2362, (byte)63); Arrays.fill(data, 2362, 2364, (byte)57); data[2364] = (byte)59; data[2365] = (byte)63; Arrays.fill(data, 2366, 2382, (byte)59); Arrays.fill(data, 2382, 2385, (byte)57); Arrays.fill(data, 2385, 2389, (byte)59); Arrays.fill(data, 2389, 2392, (byte)57); Arrays.fill(data, 2392, 2402, (byte)63); Arrays.fill(data, 2402, 2404, (byte)59); Arrays.fill(data, 2404, 2406, (byte)57); Arrays.fill(data, 2406, 2416, (byte)59); Arrays.fill(data, 2416, 2433, (byte)57); Arrays.fill(data, 2433, 2436, (byte)59); data[2436] = (byte)57; Arrays.fill(data, 2437, 2445, (byte)63); Arrays.fill(data, 2445, 2447, (byte)57); Arrays.fill(data, 2447, 2449, (byte)63); Arrays.fill(data, 2449, 2451, (byte)57); Arrays.fill(data, 2451, 2473, (byte)63); data[2473] = (byte)57; Arrays.fill(data, 2474, 2481, (byte)63); data[2481] = (byte)57; data[2482] = (byte)63; Arrays.fill(data, 2483, 2486, (byte)57); Arrays.fill(data, 2486, 2490, (byte)63); Arrays.fill(data, 2490, 2492, (byte)57); data[2492] = (byte)59; data[2493] = (byte)57; Arrays.fill(data, 2494, 2501, (byte)59); Arrays.fill(data, 2501, 2503, (byte)57); Arrays.fill(data, 2503, 2505, (byte)59); Arrays.fill(data, 2505, 2507, (byte)57); Arrays.fill(data, 2507, 2510, (byte)59); Arrays.fill(data, 2510, 2519, (byte)57); data[2519] = (byte)59; Arrays.fill(data, 2520, 2524, (byte)57); Arrays.fill(data, 2524, 2526, (byte)63); data[2526] = (byte)57; Arrays.fill(data, 2527, 2530, (byte)63); Arrays.fill(data, 2530, 2532, (byte)59); Arrays.fill(data, 2532, 2534, (byte)57); Arrays.fill(data, 2534, 2544, (byte)59); Arrays.fill(data, 2544, 2546, (byte)63); Arrays.fill(data, 2546, 2562, (byte)57); data[2562] = (byte)59; Arrays.fill(data, 2563, 2565, (byte)57); Arrays.fill(data, 2565, 2571, (byte)63); Arrays.fill(data, 2571, 2575, (byte)57); Arrays.fill(data, 2575, 2577, (byte)63); Arrays.fill(data, 2577, 2579, (byte)57); Arrays.fill(data, 2579, 2601, (byte)63); data[2601] = (byte)57; Arrays.fill(data, 2602, 2609, (byte)63); data[2609] = (byte)57; Arrays.fill(data, 2610, 2612, (byte)63); data[2612] = (byte)57; Arrays.fill(data, 2613, 2615, (byte)63); data[2615] = (byte)57; Arrays.fill(data, 2616, 2618, (byte)63); Arrays.fill(data, 2618, 2620, (byte)57); data[2620] = (byte)59; data[2621] = (byte)57; Arrays.fill(data, 2622, 2627, (byte)59); Arrays.fill(data, 2627, 2631, (byte)57); Arrays.fill(data, 2631, 2633, (byte)59); Arrays.fill(data, 2633, 2635, (byte)57); Arrays.fill(data, 2635, 2638, (byte)59); Arrays.fill(data, 2638, 2649, (byte)57); Arrays.fill(data, 2649, 2653, (byte)63); data[2653] = (byte)57; data[2654] = (byte)63; Arrays.fill(data, 2655, 2662, (byte)57); Arrays.fill(data, 2662, 2674, (byte)59); Arrays.fill(data, 2674, 2677, (byte)63); Arrays.fill(data, 2677, 2689, (byte)57); Arrays.fill(data, 2689, 2692, (byte)59); data[2692] = (byte)57; Arrays.fill(data, 2693, 2700, (byte)63); data[2700] = (byte)57; data[2701] = (byte)63; data[2702] = (byte)57; Arrays.fill(data, 2703, 2706, (byte)63); data[2706] = (byte)57; Arrays.fill(data, 2707, 2729, (byte)63); data[2729] = (byte)57; Arrays.fill(data, 2730, 2737, (byte)63); data[2737] = (byte)57; Arrays.fill(data, 2738, 2740, (byte)63); data[2740] = (byte)57; Arrays.fill(data, 2741, 2746, (byte)63); Arrays.fill(data, 2746, 2748, (byte)57); data[2748] = (byte)59; data[2749] = (byte)63; Arrays.fill(data, 2750, 2758, (byte)59); data[2758] = (byte)57; Arrays.fill(data, 2759, 2762, (byte)59); data[2762] = (byte)57; Arrays.fill(data, 2763, 2766, (byte)59); Arrays.fill(data, 2766, 2784, (byte)57); data[2784] = (byte)63; Arrays.fill(data, 2785, 2790, (byte)57); Arrays.fill(data, 2790, 2800, (byte)59); Arrays.fill(data, 2800, 2817, (byte)57); Arrays.fill(data, 2817, 2820, (byte)59); data[2820] = (byte)57; Arrays.fill(data, 2821, 2829, (byte)63); Arrays.fill(data, 2829, 2831, (byte)57); Arrays.fill(data, 2831, 2833, (byte)63); Arrays.fill(data, 2833, 2835, (byte)57); Arrays.fill(data, 2835, 2857, (byte)63); data[2857] = (byte)57; Arrays.fill(data, 2858, 2865, (byte)63); data[2865] = (byte)57; Arrays.fill(data, 2866, 2868, (byte)63); Arrays.fill(data, 2868, 2870, (byte)57); Arrays.fill(data, 2870, 2874, (byte)63); Arrays.fill(data, 2874, 2876, (byte)57); data[2876] = (byte)59; data[2877] = (byte)63; Arrays.fill(data, 2878, 2884, (byte)59); Arrays.fill(data, 2884, 2887, (byte)57); Arrays.fill(data, 2887, 2889, (byte)59); Arrays.fill(data, 2889, 2891, (byte)57); Arrays.fill(data, 2891, 2894, (byte)59); Arrays.fill(data, 2894, 2902, (byte)57); Arrays.fill(data, 2902, 2904, (byte)59); Arrays.fill(data, 2904, 2908, (byte)57); Arrays.fill(data, 2908, 2910, (byte)63); data[2910] = (byte)57; Arrays.fill(data, 2911, 2914, (byte)63); Arrays.fill(data, 2914, 2918, (byte)57); Arrays.fill(data, 2918, 2928, (byte)59); Arrays.fill(data, 2928, 2946, (byte)57); Arrays.fill(data, 2946, 2948, (byte)59); data[2948] = (byte)57; Arrays.fill(data, 2949, 2955, (byte)63); Arrays.fill(data, 2955, 2958, (byte)57); Arrays.fill(data, 2958, 2961, (byte)63); data[2961] = (byte)57; Arrays.fill(data, 2962, 2966, (byte)63); Arrays.fill(data, 2966, 2969, (byte)57); Arrays.fill(data, 2969, 2971, (byte)63); data[2971] = (byte)57; data[2972] = (byte)63; data[2973] = (byte)57; Arrays.fill(data, 2974, 2976, (byte)63); Arrays.fill(data, 2976, 2979, (byte)57); Arrays.fill(data, 2979, 2981, (byte)63); Arrays.fill(data, 2981, 2984, (byte)57); Arrays.fill(data, 2984, 2987, (byte)63); Arrays.fill(data, 2987, 2990, (byte)57); Arrays.fill(data, 2990, 2998, (byte)63); data[2998] = (byte)57; Arrays.fill(data, 2999, 3002, (byte)63); Arrays.fill(data, 3002, 3006, (byte)57); Arrays.fill(data, 3006, 3011, (byte)59); Arrays.fill(data, 3011, 3014, (byte)57); Arrays.fill(data, 3014, 3017, (byte)59); data[3017] = (byte)57; Arrays.fill(data, 3018, 3022, (byte)59); Arrays.fill(data, 3022, 3031, (byte)57); data[3031] = (byte)59; Arrays.fill(data, 3032, 3047, (byte)57); Arrays.fill(data, 3047, 3056, (byte)59); Arrays.fill(data, 3056, 3073, (byte)57); Arrays.fill(data, 3073, 3076, (byte)59); data[3076] = (byte)57; Arrays.fill(data, 3077, 3085, (byte)63); data[3085] = (byte)57; Arrays.fill(data, 3086, 3089, (byte)63); data[3089] = (byte)57; Arrays.fill(data, 3090, 3113, (byte)63); data[3113] = (byte)57; Arrays.fill(data, 3114, 3124, (byte)63); data[3124] = (byte)57; Arrays.fill(data, 3125, 3130, (byte)63); Arrays.fill(data, 3130, 3134, (byte)57); Arrays.fill(data, 3134, 3141, (byte)59); data[3141] = (byte)57; Arrays.fill(data, 3142, 3145, (byte)59); data[3145] = (byte)57; Arrays.fill(data, 3146, 3150, (byte)59); Arrays.fill(data, 3150, 3157, (byte)57); Arrays.fill(data, 3157, 3159, (byte)59); Arrays.fill(data, 3159, 3168, (byte)57); Arrays.fill(data, 3168, 3170, (byte)63); Arrays.fill(data, 3170, 3174, (byte)57); Arrays.fill(data, 3174, 3184, (byte)59); Arrays.fill(data, 3184, 3202, (byte)57); Arrays.fill(data, 3202, 3204, (byte)59); data[3204] = (byte)57; Arrays.fill(data, 3205, 3213, (byte)63); data[3213] = (byte)57; Arrays.fill(data, 3214, 3217, (byte)63); data[3217] = (byte)57; Arrays.fill(data, 3218, 3241, (byte)63); data[3241] = (byte)57; Arrays.fill(data, 3242, 3252, (byte)63); data[3252] = (byte)57; Arrays.fill(data, 3253, 3258, (byte)63); Arrays.fill(data, 3258, 3262, (byte)57); Arrays.fill(data, 3262, 3269, (byte)59); data[3269] = (byte)57; Arrays.fill(data, 3270, 3273, (byte)59); data[3273] = (byte)57; Arrays.fill(data, 3274, 3278, (byte)59); Arrays.fill(data, 3278, 3285, (byte)57); Arrays.fill(data, 3285, 3287, (byte)59); Arrays.fill(data, 3287, 3294, (byte)57); data[3294] = (byte)63; data[3295] = (byte)57; Arrays.fill(data, 3296, 3298, (byte)63); Arrays.fill(data, 3298, 3302, (byte)57); Arrays.fill(data, 3302, 3312, (byte)59); Arrays.fill(data, 3312, 3330, (byte)57); Arrays.fill(data, 3330, 3332, (byte)59); data[3332] = (byte)57; Arrays.fill(data, 3333, 3341, (byte)63); data[3341] = (byte)57; Arrays.fill(data, 3342, 3345, (byte)63); data[3345] = (byte)57; Arrays.fill(data, 3346, 3369, (byte)63); data[3369] = (byte)57; Arrays.fill(data, 3370, 3386, (byte)63); Arrays.fill(data, 3386, 3390, (byte)57); Arrays.fill(data, 3390, 3396, (byte)59); Arrays.fill(data, 3396, 3398, (byte)57); Arrays.fill(data, 3398, 3401, (byte)59); data[3401] = (byte)57; Arrays.fill(data, 3402, 3406, (byte)59); Arrays.fill(data, 3406, 3415, (byte)57); data[3415] = (byte)59; Arrays.fill(data, 3416, 3424, (byte)57); Arrays.fill(data, 3424, 3426, (byte)63); Arrays.fill(data, 3426, 3430, (byte)57); Arrays.fill(data, 3430, 3440, (byte)59); Arrays.fill(data, 3440, 3585, (byte)57); Arrays.fill(data, 3585, 3631, (byte)63); data[3631] = (byte)57; data[3632] = (byte)63; data[3633] = (byte)59; Arrays.fill(data, 3634, 3636, (byte)63); Arrays.fill(data, 3636, 3643, (byte)59); Arrays.fill(data, 3643, 3648, (byte)57); Arrays.fill(data, 3648, 3654, (byte)63); Arrays.fill(data, 3654, 3663, (byte)59); data[3663] = (byte)57; Arrays.fill(data, 3664, 3674, (byte)59); Arrays.fill(data, 3674, 3713, (byte)57); Arrays.fill(data, 3713, 3715, (byte)63); data[3715] = (byte)57; data[3716] = (byte)63; Arrays.fill(data, 3717, 3719, (byte)57); Arrays.fill(data, 3719, 3721, (byte)63); data[3721] = (byte)57; data[3722] = (byte)63; Arrays.fill(data, 3723, 3725, (byte)57); data[3725] = (byte)63; Arrays.fill(data, 3726, 3732, (byte)57); Arrays.fill(data, 3732, 3736, (byte)63); data[3736] = (byte)57; Arrays.fill(data, 3737, 3744, (byte)63); data[3744] = (byte)57; Arrays.fill(data, 3745, 3748, (byte)63); data[3748] = (byte)57; data[3749] = (byte)63; data[3750] = (byte)57; data[3751] = (byte)63; Arrays.fill(data, 3752, 3754, (byte)57); Arrays.fill(data, 3754, 3756, (byte)63); data[3756] = (byte)57; Arrays.fill(data, 3757, 3759, (byte)63); data[3759] = (byte)57; data[3760] = (byte)63; data[3761] = (byte)59; Arrays.fill(data, 3762, 3764, (byte)63); Arrays.fill(data, 3764, 3770, (byte)59); data[3770] = (byte)57; Arrays.fill(data, 3771, 3773, (byte)59); data[3773] = (byte)63; Arrays.fill(data, 3774, 3776, (byte)57); Arrays.fill(data, 3776, 3781, (byte)63); data[3781] = (byte)57; data[3782] = (byte)59; data[3783] = (byte)57; Arrays.fill(data, 3784, 3790, (byte)59); Arrays.fill(data, 3790, 3792, (byte)57); Arrays.fill(data, 3792, 3802, (byte)59); Arrays.fill(data, 3802, 3864, (byte)57); Arrays.fill(data, 3864, 3866, (byte)59); Arrays.fill(data, 3866, 3872, (byte)57); Arrays.fill(data, 3872, 3882, (byte)59); Arrays.fill(data, 3882, 3893, (byte)57); data[3893] = (byte)59; data[3894] = (byte)57; data[3895] = (byte)59; data[3896] = (byte)57; data[3897] = (byte)59; Arrays.fill(data, 3898, 3902, (byte)57); Arrays.fill(data, 3902, 3904, (byte)59); Arrays.fill(data, 3904, 3912, (byte)63); data[3912] = (byte)57; Arrays.fill(data, 3913, 3946, (byte)63); Arrays.fill(data, 3946, 3953, (byte)57); Arrays.fill(data, 3953, 3973, (byte)59); data[3973] = (byte)57; Arrays.fill(data, 3974, 3980, (byte)59); Arrays.fill(data, 3980, 3984, (byte)57); Arrays.fill(data, 3984, 3990, (byte)59); data[3990] = (byte)57; data[3991] = (byte)59; data[3992] = (byte)57; Arrays.fill(data, 3993, 4014, (byte)59); Arrays.fill(data, 4014, 4017, (byte)57); Arrays.fill(data, 4017, 4024, (byte)59); data[4024] = (byte)57; data[4025] = (byte)59; Arrays.fill(data, 4026, 4256, (byte)57); Arrays.fill(data, 4256, 4294, (byte)63); Arrays.fill(data, 4294, 4304, (byte)57); Arrays.fill(data, 4304, 4343, (byte)63); Arrays.fill(data, 4343, 4352, (byte)57); data[4352] = (byte)63; data[4353] = (byte)57; Arrays.fill(data, 4354, 4356, (byte)63); data[4356] = (byte)57; Arrays.fill(data, 4357, 4360, (byte)63); data[4360] = (byte)57; data[4361] = (byte)63; data[4362] = (byte)57; Arrays.fill(data, 4363, 4365, (byte)63); data[4365] = (byte)57; Arrays.fill(data, 4366, 4371, (byte)63); Arrays.fill(data, 4371, 4412, (byte)57); data[4412] = (byte)63; data[4413] = (byte)57; data[4414] = (byte)63; data[4415] = (byte)57; data[4416] = (byte)63; Arrays.fill(data, 4417, 4428, (byte)57); data[4428] = (byte)63; data[4429] = (byte)57; data[4430] = (byte)63; data[4431] = (byte)57; data[4432] = (byte)63; Arrays.fill(data, 4433, 4436, (byte)57); Arrays.fill(data, 4436, 4438, (byte)63); Arrays.fill(data, 4438, 4441, (byte)57); data[4441] = (byte)63; Arrays.fill(data, 4442, 4447, (byte)57); Arrays.fill(data, 4447, 4450, (byte)63); data[4450] = (byte)57; data[4451] = (byte)63; data[4452] = (byte)57; data[4453] = (byte)63; data[4454] = (byte)57; data[4455] = (byte)63; data[4456] = (byte)57; data[4457] = (byte)63; Arrays.fill(data, 4458, 4461, (byte)57); Arrays.fill(data, 4461, 4463, (byte)63); Arrays.fill(data, 4463, 4466, (byte)57); Arrays.fill(data, 4466, 4468, (byte)63); data[4468] = (byte)57; data[4469] = (byte)63; Arrays.fill(data, 4470, 4510, (byte)57); data[4510] = (byte)63; Arrays.fill(data, 4511, 4520, (byte)57); data[4520] = (byte)63; Arrays.fill(data, 4521, 4523, (byte)57); data[4523] = (byte)63; Arrays.fill(data, 4524, 4526, (byte)57); Arrays.fill(data, 4526, 4528, (byte)63); Arrays.fill(data, 4528, 4535, (byte)57); Arrays.fill(data, 4535, 4537, (byte)63); data[4537] = (byte)57; data[4538] = (byte)63; data[4539] = (byte)57; Arrays.fill(data, 4540, 4547, (byte)63); Arrays.fill(data, 4547, 4587, (byte)57); data[4587] = (byte)63; Arrays.fill(data, 4588, 4592, (byte)57); data[4592] = (byte)63; Arrays.fill(data, 4593, 4601, (byte)57); data[4601] = (byte)63; Arrays.fill(data, 4602, 7680, (byte)57); Arrays.fill(data, 7680, 7836, (byte)63); Arrays.fill(data, 7836, 7840, (byte)57); Arrays.fill(data, 7840, 7930, (byte)63); Arrays.fill(data, 7930, 7936, (byte)57); Arrays.fill(data, 7936, 7958, (byte)63); Arrays.fill(data, 7958, 7960, (byte)57); Arrays.fill(data, 7960, 7966, (byte)63); Arrays.fill(data, 7966, 7968, (byte)57); Arrays.fill(data, 7968, 8006, (byte)63); Arrays.fill(data, 8006, 8008, (byte)57); Arrays.fill(data, 8008, 8014, (byte)63); Arrays.fill(data, 8014, 8016, (byte)57); Arrays.fill(data, 8016, 8024, (byte)63); data[8024] = (byte)57; data[8025] = (byte)63; data[8026] = (byte)57; data[8027] = (byte)63; data[8028] = (byte)57; data[8029] = (byte)63; data[8030] = (byte)57; Arrays.fill(data, 8031, 8062, (byte)63); Arrays.fill(data, 8062, 8064, (byte)57); Arrays.fill(data, 8064, 8117, (byte)63); data[8117] = (byte)57; Arrays.fill(data, 8118, 8125, (byte)63); data[8125] = (byte)57; data[8126] = (byte)63; Arrays.fill(data, 8127, 8130, (byte)57); Arrays.fill(data, 8130, 8133, (byte)63); data[8133] = (byte)57; Arrays.fill(data, 8134, 8141, (byte)63); Arrays.fill(data, 8141, 8144, (byte)57); Arrays.fill(data, 8144, 8148, (byte)63); Arrays.fill(data, 8148, 8150, (byte)57); Arrays.fill(data, 8150, 8156, (byte)63); Arrays.fill(data, 8156, 8160, (byte)57); Arrays.fill(data, 8160, 8173, (byte)63); Arrays.fill(data, 8173, 8178, (byte)57); Arrays.fill(data, 8178, 8181, (byte)63); data[8181] = (byte)57; Arrays.fill(data, 8182, 8189, (byte)63); Arrays.fill(data, 8189, 8192, (byte)57); Arrays.fill(data, 8192, 8204, (byte)9); Arrays.fill(data, 8204, 8206, (byte)57); Arrays.fill(data, 8206, 8255, (byte)9); Arrays.fill(data, 8255, 8257, (byte)25); Arrays.fill(data, 8257, 8304, (byte)9); Arrays.fill(data, 8304, 8400, (byte)57); Arrays.fill(data, 8400, 8413, (byte)59); Arrays.fill(data, 8413, 8417, (byte)57); data[8417] = (byte)59; Arrays.fill(data, 8418, 8486, (byte)57); data[8486] = (byte)63; Arrays.fill(data, 8487, 8490, (byte)57); Arrays.fill(data, 8490, 8492, (byte)63); Arrays.fill(data, 8492, 8494, (byte)57); data[8494] = (byte)63; Arrays.fill(data, 8495, 8576, (byte)57); Arrays.fill(data, 8576, 8579, (byte)63); Arrays.fill(data, 8579, 8592, (byte)57); Arrays.fill(data, 8592, 11264, (byte)9); Arrays.fill(data, 11264, 12272, (byte)57); Arrays.fill(data, 12272, 12289, (byte)9); Arrays.fill(data, 12289, 12293, (byte)57); data[12293] = (byte)59; data[12294] = (byte)57; data[12295] = (byte)63; Arrays.fill(data, 12296, 12321, (byte)57); Arrays.fill(data, 12321, 12330, (byte)63); Arrays.fill(data, 12330, 12336, (byte)59); data[12336] = (byte)57; Arrays.fill(data, 12337, 12342, (byte)59); Arrays.fill(data, 12342, 12353, (byte)57); Arrays.fill(data, 12353, 12437, (byte)63); Arrays.fill(data, 12437, 12441, (byte)57); Arrays.fill(data, 12441, 12443, (byte)59); Arrays.fill(data, 12443, 12445, (byte)57); Arrays.fill(data, 12445, 12447, (byte)59); Arrays.fill(data, 12447, 12449, (byte)57); Arrays.fill(data, 12449, 12539, (byte)63); data[12539] = (byte)57; Arrays.fill(data, 12540, 12543, (byte)59); Arrays.fill(data, 12543, 12549, (byte)57); Arrays.fill(data, 12549, 12589, (byte)63); Arrays.fill(data, 12589, 19968, (byte)57); Arrays.fill(data, 19968, 40870, (byte)63); Arrays.fill(data, 40870, 44032, (byte)57); Arrays.fill(data, 44032, 55204, (byte)63); Arrays.fill(data, 55204, 55296, (byte)57); Arrays.fill(data, 55296, 57344, (byte)0); Arrays.fill(data, 57344, 63744, (byte)9); Arrays.fill(data, 63744, 64976, (byte)57); Arrays.fill(data, 64976, 65008, (byte)9); Arrays.fill(data, 65008, 65534, (byte)57); Arrays.fill(data, 65534, 65536, (byte)0); } /** * Get all the characters in a given category, as an integer set. This must be one of the four * name classes: Name characters or Name Start characters in XML 1.0 or XML 1.1. (This method * is used to populate the data tables used by the regular expression translators) * @param mask identifies the properties of the required category * @return the set of characters in the given category. */ public static IntRangeSet getCategory(byte mask) { IntRangeSet irs = new IntRangeSet(); for (int i=0; i<65536; i++) { if ((data[i]&mask) != 0) { irs.add(i); } } if ((mask & (NAME_START_11_MASK | NAME_11_MASK)) != 0) { irs.addRange(UTF16.NONBMP_MIN, MAX_XML11_NAME_CHAR); } return irs; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/charcode/CP1252CharacterSet.java0000644000175000017500000002772111033112257023130 0ustar eugeneeugenepackage net.sf.saxon.charcode; /** * This class defines properties of the CP1252 (Latin 1) character set, * as defined at http://www.microsoft.com/globaldev/reference/sbcs/1252.htm. * *

    This file was kindly provided by Sectra AB, Sweden to the DocBook community. * Author: Pontus Haglund

    */ public class CP1252CharacterSet implements CharacterSet { public static CP1252CharacterSet theInstance = new CP1252CharacterSet(); private CP1252CharacterSet() { } public static CP1252CharacterSet getInstance() { return theInstance; } public final boolean inCharset(int c) { return (c >= 0x00 && c <= 0x7F) || (c >= 0xA0 && c <= 0xFF) || (c == 0x20AC) || (c == 0x201A) || (c == 0x0192) || (c == 0x201E) || (c == 0x2026) || (c == 0x2020) || (c == 0x2021) || (c == 0x02C6) || (c == 0x2030) || (c == 0x0160) || (c == 0x2039) || (c == 0x0152) || (c == 0x017D) || (c == 0x2018) || (c == 0x2019) || (c == 0x201C) || (c == 0x201D) || (c == 0x2022) || (c == 0x2013) || (c == 0x2014) || (c == 0x02DC) || (c == 0x2122) || (c == 0x0161) || (c == 0x203A) || (c == 0x0153) || (c == 0x017E) || (c == 0x0178); } } //00 = U+0000 : NULL //01 = U+0001 : START OF HEADING //02 = U+0002 : START OF TEXT //03 = U+0003 : END OF TEXT //04 = U+0004 : END OF TRANSMISSION //05 = U+0005 : ENQUIRY //06 = U+0006 : ACKNOWLEDGE //07 = U+0007 : BELL //08 = U+0008 : BACKSPACE //09 = U+0009 : HORIZONTAL TABULATION //0A = U+000A : LINE FEED //0B = U+000B : VERTICAL TABULATION //0C = U+000C : FORM FEED //0D = U+000D : CARRIAGE RETURN //0E = U+000E : SHIFT OUT //0F = U+000F : SHIFT IN //10 = U+0010 : DATA LINK ESCAPE //11 = U+0011 : DEVICE CONTROL ONE //12 = U+0012 : DEVICE CONTROL TWO //13 = U+0013 : DEVICE CONTROL THREE //14 = U+0014 : DEVICE CONTROL FOUR //15 = U+0015 : NEGATIVE ACKNOWLEDGE //16 = U+0016 : SYNCHRONOUS IDLE //17 = U+0017 : END OF TRANSMISSION BLOCK //18 = U+0018 : CANCEL //19 = U+0019 : END OF MEDIUM //1A = U+001A : SUBSTITUTE //1B = U+001B : ESCAPE //1C = U+001C : FILE SEPARATOR //1D = U+001D : GROUP SEPARATOR //1E = U+001E : RECORD SEPARATOR //1F = U+001F : UNIT SEPARATOR //20 = U+0020 : SPACE //21 = U+0021 : EXCLAMATION MARK //22 = U+0022 : QUOTATION MARK //23 = U+0023 : NUMBER SIGN //24 = U+0024 : DOLLAR SIGN //25 = U+0025 : PERCENT SIGN //26 = U+0026 : AMPERSAND //27 = U+0027 : APOSTROPHE //28 = U+0028 : LEFT PARENTHESIS //29 = U+0029 : RIGHT PARENTHESIS //2A = U+002A : ASTERISK //2B = U+002B : PLUS SIGN //2C = U+002C : COMMA //2D = U+002D : HYPHEN-MINUS //2E = U+002E : FULL STOP //2F = U+002F : SOLIDUS //30 = U+0030 : DIGIT ZERO //31 = U+0031 : DIGIT ONE //32 = U+0032 : DIGIT TWO //33 = U+0033 : DIGIT THREE //34 = U+0034 : DIGIT FOUR //35 = U+0035 : DIGIT FIVE //36 = U+0036 : DIGIT SIX //37 = U+0037 : DIGIT SEVEN //38 = U+0038 : DIGIT EIGHT //39 = U+0039 : DIGIT NINE //3A = U+003A : COLON //3B = U+003B : SEMICOLON //3C = U+003C : LESS-THAN SIGN //3D = U+003D : EQUALS SIGN //3E = U+003E : GREATER-THAN SIGN //3F = U+003F : QUESTION MARK //40 = U+0040 : COMMERCIAL AT //41 = U+0041 : LATIN CAPITAL LETTER A //42 = U+0042 : LATIN CAPITAL LETTER B //43 = U+0043 : LATIN CAPITAL LETTER C //44 = U+0044 : LATIN CAPITAL LETTER D //45 = U+0045 : LATIN CAPITAL LETTER E //46 = U+0046 : LATIN CAPITAL LETTER F //47 = U+0047 : LATIN CAPITAL LETTER G //48 = U+0048 : LATIN CAPITAL LETTER H //49 = U+0049 : LATIN CAPITAL LETTER I //4A = U+004A : LATIN CAPITAL LETTER J //4B = U+004B : LATIN CAPITAL LETTER K //4C = U+004C : LATIN CAPITAL LETTER L //4D = U+004D : LATIN CAPITAL LETTER M //4E = U+004E : LATIN CAPITAL LETTER N //4F = U+004F : LATIN CAPITAL LETTER O //50 = U+0050 : LATIN CAPITAL LETTER P //51 = U+0051 : LATIN CAPITAL LETTER Q //52 = U+0052 : LATIN CAPITAL LETTER R //53 = U+0053 : LATIN CAPITAL LETTER S //54 = U+0054 : LATIN CAPITAL LETTER T //55 = U+0055 : LATIN CAPITAL LETTER U //56 = U+0056 : LATIN CAPITAL LETTER V //57 = U+0057 : LATIN CAPITAL LETTER W //58 = U+0058 : LATIN CAPITAL LETTER X //59 = U+0059 : LATIN CAPITAL LETTER Y //5A = U+005A : LATIN CAPITAL LETTER Z //5B = U+005B : LEFT SQUARE BRACKET //5C = U+005C : REVERSE SOLIDUS //5D = U+005D : RIGHT SQUARE BRACKET //5E = U+005E : CIRCUMFLEX ACCENT //5F = U+005F : LOW LINE //60 = U+0060 : GRAVE ACCENT //61 = U+0061 : LATIN SMALL LETTER A //62 = U+0062 : LATIN SMALL LETTER B //63 = U+0063 : LATIN SMALL LETTER C //64 = U+0064 : LATIN SMALL LETTER D //65 = U+0065 : LATIN SMALL LETTER E //66 = U+0066 : LATIN SMALL LETTER F //67 = U+0067 : LATIN SMALL LETTER G //68 = U+0068 : LATIN SMALL LETTER H //69 = U+0069 : LATIN SMALL LETTER I //6A = U+006A : LATIN SMALL LETTER J //6B = U+006B : LATIN SMALL LETTER K //6C = U+006C : LATIN SMALL LETTER L //6D = U+006D : LATIN SMALL LETTER M //6E = U+006E : LATIN SMALL LETTER N //6F = U+006F : LATIN SMALL LETTER O //70 = U+0070 : LATIN SMALL LETTER P //71 = U+0071 : LATIN SMALL LETTER Q //72 = U+0072 : LATIN SMALL LETTER R //73 = U+0073 : LATIN SMALL LETTER S //74 = U+0074 : LATIN SMALL LETTER T //75 = U+0075 : LATIN SMALL LETTER U //76 = U+0076 : LATIN SMALL LETTER V //77 = U+0077 : LATIN SMALL LETTER W //78 = U+0078 : LATIN SMALL LETTER X //79 = U+0079 : LATIN SMALL LETTER Y //7A = U+007A : LATIN SMALL LETTER Z //7B = U+007B : LEFT CURLY BRACKET //7C = U+007C : VERTICAL LINE //7D = U+007D : RIGHT CURLY BRACKET //7E = U+007E : TILDE //7F = U+007F : DELETE //80 = U+20AC : EURO SIGN //82 = U+201A : SINGLE LOW-9 QUOTATION MARK //83 = U+0192 : LATIN SMALL LETTER F WITH HOOK //84 = U+201E : DOUBLE LOW-9 QUOTATION MARK //85 = U+2026 : HORIZONTAL ELLIPSIS //86 = U+2020 : DAGGER //87 = U+2021 : DOUBLE DAGGER //88 = U+02C6 : MODIFIER LETTER CIRCUMFLEX ACCENT //89 = U+2030 : PER MILLE SIGN //8A = U+0160 : LATIN CAPITAL LETTER S WITH CARON //8B = U+2039 : SINGLE LEFT-POINTING ANGLE QUOTATION MARK //8C = U+0152 : LATIN CAPITAL LIGATURE OE //8E = U+017D : LATIN CAPITAL LETTER Z WITH CARON //91 = U+2018 : LEFT SINGLE QUOTATION MARK //92 = U+2019 : RIGHT SINGLE QUOTATION MARK //93 = U+201C : LEFT DOUBLE QUOTATION MARK //94 = U+201D : RIGHT DOUBLE QUOTATION MARK //95 = U+2022 : BULLET //96 = U+2013 : EN DASH //97 = U+2014 : EM DASH //98 = U+02DC : SMALL TILDE //99 = U+2122 : TRADE MARK SIGN //9A = U+0161 : LATIN SMALL LETTER S WITH CARON //9B = U+203A : SINGLE RIGHT-POINTING ANGLE QUOTATION MARK //9C = U+0153 : LATIN SMALL LIGATURE OE //9E = U+017E : LATIN SMALL LETTER Z WITH CARON //9F = U+0178 : LATIN CAPITAL LETTER Y WITH DIAERESIS //A0 = U+00A0 : NO-BREAK SPACE //A1 = U+00A1 : INVERTED EXCLAMATION MARK //A2 = U+00A2 : CENT SIGN //A3 = U+00A3 : POUND SIGN //A4 = U+00A4 : CURRENCY SIGN //A5 = U+00A5 : YEN SIGN //A6 = U+00A6 : BROKEN BAR //A7 = U+00A7 : SECTION SIGN //A8 = U+00A8 : DIAERESIS //A9 = U+00A9 : COPYRIGHT SIGN //AA = U+00AA : FEMININE ORDINAL INDICATOR //AB = U+00AB : LEFT-POINTING DOUBLE ANGLE QUOTATION MARK //AC = U+00AC : NOT SIGN //AD = U+00AD : SOFT HYPHEN //AE = U+00AE : REGISTERED SIGN //AF = U+00AF : MACRON //B0 = U+00B0 : DEGREE SIGN //B1 = U+00B1 : PLUS-MINUS SIGN //B2 = U+00B2 : SUPERSCRIPT TWO //B3 = U+00B3 : SUPERSCRIPT THREE //B4 = U+00B4 : ACUTE ACCENT //B5 = U+00B5 : MICRO SIGN //B6 = U+00B6 : PILCROW SIGN //B7 = U+00B7 : MIDDLE DOT //B8 = U+00B8 : CEDILLA //B9 = U+00B9 : SUPERSCRIPT ONE //BA = U+00BA : MASCULINE ORDINAL INDICATOR //BB = U+00BB : RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK //BC = U+00BC : VULGAR FRACTION ONE QUARTER //BD = U+00BD : VULGAR FRACTION ONE HALF //BE = U+00BE : VULGAR FRACTION THREE QUARTERS //BF = U+00BF : INVERTED QUESTION MARK //C0 = U+00C0 : LATIN CAPITAL LETTER A WITH GRAVE //C1 = U+00C1 : LATIN CAPITAL LETTER A WITH ACUTE //C2 = U+00C2 : LATIN CAPITAL LETTER A WITH CIRCUMFLEX //C3 = U+00C3 : LATIN CAPITAL LETTER A WITH TILDE //C4 = U+00C4 : LATIN CAPITAL LETTER A WITH DIAERESIS //C5 = U+00C5 : LATIN CAPITAL LETTER A WITH RING ABOVE //C6 = U+00C6 : LATIN CAPITAL LETTER AE //C7 = U+00C7 : LATIN CAPITAL LETTER C WITH CEDILLA //C8 = U+00C8 : LATIN CAPITAL LETTER E WITH GRAVE //C9 = U+00C9 : LATIN CAPITAL LETTER E WITH ACUTE //CA = U+00CA : LATIN CAPITAL LETTER E WITH CIRCUMFLEX //CB = U+00CB : LATIN CAPITAL LETTER E WITH DIAERESIS //CC = U+00CC : LATIN CAPITAL LETTER I WITH GRAVE //CD = U+00CD : LATIN CAPITAL LETTER I WITH ACUTE //CE = U+00CE : LATIN CAPITAL LETTER I WITH CIRCUMFLEX //CF = U+00CF : LATIN CAPITAL LETTER I WITH DIAERESIS //D0 = U+00D0 : LATIN CAPITAL LETTER ETH //D1 = U+00D1 : LATIN CAPITAL LETTER N WITH TILDE //D2 = U+00D2 : LATIN CAPITAL LETTER O WITH GRAVE //D3 = U+00D3 : LATIN CAPITAL LETTER O WITH ACUTE //D4 = U+00D4 : LATIN CAPITAL LETTER O WITH CIRCUMFLEX //D5 = U+00D5 : LATIN CAPITAL LETTER O WITH TILDE //D6 = U+00D6 : LATIN CAPITAL LETTER O WITH DIAERESIS //D7 = U+00D7 : MULTIPLICATION SIGN //D8 = U+00D8 : LATIN CAPITAL LETTER O WITH STROKE //D9 = U+00D9 : LATIN CAPITAL LETTER U WITH GRAVE //DA = U+00DA : LATIN CAPITAL LETTER U WITH ACUTE //DB = U+00DB : LATIN CAPITAL LETTER U WITH CIRCUMFLEX //DC = U+00DC : LATIN CAPITAL LETTER U WITH DIAERESIS //DD = U+00DD : LATIN CAPITAL LETTER Y WITH ACUTE //DE = U+00DE : LATIN CAPITAL LETTER THORN //DF = U+00DF : LATIN SMALL LETTER SHARP S //E0 = U+00E0 : LATIN SMALL LETTER A WITH GRAVE //E1 = U+00E1 : LATIN SMALL LETTER A WITH ACUTE //E2 = U+00E2 : LATIN SMALL LETTER A WITH CIRCUMFLEX //E3 = U+00E3 : LATIN SMALL LETTER A WITH TILDE //E4 = U+00E4 : LATIN SMALL LETTER A WITH DIAERESIS //E5 = U+00E5 : LATIN SMALL LETTER A WITH RING ABOVE //E6 = U+00E6 : LATIN SMALL LETTER AE //E7 = U+00E7 : LATIN SMALL LETTER C WITH CEDILLA //E8 = U+00E8 : LATIN SMALL LETTER E WITH GRAVE //E9 = U+00E9 : LATIN SMALL LETTER E WITH ACUTE //EA = U+00EA : LATIN SMALL LETTER E WITH CIRCUMFLEX //EB = U+00EB : LATIN SMALL LETTER E WITH DIAERESIS //EC = U+00EC : LATIN SMALL LETTER I WITH GRAVE //ED = U+00ED : LATIN SMALL LETTER I WITH ACUTE //EE = U+00EE : LATIN SMALL LETTER I WITH CIRCUMFLEX //EF = U+00EF : LATIN SMALL LETTER I WITH DIAERESIS //F0 = U+00F0 : LATIN SMALL LETTER ETH //F1 = U+00F1 : LATIN SMALL LETTER N WITH TILDE //F2 = U+00F2 : LATIN SMALL LETTER O WITH GRAVE //F3 = U+00F3 : LATIN SMALL LETTER O WITH ACUTE //F4 = U+00F4 : LATIN SMALL LETTER O WITH CIRCUMFLEX //F5 = U+00F5 : LATIN SMALL LETTER O WITH TILDE //F6 = U+00F6 : LATIN SMALL LETTER O WITH DIAERESIS //F7 = U+00F7 : DIVISION SIGN //F8 = U+00F8 : LATIN SMALL LETTER O WITH STROKE //F9 = U+00F9 : LATIN SMALL LETTER U WITH GRAVE //FA = U+00FA : LATIN SMALL LETTER U WITH ACUTE //FB = U+00FB : LATIN SMALL LETTER U WITH CIRCUMFLEX //FC = U+00FC : LATIN SMALL LETTER U WITH DIAERESIS //FD = U+00FD : LATIN SMALL LETTER Y WITH ACUTE //FE = U+00FE : LATIN SMALL LETTER THORN //FF = U+00FF : LATIN SMALL LETTER Y WITH DIAERESIS // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Pontus Haglund // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/charcode/EucKRCharacterSet.java0000644000175000017500000004412311033112257023260 0ustar eugeneeugenepackage net.sf.saxon.charcode; /* Copyright (C) 2006 Hewlett-Packard Development Company, L.P. The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. The Original Code is: all this file The Initial Developer of the Original Code is Lauren Ward. All Rights Reserved. Contributor(s): Integrated into Saxon by Michael Kay. Removed code to perform dynamic initialization of the boolean array, replaced it with generated static data. ************************* Author: Lauren Ward Date: February 01, 2006 Address: Hewlett-Packard Company 3404 East Harmony Road Fort Collins, CO 80528-9599 Revision: 1.0 - Initial creation Description: This class implements the PluggableCharacterSet to support EUC-KR encoding. The character mapping was obtained by extracting the Unicode values from an iconv character table (eucKR=ucs2) available on HP-UX 11.23. The class was tested by transforming numerous manuals and having localization engineers review the output. The class was also tested by transforming a document with EUC-KR set as the output encoding, converting EUC-KR output to utf-8 using iconv, and then comparing converted content to the same transformed document with utf-8 set as the output encoding. */ public class EucKRCharacterSet implements net.sf.saxon.charcode.PluggableCharacterSet { private static EucKRCharacterSet THE_INSTANCE = new EucKRCharacterSet(); public static EucKRCharacterSet getInstance() { return THE_INSTANCE; } public static long[] flags = { 0xffffffffffffffffL, 0xffffffffffffffffL, 0x49a0faefL, 0x200818302008182L, 0x400003007081L, 0xe070300003000000L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x10000fc00000000L, 0x0L, 0x0L, 0x7fffdfc07fffL, 0xdfc0000000000000L, 0x4000ffffffffffffL, 0xffff400000000000L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x1accc600b010L, 0x801L, 0x7800000000000000L, 0x0L, 0x1040120062100000L, 0x181effc0ffc0L, 0xffc000000000L, 0x280000000000L, 0xb191402681fa0e04L, 0x2000cc000000L, 0x3300000004000000L, 0x0L, 0x200000000000L, 0x0L, 0x0L, 0x0L, 0x0L, 0xfffe0fffL, 0xe000000ffffffc00L, 0xffffffc00000L, 0xf00fffffffffffffL, 0xfff0000000000000L, 0x2000dfc0330cL, 0xc3d3c00000000000L, 0x603000a00000000L, 0xa0000000ddec0000L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0xf0ffdc0000000000L, 0x7fffffffffffffffL, 0xfffff0007fffffffL, 0xfffffffffffffe10L, 0x7fffL, 0xffffffffffffffffL, 0xfffe000000000000L, 0x0L, 0xfffffff800000000L, 0xfffffff1L, 0x0L, 0x0L, 0x0L, 0x0L, 0xf8ffffffffffffffL, 0xffe1929c00000000L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0xd1f44ec2000420d0L, 0x341702c700141302L, 0x229aec926e9e0220L, 0xc9340fc51c00a310L, 0x4077c00000010aacL, 0x1387c47800419223L, 0x5ab5429400030601L, 0x38625925c00354a0L, 0x2254626b5bbc0010L, 0x11c1042804000e80L, 0x840440c0000c3502L, 0x461462205040051L, 0xca40200140202128L, 0xdfde200825fe4788L, 0x8224250084280304L, 0xa5c000e4000c2e4L, 0x93a241040c6283f0L, 0x113c0a1440612405L, 0x11c4601198700002L, 0x554426d7380014b3L, 0x4858740d0210041L, 0xd9e4792a8281cd05L, 0x80010a186040010L, 0x10f40b107c7df080L, 0x18efc015825010daL, 0x20a0400000a0541cL, 0x820a800008981084L, 0xc8c0000044862020L, 0xb02800800014402L, 0xa01120210000008L, 0x8b6000ec017a0000L, 0x500082918000006L, 0x240090000012a00L, 0x100000900800L, 0x2000000040a0808L, 0x24403280008060L, 0x1894328100848010L, 0xa126c0004a228408L, 0x20901000b0000000L, 0x1192000180008968L, 0xa6e000024921cc20L, 0x3149a26800044aL, 0x1440100b00c21032L, 0x450254c308190074L, 0x10e6821764102L, 0x9c3cd20a13e1884L, 0x3820134004880052L, 0x1250d86c02aa0091L, 0x5000409984400208L, 0x4240002022000000L, 0x203008000000L, 0x6848000042400000L, 0x458020000200000L, 0x9000cdad1850c4a8L, 0x5d917f83e0a9ec1L, 0xbf08b9036fdb06a0L, 0x49f74240088040fbL, 0x86964410ac094040L, 0xc000405855a2L, 0x8000004080818a14L, 0x1064b4001400000L, 0x18800000490000L, 0x1100004a02000acL, 0x4220667927906L, 0x3208425404141285L, 0x8d080401700039deL, 0x921052883140782L, 0x20e09231b0081330L, 0x48215d9103404428L, 0xaa0350237cc149L, 0xc538e1c2c0e20544L, 0x140c03c080100405L, 0x1220cc5a10000L, 0x7004a4443ced8000L, 0x44c0a319900ba8cL, 0x5004029c000d270L, 0x42c704310100890bL, 0x29b814c539928306L, 0x6022c8e0095a2222L, 0x11f00000020023a9L, 0x81aee2214022ca03L, 0xc1d4108000024249L, 0x886065900010444cL, 0x21cdbbd8000f5103L, 0x4140400000110036L, 0x49840001822131L, 0x10c82290e5e00000L, 0x8a01823040060b00L, 0x50b08200c0022L, 0x80804100e0L, 0x8070220c16a010L, 0x4d2628a067082822L, 0x88000084103903d3L, 0x4874302320c2d82L, 0x3508c1594d19814cL, 0x4419210096cc483dL, 0x36bdc038585ca30L, 0x785100570fd31ba0L, 0x9c2c384a0123852L, 0xb40024c8200b9ebL, 0x90d40d1703be4a24L, 0x243d20b0005d513L, 0x151952c00019382L, 0x801f8240049de12L, 0x3300602100ccL, 0xf082d80000040201L, 0x440119056185d600L, 0xc5425a181822060L, 0x8406200001008005L, 0x201d62f09705c0L, 0x41805020810L, 0x501c800000a00015L, 0x20205143500004e4L, 0x89030c140100000L, 0x8846010830001010L, 0x3000103000000210L, 0x8282200d0002026L, 0x30a80017e202191L, 0x1a60028200032529L, 0x46153b9000180000L, 0x81500010000982L, 0xe002852780a4a226L, 0x7788be70001210dfL, 0x6868151074939000L, 0x184152056026d6L, 0x40000068126a09c1L, 0x5ce540000012400L, 0x9f1140e240b255f0L, 0x171de1d2aaeL, 0x1824029b01133020L, 0x820d24314220L, 0x2c5a580000010883L, 0x62014c00b0186081L, 0x400049b32806802eL, 0x4886890019035042L, 0xf0200421c8594002L, 0x465144bf11810102L, 0x8c0841010808cL, 0x42220e0481d11c0L, 0x9100c500004044L, 0x848006242008200L, 0x16a824a0f4a0004L, 0x861284120084062L, 0x50c2ac010706001bL, 0x82008010002ca636L, 0x838820d561402044L, 0xc000000021090000L, 0xa8028140404000ccL, 0x20021c04700303L, 0xc00a10000a0a4b0L, 0xb520b8101443040L, 0xa06d02469e640146L, 0x57401010e6bb9ea1L, 0xd810057bace10002L, 0x3150008b55a0a445L, 0x22108a8b2020100L, 0x480044b11698f1a0L, 0x109585c262186a1L, 0x3334004041074ceL, 0x25042cd02000a828L, 0x80040041ea000010L, 0x200a22004848a09eL, 0xb02900000020021L, 0x32a0221b5902288aL, 0x48d00002804001a8L, 0x8004001052100043L, 0x104002040c9019L, 0x11834471000L, 0x2000200007082800L, 0x401000400190008L, 0x410e410011400038L, 0x4432800000890410L, 0x4002020000380022L, 0xc1c0833e84840021L, 0x4007400003225047L, 0xc07064810b400010L, 0x849409698002431dL, 0x8246010060508a65L, 0x4880348100630020L, 0xd30014594250261L, 0x14052820c0040L, 0x25dea00800a0404L, 0x1110d2440044880L, 0xcb40200088400000L, 0x100200241300007L, 0x100c000088081000L, 0x1040258105027042L, 0x20020381000012L, 0xafb489f0e01b9460L, 0x3e00800262a27241L, 0x31008a00c6cb7L, 0x13002a6d0c90810L, 0x60041750134106L, 0x53002c0240748048L, 0x2009129800000000L, 0x0L, 0x2a0L, 0x88c000032a540L, 0x4aa082208c020c4L, 0x442a2c01c0508048L, 0xd648858000041205L, 0x122002a20001b107L, 0xf58021464616820L, 0x180a00324c004884L, 0x27a000b010510042L, 0x12cc000610c0e1L, 0x80a1002c90801427L, 0xa204008115a4183aL, 0x5ac201b40380740L, 0x850000400a036282L, 0x162065064f51ddL, 0x6d1347004006L, 0x7c40010000914ec0L, 0x8161600000001110L, 0x62028220700004L, 0x446812080051e844L, 0x182e000000484084L, 0x40011052190420L, 0x884840002099L, 0xaa544020000a0808L, 0x59a2540d0005L, 0x5042104010e40000L, 0x901481002e18020L, 0x4047040c0c600131L, 0x2320032000040001L, 0x28c1b01000040L, 0x28100018400000L, 0x110085108040002L, 0xb08000a800000000L, 0x2050102800a80L, 0x2004000120001020L, 0x800000080092052L, 0x400000130004210L, 0x820c31547090a103L, 0x6094230200100800L, 0x60010c4d40801c84L, 0x100b0c004200290L, 0x4800000108202001L, 0x5311120040602024L, 0x8000200010000880L, 0xb0aa139514244a30L, 0x8c12b246f440L, 0x50c1482dea0a04bL, 0x29152218433643a2L, 0xe8028b7480981040L, 0x404300a802098904L, 0x8020b22000000000L, 0x0L, 0x101L, 0x42a8042040300060L, 0x20280006e1f99b9dL, 0xf9a0502aba24081cL, 0xda4120000000000L, 0xa109900L, 0x420004010801022L, 0x219001450811000L, 0x21800200208400L, 0x29e0004180000a00L, 0x4124000000380000L, 0x803c200100100092L, 0x14403c1f036110d3L, 0xc46000520000000L, 0x181285e000L, 0x240248000234a144L, 0xf695cd67f002648aL, 0x6136dc4ed04725adL, 0xf9a1444032a1c480L, 0x4020000240840404L, 0x2000244001042000L, 0x7e200020680580L, 0x1542008001b4c00L, 0x815fc18c11200400L, 0x4e10200000821L, 0x844001122e000000L, 0x9400528800001340L, 0x9200008200088L, 0x80080a3ea930000L, 0xb408100002040aL, 0x80a20110c8000L, 0x1000400248000200L, 0x800008004100480L, 0x800601000000005L, 0x0L, 0x0L, 0x0L, 0x100L, 0x905178801c844018L, 0x1200e0860000000L, 0x840222011L, 0xa81c801f38209784L, 0x6360cd811a04110L, 0xcf5e065830e1a350L, 0x8300524a0100a044L, 0x2880420a60440920L, 0x15000080940000L, 0x210100800001211L, 0xf6a8f180000480d0L, 0x20e08a205110000L, 0x814000L, 0x90000196007080eL, 0x1068908280800000L, 0x45c690000000000L, 0x244048e5840L, 0x4000e44500044001L, 0x4083004000108300L, 0x9404053124600000L, 0x800080L, 0x188004020000L, 0x2001204008L, 0x7c01082000010000L, 0x2400100120000L, 0x40020008800000L, 0x4a40004002010L, 0x140010000000000L, 0x0L, 0x5401a00L, 0x40001002800010L, 0x4004c0082000L, 0x410800L, 0x8000100000020e0L, 0x2200000000L, 0x445L, 0x310504000c12L, 0x1006489a00800800L, 0x182100080000010L, 0x32200141280100L, 0x4840800000000L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0xc9e0ff7c880dc0c8L, 0x801408880000c9a0L, 0xde78880dc0e980dcL, 0x48880500c9a9d60cL, 0x8a0d4088804c0c88L, 0xd408880500c9e1dL, 0x60c8800c08000100L, 0xc880d008880000c9L, 0xc0d408000000c9a0L, 0xd62e8a0dc4c880dcL, 0xc0800000000000eL, 0x880dc0c800940888L, 0x1848000000ca80dL, 0x70c0800c0c000040L, 0x8880c408000000c8L, 0x81d6080800c0c880L, 0xc808880c00800000L, 0xcaa1d440000000cL, 0x880d40e9e0df5c88L, 0xdc0c88084000000L, 0xd8b0dc1c880dc0L, 0xc880cc88800000c8L, 0xa0d4388800800000L, 0x8880d00c88054L, 0xc980d4080000808L, 0x8880c00c08L, 0xc40c8e0d6288800L, 0xc8a0d42e9f1df1L, 0xc880dc0800000000L, 0xe9b0d52c880L, 0xdc088800c0880000L, 0xc9a8d5488800008L, 0x808880d00800L, 0xc880d4080000L, 0x8080000408880540L, 0x8880840c9a0d4080L, 0xc980de0c880L, 0xdc1c880dc0000000L, 0xc8b0dc1cL, 0x880dc08000080000L, 0xc88004080800L, 0x80000008800000L, 0xc88184000L, 0x80000008880L, 0xc400000000c980d0L, 0x8880c008880d40cL, 0x880de3c880dc0c80L, 0x1400000000c880dL, 0xc1c880d40c880dc0L, 0x8800500c880d4088L, 0x4000000808880L, 0xd408880540c880d4L, 0x80000808000000cL, 0x880940c880d40c88L, 0xd660000000c880dL, 0x40cbe0d65c880de0L, 0xc0800400000000c8L, 0xa0d61c880dc0c880L, 0x1d08000000d8a0d4L, 0x88000c000000008L, 0x8805408880500e9eL, 0xd45888050080000L, 0x88800008880900L, 0x88809000000000c9L, 0xa0dd4f9f0d44c880L, 0xdc4c800400000000L, 0xc9a0d60c980dc0cL, 0x8805c48800000e88L, 0xd40880008080000L, 0x80c880c008800000L, 0xc9e0d46808008080L, 0xc8800408880L, 0x940c880d00000000L, 0xc8a0d70c8a0dc1cL, 0x880dc0c000800000L, 0xc9809c080000L, 0x40c000dc00000000L, 0xc880c40000000000L, 0x80000008000L, 0x40c880940000000L, 0x8L, 0x408880c00000L, 0xc880d40d9e0dL, 0xc4c880dc0c880d40L, 0x8880840f9b0dc2c8L, 0x80dc0c880dc08880L, 0x40e8a0d44c88004L, 0x88809808880d00cL, 0x880d40c980d56800L, 0x80c880840c880dL, 0x40c080940c8c0d40L, 0xc981d42d8L, 0x80cc1c880cc00000L, 0x400000000c8a0ccL, 0x888000000000000L, 0x800000c9a0c40c80L, 0x8080000808880cL, 0x8000000c880c40L, 0x8000080800000088L, 0x40c8a1L, 0xc008880800c880d4L, 0xcee1dc6c880dc0cL, 0x890d458880400cdeL, 0xfeac880d40e8b0fL, 0xc78880d80c8e9d50L, 0xc880dc0c800940c8L, 0x80d40c880d40c8e0L, 0xd40c880cc0c880c4L, 0xc880d40c880d50cL, 0x882d7f8880900c8eL, 0x1de2cba0de0c880dL, 0xc0ca808408880000L, 0xc8a0d60c880d4088L, 0x80cc08000000c8a0L, 0xd71c08054080000cL, 0x8880d40c800040cL, 0x8e0d408000080800L, 0xc880d0088808L, 0xc880d400000000L, 0xc9a0d66ca90dc0c8L, 0x80dc088000400000L, 0xc880dc0800004L, 0x80000800000000cL, 0x880d50c080080800L, 0x808880c0000000L, 0x40c880c4080000c0L, 0x800000080L, 0x80009400000L, 0xc880c61ca80deL, 0xc880dc08a808400L, 0xc880dc0c88L, 0xd40880008088000L, 0x40c880d408880040L, 0x8880d4080L, 0x800c880d408000L, 0x8088000008880d4L, 0x8880840c880d400L, 0xc9c0d40c88L, 0xd40c880dc0c0000L, 0x400000000c980dc0L, 0xc880d408880dc080L, 0xc880d40c880L, 0x8408000040808000L, 0x8000000c880d408L, 0x8800408000040c88L, 0xd408880800c880cL, 0x400000000c880d40L, 0xc8c0dc0c880dc080L, 0x400000000c8a0L, 0xdc0c880d40880008L, 0x8800000c880d428L, 0x8000008000000880L, 0x1408000000c880dL, 0x4080000808000000L, 0xc880c408880840c9L, 0xa0d008880c00c880L, 0xd40e8a0dc4c880dcL, 0xc0000000000000cL, 0x880dc0c880d40888L, 0xcc08080500c880dL, 0x4080000400000000L, 0x88000008880500c9L, 0xa0d4080000400000L, 0x8880900888094L, 0x8880d000000000cL, 0x880d40c884d40c88L, 0xdc0800004000000L, 0xc8a0d40c880d40L, 0xc880dc08880400c8L, 0x84d44c880140c800L, 0x140c880540888050L, 0xc8849408880840cL, 0x880040c880d40c88L, 0x940cbc0d448880cL, 0x40c880d400000000L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0xffffffffffffffffL, 0xffffffffffffffffL, 0xffffffffffffffffL, 0xffffffffffffffffL, 0xfff0000000000000L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x7fffffffffffffffL, 0xfffffffe00000000L, 0x0L, 0xf6000000L }; // raqou and laquo symbol not handled correctly in browser // during testing if not numeric character reference */ // c[187] = false; // c[171] = false; public EucKRCharacterSet() { } // Determine if it is a valid character public final boolean inCharset(int ch) { if (ch > 65535) { return false; } long g = flags[ch>>6]; long h = (g>>(63 - (ch&0x3f))) & 1L; return h == 1L; } public final String getEncodingName() { // Canonical Name for java.io and java.lang API return "EUC_KR"; } } saxonb-9.1.0.8/bj/net/sf/saxon/charcode/Big5CharacterSet.java0000644000175000017500000003312611033112257023076 0ustar eugeneeugenepackage net.sf.saxon.charcode; /* Copyright (C) 2006 Hewlett-Packard Development Company, L.P. The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. The Original Code is: all this file The Initial Developer of the Original Code is Lauren Ward. All Rights Reserved. Contributor(s): Integrated into Saxon by Michael Kay. Removed code to perform dynamic initialization of the boolean array, replaced it with generated static data. ************************* Author: Lauren Ward Date: February 01, 2006 Address: Hewlett-Packard Company 3404 East Harmony Road Fort Collins, CO 80528-9599 Revision: 1.0 - Initial creation Description: This class implements the PluggableCharacterSet to support Big5 encoding. The character mapping was obtained by extracting the Unicode values from an iconv character table (big5=ucs2) available on HP-UX 11.23. The class was tested by transforming numerous manuals and having localization engineers review the output. The class was also tested by transforming a document with Big5 set as the output encoding, converting Big5 output to utf-8 using iconv, and then comparing converted content to the same transformed document with utf-8 set as the output encoding. */ public class Big5CharacterSet implements CharacterSet { private static Big5CharacterSet THE_INSTANCE = new Big5CharacterSet(); public static Big5CharacterSet getInstance() { return THE_INSTANCE; } private static long[] flags = { 0xffffffffffffffffL, 0xffffffffffffffffL, 0x3500c100L, 0x10000000100L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x170004000000000L, 0x0L, 0x0L, 0x7fffdfc07fffL, 0xdfc0000000000000L, 0x40000ff81fffffffL, 0xffff400000000000L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x18cc26002412L, 0x0L, 0x0L, 0x0L, 0x1440000000000000L, 0xffc00000L, 0xf3c000000000L, 0x0L, 0x2394720c08L, 0x2000c3000000L, 0x4000001L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0xffc00ffcL, 0x0L, 0x0L, 0xa008888808080808L, 0x80024027f000L, 0x7fff0c00c000300cL, 0x31300003c000000L, 0x640000000000000L, 0xe000000000000000L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0xf4ffec067fc00000L, 0x7fffffffffffffffL, 0xfffff0067fffffffL, 0xfffffffffffffe02L, 0x7ffffffffc00000L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x10000000L, 0x0L, 0x0L, 0x0L, 0x3000e40000000L, 0x802640000000000L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0xd1ffcec30216f0d8L, 0x359732cf00401003L, 0x3a9e7c536e9e1260L, 0xfbf40fef5cc0ff15L, 0xecf7fcc4200d9abfL, 0x53cffffff97b9fffL, 0xffd5efbe00033771L, 0xfd77dbffc00b5fa2L, 0x875f7ffbf7fdd508L, 0xd7ff553ffcf7bf24L, 0xb51e6efe300fffb7L, 0x6ff35f349fefd6d7L, 0xbff8fda9ee66fdfdL, 0xdfdc2d7f75de4788L, 0x81657d82ac28c34eL, 0xebe898ec000d6e4L, 0xd3eaf30e4ce2f7b0L, 0x5b7e2e3f607f2dbdL, 0xf9fc53d1927e001aL, 0xf14437d73a51ddbbL, 0x6f7e76df025c94fL, 0xddec792ad20bf5d9L, 0x28232bef0d0c2850L, 0x10f40b117efff498L, 0x5bffe0df8ffed7deL, 0xf7a30800ff99ffbfL, 0xeb9ee6a0e7ffd3bfL, 0xffc30202eff671bdL, 0x5ffbe920032fffdaL, 0xdeb7e70b7e20071fL, 0xf9ff7ced7fbe7411L, 0xbffffe7d7fc1236fL, 0xeacfbf1d016bbef7L, 0xe6ea11e2befffbc3L, 0xff0f95ec07be3f0eL, 0xf6fc5937cd328161L, 0x79fc3abbb0ef9812L, 0xc57fe0006af5ff1cL, 0xb0191df7bc0206edL, 0x731bac09fd4efffcL, 0xeffe885eddefffd5L, 0xff7df63c954e7fL, 0xf7f3d88fd6db502fL, 0x67c37ef739d9086fL, 0x120f2f68ad7f418aL, 0x8de3dda8e176fbdfL, 0xfc27b3c6ff837e7eL, 0xd7bffabedeee7f3fL, 0xd06957db944617caL, 0xfbecf7bfaf6c81bdL, 0x183bbd3f274bffffL, 0xebfc07fff6fe1fd5L, 0x75d99b76dfafa88fL, 0x959edfbd3c5af5b5L, 0x5ddb35f83f8e9ec1L, 0xef3efac3fffbe6a0L, 0x59ffe6212ca8d1fbL, 0xcf9fceccbdef587aL, 0x2fdfc05ffffd780L, 0x3fbbbf300aecbd5L, 0xc31f6b77bfc2ffedL, 0xf57ae44235d9616fL, 0xebe43d6fe1efedacL, 0xb3556e87e792f947L, 0x3a2a4ff5fcd41b86L, 0xdc3f1dddf3ffbedeL, 0xa9fd0738bfbeffc2L, 0x6ffa7ffff7cb7323L, 0x6db13db53bc6d788L, 0x9afb0bc42d7ddbcfL, 0xe7f8e3dbc6ff275fL, 0xd44defc6dcb75db5L, 0x807fff7eefff3d40L, 0xff4c9cf73fffa001L, 0xdfeeaf3db080efffL, 0xdfff5cfdea00fffbL, 0xdef7bebd11db2b13L, 0xcfff3eb777baff6aL, 0xb07efa3569fffeabL, 0x77fc02839ff6e7ffL, 0xd9eeee71fd76ba27L, 0xf3f6f8fafe07fb7fL, 0xdbeb7f8000ffdedfL, 0x2bfffbf8001fffffL, 0xf1dfde0000fd3afeL, 0xffffcfe005d7e7bcL, 0xfdefebdffdffc006L, 0xbfffb7fdddf7fe40L, 0x27fbfbbffbf9f47L, 0xd016f8dfc7dfbff5L, 0x25f9b7efbe5ef01fL, 0x7d77abf0baddf9bfL, 0xdb4f9fdcfe7f33d7L, 0x56e15fce3fa93ff9L, 0xf908ef5fedbbb3ddL, 0x7e1fb33766cffc3cL, 0xbffffc0def977e60L, 0x7569607f6eabebfaL, 0x8bfccfc5e0f3edf6L, 0x8bf922fe9adebbcbL, 0xdcf5bd95f3be5cffL, 0x7dfd76f802dffffL, 0x5f5efded0003bff0L, 0xfefff8ff3f7fffa9L, 0x3badc6f77cfcL, 0xfedfd80000176fdfL, 0xf779fb1df9fffc00L, 0xbdeffafdbfbfffcL, 0xfbffd000421bdddL, 0xecfb7bffb6ffcff0L, 0x3206df7adfffdf5fL, 0x7a7f98402f9e7b9fL, 0xefe55fd7d7802cffL, 0xcbd7cef7ebf50203L, 0xdd4eff3bfe8f1bf4L, 0x371dd07fc5bbd0f8L, 0xb8f1f3e2d48d7bffL, 0x77fece5bff2423d3L, 0xbaef4fd3bf37b72dL, 0x9ffdbbb2bb99b1dfL, 0xfedddef5dfbb9a93L, 0xf23fad5fc7f5fab6L, 0xffffbefc001edbffL, 0xff6dff7ef5dff440L, 0xd9ffe3f7a5ffffffL, 0xe00000e3ffef8fffL, 0xbffefd80003b3dbfL, 0xaffdfffffeffff7cL, 0x9400007dff9ffeffL, 0xdf767ebfffd379c0L, 0xc7bbdfff33fb6fL, 0xfffffe88001f6fdfL, 0xf7e73cebf77ff7fbL, 0xd003fdb7fb7fb3bfL, 0xafdebf02fffffaedL, 0xfbff0c9ffbdfe93bL, 0xcf7f4ffdfbf1fdfbL, 0xfee867b7fef0caacL, 0x3e227ee1485fdda2L, 0x7b779eee8019bfdL, 0xaa7e917bf683e220L, 0x7b5ebaefffeaa094L, 0xef61a97fcde9f4cfL, 0xfff3aef9ef8ee8dfL, 0x772c987733ec86f7L, 0x6bf932f7f16bbbdfL, 0xcedef7b67feb8c25L, 0xfe7aebe9daf01bffL, 0xc1b973de3744ff3bL, 0xbc6ee1f7e7fbb7bfL, 0xfff23f05eedc3fdbL, 0xb7bc3bfe95f60eafL, 0xdffc0234fefffe21L, 0xea37ed7b3967f44fL, 0xd7f0adabd7f5e7b7L, 0xf4310ffffeca0f17L, 0xb99dffad66fff1e7L, 0x819b087d3e3983c7L, 0x8b39cce43d30b6ffL, 0xed3fedf7fb05ffffL, 0xd0fdde7fffc5fcacL, 0x33c8b3e9ec6ee4dfL, 0x6bf3367e0a378cb7L, 0x3ee6383f5f6ffdfaL, 0x5df0f475b5c57ffeL, 0xf3f2e7bf7ff004fL, 0xfddf457ff5bcff3dL, 0x296f9dfab5cff1fcL, 0x364ff805f7fffd80L, 0x14eea00eacffc05bL, 0x9f4b5fe3fdfcb83aL, 0x5cffcc37f5ed397fL, 0x6c4af95e5ffd44e7L, 0xeff9ff3fddf4b86dL, 0x60b7bfb8ebbefbf7L, 0xc4d7668f9b7e03b0L, 0xbcbcfdfba293c15dL, 0x8bbe0bb9e1decef3L, 0xcff9afc3b0fb7fa3L, 0xcd3040c19e170375L, 0xcee3f0f6bebffc90L, 0x8fffea80df46ff80L, 0x2dbfcfdcc80d4dc2L, 0xcb7a0cfffff0f9d7L, 0xf77fc04ff7fc91dfL, 0x95ec99799f7b34e5L, 0xccec6f8374817c7fL, 0x4baef4fa1abeb96L, 0xffffffffe0dbf6ffL, 0xff23fe9b73f7f07dL, 0xde8f7a0ff36fedffL, 0xef7a21f7d3ebfb70L, 0x10ffff3ffc77ffffL, 0xffc8ffebf0f5bffeL, 0xe3bd5ff800000000L, 0x0L, 0x2e7L, 0x1cbdcc9fd7feb77fL, 0x17fe6e3eefcdf7ffL, 0xf57fed1bf6fffddfL, 0xdf1fefdb4ae89f47L, 0x13a1e2ae0909f7c7L, 0x2f79b6fc74776ca0L, 0x3defcffede05fcfeL, 0xe6a006d77d5d8066L, 0x1b3ffc1aef53fbe1L, 0xb3fd05ffb3dafd7fL, 0xbf6de5f7f7ee39fbL, 0xedfcee1fe4b93fedL, 0xad53f7fb5adf6d8fL, 0x9c37f8f7fddfdffeL, 0xb0007f5bdfbdfe72L, 0xffcc035aaffd7ff9L, 0xfdfffa0000001fbfL, 0x53ffbff6bff38005L, 0xfffb4fdffdfbfeffL, 0x5b7ff010105dfffdL, 0xbf5eeb77d7df9fe6L, 0x2207c9ffe9fbeaf9L, 0xef7ffb1001fbfb7fL, 0xa3ff7fefdfffc016L, 0xdfe65fd6fffe47faL, 0xffffcefffbe1dfe7L, 0xbfd7e5ef7efde3f7L, 0xcf7841fbff6e7efbL, 0x939ebe5b7df7d978L, 0x73edfee7de1dfffL, 0xffd8dbff3afc07f2L, 0xfffe70faffeefdbbL, 0xf20fffffffff1ff0L, 0x7dc5fbbf383fbfffL, 0xbef879dfffbd3b7bL, 0xf6fcdf5dfefbf7dfL, 0xd8be377471f5ef4fL, 0xf0de77f369b863eeL, 0xe07eafff419bfbfeL, 0x677affe3777ff79eL, 0x6a59f3fffa7f7a7bL, 0x7691179f7a2f2367L, 0x80003e7dfedcfbbbL, 0xb9abf797352cca7bL, 0xceafefd2f2deff79L, 0x7f1d76e2dfb0a2ffL, 0xbfd57fdfeb97ffbbL, 0xefb7fffebfbbd77eL, 0xe7f3ffed97bd89f7L, 0xaeba3eeb00000000L, 0x0L, 0x15fL, 0x77ff8f2d6efdf7f4L, 0xee6dfdeefdf9bfffL, 0xfda9756fffaedcfeL, 0xafe59f5000000000L, 0xbdfbbd4L, 0xcc6ffe59d5bf3f6bL, 0x679fd7fdfbfbf82fL, 0xbf65ffffff52decfL, 0xedfe9f7fff6d3ab8L, 0x6ffeffa7def82024L, 0xa07d799fc7db4ffbL, 0xf7f6ffbf9e6b3fd3L, 0xbfd7fff7f8000000L, 0x191287e801L, 0x2e567f00feb68fbfL, 0xfe1dcf7ff8076e8fL, 0x6977fcdeb1d7bfffL, 0xffb5cdd3f721fe87L, 0x55b20ffdfcfdfc7fL, 0xffd7ebfffbfffef3L, 0xdfffb7a1fceb3de0L, 0xff75f07ff5bffd6eL, 0xf75fddec3bfe5dc5L, 0xff6def6a1f06fbe7L, 0x86fffb32df0da2ffL, 0xb7be5ffcfff83f18L, 0xfffff5c7cbe3c1fbL, 0xeadfbef7fff71ec8L, 0x37feffadd2cc77aL, 0xb0ef6ff77febfd00L, 0xb9afefef7b8a07ffL, 0x937ffec080faf7fdL, 0x8ff9e506b8f7ff8fL, 0xf000000000000000L, 0x0L, 0x0L, 0x13cL, 0xb2dff89b5cdec77fL, 0x97fcfe3bfc000000L, 0xaf8afe07dL, 0xb83fd89f783dff8eL, 0x9ff67dda69ead8d9L, 0xfffe3fff74e1e7f5L, 0xafd7f2cfbffba4e7L, 0x3bd022bae2eabbbfL, 0xfcb709eefebe1351L, 0x5f5f9fcf5404d2f7L, 0xffaff39ecbd5a5d0L, 0x5eeff1dfbd71f800L, 0xcf72bfL, 0xea58001135752a6eL, 0xb5e8ffb34dfff42fL, 0x55daffdb40000000L, 0x3ce579ffc74L, 0x715fffdd3d6ecbffL, 0x7f774e7ebd7eefe7L, 0xfeefbf73aff00000L, 0x95d9dbL, 0xe325fe89531f737eL, 0x5ebee7e3bdd3753bL, 0x7ebf6ef1cb89cf3eL, 0xa780f432eeb706c5L, 0xdbe01f7aefb88184L, 0x7d6390c5cdc7b5fL, 0xcafeafc3b3865de0L, 0x0L, 0x7647f7dL, 0x9fc0add7b6c7d397L, 0xf4397bfdc1f9fdd5L, 0xeff8abfffbed7ffbL, 0x75bff7ff7edfbff7L, 0xff55fd7600000000L, 0x46dL, 0xb3fe797dcd468f1aL, 0xb08fdebf8f97bf7dL, 0xc363b6fabcffff96L, 0xf3ff2fdfdf3beff2L, 0x4ec88a8000000L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0xc000000000000L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0xdfffL, 0xf87faf7ffe700000L, 0x0L, 0x0L, 0x5effffffffffffe9L, 0x7ffffffc08000000L, 0x0L, 0x0L }; public Big5CharacterSet() { } // Determine if it is a valid character public final boolean inCharset(int ch) { if (ch > 65535) { return false; } long g = flags[ch>>6]; long h = (g>>(63 - (ch&0x3f))) & 1L; return h == 1L; } public final String getEncodingName() { // Canonical Name for java.io and java.lang API return "Big5"; } } saxonb-9.1.0.8/bj/net/sf/saxon/charcode/ISO88598CharacterSet.java0000644000175000017500000000531711033112257023371 0ustar eugeneeugenepackage net.sf.saxon.charcode; import java.util.Arrays; /* Copyright (C) 2006 Hewlett-Packard Development Company, L.P. The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. The Original Code is: all this file The Initial Developer of the Original Code is Lauren Ward. All Rights Reserved. Contributor(s): Integrated into Saxon by Michael Kay ************************* Author: Lauren Ward Date: February 01, 2006 Address: Hewlett-Packard Company 3404 East Harmony Road Fort Collins, CO 80528-9599 Revision: 1.0 - Initial creation Description: This class implements the PluggableCharacterSet to support iso-8859-8 encoding. The character mapping was obtained by extracting the Unicode values from an iconv character table (iso88=ucs2) available on HP-UX 11.23. The class was tested by transforming a document with ISO-8859-8 set as the output encoding, converting ISO-8859-8 output to utf-8 using iconv, and then comparing converted content to the same transformed document with utf-8 set as the output encoding. */ public class ISO88598CharacterSet implements CharacterSet { private static ISO88598CharacterSet THE_INSTANCE = new ISO88598CharacterSet(); public static ISO88598CharacterSet getInstance() { return THE_INSTANCE; } private static boolean c[] = null; static { c = new boolean[1520]; // for (int i=0; i<=25; ++i) { c[i] = true; } // for (int i=27; i<=160; ++i) { c[i] = true; } Arrays.fill(c, 0, 191, true); c[26] = false; // for (int i=162; i<=169; ++i) { c[i] = true; } // for (int i=171; i<=174; ++i) { c[i] = true; } // for (int i=176; i<=185; ++i) { c[i] = true; } // for (int i=187; i<=190; ++i) { c[i] = true; } c[161] = false; c[170] = false; c[175] = false; c[186] = false; c[215] = true; c[247] = true; // for (int i=1488; i<=1514; ++i) { c[i] = true; } Arrays.fill(c, 1488, 1515, true); //c[8215] = true; //c[8254] = true; } public ISO88598CharacterSet() { } // Determine if it is a valid character public final boolean inCharset(int ch) { return (ch < 1520 && c[ch]) || ch==8215 || ch==8254; } public final String getEncodingName() { // Canonical Name for java.io and java.lang API return "ISO8859_8"; } } saxonb-9.1.0.8/bj/net/sf/saxon/charcode/ShiftJISCharacterSet.java0000644000175000017500000003676011033112257023742 0ustar eugeneeugenepackage net.sf.saxon.charcode; /* Copyright (C) 2006 Hewlett-Packard Development Company, L.P. The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. The Original Code is: all this file The Initial Developer of the Original Code is Lauren Ward. All Rights Reserved. Contributor(s): Integrated into Saxon by Michael Kay. Removed code to perform dynamic initialization of the boolean array, replaced it with generated static data. ************************* Author: Lauren Ward Date: February 01, 2006 Address: Hewlett-Packard Company 3404 East Harmony Road Fort Collins, CO 80528-9599 Revision: 1.0 - Initial creation Description: This class implements the PluggableCharacterSet to support Shift_JIS encoding. The character mapping was obtained by extracting the Unicode values from an iconv character table (sjis=ucs2) available on HP-UX 11.23. The class was tested by transforming numerous manuals and having localization engineers review the output. The class was also tested by transforming a document with Shift_JIS set as the output encoding, converting Shif_JIS output to utf-8 using iconv, and then comparing converted content to the same transformed document with utf-8 set as the output encoding. */ public class ShiftJISCharacterSet implements CharacterSet { private static ShiftJISCharacterSet THE_INSTANCE = new ShiftJISCharacterSet(); public static ShiftJISCharacterSet getInstance() { return THE_INSTANCE; } public static long[] flags = { 0xffffffffffffffffL, 0xffffffffffffffffL, 0x3588ca00L, 0x10000000100L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x7fffdfc07fffL, 0xdfc0000000000000L, 0x4000ffffffffffffL, 0xffff400000000000L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x8accc600b012L, 0x0L, 0x0L, 0x0L, 0x1000000000100000L, 0x0L, 0xf00000000000L, 0x280000000000L, 0xb190202681f80c04L, 0x2000c3300000L, 0x3300000004000000L, 0x0L, 0x200000000000L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0xf009999c9c999999L, 0x2010000000000000L, 0xc000300cL, 0x313000000010000L, 0x600000000000000L, 0xa000000000250000L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0xf7fffc0800000000L, 0x7fffffffffffffffL, 0xfffff01e7fffffffL, 0xfffffffffffffe1eL, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0xd1f6cfc2422462d9L, 0x341707c720005002L, 0xa6fa6cdbee9e9220L, 0xeb370fc71c06a310L, 0x4067c02c00018aacL, 0x1307d57e00419619L, 0x12954294c0170601L, 0x3822c9b55c0316a2L, 0x6556a615efc0240L, 0x11c1862804082e84L, 0x840440e0000c3d02L, 0x2465462215060450L, 0xe8402ea140202139L, 0xdfdea82824fe4788L, 0xa66df740aef8ff04L, 0xe5c021cc364c6e6L, 0x9bb249040d6293f0L, 0x193d0a121c61fc05L, 0x11c46811907c4c4aL, 0x554425c7bb0034e3L, 0x66858764d02150f1L, 0xd7e479aa8243dd91L, 0x280002a186c69210L, 0x30fe0b517cfff3a0L, 0x58ffc015825e02deL, 0xa2e2400100a0d71cL, 0x8a1ba0002c99308eL, 0xe9c0008066c62024L, 0xb018a00000350c2L, 0x8e09130c1000001aL, 0x997000ef01fa8200L, 0xd00082918000146L, 0x2400b9000416a80L, 0x200a801008b808a0L, 0x83210800a4020a08L, 0xf08251b29002b065L, 0x98d5328903848190L, 0xa123c0004a600001L, 0x20d01000b8209000L, 0x92123a0990000968L, 0xa63004444821cc24L, 0xc03069e22050a442L, 0x14001109009210f2L, 0x452855cb0c1be17cL, 0x206186f8257e6182L, 0x9c3cda0a5ea1884L, 0x7824125414882052L, 0x250d86806b00211L, 0x504040a984410608L, 0xc240002022280001L, 0x20300000000eL, 0x6058830052400030L, 0x5802002028a202L, 0x9400cdbd1e50d4a0L, 0x95dd05fd3e029ec1L, 0x3f48b8176fd296a3L, 0x6ff75220a88440ffL, 0xc6b7d402cc0b4240L, 0x8c80040d8539aL, 0x5000040c0e58234L, 0x1124ff120400000L, 0x1aa00800491200L, 0x29188004200a012cL, 0x4c321657927d16L, 0x3218427404159384L, 0x9d0a0d0178003effL, 0x5921072883140780L, 0x70e19235f0c8dbbbL, 0x587ddf910745458aL, 0x40aa534c627cd149L, 0xfdb8f1c2c0e6184cL, 0x140c03cc8810c495L, 0x3a65cc7f14020L, 0x7234a461bcfd8500L, 0x585c2b3193603e8cL, 0x70050a9d180db70L, 0xd2c704314188080fL, 0x29be14e53593df02L, 0x2122ca60095a2222L, 0x13fc800012002bafL, 0x80eeea374223b891L, 0xc1d614929082424bL, 0xb8607f9a0018445cL, 0x27edf9dcc00f5703L, 0x61c8404101910027L, 0x4d850801d22330L, 0x90cb2291f5f82c12L, 0x9a41a23050420a20L, 0x2051308028c0a22L, 0x20020080014102a0L, 0x108034220c56a058L, 0x650428a0f3096a26L, 0x8400008c18390fd3L, 0x48547c63208ad80L, 0x31cac1594d1d814cL, 0x5e192150e7cc4030L, 0x332b180985850e09L, 0x785120072bc38a20L, 0x59c24384221208caL, 0x4940026c8240bdcfL, 0x90d50f1703be4ba5L, 0x4243d24bfc25f50bL, 0x558852ce2411bc0L, 0x4a23d8a6294b5c13L, 0x38001302607028ccL, 0xf286d84d11000b03L, 0x54051915a385d668L, 0xa742da1d1032060L, 0xcc9f207876a08a45L, 0x201c6ee0371dceL, 0x60224c1881026813L, 0x513e90c601942055L, 0x24383953707206e4L, 0x99000c162002081L, 0x88068108b02a1090L, 0x7000503300a00030L, 0xc202205d10021e6L, 0x114a98517a6118d1L, 0x9a74068208317d39L, 0x8616389100191000L, 0x81591018000982L, 0xe0028527a0a0b026L, 0x708cb270601250ffL, 0x4c68155474a1d000L, 0x18215304703696L, 0x4c0000681a6a09c0L, 0x48a145800012488L, 0x871864c24aba5570L, 0x5f01475de5f00a2L, 0x1026029101132203L, 0xa009828d24212324L, 0x2c585c0600092983L, 0x62415c00b0186083L, 0x440008990a0788a8L, 0xea02410058205040L, 0xf2000c91c81b5222L, 0x405144b70308a002L, 0x840801011808cL, 0x622040000f10e0L, 0x91004500004044L, 0x40086842000208L, 0x4a06402f4a0004L, 0x8a10c4100884042L, 0x10c2ad01870e0459L, 0x204801000aca63fL, 0x839820d561402846L, 0xe1002200a1092240L, 0x3a02a150e04c01ccL, 0x20031d04730b03L, 0xc03010010a0a4b0L, 0x950020000403010L, 0xa0a6000284264082L, 0x1640000024003e21L, 0x4000047b98619202L, 0x1010000221008004L, 0x210808b342e380L, 0x1c0e54ab1698f1b8L, 0xa7d487caf749b81L, 0x23734824141074ceL, 0x35242cd23040b82bL, 0x40540001e9008810L, 0x2388228861e8a2beL, 0x9b929260000289e1L, 0x32a4231b5d222892L, 0x49d800138e4001a8L, 0x8100003056900043L, 0x124002840c925dL, 0x104013835471008L, 0x20082c0087002821L, 0x400000400192808L, 0x430e55201161042aL, 0x4630c82001890804L, 0x410260400238002aL, 0xc1c09727a4840121L, 0xcc27000403229067L, 0xc05064815b488010L, 0x809609e98002611fL, 0xb247810070508a65L, 0x5880378100638221L, 0x1db5346df62582e1L, 0x2ab140d286881640L, 0x6ddea04050acc20L, 0x3152ded40244880L, 0xcb5900048e441300L, 0x8104790151300187L, 0x900d8a818c081402L, 0x7054a5916d967046L, 0xa422228ba1012ab2L, 0xae348df8e01bb461L, 0x3e1b821272827644L, 0x411079301fecb7L, 0x13164aec8c92810L, 0x4c70201372126576L, 0x52340e660364805dL, 0x30cbba1800000000L, 0x0L, 0x2a0L, 0x40ecc8181f2a5c0L, 0x37aa082618c322c4L, 0x46282c00c2509058L, 0xde18a5c840801215L, 0x22022a36081bb47L, 0xf5812b4646d6820L, 0x1a0a02764c01488cL, 0x27e0003010415042L, 0x212dc010612c8e1L, 0xb0a1142c98c094a7L, 0xa2c450e195a4183aL, 0x65eea39b007a17c0L, 0x810000e52ab36382L, 0x142045061d50d4L, 0x400795b57105870L, 0x3e42038810916ec0L, 0x8461a08000001518L, 0x5621223a0b04404L, 0x442a12898051e914L, 0x191e1000a068448cL, 0x2420110725f4560L, 0x28108849400420d9L, 0x4a74c260000a0809L, 0x82005da1420c0404L, 0xd0f205a010e40102L, 0x89a0c9580afb0060L, 0x4045840c0c600172L, 0x2330132020058001L, 0x68c2b01104050L, 0x38140018718200L, 0xb560853084f00d2L, 0xb2e460a804400911L, 0x5a154192a20a81L, 0x2004000120111034L, 0x8b10a00080012352L, 0x407460071004250L, 0xaa0c31567090a507L, 0x609423422812cd01L, 0x7c010ccd408038ceL, 0x2928b00604300290L, 0x580c02038a252903L, 0x53b113a043693025L, 0x8000202c13000880L, 0xb0aa939514245a38L, 0x4280ec12b25ef008L, 0x2d4c54a2de8ca049L, 0x291d223aeb1651a2L, 0xe90a8b74c2981042L, 0x404b02b90219e904L, 0x902ab26000000000L, 0x0L, 0x121L, 0x42aa8420603800e8L, 0x246e0886e1ffbb9dL, 0xf9a6503aba24003cL, 0xdb59a0000000000L, 0xb14d900L, 0x4420004010801022L, 0x2019023550b11409L, 0xe1800700208c00L, 0x29e8844198002a08L, 0x4d3458404039c002L, 0x6bc20113010009eL, 0x14683c5d026110d3L, 0x2e4e010978000000L, 0x1b1187e139L, 0x2c024820267589e4L, 0xd617df67f10266caL, 0x6577fecad4c727adL, 0xf961400012a14480L, 0x4022001068840504L, 0x200020400004a000L, 0x7e2a8034683580L, 0x2154a10828310ca0L, 0xc3dfc29d53000609L, 0x64c0200480901L, 0xcd081322a004002L, 0x940056b800040140L, 0x12000086430a8L, 0x20180e0b29b2430L, 0x8140a18800a040aL, 0x80b20010e8040L, 0x1080c3844c800000L, 0x110098e0401006a0L, 0x48007032a020850fL, 0x4000000000000000L, 0x0L, 0x0L, 0x100L, 0xb1715ac0bd84205aL, 0x112c0e8864000000L, 0x840a32011L, 0xa81d801f3e28b7a4L, 0x6b70dd891a0ebd8L, 0xcf5e465830b0a350L, 0x8ba7524a0920a0c6L, 0x2ac0224aead44868L, 0x4e15808892941800L, 0x1290100800063611L, 0x7689f1a0480c099cL, 0x21f0c920111d800L, 0xa14200L, 0x1a0000192057280eL, 0x1468b886c88a0006L, 0x2458e50000000000L, 0x3c0048e1808L, 0x4e80e49520066091L, 0x4403304000908102L, 0xb40405312c700000L, 0x848088L, 0x8801588332374910L, 0x20000a135e36018L, 0x7c0748a000010800L, 0x1002730180b60840L, 0x82616a107880e400L, 0xaecbc104c07a072L, 0x380212081000280L, 0x0L, 0x5589a00L, 0x13c2241112b80013L, 0x4a80c04ec8092020L, 0x1410020085128b0L, 0x6a011040020520e4L, 0x3200000000L, 0x4c5L, 0x40987505066400fbL, 0x80fa8de84810b5cL, 0x1821400c0080012L, 0x332801f3282300L, 0x4040c80000000L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x5efbffffffffffffL, 0xfffffffc7fffffffL, 0xffffffff00000000L, 0x0L }; public ShiftJISCharacterSet() { } // Determine if it is a valid character public final boolean inCharset(int ch) { if (ch > 65535) { return false; } long g = flags[ch >> 6]; long h = (g >> (63 - (ch & 0x3f))) & 1L; return h == 1L; } public final String getEncodingName() { // Canonical Name for java.io and java.lang API return "SJIS"; } } saxonb-9.1.0.8/bj/net/sf/saxon/charcode/CharacterSetFactory.java0000644000175000017500000002315711033112257023722 0ustar eugeneeugenepackage net.sf.saxon.charcode; import net.sf.saxon.event.PipelineConfiguration; import net.sf.saxon.trans.XPathException; import javax.xml.transform.OutputKeys; import java.nio.charset.Charset; import java.nio.charset.IllegalCharsetNameException; import java.nio.charset.UnsupportedCharsetException; import java.util.Iterator; import java.util.Properties; /** * This class creates a CharacterSet object for a given named encoding. */ public class CharacterSetFactory { /** * Class is never instantiated */ private CharacterSetFactory() { } /** * Make a CharacterSet appropriate to the encoding * @param details the serialization properties * @param pipe the PipelineConfiguration (used to get the current ClassLoader) * @return the constructed CharacterSet */ public static CharacterSet getCharacterSet(Properties details, PipelineConfiguration pipe) throws XPathException { String encoding = details.getProperty(OutputKeys.ENCODING); if (encoding == null) { encoding = "UTF8"; } if (encoding.equalsIgnoreCase("UTF-8")) { encoding = "UTF8"; // needed for Microsoft Java VM } CharacterSet charSet = makeCharacterSet(encoding, pipe); if (charSet==null) { XPathException err = new XPathException("Unknown encoding requested: " + encoding); err.setErrorCode("SESU0007"); throw err; } return charSet; } private static CharacterSet makeCharacterSet(String encoding, PipelineConfiguration pipe) throws XPathException { String enc2 = encoding.replace('_', '-'); switch(enc2.length()) { case 4: if (enc2.equalsIgnoreCase("UTF8")) { return UnicodeCharacterSet.getInstance(); } else if (enc2.equalsIgnoreCase("Big5")) { return Big5CharacterSet.getInstance(); } else if (enc2.equalsIgnoreCase("SJIS")) { return ShiftJISCharacterSet.getInstance(); } break; case 5: if (enc2.equalsIgnoreCase("ASCII")) { return ASCIICharacterSet.getInstance(); } else if (enc2.equalsIgnoreCase("UTF-8")) { return UnicodeCharacterSet.getInstance(); } if (enc2.equalsIgnoreCase("UTF16")) { return UnicodeCharacterSet.getInstance(); } else if (enc2.equalsIgnoreCase("cp852")) { return CP852CharacterSet.getInstance(); } break; case 6: if (enc2.equalsIgnoreCase("iso646")) { return ASCIICharacterSet.getInstance(); } else if (enc2.equalsIgnoreCase("UTF-16")) { return UnicodeCharacterSet.getInstance(); } else if (enc2.equalsIgnoreCase("EUC-CN")) { return GB2312CharacterSet.getInstance(); } else if (enc2.equalsIgnoreCase("GB2312")) { return GB2312CharacterSet.getInstance(); } else if (enc2.equalsIgnoreCase("EUC-JP")) { return EucJPCharacterSet.getInstance(); } else if (enc2.equalsIgnoreCase("EUC-KR")) { return EucKRCharacterSet.getInstance(); } else if (enc2.equalsIgnoreCase("KOI8-R")) { return KOI8RCharacterSet.getInstance(); } else if (enc2.equalsIgnoreCase("cp1251")) { return CP1251CharacterSet.getInstance(); } else if (enc2.equalsIgnoreCase("cp1250")) { return CP1250CharacterSet.getInstance(); } else if (enc2.equalsIgnoreCase("cp1252")) { return CP1252CharacterSet.getInstance(); } break; case 7: if (enc2.equalsIgnoreCase("iso-646")) { return ASCIICharacterSet.getInstance(); } else break; case 8: if (enc2.equalsIgnoreCase("US-ASCII")) { return ASCIICharacterSet.getInstance(); } break; case 9: if (enc2.equalsIgnoreCase("Shift-JIS")) { return ShiftJISCharacterSet.getInstance(); } else if (enc2.equalsIgnoreCase("ISO8859-1")) { return ISO88591CharacterSet.getInstance(); } else if (enc2.equalsIgnoreCase("ISO8859-2")) { return ISO88592CharacterSet.getInstance(); } else if (enc2.equalsIgnoreCase("ISO8859-5")) { return ISO88595CharacterSet.getInstance(); } else if (enc2.equalsIgnoreCase("ISO8859-7")) { return ISO88597CharacterSet.getInstance(); } else if (enc2.equalsIgnoreCase("ISO8859-8")) { return ISO88598CharacterSet.getInstance(); } else if (enc2.equalsIgnoreCase("ISO8859-9")) { return ISO88599CharacterSet.getInstance(); } break; case 10: if (enc2.equalsIgnoreCase("iso-8859-1")) { return ISO88591CharacterSet.getInstance(); } else if (enc2.equalsIgnoreCase("iso-8859-2")) { return ISO88592CharacterSet.getInstance(); } else if (enc2.equalsIgnoreCase("iso-8859-5")) { return ISO88595CharacterSet.getInstance(); } else if (enc2.equalsIgnoreCase("iso-8859-7")) { return ISO88597CharacterSet.getInstance(); } else if (enc2.equalsIgnoreCase("iso-8859-8")) { return ISO88598CharacterSet.getInstance(); } else if (enc2.equalsIgnoreCase("iso-8859-9")) { return ISO88599CharacterSet.getInstance(); } case 11: if (enc2.equalsIgnoreCase("windows-852")) { return CP852CharacterSet.getInstance(); } break; case 12: if (enc2.equalsIgnoreCase("windows-1251")) { return CP1251CharacterSet.getInstance(); } else if (enc2.equalsIgnoreCase("windows-1250")) { return CP1250CharacterSet.getInstance(); } else if (enc2.equalsIgnoreCase("windows-1252")) { return CP1252CharacterSet.getInstance(); } break; default: break; } // Allow an alias for the character set to be specified as a system property String csname = System.getProperty("encoding." + enc2); if (csname == null) { Charset charset; try { charset = Charset.forName(encoding); CharacterSet res = UnknownCharacterSet.makeCharSet(charset); // Some JDK1.4 charsets are known to be buggy, for example SJIS. // We'll see whether the charset claims to be able to encode some // tricky characters; if it says it can, the chances are it's lying. if (res.inCharset(0x1ff) && res.inCharset(0x300) && res.inCharset(0xa90) && res.inCharset(0x2200) && res.inCharset(0x3400)) { res = BuggyCharacterSet.makeCharSet(charset); } return res; } catch (IllegalCharsetNameException err) { throw new XPathException("Invalid encoding name: " + encoding); } catch (UnsupportedCharsetException err) { return null; } } else { try { Object obj = pipe.getConfiguration().getInstance(csname, pipe.getController().getClassLoader()); if (obj instanceof PluggableCharacterSet) { return (PluggableCharacterSet)obj; } } catch (Exception err) { throw new XPathException("Failed to load " + csname); } } return null; } /** * Main program is a utility to give a list of the character sets supported * by the Java VM * @param args command line arguments */ public static void main(String[] args) throws Exception { System.err.println("Available Character Sets in the java.nio package for this Java VM:"); Iterator iter = Charset.availableCharsets().keySet().iterator(); while (iter.hasNext()) { String s = (String) iter.next(); System.err.println(s); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/charcode/GB2312CharacterSet.java0000644000175000017500000003654111033112257023114 0ustar eugeneeugenepackage net.sf.saxon.charcode; /* Copyright (C) 2006 Hewlett-Packard Development Company, L.P. The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. The Original Code is: all this file The Initial Developer of the Original Code is Lauren Ward. All Rights Reserved. Contributor(s): Integrated into Saxon by Michael Kay. Removed code to perform dynamic initialization of the boolean array, replaced it with generated static data. ************************* Author: Lauren Ward Date: February 01, 2006 Address: Hewlett-Packard Company 3404 East Harmony Road Fort Collins, CO 80528-9599 Revision: 1.0 - Initial creation Description: This class implements the PluggableCharacterSet to support GB2312 encoding. The character mapping was obtained by extracting the Unicode values from an iconv character table (hp15CN=ucs2) available on HP-UX 11.23. The class was tested by transforming numerous manuals and having localization engineers review the output. The class was also tested by transforming a document with GB2312 set as the output encoding, converting GB2312 output to utf-8 using iconv, and then comparing converted content to the same transformed document with utf-8 set as the output encoding. */ public class GB2312CharacterSet implements net.sf.saxon.charcode.PluggableCharacterSet { private static GB2312CharacterSet THE_INSTANCE = new GB2312CharacterSet(); public static GB2312CharacterSet getInstance() { return THE_INSTANCE; } private static long[] flags = { 0xffffffffffffffffL, 0xffffffffffffffffL, 0x980c000L, 0x100c0ec3168L, 0x4000101000100000L, 0x4000000100000L, 0x0L, 0x2aaa800000000L, 0x0L, 0x0L, 0x0L, 0x140000000000000L, 0x0L, 0x0L, 0x7fffdfc07fffL, 0xdfc0000000000000L, 0x4000ffffffffffffL, 0xffff400000000000L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x6cc0200b010L, 0x0L, 0x0L, 0x0L, 0x1000020000000000L, 0xfff00000L, 0xf00000000000L, 0x0L, 0x81402685f20f04L, 0x880000cc030000L, 0x4004000000L, 0x0L, 0x200000000000L, 0x0L, 0x0L, 0x0L, 0x0L, 0xffc00fffL, 0xfffffff000000000L, 0x0L, 0xffffffffffffffffL, 0xfff0000000000000L, 0xc0003000L, 0x313000000000000L, 0x600000000000000L, 0xa000000000000000L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0xf4ffdf0000000000L, 0x7fffffffffffffffL, 0xfffff0007fffffffL, 0xfffffffffffffe10L, 0x7ffffffffc00000L, 0x0L, 0x0L, 0x0L, 0xffc00000L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0xd1fedefe2dbcaaf7L, 0x15dfbacfc240d002L, 0x2df7cb1efde3431L, 0xff765fc75cb8b715L, 0x4067c1f3af31aaacL, 0x1207d5ff9d499a1bL, 0x18d5491497eb0401L, 0x1c23c1af52e750a2L, 0xd28e946ee002aL, 0x118b042804080313L, 0x8484000015c82030L, 0x10220030e1410L, 0x310200040000001L, 0xded44e28249edfdcL, 0xe4cc2758ac19f71cL, 0x8b594014c81596fdL, 0xf3a663f488d693f5L, 0xf02cca0a45612005L, 0x60809017f0fc7003L, 0x1150a28108008063L, 0x86858764d2220073L, 0x55e3772bfb53dda1L, 0x2e5c04a536c20211L, 0x60fc4bd19efff7dcL, 0x5aeff717d3df6cdaL, 0x92b0bfd82a80779cL, 0xaa1bae741bfd5895L, 0xebcffd6f07e6302dL, 0x4341c810b92bd10bL, 0x5a6086084f2e079aL, 0xf9f148cd01005556L, 0xc4c7a0d5eb93506L, 0xc0cb0093190c6a51L, 0xe09c828f84218L, 0x603100010010108L, 0x200937e814cc67L, 0x1ae0000910ef9072L, 0xa12fc13fcaf51318L, 0x3e183010fb562880L, 0x30132ce5880508e4L, 0xa3144442c8208400L, 0x80c488204180002L, 0xd440306300c00008L, 0x44004400081a9240L, 0x29050e690d7749e8L, 0x69d34fa0a4001ac4L, 0x7ba433421cf32052L, 0x230f9ac14880051L, 0x5fc8508994406a08L, 0x8260042021200f21L, 0x203000203482L, 0x60482a88d2504000L, 0x40030000002900L, 0x8000ddfd3e68d424L, 0xddd915fefe309ec7L, 0x2f08b0074c8280f9L, 0x4a614eac2d0848ffL, 0xe4f3c442d6034061L, 0x608ccbf8305c5585L, 0x481020404ea48010L, 0x33020a120b460806L, 0x138009400590800L, 0x2000004400000100L, 0x404001667d37906L, 0x7689cefc0306419cL, 0x2c080c1260003abdL, 0x8b31df6b870417c2L, 0x60721000a00b23L, 0xf8b1559187654068L, 0x8000b7846a6cd158L, 0xedf8a5c840a6050cL, 0x1e4de3c4c9364497L, 0xfe272e5cc7f10419L, 0x7014a46439fd92fdL, 0x184c2a35929d6898L, 0x63044ad83df9a60L, 0xc2c704219b100001L, 0xaa440421808500L, 0x12080401c80102L, 0x20b0680002000401L, 0x2bfe7b16c2a1907L, 0xd1de7890137f924bL, 0x886077b1ec98445dL, 0x2feebbf937cf5b0fL, 0x61c24237fcb12064L, 0x365f840371464330L, 0xa1eba280b5ee99aaL, 0xa47a202d0642a85L, 0xe419981ac22c0825L, 0x4fa02882014400e0L, 0x2d006642084e85a8L, 0xa406a1822a000000L, 0x8040208004130ed3L, 0x4c946563218a900L, 0x118d1594d55804cL, 0x5e1b2300a7cfc320L, 0xb22b1c4585854e0aL, 0x50193f214a838b22L, 0x2908430401820842L, 0x5c0240b94bL, 0x80f48d1502bd4c24L, 0xb2cbd20bc4e5b50bL, 0x495085ae35b59780L, 0x5801f8eea449d805L, 0x85fb5304406031ceL, 0xfeeadc00ffd00b00L, 0x5601110023859400L, 0xa05424a09002c468L, 0x4416a00188048845L, 0x20000926921241c8L, 0xabc40c9801944910L, 0x402a881180042005L, 0x20018140a14406L, 0x90080d044004048L, 0x8802c10080580000L, 0x0L, 0xf9002162L, 0x134800403f200058L, 0x7b74323040201d01L, 0x64153f5040311444L, 0x705def16be3ac84L, 0xe3608d1fc8e0aa46L, 0x76c998515f7670dfL, 0xc689f12f4b3d7beL, 0x491a21720532745eL, 0x57b7786a92630988L, 0x24ca5c17dbf32481L, 0x8f1842c6ca1a5158L, 0x42ecb24dc5528a0L, 0x18061a9100120003L, 0x1641808925216b34L, 0x61115d23eec00840L, 0x22411c0088755202L, 0x314008a220628a8L, 0x8ce000841001240L, 0xa0406002c0030000L, 0x403010000440L, 0x90002001d868bL, 0x84622e4c001f51dcL, 0xf0a000d10bdd0144L, 0x6096e00201c200L, 0x42a000a0b8230a4L, 0x82108c180881440L, 0x10020c0085020040L, 0x200000400a8c7d5L, 0x18c225563432463L, 0xc8352001000d8bc0L, 0x7886a142c0cff9b8L, 0x5022171e647a49c3L, 0x4a100800d0002L, 0x95242112053b130L, 0xa0e5c04285442000L, 0x1661803026aa9e08L, 0x4000057b00048302L, 0xd112800a01c00020L, 0x200aba030b01L, 0x80550e904ddf5b2L, 0x849b0878062028c1L, 0x12116b65dc1bfcceL, 0x3de42e923bb0c849L, 0xd42885d1ae749c8bL, 0x900c0a0a10110096L, 0x2b92524008026801L, 0x26a7eb91040368caL, 0x49d40061a2c507a8L, 0xd100c03076980047L, 0x8c0e6001a5689415L, 0x40118355e1287L, 0xe04c6bad174c89faL, 0x850aa704003e0108L, 0x14e51b95500f842L, 0x44708c4000882920L, 0x440010020800083aL, 0xc2c0133fa58501a0L, 0xcc21002001001076L, 0xd25464811b558094L, 0xb21609229000115dL, 0x200410000008be1L, 0xda84678d868c1001L, 0x10024396050065L, 0x1ab14c528eba50aaL, 0x559eab4a0026552L, 0x84048d0c63fc4880L, 0x430850644622410aL, 0x119020103200081L, 0xc00400000000181cL, 0x40658f2c22704eL, 0x45ac074980810090L, 0x200000a1110000L, 0x20100L, 0x2020000L, 0x0L, 0x10L, 0x4100000000000000L, 0x20000011fffdf7e7L, 0xfffffdfff7f7ffbfL, 0xffdf7ffdfffffea0L, 0x2c00cda160e26842L, 0x402a08274901a0cdL, 0x442a0c81c642d018L, 0xde1cafc8a7e05795L, 0x323c28a000604001L, 0x9b5812bdec77692fL, 0xfa0e037e4dfdfaacL, 0x2267faa200096282L, 0x2b8dc608546c87fL, 0xa0a1409c12a01030L, 0xf2280000112c181aL, 0xee0ca81b70bddfd2L, 0x95100a10083b867L, 0x28b761cd4effd9c6L, 0x49bf7d9bde114950L, 0x7fcb4d38019d5ee8L, 0x9341e83bdfff019cL, 0x642309a80f0fbecL, 0xc5290a8dc460e0c4L, 0x5a1f408c0f80408cL, 0x2004178505c56a0L, 0x21da0148400128e5L, 0x4864d20596088009L, 0x85121401801fcL, 0x10e0024208802872L, 0xd01001808a38140L, 0x4041940808400011L, 0x400420001400088L, 0x7c822201a407fL, 0xe03c140c19e9ce20L, 0x8b73c8d30846f8c2L, 0xb1e435aa74424913L, 0x1ca11409c028a1eL, 0x34941101009d1424L, 0x8230701084220042L, 0x1020161060002048L, 0x8c0c09407cdaa107L, 0x6c94220828144108L, 0x66422cc13c80d8caL, 0x2020b07044308a00L, 0x4800000302000011L, 0x5200000000000000L, 0x6ffbe22a16111000L, 0x8100000000000002L, 0x80000000000040L, 0x60100000000000L, 0x0L, 0x100000002000000L, 0x2080000L, 0xfff7bfefL, 0xfeff7fffffdfffffL, 0xffbffffdffffff00L, 0x43480420603010e0L, 0x2468088000000000L, 0x0L, 0x77fffffffL, 0xffff9efefb149f00L, 0x4c30480110005cabL, 0x1a1b433718b915f4L, 0x4690807306b4464L, 0xe9f06040024daa09L, 0x4501880a00192020L, 0x2000000000000L, 0x0L, 0x3dfffffL, 0x7ff7dffb10d0c246L, 0x6d82dcdf2ef691c4L, 0xfe75eb37e207069aL, 0x6905f19034860c05L, 0xb0905554722bdef2L, 0x4d23d11c63950886L, 0x2800004230014040L, 0x127fa1267c6befc7L, 0x55ce03030270c20L, 0x16f400800000000L, 0x0L, 0x800L, 0x2000000020000L, 0x80000000000000L, 0x2L, 0x200000L, 0x1000000000000L, 0x20020000000000L, 0x2L, 0x100000L, 0x7ffbd7fffffffffL, 0xfefee7dffdffffefL, 0xfffffff77effeffbL, 0xef6ffbdf7ffdf201L, 0x0L, 0xf7fffeL, 0xfeffef6d60227e1dL, 0xafdc8c1169e82f00L, 0x69589c80100924eL, 0xcf4f240080e11342L, 0xcbc7120a0024a0c2L, 0x3252e4401a08L, 0x414688090152800L, 0x37c1600L, 0x0L, 0x7ffL, 0xffeddbbfef000000L, 0x274e301800000L, 0x4800000020000L, 0xc0015ffef2dL, 0xcfb5ffc004800000L, 0x0L, 0x0L, 0xfdfffL, 0xefb9f3bffd80c3a8L, 0xe418508142150050L, 0x1081100110012018L, 0x7dc5480000000000L, 0x0L, 0x0L, 0x0L, 0x9L, 0x6796ec3bffd6ffbcL, 0x1f3f9fcf20000000L, 0x0L, 0x0L, 0x0L, 0x0L, 0x1f6fd77e7L, 0x7ffb45ba1bfcd003L, 0x2190300502000896L, 0x847489da561005aL, 0x169140a0090156L, 0x800c00000000001L, 0x9ff8007180000000L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x0L, 0x7fffffffffffffffL, 0xfffffffe00000000L, 0x0L, 0xd4000000L }; public GB2312CharacterSet() { //if (c == null) init(); } // Determine if it is a valid character public final boolean inCharset(int ch) { if (ch > 65535) { return false; } long g = flags[ch >> 6]; long h = (g >> (63 - (ch & 0x3f))) & 1L; return h == 1L; } public final String getEncodingName() { // Canonical Name for java.io and java.lang API return "EUC_CN"; } } saxonb-9.1.0.8/bj/net/sf/saxon/charcode/ISO88597CharacterSet.java0000644000175000017500000000623211033112257023365 0ustar eugeneeugenepackage net.sf.saxon.charcode; import java.util.Arrays; /* Copyright (C) 2006 Hewlett-Packard Development Company, L.P. The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. The Original Code is: all this file The Initial Developer of the Original Code is Lauren Ward. All Rights Reserved. Contributor(s): Integrated into Saxon by Michael Kay ************************* Author: Lauren Ward Date: February 01, 2006 Address: Hewlett-Packard Company 3404 East Harmony Road Fort Collins, CO 80528-9599 Revision: 1.0 - Initial creation Description: This class implements the PluggableCharacterSet to support iso-8859-7 encoding. The character mapping was obtained by extracting the Unicode values from an iconv character table (iso87=ucs2) available on HP-UX 11.23. The class was tested by transforming a document with ISO-8859-7 set as the output encoding, converting ISO-8859-7 output to utf-8 using iconv, and then comparing converted content to the same transformed document with utf-8 set as the output encoding. */ public class ISO88597CharacterSet implements CharacterSet { private static ISO88597CharacterSet THE_INSTANCE = new ISO88597CharacterSet(); public static ISO88597CharacterSet getInstance() { return THE_INSTANCE; } private static boolean c[] = null; static { c = new boolean[1000]; // for (int i=0; i<=25; ++i) { c[i] = true; } // for (int i=27; i<=160; ++i) { c[i] = true; } Arrays.fill(c, 0, 161, true); c[26] = false; c[163] = true; // for (int i=166; i<=169; ++i) { c[i] = true; } // for (int i=171; i<=173; ++i) { c[i] = true; } // for (int i=176; i<=179; ++i) { c[i] = true; } Arrays.fill(c, 166, 180, true); c[170] = false; c[174] = false; c[175] = false; c[183] = true; c[187] = true; c[189] = true; //for (int i=700; i<=701; ++i) { c[i] = true; } c[700] = true; c[701] = true; c[890] = true; c[894] = true; // for (int i=900; i<=902; ++i) { c[i] = true; } // for (int i=904; i<=906; ++i) { c[i] = true; } // c[908] = true; // for (int i=910; i<=929; ++i) { c[i] = true; } // for (int i=931; i<=974; ++i) { c[i] = true; } Arrays.fill(c, 900, 975, true); c[903] = false; c[907] = false; c[909] = false; c[930] = false; // c[8213] = true; // c[8364] = true; // c[8367] = true; } public ISO88597CharacterSet() { } // Determine if it is a valid character public final boolean inCharset(int ch) { return (ch < 1000 && c[ch]) || (ch > 8212 && (ch==8213 || ch==8364 || ch==8367)); } public final String getEncodingName() { // Canonical Name for java.io and java.lang API return "ISO8859_7"; } } saxonb-9.1.0.8/bj/net/sf/saxon/charcode/ISO88591CharacterSet.java0000644000175000017500000000234011033112257023353 0ustar eugeneeugenepackage net.sf.saxon.charcode; /** * This class defines properties of the ISO-8859-1 character set */ public class ISO88591CharacterSet implements CharacterSet { private static ISO88591CharacterSet theInstance = new ISO88591CharacterSet(); private ISO88591CharacterSet() {} public static ISO88591CharacterSet getInstance() { return theInstance; } public final boolean inCharset(int c) { return c <= 0xff; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is // Aleksei Makarov [makarov@iitam.omsk.net.ru] // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/charcode/package.html0000644000175000017500000000415011033112257021430 0ustar eugeneeugene Package overview for net.sf.saxon.charcode

    This package provides classes for handling different output character sets.

    The sole function of these classes is to determine whether a particular character is present in the character set or not: if not, Saxon has to replace it with a character reference.

    The actual translation of Unicode characters to characters in the selected encoding is left to the Java run-time library. (Note that different versions of Java support different sets of encodings, and there is no easy way to find out which encodings are supported in a given installation).

    It is possible to configure Saxon to support additional character sets by writing an implementation of the PluggableCharacterSet interface, and registering this class as the value of the system property whose name is given by the expression:

    OutputKeys.ENCODING + "." + encoding

    where "encoding" is the name of the encoding as used in <xsl:output> - for example, iso-8859-10.

    If an output encoding is requested that Saxon does not recognize, but which the Java platform does recognize, then Saxon attempts to determine which characters the encoding can represent, so that unsupported characters can be written as numeric character references. Saxon uses two approaches to doing this. (The logic for this is in the CharacterSetFactory class.) Where possible, it uses the UnknownCharacterSet class, which tests the availability of individual characters using the Java interrogative encoding.canEncode(). However, some encodings do not implement this method reliably; Saxon attempts to detect this, and represents such encodings instead using the BuggyCharacterSet class. This class attempts to encode each character, and relies on catching an exception when it fails: expensive, but it only happens once for any given character.


    Michael H. Kay
    Saxonica Limited
    9 February 2005

    saxonb-9.1.0.8/bj/net/sf/saxon/regex/0000755000175000017500000000000012216261747016526 5ustar eugeneeugenesaxonb-9.1.0.8/bj/net/sf/saxon/regex/RegexIterator.java0000644000175000017500000000370011033112257022140 0ustar eugeneeugenepackage net.sf.saxon.regex; import net.sf.saxon.om.SequenceIterator; /** * This class is an interator that supports the evaluation of xsl:analyze-string. * It returns all the matching and non-matching substrings in an input string, and * provides access to their captured groups */ public interface RegexIterator extends SequenceIterator { /** * Determine whether the current item in the sequence is a matching item or a non-matching item * @return true if the current item is a matching item */ public boolean isMatching(); /** * Get a substring that matches a parenthesised group within the regular expression * @param number the number of the group to be obtained * @return the substring of the current item that matches the n'th parenthesized group * within the regular expression */ public String getRegexGroup(int number); /** * Get a sequence containing all the regex captured groups relating to the current matching item * (except group 0, because we want to use indexing from 1). * This is used by the saxon:analyze-string() higher-order extension function. */ public SequenceIterator getRegexGroupIterator(); } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/regex/RegexTranslator.java0000644000175000017500000003045111033112257022503 0ustar eugeneeugenepackage net.sf.saxon.regex; import net.sf.saxon.trans.Err; import net.sf.saxon.charcode.UTF16; import net.sf.saxon.om.FastStringBuffer; import net.sf.saxon.sort.IntHashSet; import net.sf.saxon.value.Whitespace; import java.math.BigDecimal; import java.util.Collections; import java.util.List; /** * Abstract superclass for the various regex translators, which differ according to the target platform. */ public abstract class RegexTranslator { protected CharSequence regExp; protected int xmlVersion; protected boolean isXPath; protected boolean ignoreWhitespace; protected boolean inCharClassExpr; protected boolean caseBlind; protected int pos = 0; protected int length; protected char curChar; protected boolean eos = false; protected int currentCapture = 0; protected IntHashSet captures = new IntHashSet(); protected final FastStringBuffer result = new FastStringBuffer(32); protected void translateTop() throws RegexSyntaxException { translateRegExp(); if (!eos) { throw makeException("expected end of string"); } } protected void translateRegExp() throws RegexSyntaxException { translateBranch(); while (curChar == '|') { copyCurChar(); translateBranch(); } } protected void translateBranch() throws RegexSyntaxException { while (translateAtom()) translateQuantifier(); } protected abstract boolean translateAtom() throws RegexSyntaxException; protected void translateQuantifier() throws RegexSyntaxException { switch (curChar) { case '*': case '?': case '+': copyCurChar(); break; case '{': copyCurChar(); translateQuantity(); expect('}'); copyCurChar(); break; default: return; } if (curChar == '?' && isXPath) { copyCurChar(); } } protected void translateQuantity() throws RegexSyntaxException { String lower = parseQuantExact().toString(); int lowerValue = -1; try { lowerValue = Integer.parseInt(lower); result.append(lower); } catch (NumberFormatException e) { // JDK 1.4 cannot handle ranges bigger than this result.append("" + Integer.MAX_VALUE); } if (curChar == ',') { copyCurChar(); if (curChar != '}') { String upper = parseQuantExact().toString(); try { int upperValue = Integer.parseInt(upper); result.append(upper); if (lowerValue < 0 || upperValue < lowerValue) throw makeException("invalid range in quantifier"); } catch (NumberFormatException e) { result.append("" + Integer.MAX_VALUE); if (lowerValue < 0 && new BigDecimal(lower).compareTo(new BigDecimal(upper)) > 0) throw makeException("invalid range in quantifier"); } } } } protected CharSequence parseQuantExact() throws RegexSyntaxException { FastStringBuffer buf = new FastStringBuffer(10); do { if ("0123456789".indexOf(curChar) < 0) throw makeException("expected digit in quantifier"); buf.append(curChar); advance(); } while (curChar != ',' && curChar != '}'); return buf; } protected void copyCurChar() { result.append(curChar); advance(); } public static final int NONE = -1; public static final int SOME = 0; public static final int ALL = 1; public static final String SURROGATES1_CLASS = "[\uD800-\uDBFF]"; public static final String SURROGATES2_CLASS = "[\uDC00-\uDFFF]"; public static final String NOT_ALLOWED_CLASS = "[\u0000&&[^\u0000]]"; /** * A Range represents a range of consecutive Unicode codepoints */ public static final class Range implements Comparable { private final int min; private final int max; /** * Create a range of unicode codepoints * @param min the first codepoint in the range * @param max the last codepoint in the range */ public Range(int min, int max) { this.min = min; this.max = max; } /** * Get the start of the range * @return the first codepoint in the range */ public int getMin() { return min; } /** * Get the end of the range * @return the last codepoint in the range */ public int getMax() { return max; } /** * Compare this range with another range for ordering purposes. If the two ranges have different * start points, the order is the order of the start points; otherwise it is the order of the end * points. * @param o the other range * @return -1 if this range comes first, +1 if the other range comes first, 0 if they are equal * (start and end both equal) */ public int compareTo(Object o) { Range other = (Range) o; if (min < other.min) return -1; if (min > other.min) return 1; if (max > other.max) return -1; if (max < other.max) return 1; return 0; } } protected void advance() { if (pos < length) { curChar = regExp.charAt(pos++); if (ignoreWhitespace && !inCharClassExpr) { while (Whitespace.isWhitespace(curChar)) { advance(); } } } else { pos++; curChar = RegexData.EOS; eos = true; } } protected int absorbSurrogatePair() throws RegexSyntaxException { if (UTF16.isSurrogate(curChar)) { if (!UTF16.isHighSurrogate(curChar)) throw makeException("invalid surrogate pair"); char c1 = curChar; advance(); if (!UTF16.isLowSurrogate(curChar)) throw makeException("invalid surrogate pair"); return UTF16.combinePair(c1, curChar); } else { return curChar; } } protected void recede() { // The caller must ensure we don't fall off the start of the expression if (eos) { curChar = regExp.charAt(length - 1); pos = length; eos = false; } else { curChar = regExp.charAt((--pos)-1); } if (ignoreWhitespace && !inCharClassExpr) { while (Whitespace.isWhitespace(curChar)) { recede(); } } } protected void expect(char c) throws RegexSyntaxException { if (curChar != c) { throw makeException("expected", new String(new char[]{c})); } } protected RegexSyntaxException makeException(String key) { return new RegexSyntaxException("Error at character " + (pos - 1) + " in regular expression " + Err.wrap(regExp, Err.VALUE) + ": " + key); } protected RegexSyntaxException makeException(String key, String arg) { return new RegexSyntaxException("Error at character " + (pos - 1) + " in regular expression " + Err.wrap(regExp, Err.VALUE) + ": " + key + " (" + arg + ')'); } protected static boolean isJavaMetaChar(int c) { switch (c) { case '\\': case '^': case '?': case '*': case '+': case '(': case ')': case '{': case '}': case '|': case '[': case ']': case '-': case '&': case '$': case '.': return true; } return false; } protected static String highSurrogateRanges(List ranges) { FastStringBuffer highRanges = new FastStringBuffer(ranges.size() * 2); for (int i = 0, len = ranges.size(); i < len; i++) { Range r = (Range)ranges.get(i); char min1 = UTF16.highSurrogate(r.getMin()); char min2 = UTF16.lowSurrogate(r.getMin()); char max1 = UTF16.highSurrogate(r.getMax()); char max2 = UTF16.lowSurrogate(r.getMax()); if (min2 != UTF16.SURROGATE2_MIN) { min1++; } if (max2 != UTF16.SURROGATE2_MAX) { max1--; } if (max1 >= min1) { highRanges.append(min1); highRanges.append(max1); } } return highRanges.toString(); } protected static String lowSurrogateRanges(List ranges) { FastStringBuffer lowRanges = new FastStringBuffer(ranges.size() * 2); for (int i = 0, len = ranges.size(); i < len; i++) { Range r = (Range)ranges.get(i); char min1 = UTF16.highSurrogate(r.getMin()); char min2 = UTF16.lowSurrogate(r.getMin()); char max1 = UTF16.highSurrogate(r.getMax()); char max2 = UTF16.lowSurrogate(r.getMax()); if (min1 == max1) { if (min2 != UTF16.SURROGATE2_MIN || max2 != UTF16.SURROGATE2_MAX) { lowRanges.append(min1); lowRanges.append(min2); lowRanges.append(max2); } } else { if (min2 != UTF16.SURROGATE2_MIN) { lowRanges.append(min1); lowRanges.append(min2); lowRanges.append(UTF16.SURROGATE2_MAX); } if (max2 != UTF16.SURROGATE2_MAX) { lowRanges.append(max1); lowRanges.append(UTF16.SURROGATE2_MIN); lowRanges.append(max2); } } } return lowRanges.toString(); } protected static void sortRangeList(List ranges) { Collections.sort(ranges); int toIndex = 0; int fromIndex = 0; int len = ranges.size(); while (fromIndex < len) { Range r = (Range)ranges.get(fromIndex); int min = r.getMin(); int max = r.getMax(); while (++fromIndex < len) { Range r2 = (Range)ranges.get(fromIndex); if (r2.getMin() > max + 1) break; if (r2.getMax() > max) max = r2.getMax(); } if (max != r.getMax()) r = new Range(min, max); ranges.set(toIndex++, r); } while (len > toIndex) ranges.remove(--len); } protected static boolean isBlock(String name) { for (int i = 0; i < RegexData.blockNames.length; i++) { if (name.equals(RegexData.blockNames[i])) { return true; } } return false; } protected static boolean isAsciiAlnum(char c) { return 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || '0' <= c && c <= '9'; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/regex/RegexData.java0000644000175000017500000003014611033112257021224 0ustar eugeneeugenepackage net.sf.saxon.regex; /** * Non-instantiable class containing constant data definitions used by the various Regular Expression translators */ public class RegexData { public static final String categories = "LMNPZSC"; public static final String subCategories = "LuLlLtLmLoMnMcMeNdNlNoPcPdPsPePiPfPoZsZlZpSmScSkSoCcCfCoCn"; public static final char EOS = '\0'; public static final String[] blockNames = { "BasicLatin", "Latin-1Supplement", "LatinExtended-A", "LatinExtended-B", "IPAExtensions", "SpacingModifierLetters", "CombiningDiacriticalMarks", "Greek", "Cyrillic", "Armenian", "Hebrew", "Arabic", "Syriac", "Thaana", "Devanagari", "Bengali", "Gurmukhi", "Gujarati", "Oriya", "Tamil", "Telugu", "Kannada", "Malayalam", "Sinhala", "Thai", "Lao", "Tibetan", "Myanmar", "Georgian", "HangulJamo", "Ethiopic", "Cherokee", "UnifiedCanadianAboriginalSyllabics", "Ogham", "Runic", "Khmer", "Mongolian", "LatinExtendedAdditional", "GreekExtended", "GeneralPunctuation", "SuperscriptsandSubscripts", "CurrencySymbols", "CombiningMarksforSymbols", "LetterlikeSymbols", "NumberForms", "Arrows", "MathematicalOperators", "MiscellaneousTechnical", "ControlPictures", "OpticalCharacterRecognition", "EnclosedAlphanumerics", "BoxDrawing", "BlockElements", "GeometricShapes", "MiscellaneousSymbols", "Dingbats", "BraillePatterns", "CJKRadicalsSupplement", "KangxiRadicals", "IdeographicDescriptionCharacters", "CJKSymbolsandPunctuation", "Hiragana", "Katakana", "Bopomofo", "HangulCompatibilityJamo", "Kanbun", "BopomofoExtended", "EnclosedCJKLettersandMonths", "CJKCompatibility", "CJKUnifiedIdeographsExtensionA", "CJKUnifiedIdeographs", "YiSyllables", "YiRadicals", "HangulSyllables", // surrogates excluded because there are never any *characters* with codes in surrogate range // "PrivateUse", excluded because 3.1 adds non-BMP ranges "CJKCompatibilityIdeographs", "AlphabeticPresentationForms", "ArabicPresentationForms-A", "CombiningHalfMarks", "CJKCompatibilityForms", "SmallFormVariants", "ArabicPresentationForms-B", "Specials", "HalfwidthandFullwidthForms", "Specials" }; /** * Names of blocks including ranges outside the BMP. */ public static final String[] specialBlockNames = { "OldItalic", // TODO: these have disappeared from Schema 1.0 2nd edition, but are largely back in 1.1 "Gothic", "Deseret", "ByzantineMusicalSymbols", "MusicalSymbols", "MathematicalAlphanumericSymbols", "CJKUnifiedIdeographsExtensionB", "CJKCompatibilityIdeographsSupplement", "Tags", "PrivateUse", "HighSurrogates", "HighPrivateUseSurrogates", "LowSurrogates", }; // This file was automatically generated by CategoriesGen public static final String CATEGORY_NAMES = "NoLoMnCfLlNlPoLuMcNdSoSmCo"; public static final int[][] CATEGORY_RANGES = { { // No 0x10107, 0x10133, 0x10320, 0x10323 }, { // Lo 0x10000, 0x1000b, 0x1000d, 0x10026, 0x10028, 0x1003a, 0x1003c, 0x1003d, 0x1003f, 0x1004d, 0x10050, 0x1005d, 0x10080, 0x100fa, 0x10300, 0x1031e, 0x10330, 0x10349, 0x10380, 0x1039d, 0x10450, 0x1049d, 0x10800, 0x10805, 0x10808, 0x10808, 0x1080a, 0x10835, 0x10837, 0x10838, 0x1083c, 0x1083c, 0x1083f, 0x1083f, 0x20000, 0x2a6d6, 0x2f800, 0x2fa1d }, { // Mn 0x1d167, 0x1d169, 0x1d17b, 0x1d182, 0x1d185, 0x1d18b, 0x1d1aa, 0x1d1ad, 0xe0100, 0xe01ef }, { // Cf 0x1d173, 0x1d17a, 0xe0001, 0xe0001, 0xe0020, 0xe007f }, { // Ll 0x10428, 0x1044f, 0x1d41a, 0x1d433, 0x1d44e, 0x1d454, 0x1d456, 0x1d467, 0x1d482, 0x1d49b, 0x1d4b6, 0x1d4b9, 0x1d4bb, 0x1d4bb, 0x1d4bd, 0x1d4c3, 0x1d4c5, 0x1d4cf, 0x1d4ea, 0x1d503, 0x1d51e, 0x1d537, 0x1d552, 0x1d56b, 0x1d586, 0x1d59f, 0x1d5ba, 0x1d5d3, 0x1d5ee, 0x1d607, 0x1d622, 0x1d63b, 0x1d656, 0x1d66f, 0x1d68a, 0x1d6a3, 0x1d6c2, 0x1d6da, 0x1d6dc, 0x1d6e1, 0x1d6fc, 0x1d714, 0x1d716, 0x1d71b, 0x1d736, 0x1d74e, 0x1d750, 0x1d755, 0x1d770, 0x1d788, 0x1d78a, 0x1d78f, 0x1d7aa, 0x1d7c2, 0x1d7c4, 0x1d7c9 }, { // Nl 0x1034a, 0x1034a }, { // Po 0x10100, 0x10101, 0x1039f, 0x1039f }, { // Lu 0x10400, 0x10427, 0x1d400, 0x1d419, 0x1d434, 0x1d44d, 0x1d468, 0x1d481, 0x1d49c, 0x1d49c, 0x1d49e, 0x1d49f, 0x1d4a2, 0x1d4a2, 0x1d4a5, 0x1d4a6, 0x1d4a9, 0x1d4ac, 0x1d4ae, 0x1d4b5, 0x1d4d0, 0x1d4e9, 0x1d504, 0x1d505, 0x1d507, 0x1d50a, 0x1d50d, 0x1d514, 0x1d516, 0x1d51c, 0x1d538, 0x1d539, 0x1d53b, 0x1d53e, 0x1d540, 0x1d544, 0x1d546, 0x1d546, 0x1d54a, 0x1d550, 0x1d56c, 0x1d585, 0x1d5a0, 0x1d5b9, 0x1d5d4, 0x1d5ed, 0x1d608, 0x1d621, 0x1d63c, 0x1d655, 0x1d670, 0x1d689, 0x1d6a8, 0x1d6c0, 0x1d6e2, 0x1d6fa, 0x1d71c, 0x1d734, 0x1d756, 0x1d76e, 0x1d790, 0x1d7a8 }, { // Mc 0x1d165, 0x1d166, 0x1d16d, 0x1d172 }, { // Nd 0x104a0, 0x104a9, 0x1d7ce, 0x1d7ff }, { // So 0x10102, 0x10102, 0x10137, 0x1013f, 0x1d000, 0x1d0f5, 0x1d100, 0x1d126, 0x1d12a, 0x1d164, 0x1d16a, 0x1d16c, 0x1d183, 0x1d184, 0x1d18c, 0x1d1a9, 0x1d1ae, 0x1d1dd, 0x1d300, 0x1d356 }, { // Sm 0x1d6c1, 0x1d6c1, 0x1d6db, 0x1d6db, 0x1d6fb, 0x1d6fb, 0x1d715, 0x1d715, 0x1d735, 0x1d735, 0x1d74f, 0x1d74f, 0x1d76f, 0x1d76f, 0x1d789, 0x1d789, 0x1d7a9, 0x1d7a9, 0x1d7c3, 0x1d7c3 }, { // Co 0xf0000, 0xffffd, 0x100000, 0x10fffd } }; // end of generated code // This file was automatically generated by NamingExceptionsGen // class NamingExceptions { // public static final String NMSTRT_INCLUDES = // "\u003A\u005F\u02BB\u02BC\u02BD\u02BE\u02BF\u02C0\u02C1\u0559" + // "\u06E5\u06E6\u212E"; // public static final String NMSTRT_EXCLUDE_RANGES = // "\u00AA\u00BA\u0132\u0133\u013F\u0140\u0149\u0149\u017F\u017F" + // "\u01C4\u01CC\u01F1\u01F3\u01F6\u01F9\u0218\u0233\u02A9\u02AD" + // "\u03D7\u03D7\u03DB\u03DB\u03DD\u03DD\u03DF\u03DF\u03E1\u03E1" + // "\u0400\u0400\u040D\u040D\u0450\u0450\u045D\u045D\u048C\u048F" + // "\u04EC\u04ED\u0587\u0587\u06B8\u06B9\u06BF\u06BF\u06CF\u06CF" + // "\u06FA\u07A5\u0950\u0950\u0AD0\u0AD0\u0D85\u0DC6\u0E2F\u0E2F" + // "\u0EAF\u0EAF\u0EDC\u0F00\u0F6A\u1055\u1101\u1101\u1104\u1104" + // "\u1108\u1108\u110A\u110A\u110D\u110D\u1113\u113B\u113D\u113D" + // "\u113F\u113F\u1141\u114B\u114D\u114D\u114F\u114F\u1151\u1153" + // "\u1156\u1158\u1162\u1162\u1164\u1164\u1166\u1166\u1168\u1168" + // "\u116A\u116C\u116F\u1171\u1174\u1174\u1176\u119D\u119F\u11A2" + // "\u11A9\u11AA\u11AC\u11AD\u11B0\u11B6\u11B9\u11B9\u11BB\u11BB" + // "\u11C3\u11EA\u11EC\u11EF\u11F1\u11F8\u1200\u18A8\u207F\u2124" + // "\u2128\u2128\u212C\u212D\u212F\u217F\u2183\u3006\u3038\u303A" + // "\u3131\u4DB5\uA000\uA48C\uF900\uFFDC"; // public static final String NMSTRT_CATEGORIES = "LlLuLoLtNl"; // public static final String NMCHAR_INCLUDES = // "\u002D\u002E\u003A\u005F\u00B7\u0387\u06dd\u212E"; // MHK: added 06dd // public static final String NMCHAR_EXCLUDE_RANGES = // "\u00AA\u00B5\u00BA\u00BA\u0132\u0133\u013F\u0140\u0149\u0149" + // "\u017F\u017F\u01C4\u01CC\u01F1\u01F3\u01F6\u01F9\u0218\u0233" + // "\u02A9\u02B8\u02E0\u02EE\u0346\u034E\u0362\u037A\u03D7\u03D7" + // "\u03DB\u03DB\u03DD\u03DD\u03DF\u03DF\u03E1\u03E1\u0400\u0400" + // "\u040D\u040D\u0450\u0450\u045D\u045D\u0488\u048F\u04EC\u04ED" + // "\u0587\u0587\u0653\u0655\u06B8\u06B9\u06BF\u06BF\u06CF\u06CF" + // "\u06FA\u07B0\u0950\u0950\u0AD0\u0AD0\u0D82\u0DF3\u0E2F\u0E2F" + // "\u0EAF\u0EAF\u0EDC\u0F00\u0F6A\u0F6A\u0F96\u0F96\u0FAE\u0FB0" + // "\u0FB8\u0FB8\u0FBA\u1059\u1101\u1101\u1104\u1104\u1108\u1108" + // "\u110A\u110A\u110D\u110D\u1113\u113B\u113D\u113D\u113F\u113F" + // "\u1141\u114B\u114D\u114D\u114F\u114F\u1151\u1153\u1156\u1158" + // "\u1162\u1162\u1164\u1164\u1166\u1166\u1168\u1168\u116A\u116C" + // "\u116F\u1171\u1174\u1174\u1176\u119D\u119F\u11A2\u11A9\u11AA" + // "\u11AC\u11AD\u11B0\u11B6\u11B9\u11B9\u11BB\u11BB\u11C3\u11EA" + // "\u11EC\u11EF\u11F1\u11F8\u1200\u18A9\u207F\u207F\u20DD\u20E0" + // "\u20E2\u2124\u2128\u2128\u212C\u212D\u212F\u217F\u2183\u2183" + // "\u3006\u3006\u3038\u303A\u3131\u4DB5\uA000\uA48C\uF900\uFFDC"; // public static final String NMCHAR_CATEGORIES = "LlLuLoLtNlMcMeMnLmNd"; // end of generated code public static final char UNICODE_3_1_ADD_Lu = '\u03F4'; // added in 3.1 public static final char UNICODE_3_1_ADD_Ll = '\u03F5'; // added in 3.1 // 3 characters changed from No to Nl between 3.0 and 3.1 public static final char UNICODE_3_1_CHANGE_No_to_Nl_MIN = '\u16EE'; public static final char UNICODE_3_1_CHANGE_No_to_Nl_MAX = '\u16F0'; public static final String CATEGORY_Pi = "\u00AB\u2018\u201B\u201C\u201F\u2039"; // Java doesn't know about category Pi public static final String CATEGORY_Pf = "\u00BB\u2019\u201D\u203A"; // Java doesn't know about category Pf } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/regex/RegularExpression.java0000644000175000017500000000650611033112257023044 0ustar eugeneeugenepackage net.sf.saxon.regex; import net.sf.saxon.trans.XPathException; import net.sf.saxon.om.SequenceIterator; import java.io.Serializable; /** * This interface represents a compiled regular expression */ public interface RegularExpression extends Serializable { /** * Constant indicating the regular expression language is XPath 2.0 */ public static final int XPATH_SYNTAX = 0; /** * Constant indication the regular expression language is XML Schema Part 2 */ public static final int XML_SCHEMA_SYNTAX = 1; /** * Constant indicating the regular expression syntax is the native syntax for the platform (Java or .NET) */ public static final int NATIVE_SYNTAX = 2; /** * Determine whether the regular expression match a given string in its entirety * @param input the string to match * @return true if the string matches, false otherwise */ public boolean matches(CharSequence input); /** * Determine whether the regular expression contains a match of a given string * @param input the string to match * @return true if the string matches, false otherwise */ public boolean containsMatch(CharSequence input); /** * Use this regular expression to tokenize an input string. * @param input the string to be tokenized * @return a SequenceIterator containing the resulting tokens, as objects of type StringValue */ public SequenceIterator tokenize(CharSequence input); /** * Use this regular expression to analyze an input string, in support of the XSLT * analyze-string instruction. The resulting RegexIterator provides both the matching and * non-matching substrings, and allows them to be distinguished. It also provides access * to matched subgroups. * @param input the character string to be analyzed using the regular expression * @return an iterator over matched and unmatched substrings */ public RegexIterator analyze(CharSequence input); /** * Replace all substrings of a supplied input string that match the regular expression * with a replacement string. * @param input the input string on which replacements are to be performed * @param replacement the replacement string in the format of the XPath replace() function * @return the result of performing the replacement * @throws XPathException if the replacement string is invalid */ public CharSequence replace(CharSequence input, CharSequence replacement) throws XPathException; } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/regex/RegexSyntaxException.java0000644000175000017500000000326711033112257023524 0ustar eugeneeugenepackage net.sf.saxon.regex; /** * Thrown when an syntactically incorrect regular expression is detected. */ public class RegexSyntaxException extends Exception { private final int position; /** * Represents an unknown position within a string containing a regular expression. */ public static final int UNKNOWN_POSITION = -1; public RegexSyntaxException(String detail) { this(detail, UNKNOWN_POSITION); } public RegexSyntaxException(String detail, int position) { super(detail); this.position = position; } /** * Returns the index into the regular expression where the error was detected * or UNKNOWN_POSITION if this is unknown. * * @return the index into the regular expression where the error was detected, * or UNKNOWNN_POSITION if this is unknown */ public int getPosition() { return position; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/regex/CaseVariants.java0000644000175000017500000015517011033112257021750 0ustar eugeneeugenepackage net.sf.saxon.regex; import net.sf.saxon.sort.IntHashMap; import net.sf.saxon.sort.IntToIntHashMap; import net.sf.saxon.sort.IntToIntMap; /** * This class holds data about the case-variants of Unicode characters. The data is automatically * generated from the Unicode database. */ public class CaseVariants { private static int[] EMPTY_INT_ARRAY = {}; // Use one hashmap for characters with a single case variant, another for characters with multiple // case variants, to reduce the number of objects that need to be allocated private static IntToIntMap monoVariants = new IntToIntHashMap(2500); private static IntHashMap polyVariants = new IntHashMap(100); private static void cv(int a, int b) { monoVariants.put(a, b); } private static void cv(int a, int b, int c) { int[] v = {b, c}; polyVariants.put(a, v); } private static void cv(int a, int b, int c, int d) { int[] v = {b, c, d}; polyVariants.put(a, v); } /** * Get the case variants of a character * * @param code the character whose case variants are required * @return the case variants of the character, excluding the character itself */ public static int[] getCaseVariants(int code) { int mono = monoVariants.get(code); if (mono != monoVariants.getDefaultValue()) { int[] result = {mono}; return result; } else { int[] result = (int[]) polyVariants.get(code); if (result == null) { return EMPTY_INT_ARRAY; } else { return result; } } } /** * Get the case variants of roman letters (A-Z, a-z), other than the letters A-Z and a-z themselves */ public static int[] ROMAN_VARIANTS = {0x0130, 0x0131, 0x212A, 0x017F}; /** * The following data was generated from the Unicode database as follows: * (a) the database was converted to XML * (b) the following query was run: * let $chars := doc('UnicodeData.xml')/ * /Char[string(toUpper) or string(toLower)] * for $c in $chars * let $variants := ($chars[(code, toUpper) = $c/(code, toUpper)] | * $chars[(code, toLower) = $c/(code, toLower)]) except $c * return * if (count($variants) gt 0) then * concat("cv(0x", $c/code, ", 0x", string-join($variants/code, ", 0x"), "); ") * else () */ static { cv(0x0041, 0x0061); cv(0x0042, 0x0062); cv(0x0043, 0x0063); cv(0x0044, 0x0064); cv(0x0045, 0x0065); cv(0x0046, 0x0066); cv(0x0047, 0x0067); cv(0x0048, 0x0068); cv(0x0049, 0x0069, 0x0130, 0x0131); cv(0x004A, 0x006A); cv(0x004B, 0x006B, 0x212A); cv(0x004C, 0x006C); cv(0x004D, 0x006D); cv(0x004E, 0x006E); cv(0x004F, 0x006F); cv(0x0050, 0x0070); cv(0x0051, 0x0071); cv(0x0052, 0x0072); cv(0x0053, 0x0073, 0x017F); cv(0x0054, 0x0074); cv(0x0055, 0x0075); cv(0x0056, 0x0076); cv(0x0057, 0x0077); cv(0x0058, 0x0078); cv(0x0059, 0x0079); cv(0x005A, 0x007A); cv(0x0061, 0x0041); cv(0x0062, 0x0042); cv(0x0063, 0x0043); cv(0x0064, 0x0044); cv(0x0065, 0x0045); cv(0x0066, 0x0046); cv(0x0067, 0x0047); cv(0x0068, 0x0048); cv(0x0069, 0x0049, 0x0130, 0x0131); cv(0x006A, 0x004A); cv(0x006B, 0x004B, 0x212A); cv(0x006C, 0x004C); cv(0x006D, 0x004D); cv(0x006E, 0x004E); cv(0x006F, 0x004F); cv(0x0070, 0x0050); cv(0x0071, 0x0051); cv(0x0072, 0x0052); cv(0x0073, 0x0053, 0x017F); cv(0x0074, 0x0054); cv(0x0075, 0x0055); cv(0x0076, 0x0056); cv(0x0077, 0x0057); cv(0x0078, 0x0058); cv(0x0079, 0x0059); cv(0x007A, 0x005A); cv(0x00B5, 0x039C, 0x03BC); cv(0x00C0, 0x00E0); cv(0x00C1, 0x00E1); cv(0x00C2, 0x00E2); cv(0x00C3, 0x00E3); cv(0x00C4, 0x00E4); cv(0x00C5, 0x00E5, 0x212B); cv(0x00C6, 0x00E6); cv(0x00C7, 0x00E7); cv(0x00C8, 0x00E8); cv(0x00C9, 0x00E9); cv(0x00CA, 0x00EA); cv(0x00CB, 0x00EB); cv(0x00CC, 0x00EC); cv(0x00CD, 0x00ED); cv(0x00CE, 0x00EE); cv(0x00CF, 0x00EF); cv(0x00D0, 0x00F0); cv(0x00D1, 0x00F1); cv(0x00D2, 0x00F2); cv(0x00D3, 0x00F3); cv(0x00D4, 0x00F4); cv(0x00D5, 0x00F5); cv(0x00D6, 0x00F6); cv(0x00D8, 0x00F8); cv(0x00D9, 0x00F9); cv(0x00DA, 0x00FA); cv(0x00DB, 0x00FB); cv(0x00DC, 0x00FC); cv(0x00DD, 0x00FD); cv(0x00DE, 0x00FE); cv(0x00E0, 0x00C0); cv(0x00E1, 0x00C1); cv(0x00E2, 0x00C2); cv(0x00E3, 0x00C3); cv(0x00E4, 0x00C4); cv(0x00E5, 0x00C5, 0x212B); cv(0x00E6, 0x00C6); cv(0x00E7, 0x00C7); cv(0x00E8, 0x00C8); cv(0x00E9, 0x00C9); cv(0x00EA, 0x00CA); cv(0x00EB, 0x00CB); cv(0x00EC, 0x00CC); cv(0x00ED, 0x00CD); cv(0x00EE, 0x00CE); cv(0x00EF, 0x00CF); cv(0x00F0, 0x00D0); cv(0x00F1, 0x00D1); cv(0x00F2, 0x00D2); cv(0x00F3, 0x00D3); cv(0x00F4, 0x00D4); cv(0x00F5, 0x00D5); cv(0x00F6, 0x00D6); cv(0x00F8, 0x00D8); cv(0x00F9, 0x00D9); cv(0x00FA, 0x00DA); cv(0x00FB, 0x00DB); cv(0x00FC, 0x00DC); cv(0x00FD, 0x00DD); cv(0x00FE, 0x00DE); cv(0x00FF, 0x0178); cv(0x0100, 0x0101); cv(0x0101, 0x0100); cv(0x0102, 0x0103); cv(0x0103, 0x0102); cv(0x0104, 0x0105); cv(0x0105, 0x0104); cv(0x0106, 0x0107); cv(0x0107, 0x0106); cv(0x0108, 0x0109); cv(0x0109, 0x0108); cv(0x010A, 0x010B); cv(0x010B, 0x010A); cv(0x010C, 0x010D); cv(0x010D, 0x010C); cv(0x010E, 0x010F); cv(0x010F, 0x010E); cv(0x0110, 0x0111); cv(0x0111, 0x0110); cv(0x0112, 0x0113); cv(0x0113, 0x0112); cv(0x0114, 0x0115); cv(0x0115, 0x0114); cv(0x0116, 0x0117); cv(0x0117, 0x0116); cv(0x0118, 0x0119); cv(0x0119, 0x0118); cv(0x011A, 0x011B); cv(0x011B, 0x011A); cv(0x011C, 0x011D); cv(0x011D, 0x011C); cv(0x011E, 0x011F); cv(0x011F, 0x011E); cv(0x0120, 0x0121); cv(0x0121, 0x0120); cv(0x0122, 0x0123); cv(0x0123, 0x0122); cv(0x0124, 0x0125); cv(0x0125, 0x0124); cv(0x0126, 0x0127); cv(0x0127, 0x0126); cv(0x0128, 0x0129); cv(0x0129, 0x0128); cv(0x012A, 0x012B); cv(0x012B, 0x012A); cv(0x012C, 0x012D); cv(0x012D, 0x012C); cv(0x012E, 0x012F); cv(0x012F, 0x012E); cv(0x0130, 0x0049, 0x0069); cv(0x0131, 0x0049, 0x0069); cv(0x0132, 0x0133); cv(0x0133, 0x0132); cv(0x0134, 0x0135); cv(0x0135, 0x0134); cv(0x0136, 0x0137); cv(0x0137, 0x0136); cv(0x0139, 0x013A); cv(0x013A, 0x0139); cv(0x013B, 0x013C); cv(0x013C, 0x013B); cv(0x013D, 0x013E); cv(0x013E, 0x013D); cv(0x013F, 0x0140); cv(0x0140, 0x013F); cv(0x0141, 0x0142); cv(0x0142, 0x0141); cv(0x0143, 0x0144); cv(0x0144, 0x0143); cv(0x0145, 0x0146); cv(0x0146, 0x0145); cv(0x0147, 0x0148); cv(0x0148, 0x0147); cv(0x014A, 0x014B); cv(0x014B, 0x014A); cv(0x014C, 0x014D); cv(0x014D, 0x014C); cv(0x014E, 0x014F); cv(0x014F, 0x014E); cv(0x0150, 0x0151); cv(0x0151, 0x0150); cv(0x0152, 0x0153); cv(0x0153, 0x0152); cv(0x0154, 0x0155); cv(0x0155, 0x0154); cv(0x0156, 0x0157); cv(0x0157, 0x0156); cv(0x0158, 0x0159); cv(0x0159, 0x0158); cv(0x015A, 0x015B); cv(0x015B, 0x015A); cv(0x015C, 0x015D); cv(0x015D, 0x015C); cv(0x015E, 0x015F); cv(0x015F, 0x015E); cv(0x0160, 0x0161); cv(0x0161, 0x0160); cv(0x0162, 0x0163); cv(0x0163, 0x0162); cv(0x0164, 0x0165); cv(0x0165, 0x0164); cv(0x0166, 0x0167); cv(0x0167, 0x0166); cv(0x0168, 0x0169); cv(0x0169, 0x0168); cv(0x016A, 0x016B); cv(0x016B, 0x016A); cv(0x016C, 0x016D); cv(0x016D, 0x016C); cv(0x016E, 0x016F); cv(0x016F, 0x016E); cv(0x0170, 0x0171); cv(0x0171, 0x0170); cv(0x0172, 0x0173); cv(0x0173, 0x0172); cv(0x0174, 0x0175); cv(0x0175, 0x0174); cv(0x0176, 0x0177); cv(0x0177, 0x0176); cv(0x0178, 0x00FF); cv(0x0179, 0x017A); cv(0x017A, 0x0179); cv(0x017B, 0x017C); cv(0x017C, 0x017B); cv(0x017D, 0x017E); cv(0x017E, 0x017D); cv(0x017F, 0x0053, 0x0073); cv(0x0181, 0x0253); cv(0x0182, 0x0183); cv(0x0183, 0x0182); cv(0x0184, 0x0185); cv(0x0185, 0x0184); cv(0x0186, 0x0254); cv(0x0187, 0x0188); cv(0x0188, 0x0187); cv(0x0189, 0x0256); cv(0x018A, 0x0257); cv(0x018B, 0x018C); cv(0x018C, 0x018B); cv(0x018E, 0x01DD); cv(0x018F, 0x0259); cv(0x0190, 0x025B); cv(0x0191, 0x0192); cv(0x0192, 0x0191); cv(0x0193, 0x0260); cv(0x0194, 0x0263); cv(0x0195, 0x01F6); cv(0x0196, 0x0269); cv(0x0197, 0x0268); cv(0x0198, 0x0199); cv(0x0199, 0x0198); cv(0x019A, 0x023D); cv(0x019C, 0x026F); cv(0x019D, 0x0272); cv(0x019E, 0x0220); cv(0x019F, 0x0275); cv(0x01A0, 0x01A1); cv(0x01A1, 0x01A0); cv(0x01A2, 0x01A3); cv(0x01A3, 0x01A2); cv(0x01A4, 0x01A5); cv(0x01A5, 0x01A4); cv(0x01A6, 0x0280); cv(0x01A7, 0x01A8); cv(0x01A8, 0x01A7); cv(0x01A9, 0x0283); cv(0x01AC, 0x01AD); cv(0x01AD, 0x01AC); cv(0x01AE, 0x0288); cv(0x01AF, 0x01B0); cv(0x01B0, 0x01AF); cv(0x01B1, 0x028A); cv(0x01B2, 0x028B); cv(0x01B3, 0x01B4); cv(0x01B4, 0x01B3); cv(0x01B5, 0x01B6); cv(0x01B6, 0x01B5); cv(0x01B7, 0x0292); cv(0x01B8, 0x01B9); cv(0x01B9, 0x01B8); cv(0x01BC, 0x01BD); cv(0x01BD, 0x01BC); cv(0x01BF, 0x01F7); cv(0x01C4, 0x01C5, 0x01C6); cv(0x01C5, 0x01C4, 0x01C6); cv(0x01C6, 0x01C4, 0x01C5); cv(0x01C7, 0x01C8, 0x01C9); cv(0x01C8, 0x01C7, 0x01C9); cv(0x01C9, 0x01C7, 0x01C8); cv(0x01CA, 0x01CB, 0x01CC); cv(0x01CB, 0x01CA, 0x01CC); cv(0x01CC, 0x01CA, 0x01CB); cv(0x01CD, 0x01CE); cv(0x01CE, 0x01CD); cv(0x01CF, 0x01D0); cv(0x01D0, 0x01CF); cv(0x01D1, 0x01D2); cv(0x01D2, 0x01D1); cv(0x01D3, 0x01D4); cv(0x01D4, 0x01D3); cv(0x01D5, 0x01D6); cv(0x01D6, 0x01D5); cv(0x01D7, 0x01D8); cv(0x01D8, 0x01D7); cv(0x01D9, 0x01DA); cv(0x01DA, 0x01D9); cv(0x01DB, 0x01DC); cv(0x01DC, 0x01DB); cv(0x01DD, 0x018E); cv(0x01DE, 0x01DF); cv(0x01DF, 0x01DE); cv(0x01E0, 0x01E1); cv(0x01E1, 0x01E0); cv(0x01E2, 0x01E3); cv(0x01E3, 0x01E2); cv(0x01E4, 0x01E5); cv(0x01E5, 0x01E4); cv(0x01E6, 0x01E7); cv(0x01E7, 0x01E6); cv(0x01E8, 0x01E9); cv(0x01E9, 0x01E8); cv(0x01EA, 0x01EB); cv(0x01EB, 0x01EA); cv(0x01EC, 0x01ED); cv(0x01ED, 0x01EC); cv(0x01EE, 0x01EF); cv(0x01EF, 0x01EE); cv(0x01F1, 0x01F2, 0x01F3); cv(0x01F2, 0x01F1, 0x01F3); cv(0x01F3, 0x01F1, 0x01F2); cv(0x01F4, 0x01F5); cv(0x01F5, 0x01F4); cv(0x01F6, 0x0195); cv(0x01F7, 0x01BF); cv(0x01F8, 0x01F9); cv(0x01F9, 0x01F8); cv(0x01FA, 0x01FB); cv(0x01FB, 0x01FA); cv(0x01FC, 0x01FD); cv(0x01FD, 0x01FC); cv(0x01FE, 0x01FF); cv(0x01FF, 0x01FE); cv(0x0200, 0x0201); cv(0x0201, 0x0200); cv(0x0202, 0x0203); cv(0x0203, 0x0202); cv(0x0204, 0x0205); cv(0x0205, 0x0204); cv(0x0206, 0x0207); cv(0x0207, 0x0206); cv(0x0208, 0x0209); cv(0x0209, 0x0208); cv(0x020A, 0x020B); cv(0x020B, 0x020A); cv(0x020C, 0x020D); cv(0x020D, 0x020C); cv(0x020E, 0x020F); cv(0x020F, 0x020E); cv(0x0210, 0x0211); cv(0x0211, 0x0210); cv(0x0212, 0x0213); cv(0x0213, 0x0212); cv(0x0214, 0x0215); cv(0x0215, 0x0214); cv(0x0216, 0x0217); cv(0x0217, 0x0216); cv(0x0218, 0x0219); cv(0x0219, 0x0218); cv(0x021A, 0x021B); cv(0x021B, 0x021A); cv(0x021C, 0x021D); cv(0x021D, 0x021C); cv(0x021E, 0x021F); cv(0x021F, 0x021E); cv(0x0220, 0x019E); cv(0x0222, 0x0223); cv(0x0223, 0x0222); cv(0x0224, 0x0225); cv(0x0225, 0x0224); cv(0x0226, 0x0227); cv(0x0227, 0x0226); cv(0x0228, 0x0229); cv(0x0229, 0x0228); cv(0x022A, 0x022B); cv(0x022B, 0x022A); cv(0x022C, 0x022D); cv(0x022D, 0x022C); cv(0x022E, 0x022F); cv(0x022F, 0x022E); cv(0x0230, 0x0231); cv(0x0231, 0x0230); cv(0x0232, 0x0233); cv(0x0233, 0x0232); cv(0x023B, 0x023C); cv(0x023C, 0x023B); cv(0x023D, 0x019A); cv(0x0241, 0x0294); cv(0x0253, 0x0181); cv(0x0254, 0x0186); cv(0x0256, 0x0189); cv(0x0257, 0x018A); cv(0x0259, 0x018F); cv(0x025B, 0x0190); cv(0x0260, 0x0193); cv(0x0263, 0x0194); cv(0x0268, 0x0197); cv(0x0269, 0x0196); cv(0x026F, 0x019C); cv(0x0272, 0x019D); cv(0x0275, 0x019F); cv(0x0280, 0x01A6); cv(0x0283, 0x01A9); cv(0x0288, 0x01AE); cv(0x028A, 0x01B1); cv(0x028B, 0x01B2); cv(0x0292, 0x01B7); cv(0x0294, 0x0241); cv(0x0345, 0x0399, 0x03B9, 0x1FBE); cv(0x0386, 0x03AC); cv(0x0388, 0x03AD); cv(0x0389, 0x03AE); cv(0x038A, 0x03AF); cv(0x038C, 0x03CC); cv(0x038E, 0x03CD); cv(0x038F, 0x03CE); cv(0x0391, 0x03B1); cv(0x0392, 0x03B2, 0x03D0); cv(0x0393, 0x03B3); cv(0x0394, 0x03B4); cv(0x0395, 0x03B5, 0x03F5); cv(0x0396, 0x03B6); cv(0x0397, 0x03B7); cv(0x0398, 0x03B8, 0x03D1, 0x03F4); cv(0x0399, 0x0345, 0x03B9, 0x1FBE); cv(0x039A, 0x03BA, 0x03F0); cv(0x039B, 0x03BB); cv(0x039C, 0x00B5, 0x03BC); cv(0x039D, 0x03BD); cv(0x039E, 0x03BE); cv(0x039F, 0x03BF); cv(0x03A0, 0x03C0, 0x03D6); cv(0x03A1, 0x03C1, 0x03F1); cv(0x03A3, 0x03C2, 0x03C3); cv(0x03A4, 0x03C4); cv(0x03A5, 0x03C5); cv(0x03A6, 0x03C6, 0x03D5); cv(0x03A7, 0x03C7); cv(0x03A8, 0x03C8); cv(0x03A9, 0x03C9, 0x2126); cv(0x03AA, 0x03CA); cv(0x03AB, 0x03CB); cv(0x03AC, 0x0386); cv(0x03AD, 0x0388); cv(0x03AE, 0x0389); cv(0x03AF, 0x038A); cv(0x03B1, 0x0391); cv(0x03B2, 0x0392, 0x03D0); cv(0x03B3, 0x0393); cv(0x03B4, 0x0394); cv(0x03B5, 0x0395, 0x03F5); cv(0x03B6, 0x0396); cv(0x03B7, 0x0397); cv(0x03B8, 0x0398, 0x03D1, 0x03F4); cv(0x03B9, 0x0345, 0x0399, 0x1FBE); cv(0x03BA, 0x039A, 0x03F0); cv(0x03BB, 0x039B); cv(0x03BC, 0x00B5, 0x039C); cv(0x03BD, 0x039D); cv(0x03BE, 0x039E); cv(0x03BF, 0x039F); cv(0x03C0, 0x03A0, 0x03D6); cv(0x03C1, 0x03A1, 0x03F1); cv(0x03C2, 0x03A3, 0x03C3); cv(0x03C3, 0x03A3, 0x03C2); cv(0x03C4, 0x03A4); cv(0x03C5, 0x03A5); cv(0x03C6, 0x03A6, 0x03D5); cv(0x03C7, 0x03A7); cv(0x03C8, 0x03A8); cv(0x03C9, 0x03A9, 0x2126); cv(0x03CA, 0x03AA); cv(0x03CB, 0x03AB); cv(0x03CC, 0x038C); cv(0x03CD, 0x038E); cv(0x03CE, 0x038F); cv(0x03D0, 0x0392, 0x03B2); cv(0x03D1, 0x0398, 0x03B8); cv(0x03D5, 0x03A6, 0x03C6); cv(0x03D6, 0x03A0, 0x03C0); cv(0x03D8, 0x03D9); cv(0x03D9, 0x03D8); cv(0x03DA, 0x03DB); cv(0x03DB, 0x03DA); cv(0x03DC, 0x03DD); cv(0x03DD, 0x03DC); cv(0x03DE, 0x03DF); cv(0x03DF, 0x03DE); cv(0x03E0, 0x03E1); cv(0x03E1, 0x03E0); cv(0x03E2, 0x03E3); cv(0x03E3, 0x03E2); cv(0x03E4, 0x03E5); cv(0x03E5, 0x03E4); cv(0x03E6, 0x03E7); cv(0x03E7, 0x03E6); cv(0x03E8, 0x03E9); cv(0x03E9, 0x03E8); cv(0x03EA, 0x03EB); cv(0x03EB, 0x03EA); cv(0x03EC, 0x03ED); cv(0x03ED, 0x03EC); cv(0x03EE, 0x03EF); cv(0x03EF, 0x03EE); cv(0x03F0, 0x039A, 0x03BA); cv(0x03F1, 0x03A1, 0x03C1); cv(0x03F2, 0x03F9); cv(0x03F4, 0x0398, 0x03B8); cv(0x03F5, 0x0395, 0x03B5); cv(0x03F7, 0x03F8); cv(0x03F8, 0x03F7); cv(0x03F9, 0x03F2); cv(0x03FA, 0x03FB); cv(0x03FB, 0x03FA); cv(0x0400, 0x0450); cv(0x0401, 0x0451); cv(0x0402, 0x0452); cv(0x0403, 0x0453); cv(0x0404, 0x0454); cv(0x0405, 0x0455); cv(0x0406, 0x0456); cv(0x0407, 0x0457); cv(0x0408, 0x0458); cv(0x0409, 0x0459); cv(0x040A, 0x045A); cv(0x040B, 0x045B); cv(0x040C, 0x045C); cv(0x040D, 0x045D); cv(0x040E, 0x045E); cv(0x040F, 0x045F); cv(0x0410, 0x0430); cv(0x0411, 0x0431); cv(0x0412, 0x0432); cv(0x0413, 0x0433); cv(0x0414, 0x0434); cv(0x0415, 0x0435); cv(0x0416, 0x0436); cv(0x0417, 0x0437); cv(0x0418, 0x0438); cv(0x0419, 0x0439); cv(0x041A, 0x043A); cv(0x041B, 0x043B); cv(0x041C, 0x043C); cv(0x041D, 0x043D); cv(0x041E, 0x043E); cv(0x041F, 0x043F); cv(0x0420, 0x0440); cv(0x0421, 0x0441); cv(0x0422, 0x0442); cv(0x0423, 0x0443); cv(0x0424, 0x0444); cv(0x0425, 0x0445); cv(0x0426, 0x0446); cv(0x0427, 0x0447); cv(0x0428, 0x0448); cv(0x0429, 0x0449); cv(0x042A, 0x044A); cv(0x042B, 0x044B); cv(0x042C, 0x044C); cv(0x042D, 0x044D); cv(0x042E, 0x044E); cv(0x042F, 0x044F); cv(0x0430, 0x0410); cv(0x0431, 0x0411); cv(0x0432, 0x0412); cv(0x0433, 0x0413); cv(0x0434, 0x0414); cv(0x0435, 0x0415); cv(0x0436, 0x0416); cv(0x0437, 0x0417); cv(0x0438, 0x0418); cv(0x0439, 0x0419); cv(0x043A, 0x041A); cv(0x043B, 0x041B); cv(0x043C, 0x041C); cv(0x043D, 0x041D); cv(0x043E, 0x041E); cv(0x043F, 0x041F); cv(0x0440, 0x0420); cv(0x0441, 0x0421); cv(0x0442, 0x0422); cv(0x0443, 0x0423); cv(0x0444, 0x0424); cv(0x0445, 0x0425); cv(0x0446, 0x0426); cv(0x0447, 0x0427); cv(0x0448, 0x0428); cv(0x0449, 0x0429); cv(0x044A, 0x042A); cv(0x044B, 0x042B); cv(0x044C, 0x042C); cv(0x044D, 0x042D); cv(0x044E, 0x042E); cv(0x044F, 0x042F); cv(0x0450, 0x0400); cv(0x0451, 0x0401); cv(0x0452, 0x0402); cv(0x0453, 0x0403); cv(0x0454, 0x0404); cv(0x0455, 0x0405); cv(0x0456, 0x0406); cv(0x0457, 0x0407); cv(0x0458, 0x0408); cv(0x0459, 0x0409); cv(0x045A, 0x040A); cv(0x045B, 0x040B); cv(0x045C, 0x040C); cv(0x045D, 0x040D); cv(0x045E, 0x040E); cv(0x045F, 0x040F); cv(0x0460, 0x0461); cv(0x0461, 0x0460); cv(0x0462, 0x0463); cv(0x0463, 0x0462); cv(0x0464, 0x0465); cv(0x0465, 0x0464); cv(0x0466, 0x0467); cv(0x0467, 0x0466); cv(0x0468, 0x0469); cv(0x0469, 0x0468); cv(0x046A, 0x046B); cv(0x046B, 0x046A); cv(0x046C, 0x046D); cv(0x046D, 0x046C); cv(0x046E, 0x046F); cv(0x046F, 0x046E); cv(0x0470, 0x0471); cv(0x0471, 0x0470); cv(0x0472, 0x0473); cv(0x0473, 0x0472); cv(0x0474, 0x0475); cv(0x0475, 0x0474); cv(0x0476, 0x0477); cv(0x0477, 0x0476); cv(0x0478, 0x0479); cv(0x0479, 0x0478); cv(0x047A, 0x047B); cv(0x047B, 0x047A); cv(0x047C, 0x047D); cv(0x047D, 0x047C); cv(0x047E, 0x047F); cv(0x047F, 0x047E); cv(0x0480, 0x0481); cv(0x0481, 0x0480); cv(0x048A, 0x048B); cv(0x048B, 0x048A); cv(0x048C, 0x048D); cv(0x048D, 0x048C); cv(0x048E, 0x048F); cv(0x048F, 0x048E); cv(0x0490, 0x0491); cv(0x0491, 0x0490); cv(0x0492, 0x0493); cv(0x0493, 0x0492); cv(0x0494, 0x0495); cv(0x0495, 0x0494); cv(0x0496, 0x0497); cv(0x0497, 0x0496); cv(0x0498, 0x0499); cv(0x0499, 0x0498); cv(0x049A, 0x049B); cv(0x049B, 0x049A); cv(0x049C, 0x049D); cv(0x049D, 0x049C); cv(0x049E, 0x049F); cv(0x049F, 0x049E); cv(0x04A0, 0x04A1); cv(0x04A1, 0x04A0); cv(0x04A2, 0x04A3); cv(0x04A3, 0x04A2); cv(0x04A4, 0x04A5); cv(0x04A5, 0x04A4); cv(0x04A6, 0x04A7); cv(0x04A7, 0x04A6); cv(0x04A8, 0x04A9); cv(0x04A9, 0x04A8); cv(0x04AA, 0x04AB); cv(0x04AB, 0x04AA); cv(0x04AC, 0x04AD); cv(0x04AD, 0x04AC); cv(0x04AE, 0x04AF); cv(0x04AF, 0x04AE); cv(0x04B0, 0x04B1); cv(0x04B1, 0x04B0); cv(0x04B2, 0x04B3); cv(0x04B3, 0x04B2); cv(0x04B4, 0x04B5); cv(0x04B5, 0x04B4); cv(0x04B6, 0x04B7); cv(0x04B7, 0x04B6); cv(0x04B8, 0x04B9); cv(0x04B9, 0x04B8); cv(0x04BA, 0x04BB); cv(0x04BB, 0x04BA); cv(0x04BC, 0x04BD); cv(0x04BD, 0x04BC); cv(0x04BE, 0x04BF); cv(0x04BF, 0x04BE); cv(0x04C1, 0x04C2); cv(0x04C2, 0x04C1); cv(0x04C3, 0x04C4); cv(0x04C4, 0x04C3); cv(0x04C5, 0x04C6); cv(0x04C6, 0x04C5); cv(0x04C7, 0x04C8); cv(0x04C8, 0x04C7); cv(0x04C9, 0x04CA); cv(0x04CA, 0x04C9); cv(0x04CB, 0x04CC); cv(0x04CC, 0x04CB); cv(0x04CD, 0x04CE); cv(0x04CE, 0x04CD); cv(0x04D0, 0x04D1); cv(0x04D1, 0x04D0); cv(0x04D2, 0x04D3); cv(0x04D3, 0x04D2); cv(0x04D4, 0x04D5); cv(0x04D5, 0x04D4); cv(0x04D6, 0x04D7); cv(0x04D7, 0x04D6); cv(0x04D8, 0x04D9); cv(0x04D9, 0x04D8); cv(0x04DA, 0x04DB); cv(0x04DB, 0x04DA); cv(0x04DC, 0x04DD); cv(0x04DD, 0x04DC); cv(0x04DE, 0x04DF); cv(0x04DF, 0x04DE); cv(0x04E0, 0x04E1); cv(0x04E1, 0x04E0); cv(0x04E2, 0x04E3); cv(0x04E3, 0x04E2); cv(0x04E4, 0x04E5); cv(0x04E5, 0x04E4); cv(0x04E6, 0x04E7); cv(0x04E7, 0x04E6); cv(0x04E8, 0x04E9); cv(0x04E9, 0x04E8); cv(0x04EA, 0x04EB); cv(0x04EB, 0x04EA); cv(0x04EC, 0x04ED); cv(0x04ED, 0x04EC); cv(0x04EE, 0x04EF); cv(0x04EF, 0x04EE); cv(0x04F0, 0x04F1); cv(0x04F1, 0x04F0); cv(0x04F2, 0x04F3); cv(0x04F3, 0x04F2); cv(0x04F4, 0x04F5); cv(0x04F5, 0x04F4); cv(0x04F6, 0x04F7); cv(0x04F7, 0x04F6); cv(0x04F8, 0x04F9); cv(0x04F9, 0x04F8); cv(0x0500, 0x0501); cv(0x0501, 0x0500); cv(0x0502, 0x0503); cv(0x0503, 0x0502); cv(0x0504, 0x0505); cv(0x0505, 0x0504); cv(0x0506, 0x0507); cv(0x0507, 0x0506); cv(0x0508, 0x0509); cv(0x0509, 0x0508); cv(0x050A, 0x050B); cv(0x050B, 0x050A); cv(0x050C, 0x050D); cv(0x050D, 0x050C); cv(0x050E, 0x050F); cv(0x050F, 0x050E); cv(0x0531, 0x0561); cv(0x0532, 0x0562); cv(0x0533, 0x0563); cv(0x0534, 0x0564); cv(0x0535, 0x0565); cv(0x0536, 0x0566); cv(0x0537, 0x0567); cv(0x0538, 0x0568); cv(0x0539, 0x0569); cv(0x053A, 0x056A); cv(0x053B, 0x056B); cv(0x053C, 0x056C); cv(0x053D, 0x056D); cv(0x053E, 0x056E); cv(0x053F, 0x056F); cv(0x0540, 0x0570); cv(0x0541, 0x0571); cv(0x0542, 0x0572); cv(0x0543, 0x0573); cv(0x0544, 0x0574); cv(0x0545, 0x0575); cv(0x0546, 0x0576); cv(0x0547, 0x0577); cv(0x0548, 0x0578); cv(0x0549, 0x0579); cv(0x054A, 0x057A); cv(0x054B, 0x057B); cv(0x054C, 0x057C); cv(0x054D, 0x057D); cv(0x054E, 0x057E); cv(0x054F, 0x057F); cv(0x0550, 0x0580); cv(0x0551, 0x0581); cv(0x0552, 0x0582); cv(0x0553, 0x0583); cv(0x0554, 0x0584); cv(0x0555, 0x0585); cv(0x0556, 0x0586); cv(0x0561, 0x0531); cv(0x0562, 0x0532); cv(0x0563, 0x0533); cv(0x0564, 0x0534); cv(0x0565, 0x0535); cv(0x0566, 0x0536); cv(0x0567, 0x0537); cv(0x0568, 0x0538); cv(0x0569, 0x0539); cv(0x056A, 0x053A); cv(0x056B, 0x053B); cv(0x056C, 0x053C); cv(0x056D, 0x053D); cv(0x056E, 0x053E); cv(0x056F, 0x053F); cv(0x0570, 0x0540); cv(0x0571, 0x0541); cv(0x0572, 0x0542); cv(0x0573, 0x0543); cv(0x0574, 0x0544); cv(0x0575, 0x0545); cv(0x0576, 0x0546); cv(0x0577, 0x0547); cv(0x0578, 0x0548); cv(0x0579, 0x0549); cv(0x057A, 0x054A); cv(0x057B, 0x054B); cv(0x057C, 0x054C); cv(0x057D, 0x054D); cv(0x057E, 0x054E); cv(0x057F, 0x054F); cv(0x0580, 0x0550); cv(0x0581, 0x0551); cv(0x0582, 0x0552); cv(0x0583, 0x0553); cv(0x0584, 0x0554); cv(0x0585, 0x0555); cv(0x0586, 0x0556); cv(0x10A0, 0x2D00); cv(0x10A1, 0x2D01); cv(0x10A2, 0x2D02); cv(0x10A3, 0x2D03); cv(0x10A4, 0x2D04); cv(0x10A5, 0x2D05); cv(0x10A6, 0x2D06); cv(0x10A7, 0x2D07); cv(0x10A8, 0x2D08); cv(0x10A9, 0x2D09); cv(0x10AA, 0x2D0A); cv(0x10AB, 0x2D0B); cv(0x10AC, 0x2D0C); cv(0x10AD, 0x2D0D); cv(0x10AE, 0x2D0E); cv(0x10AF, 0x2D0F); cv(0x10B0, 0x2D10); cv(0x10B1, 0x2D11); cv(0x10B2, 0x2D12); cv(0x10B3, 0x2D13); cv(0x10B4, 0x2D14); cv(0x10B5, 0x2D15); cv(0x10B6, 0x2D16); cv(0x10B7, 0x2D17); cv(0x10B8, 0x2D18); cv(0x10B9, 0x2D19); cv(0x10BA, 0x2D1A); cv(0x10BB, 0x2D1B); cv(0x10BC, 0x2D1C); cv(0x10BD, 0x2D1D); cv(0x10BE, 0x2D1E); cv(0x10BF, 0x2D1F); cv(0x10C0, 0x2D20); cv(0x10C1, 0x2D21); cv(0x10C2, 0x2D22); cv(0x10C3, 0x2D23); cv(0x10C4, 0x2D24); cv(0x10C5, 0x2D25); cv(0x1E00, 0x1E01); cv(0x1E01, 0x1E00); cv(0x1E02, 0x1E03); cv(0x1E03, 0x1E02); cv(0x1E04, 0x1E05); cv(0x1E05, 0x1E04); cv(0x1E06, 0x1E07); cv(0x1E07, 0x1E06); cv(0x1E08, 0x1E09); cv(0x1E09, 0x1E08); cv(0x1E0A, 0x1E0B); cv(0x1E0B, 0x1E0A); cv(0x1E0C, 0x1E0D); cv(0x1E0D, 0x1E0C); cv(0x1E0E, 0x1E0F); cv(0x1E0F, 0x1E0E); cv(0x1E10, 0x1E11); cv(0x1E11, 0x1E10); cv(0x1E12, 0x1E13); cv(0x1E13, 0x1E12); cv(0x1E14, 0x1E15); cv(0x1E15, 0x1E14); cv(0x1E16, 0x1E17); cv(0x1E17, 0x1E16); cv(0x1E18, 0x1E19); cv(0x1E19, 0x1E18); cv(0x1E1A, 0x1E1B); cv(0x1E1B, 0x1E1A); cv(0x1E1C, 0x1E1D); cv(0x1E1D, 0x1E1C); cv(0x1E1E, 0x1E1F); cv(0x1E1F, 0x1E1E); cv(0x1E20, 0x1E21); cv(0x1E21, 0x1E20); cv(0x1E22, 0x1E23); cv(0x1E23, 0x1E22); cv(0x1E24, 0x1E25); cv(0x1E25, 0x1E24); cv(0x1E26, 0x1E27); cv(0x1E27, 0x1E26); cv(0x1E28, 0x1E29); cv(0x1E29, 0x1E28); cv(0x1E2A, 0x1E2B); cv(0x1E2B, 0x1E2A); cv(0x1E2C, 0x1E2D); cv(0x1E2D, 0x1E2C); cv(0x1E2E, 0x1E2F); cv(0x1E2F, 0x1E2E); cv(0x1E30, 0x1E31); cv(0x1E31, 0x1E30); cv(0x1E32, 0x1E33); cv(0x1E33, 0x1E32); cv(0x1E34, 0x1E35); cv(0x1E35, 0x1E34); cv(0x1E36, 0x1E37); cv(0x1E37, 0x1E36); cv(0x1E38, 0x1E39); cv(0x1E39, 0x1E38); cv(0x1E3A, 0x1E3B); cv(0x1E3B, 0x1E3A); cv(0x1E3C, 0x1E3D); cv(0x1E3D, 0x1E3C); cv(0x1E3E, 0x1E3F); cv(0x1E3F, 0x1E3E); cv(0x1E40, 0x1E41); cv(0x1E41, 0x1E40); cv(0x1E42, 0x1E43); cv(0x1E43, 0x1E42); cv(0x1E44, 0x1E45); cv(0x1E45, 0x1E44); cv(0x1E46, 0x1E47); cv(0x1E47, 0x1E46); cv(0x1E48, 0x1E49); cv(0x1E49, 0x1E48); cv(0x1E4A, 0x1E4B); cv(0x1E4B, 0x1E4A); cv(0x1E4C, 0x1E4D); cv(0x1E4D, 0x1E4C); cv(0x1E4E, 0x1E4F); cv(0x1E4F, 0x1E4E); cv(0x1E50, 0x1E51); cv(0x1E51, 0x1E50); cv(0x1E52, 0x1E53); cv(0x1E53, 0x1E52); cv(0x1E54, 0x1E55); cv(0x1E55, 0x1E54); cv(0x1E56, 0x1E57); cv(0x1E57, 0x1E56); cv(0x1E58, 0x1E59); cv(0x1E59, 0x1E58); cv(0x1E5A, 0x1E5B); cv(0x1E5B, 0x1E5A); cv(0x1E5C, 0x1E5D); cv(0x1E5D, 0x1E5C); cv(0x1E5E, 0x1E5F); cv(0x1E5F, 0x1E5E); cv(0x1E60, 0x1E61, 0x1E9B); cv(0x1E61, 0x1E60, 0x1E9B); cv(0x1E62, 0x1E63); cv(0x1E63, 0x1E62); cv(0x1E64, 0x1E65); cv(0x1E65, 0x1E64); cv(0x1E66, 0x1E67); cv(0x1E67, 0x1E66); cv(0x1E68, 0x1E69); cv(0x1E69, 0x1E68); cv(0x1E6A, 0x1E6B); cv(0x1E6B, 0x1E6A); cv(0x1E6C, 0x1E6D); cv(0x1E6D, 0x1E6C); cv(0x1E6E, 0x1E6F); cv(0x1E6F, 0x1E6E); cv(0x1E70, 0x1E71); cv(0x1E71, 0x1E70); cv(0x1E72, 0x1E73); cv(0x1E73, 0x1E72); cv(0x1E74, 0x1E75); cv(0x1E75, 0x1E74); cv(0x1E76, 0x1E77); cv(0x1E77, 0x1E76); cv(0x1E78, 0x1E79); cv(0x1E79, 0x1E78); cv(0x1E7A, 0x1E7B); cv(0x1E7B, 0x1E7A); cv(0x1E7C, 0x1E7D); cv(0x1E7D, 0x1E7C); cv(0x1E7E, 0x1E7F); cv(0x1E7F, 0x1E7E); cv(0x1E80, 0x1E81); cv(0x1E81, 0x1E80); cv(0x1E82, 0x1E83); cv(0x1E83, 0x1E82); cv(0x1E84, 0x1E85); cv(0x1E85, 0x1E84); cv(0x1E86, 0x1E87); cv(0x1E87, 0x1E86); cv(0x1E88, 0x1E89); cv(0x1E89, 0x1E88); cv(0x1E8A, 0x1E8B); cv(0x1E8B, 0x1E8A); cv(0x1E8C, 0x1E8D); cv(0x1E8D, 0x1E8C); cv(0x1E8E, 0x1E8F); cv(0x1E8F, 0x1E8E); cv(0x1E90, 0x1E91); cv(0x1E91, 0x1E90); cv(0x1E92, 0x1E93); cv(0x1E93, 0x1E92); cv(0x1E94, 0x1E95); cv(0x1E95, 0x1E94); cv(0x1E9B, 0x1E60, 0x1E61); cv(0x1EA0, 0x1EA1); cv(0x1EA1, 0x1EA0); cv(0x1EA2, 0x1EA3); cv(0x1EA3, 0x1EA2); cv(0x1EA4, 0x1EA5); cv(0x1EA5, 0x1EA4); cv(0x1EA6, 0x1EA7); cv(0x1EA7, 0x1EA6); cv(0x1EA8, 0x1EA9); cv(0x1EA9, 0x1EA8); cv(0x1EAA, 0x1EAB); cv(0x1EAB, 0x1EAA); cv(0x1EAC, 0x1EAD); cv(0x1EAD, 0x1EAC); cv(0x1EAE, 0x1EAF); cv(0x1EAF, 0x1EAE); cv(0x1EB0, 0x1EB1); cv(0x1EB1, 0x1EB0); cv(0x1EB2, 0x1EB3); cv(0x1EB3, 0x1EB2); cv(0x1EB4, 0x1EB5); cv(0x1EB5, 0x1EB4); cv(0x1EB6, 0x1EB7); cv(0x1EB7, 0x1EB6); cv(0x1EB8, 0x1EB9); cv(0x1EB9, 0x1EB8); cv(0x1EBA, 0x1EBB); cv(0x1EBB, 0x1EBA); cv(0x1EBC, 0x1EBD); cv(0x1EBD, 0x1EBC); cv(0x1EBE, 0x1EBF); cv(0x1EBF, 0x1EBE); cv(0x1EC0, 0x1EC1); cv(0x1EC1, 0x1EC0); cv(0x1EC2, 0x1EC3); cv(0x1EC3, 0x1EC2); cv(0x1EC4, 0x1EC5); cv(0x1EC5, 0x1EC4); cv(0x1EC6, 0x1EC7); cv(0x1EC7, 0x1EC6); cv(0x1EC8, 0x1EC9); cv(0x1EC9, 0x1EC8); cv(0x1ECA, 0x1ECB); cv(0x1ECB, 0x1ECA); cv(0x1ECC, 0x1ECD); cv(0x1ECD, 0x1ECC); cv(0x1ECE, 0x1ECF); cv(0x1ECF, 0x1ECE); cv(0x1ED0, 0x1ED1); cv(0x1ED1, 0x1ED0); cv(0x1ED2, 0x1ED3); cv(0x1ED3, 0x1ED2); cv(0x1ED4, 0x1ED5); cv(0x1ED5, 0x1ED4); cv(0x1ED6, 0x1ED7); cv(0x1ED7, 0x1ED6); cv(0x1ED8, 0x1ED9); cv(0x1ED9, 0x1ED8); cv(0x1EDA, 0x1EDB); cv(0x1EDB, 0x1EDA); cv(0x1EDC, 0x1EDD); cv(0x1EDD, 0x1EDC); cv(0x1EDE, 0x1EDF); cv(0x1EDF, 0x1EDE); cv(0x1EE0, 0x1EE1); cv(0x1EE1, 0x1EE0); cv(0x1EE2, 0x1EE3); cv(0x1EE3, 0x1EE2); cv(0x1EE4, 0x1EE5); cv(0x1EE5, 0x1EE4); cv(0x1EE6, 0x1EE7); cv(0x1EE7, 0x1EE6); cv(0x1EE8, 0x1EE9); cv(0x1EE9, 0x1EE8); cv(0x1EEA, 0x1EEB); cv(0x1EEB, 0x1EEA); cv(0x1EEC, 0x1EED); cv(0x1EED, 0x1EEC); cv(0x1EEE, 0x1EEF); cv(0x1EEF, 0x1EEE); cv(0x1EF0, 0x1EF1); cv(0x1EF1, 0x1EF0); cv(0x1EF2, 0x1EF3); cv(0x1EF3, 0x1EF2); cv(0x1EF4, 0x1EF5); cv(0x1EF5, 0x1EF4); cv(0x1EF6, 0x1EF7); cv(0x1EF7, 0x1EF6); cv(0x1EF8, 0x1EF9); cv(0x1EF9, 0x1EF8); cv(0x1F00, 0x1F08); cv(0x1F01, 0x1F09); cv(0x1F02, 0x1F0A); cv(0x1F03, 0x1F0B); cv(0x1F04, 0x1F0C); cv(0x1F05, 0x1F0D); cv(0x1F06, 0x1F0E); cv(0x1F07, 0x1F0F); cv(0x1F08, 0x1F00); cv(0x1F09, 0x1F01); cv(0x1F0A, 0x1F02); cv(0x1F0B, 0x1F03); cv(0x1F0C, 0x1F04); cv(0x1F0D, 0x1F05); cv(0x1F0E, 0x1F06); cv(0x1F0F, 0x1F07); cv(0x1F10, 0x1F18); cv(0x1F11, 0x1F19); cv(0x1F12, 0x1F1A); cv(0x1F13, 0x1F1B); cv(0x1F14, 0x1F1C); cv(0x1F15, 0x1F1D); cv(0x1F18, 0x1F10); cv(0x1F19, 0x1F11); cv(0x1F1A, 0x1F12); cv(0x1F1B, 0x1F13); cv(0x1F1C, 0x1F14); cv(0x1F1D, 0x1F15); cv(0x1F20, 0x1F28); cv(0x1F21, 0x1F29); cv(0x1F22, 0x1F2A); cv(0x1F23, 0x1F2B); cv(0x1F24, 0x1F2C); cv(0x1F25, 0x1F2D); cv(0x1F26, 0x1F2E); cv(0x1F27, 0x1F2F); cv(0x1F28, 0x1F20); cv(0x1F29, 0x1F21); cv(0x1F2A, 0x1F22); cv(0x1F2B, 0x1F23); cv(0x1F2C, 0x1F24); cv(0x1F2D, 0x1F25); cv(0x1F2E, 0x1F26); cv(0x1F2F, 0x1F27); cv(0x1F30, 0x1F38); cv(0x1F31, 0x1F39); cv(0x1F32, 0x1F3A); cv(0x1F33, 0x1F3B); cv(0x1F34, 0x1F3C); cv(0x1F35, 0x1F3D); cv(0x1F36, 0x1F3E); cv(0x1F37, 0x1F3F); cv(0x1F38, 0x1F30); cv(0x1F39, 0x1F31); cv(0x1F3A, 0x1F32); cv(0x1F3B, 0x1F33); cv(0x1F3C, 0x1F34); cv(0x1F3D, 0x1F35); cv(0x1F3E, 0x1F36); cv(0x1F3F, 0x1F37); cv(0x1F40, 0x1F48); cv(0x1F41, 0x1F49); cv(0x1F42, 0x1F4A); cv(0x1F43, 0x1F4B); cv(0x1F44, 0x1F4C); cv(0x1F45, 0x1F4D); cv(0x1F48, 0x1F40); cv(0x1F49, 0x1F41); cv(0x1F4A, 0x1F42); cv(0x1F4B, 0x1F43); cv(0x1F4C, 0x1F44); cv(0x1F4D, 0x1F45); cv(0x1F51, 0x1F59); cv(0x1F53, 0x1F5B); cv(0x1F55, 0x1F5D); cv(0x1F57, 0x1F5F); cv(0x1F59, 0x1F51); cv(0x1F5B, 0x1F53); cv(0x1F5D, 0x1F55); cv(0x1F5F, 0x1F57); cv(0x1F60, 0x1F68); cv(0x1F61, 0x1F69); cv(0x1F62, 0x1F6A); cv(0x1F63, 0x1F6B); cv(0x1F64, 0x1F6C); cv(0x1F65, 0x1F6D); cv(0x1F66, 0x1F6E); cv(0x1F67, 0x1F6F); cv(0x1F68, 0x1F60); cv(0x1F69, 0x1F61); cv(0x1F6A, 0x1F62); cv(0x1F6B, 0x1F63); cv(0x1F6C, 0x1F64); cv(0x1F6D, 0x1F65); cv(0x1F6E, 0x1F66); cv(0x1F6F, 0x1F67); cv(0x1F70, 0x1FBA); cv(0x1F71, 0x1FBB); cv(0x1F72, 0x1FC8); cv(0x1F73, 0x1FC9); cv(0x1F74, 0x1FCA); cv(0x1F75, 0x1FCB); cv(0x1F76, 0x1FDA); cv(0x1F77, 0x1FDB); cv(0x1F78, 0x1FF8); cv(0x1F79, 0x1FF9); cv(0x1F7A, 0x1FEA); cv(0x1F7B, 0x1FEB); cv(0x1F7C, 0x1FFA); cv(0x1F7D, 0x1FFB); cv(0x1F80, 0x1F88); cv(0x1F81, 0x1F89); cv(0x1F82, 0x1F8A); cv(0x1F83, 0x1F8B); cv(0x1F84, 0x1F8C); cv(0x1F85, 0x1F8D); cv(0x1F86, 0x1F8E); cv(0x1F87, 0x1F8F); cv(0x1F88, 0x1F80); cv(0x1F89, 0x1F81); cv(0x1F8A, 0x1F82); cv(0x1F8B, 0x1F83); cv(0x1F8C, 0x1F84); cv(0x1F8D, 0x1F85); cv(0x1F8E, 0x1F86); cv(0x1F8F, 0x1F87); cv(0x1F90, 0x1F98); cv(0x1F91, 0x1F99); cv(0x1F92, 0x1F9A); cv(0x1F93, 0x1F9B); cv(0x1F94, 0x1F9C); cv(0x1F95, 0x1F9D); cv(0x1F96, 0x1F9E); cv(0x1F97, 0x1F9F); cv(0x1F98, 0x1F90); cv(0x1F99, 0x1F91); cv(0x1F9A, 0x1F92); cv(0x1F9B, 0x1F93); cv(0x1F9C, 0x1F94); cv(0x1F9D, 0x1F95); cv(0x1F9E, 0x1F96); cv(0x1F9F, 0x1F97); cv(0x1FA0, 0x1FA8); cv(0x1FA1, 0x1FA9); cv(0x1FA2, 0x1FAA); cv(0x1FA3, 0x1FAB); cv(0x1FA4, 0x1FAC); cv(0x1FA5, 0x1FAD); cv(0x1FA6, 0x1FAE); cv(0x1FA7, 0x1FAF); cv(0x1FA8, 0x1FA0); cv(0x1FA9, 0x1FA1); cv(0x1FAA, 0x1FA2); cv(0x1FAB, 0x1FA3); cv(0x1FAC, 0x1FA4); cv(0x1FAD, 0x1FA5); cv(0x1FAE, 0x1FA6); cv(0x1FAF, 0x1FA7); cv(0x1FB0, 0x1FB8); cv(0x1FB1, 0x1FB9); cv(0x1FB3, 0x1FBC); cv(0x1FB8, 0x1FB0); cv(0x1FB9, 0x1FB1); cv(0x1FBA, 0x1F70); cv(0x1FBB, 0x1F71); cv(0x1FBC, 0x1FB3); cv(0x1FBE, 0x0345, 0x0399, 0x03B9); cv(0x1FC3, 0x1FCC); cv(0x1FC8, 0x1F72); cv(0x1FC9, 0x1F73); cv(0x1FCA, 0x1F74); cv(0x1FCB, 0x1F75); cv(0x1FCC, 0x1FC3); cv(0x1FD0, 0x1FD8); cv(0x1FD1, 0x1FD9); cv(0x1FD8, 0x1FD0); cv(0x1FD9, 0x1FD1); cv(0x1FDA, 0x1F76); cv(0x1FDB, 0x1F77); cv(0x1FE0, 0x1FE8); cv(0x1FE1, 0x1FE9); cv(0x1FE5, 0x1FEC); cv(0x1FE8, 0x1FE0); cv(0x1FE9, 0x1FE1); cv(0x1FEA, 0x1F7A); cv(0x1FEB, 0x1F7B); cv(0x1FEC, 0x1FE5); cv(0x1FF3, 0x1FFC); cv(0x1FF8, 0x1F78); cv(0x1FF9, 0x1F79); cv(0x1FFA, 0x1F7C); cv(0x1FFB, 0x1F7D); cv(0x1FFC, 0x1FF3); cv(0x2126, 0x03A9, 0x03C9); cv(0x212A, 0x004B, 0x006B); cv(0x212B, 0x00C5, 0x00E5); cv(0x2160, 0x2170); cv(0x2161, 0x2171); cv(0x2162, 0x2172); cv(0x2163, 0x2173); cv(0x2164, 0x2174); cv(0x2165, 0x2175); cv(0x2166, 0x2176); cv(0x2167, 0x2177); cv(0x2168, 0x2178); cv(0x2169, 0x2179); cv(0x216A, 0x217A); cv(0x216B, 0x217B); cv(0x216C, 0x217C); cv(0x216D, 0x217D); cv(0x216E, 0x217E); cv(0x216F, 0x217F); cv(0x2170, 0x2160); cv(0x2171, 0x2161); cv(0x2172, 0x2162); cv(0x2173, 0x2163); cv(0x2174, 0x2164); cv(0x2175, 0x2165); cv(0x2176, 0x2166); cv(0x2177, 0x2167); cv(0x2178, 0x2168); cv(0x2179, 0x2169); cv(0x217A, 0x216A); cv(0x217B, 0x216B); cv(0x217C, 0x216C); cv(0x217D, 0x216D); cv(0x217E, 0x216E); cv(0x217F, 0x216F); cv(0x24B6, 0x24D0); cv(0x24B7, 0x24D1); cv(0x24B8, 0x24D2); cv(0x24B9, 0x24D3); cv(0x24BA, 0x24D4); cv(0x24BB, 0x24D5); cv(0x24BC, 0x24D6); cv(0x24BD, 0x24D7); cv(0x24BE, 0x24D8); cv(0x24BF, 0x24D9); cv(0x24C0, 0x24DA); cv(0x24C1, 0x24DB); cv(0x24C2, 0x24DC); cv(0x24C3, 0x24DD); cv(0x24C4, 0x24DE); cv(0x24C5, 0x24DF); cv(0x24C6, 0x24E0); cv(0x24C7, 0x24E1); cv(0x24C8, 0x24E2); cv(0x24C9, 0x24E3); cv(0x24CA, 0x24E4); cv(0x24CB, 0x24E5); cv(0x24CC, 0x24E6); cv(0x24CD, 0x24E7); cv(0x24CE, 0x24E8); cv(0x24CF, 0x24E9); cv(0x24D0, 0x24B6); cv(0x24D1, 0x24B7); cv(0x24D2, 0x24B8); cv(0x24D3, 0x24B9); cv(0x24D4, 0x24BA); cv(0x24D5, 0x24BB); cv(0x24D6, 0x24BC); cv(0x24D7, 0x24BD); cv(0x24D8, 0x24BE); cv(0x24D9, 0x24BF); cv(0x24DA, 0x24C0); cv(0x24DB, 0x24C1); cv(0x24DC, 0x24C2); cv(0x24DD, 0x24C3); cv(0x24DE, 0x24C4); cv(0x24DF, 0x24C5); cv(0x24E0, 0x24C6); cv(0x24E1, 0x24C7); cv(0x24E2, 0x24C8); cv(0x24E3, 0x24C9); cv(0x24E4, 0x24CA); cv(0x24E5, 0x24CB); cv(0x24E6, 0x24CC); cv(0x24E7, 0x24CD); cv(0x24E8, 0x24CE); cv(0x24E9, 0x24CF); cv(0x2C00, 0x2C30); cv(0x2C01, 0x2C31); cv(0x2C02, 0x2C32); cv(0x2C03, 0x2C33); cv(0x2C04, 0x2C34); cv(0x2C05, 0x2C35); cv(0x2C06, 0x2C36); cv(0x2C07, 0x2C37); cv(0x2C08, 0x2C38); cv(0x2C09, 0x2C39); cv(0x2C0A, 0x2C3A); cv(0x2C0B, 0x2C3B); cv(0x2C0C, 0x2C3C); cv(0x2C0D, 0x2C3D); cv(0x2C0E, 0x2C3E); cv(0x2C0F, 0x2C3F); cv(0x2C10, 0x2C40); cv(0x2C11, 0x2C41); cv(0x2C12, 0x2C42); cv(0x2C13, 0x2C43); cv(0x2C14, 0x2C44); cv(0x2C15, 0x2C45); cv(0x2C16, 0x2C46); cv(0x2C17, 0x2C47); cv(0x2C18, 0x2C48); cv(0x2C19, 0x2C49); cv(0x2C1A, 0x2C4A); cv(0x2C1B, 0x2C4B); cv(0x2C1C, 0x2C4C); cv(0x2C1D, 0x2C4D); cv(0x2C1E, 0x2C4E); cv(0x2C1F, 0x2C4F); cv(0x2C20, 0x2C50); cv(0x2C21, 0x2C51); cv(0x2C22, 0x2C52); cv(0x2C23, 0x2C53); cv(0x2C24, 0x2C54); cv(0x2C25, 0x2C55); cv(0x2C26, 0x2C56); cv(0x2C27, 0x2C57); cv(0x2C28, 0x2C58); cv(0x2C29, 0x2C59); cv(0x2C2A, 0x2C5A); cv(0x2C2B, 0x2C5B); cv(0x2C2C, 0x2C5C); cv(0x2C2D, 0x2C5D); cv(0x2C2E, 0x2C5E); cv(0x2C30, 0x2C00); cv(0x2C31, 0x2C01); cv(0x2C32, 0x2C02); cv(0x2C33, 0x2C03); cv(0x2C34, 0x2C04); cv(0x2C35, 0x2C05); cv(0x2C36, 0x2C06); cv(0x2C37, 0x2C07); cv(0x2C38, 0x2C08); cv(0x2C39, 0x2C09); cv(0x2C3A, 0x2C0A); cv(0x2C3B, 0x2C0B); cv(0x2C3C, 0x2C0C); cv(0x2C3D, 0x2C0D); cv(0x2C3E, 0x2C0E); cv(0x2C3F, 0x2C0F); cv(0x2C40, 0x2C10); cv(0x2C41, 0x2C11); cv(0x2C42, 0x2C12); cv(0x2C43, 0x2C13); cv(0x2C44, 0x2C14); cv(0x2C45, 0x2C15); cv(0x2C46, 0x2C16); cv(0x2C47, 0x2C17); cv(0x2C48, 0x2C18); cv(0x2C49, 0x2C19); cv(0x2C4A, 0x2C1A); cv(0x2C4B, 0x2C1B); cv(0x2C4C, 0x2C1C); cv(0x2C4D, 0x2C1D); cv(0x2C4E, 0x2C1E); cv(0x2C4F, 0x2C1F); cv(0x2C50, 0x2C20); cv(0x2C51, 0x2C21); cv(0x2C52, 0x2C22); cv(0x2C53, 0x2C23); cv(0x2C54, 0x2C24); cv(0x2C55, 0x2C25); cv(0x2C56, 0x2C26); cv(0x2C57, 0x2C27); cv(0x2C58, 0x2C28); cv(0x2C59, 0x2C29); cv(0x2C5A, 0x2C2A); cv(0x2C5B, 0x2C2B); cv(0x2C5C, 0x2C2C); cv(0x2C5D, 0x2C2D); cv(0x2C5E, 0x2C2E); cv(0x2C80, 0x2C81); cv(0x2C81, 0x2C80); cv(0x2C82, 0x2C83); cv(0x2C83, 0x2C82); cv(0x2C84, 0x2C85); cv(0x2C85, 0x2C84); cv(0x2C86, 0x2C87); cv(0x2C87, 0x2C86); cv(0x2C88, 0x2C89); cv(0x2C89, 0x2C88); cv(0x2C8A, 0x2C8B); cv(0x2C8B, 0x2C8A); cv(0x2C8C, 0x2C8D); cv(0x2C8D, 0x2C8C); cv(0x2C8E, 0x2C8F); cv(0x2C8F, 0x2C8E); cv(0x2C90, 0x2C91); cv(0x2C91, 0x2C90); cv(0x2C92, 0x2C93); cv(0x2C93, 0x2C92); cv(0x2C94, 0x2C95); cv(0x2C95, 0x2C94); cv(0x2C96, 0x2C97); cv(0x2C97, 0x2C96); cv(0x2C98, 0x2C99); cv(0x2C99, 0x2C98); cv(0x2C9A, 0x2C9B); cv(0x2C9B, 0x2C9A); cv(0x2C9C, 0x2C9D); cv(0x2C9D, 0x2C9C); cv(0x2C9E, 0x2C9F); cv(0x2C9F, 0x2C9E); cv(0x2CA0, 0x2CA1); cv(0x2CA1, 0x2CA0); cv(0x2CA2, 0x2CA3); cv(0x2CA3, 0x2CA2); cv(0x2CA4, 0x2CA5); cv(0x2CA5, 0x2CA4); cv(0x2CA6, 0x2CA7); cv(0x2CA7, 0x2CA6); cv(0x2CA8, 0x2CA9); cv(0x2CA9, 0x2CA8); cv(0x2CAA, 0x2CAB); cv(0x2CAB, 0x2CAA); cv(0x2CAC, 0x2CAD); cv(0x2CAD, 0x2CAC); cv(0x2CAE, 0x2CAF); cv(0x2CAF, 0x2CAE); cv(0x2CB0, 0x2CB1); cv(0x2CB1, 0x2CB0); cv(0x2CB2, 0x2CB3); cv(0x2CB3, 0x2CB2); cv(0x2CB4, 0x2CB5); cv(0x2CB5, 0x2CB4); cv(0x2CB6, 0x2CB7); cv(0x2CB7, 0x2CB6); cv(0x2CB8, 0x2CB9); cv(0x2CB9, 0x2CB8); cv(0x2CBA, 0x2CBB); cv(0x2CBB, 0x2CBA); cv(0x2CBC, 0x2CBD); cv(0x2CBD, 0x2CBC); cv(0x2CBE, 0x2CBF); cv(0x2CBF, 0x2CBE); cv(0x2CC0, 0x2CC1); cv(0x2CC1, 0x2CC0); cv(0x2CC2, 0x2CC3); cv(0x2CC3, 0x2CC2); cv(0x2CC4, 0x2CC5); cv(0x2CC5, 0x2CC4); cv(0x2CC6, 0x2CC7); cv(0x2CC7, 0x2CC6); cv(0x2CC8, 0x2CC9); cv(0x2CC9, 0x2CC8); cv(0x2CCA, 0x2CCB); cv(0x2CCB, 0x2CCA); cv(0x2CCC, 0x2CCD); cv(0x2CCD, 0x2CCC); cv(0x2CCE, 0x2CCF); cv(0x2CCF, 0x2CCE); cv(0x2CD0, 0x2CD1); cv(0x2CD1, 0x2CD0); cv(0x2CD2, 0x2CD3); cv(0x2CD3, 0x2CD2); cv(0x2CD4, 0x2CD5); cv(0x2CD5, 0x2CD4); cv(0x2CD6, 0x2CD7); cv(0x2CD7, 0x2CD6); cv(0x2CD8, 0x2CD9); cv(0x2CD9, 0x2CD8); cv(0x2CDA, 0x2CDB); cv(0x2CDB, 0x2CDA); cv(0x2CDC, 0x2CDD); cv(0x2CDD, 0x2CDC); cv(0x2CDE, 0x2CDF); cv(0x2CDF, 0x2CDE); cv(0x2CE0, 0x2CE1); cv(0x2CE1, 0x2CE0); cv(0x2CE2, 0x2CE3); cv(0x2CE3, 0x2CE2); cv(0x2D00, 0x10A0); cv(0x2D01, 0x10A1); cv(0x2D02, 0x10A2); cv(0x2D03, 0x10A3); cv(0x2D04, 0x10A4); cv(0x2D05, 0x10A5); cv(0x2D06, 0x10A6); cv(0x2D07, 0x10A7); cv(0x2D08, 0x10A8); cv(0x2D09, 0x10A9); cv(0x2D0A, 0x10AA); cv(0x2D0B, 0x10AB); cv(0x2D0C, 0x10AC); cv(0x2D0D, 0x10AD); cv(0x2D0E, 0x10AE); cv(0x2D0F, 0x10AF); cv(0x2D10, 0x10B0); cv(0x2D11, 0x10B1); cv(0x2D12, 0x10B2); cv(0x2D13, 0x10B3); cv(0x2D14, 0x10B4); cv(0x2D15, 0x10B5); cv(0x2D16, 0x10B6); cv(0x2D17, 0x10B7); cv(0x2D18, 0x10B8); cv(0x2D19, 0x10B9); cv(0x2D1A, 0x10BA); cv(0x2D1B, 0x10BB); cv(0x2D1C, 0x10BC); cv(0x2D1D, 0x10BD); cv(0x2D1E, 0x10BE); cv(0x2D1F, 0x10BF); cv(0x2D20, 0x10C0); cv(0x2D21, 0x10C1); cv(0x2D22, 0x10C2); cv(0x2D23, 0x10C3); cv(0x2D24, 0x10C4); cv(0x2D25, 0x10C5); cv(0xFF21, 0xFF41); cv(0xFF22, 0xFF42); cv(0xFF23, 0xFF43); cv(0xFF24, 0xFF44); cv(0xFF25, 0xFF45); cv(0xFF26, 0xFF46); cv(0xFF27, 0xFF47); cv(0xFF28, 0xFF48); cv(0xFF29, 0xFF49); cv(0xFF2A, 0xFF4A); cv(0xFF2B, 0xFF4B); cv(0xFF2C, 0xFF4C); cv(0xFF2D, 0xFF4D); cv(0xFF2E, 0xFF4E); cv(0xFF2F, 0xFF4F); cv(0xFF30, 0xFF50); cv(0xFF31, 0xFF51); cv(0xFF32, 0xFF52); cv(0xFF33, 0xFF53); cv(0xFF34, 0xFF54); cv(0xFF35, 0xFF55); cv(0xFF36, 0xFF56); cv(0xFF37, 0xFF57); cv(0xFF38, 0xFF58); cv(0xFF39, 0xFF59); cv(0xFF3A, 0xFF5A); cv(0xFF41, 0xFF21); cv(0xFF42, 0xFF22); cv(0xFF43, 0xFF23); cv(0xFF44, 0xFF24); cv(0xFF45, 0xFF25); cv(0xFF46, 0xFF26); cv(0xFF47, 0xFF27); cv(0xFF48, 0xFF28); cv(0xFF49, 0xFF29); cv(0xFF4A, 0xFF2A); cv(0xFF4B, 0xFF2B); cv(0xFF4C, 0xFF2C); cv(0xFF4D, 0xFF2D); cv(0xFF4E, 0xFF2E); cv(0xFF4F, 0xFF2F); cv(0xFF50, 0xFF30); cv(0xFF51, 0xFF31); cv(0xFF52, 0xFF32); cv(0xFF53, 0xFF33); cv(0xFF54, 0xFF34); cv(0xFF55, 0xFF35); cv(0xFF56, 0xFF36); cv(0xFF57, 0xFF37); cv(0xFF58, 0xFF38); cv(0xFF59, 0xFF39); cv(0xFF5A, 0xFF3A); cv(0x10400, 0x10428); cv(0x10401, 0x10429); cv(0x10402, 0x1042A); cv(0x10403, 0x1042B); cv(0x10404, 0x1042C); cv(0x10405, 0x1042D); cv(0x10406, 0x1042E); cv(0x10407, 0x1042F); cv(0x10408, 0x10430); cv(0x10409, 0x10431); cv(0x1040A, 0x10432); cv(0x1040B, 0x10433); cv(0x1040C, 0x10434); cv(0x1040D, 0x10435); cv(0x1040E, 0x10436); cv(0x1040F, 0x10437); cv(0x10410, 0x10438); cv(0x10411, 0x10439); cv(0x10412, 0x1043A); cv(0x10413, 0x1043B); cv(0x10414, 0x1043C); cv(0x10415, 0x1043D); cv(0x10416, 0x1043E); cv(0x10417, 0x1043F); cv(0x10418, 0x10440); cv(0x10419, 0x10441); cv(0x1041A, 0x10442); cv(0x1041B, 0x10443); cv(0x1041C, 0x10444); cv(0x1041D, 0x10445); cv(0x1041E, 0x10446); cv(0x1041F, 0x10447); cv(0x10420, 0x10448); cv(0x10421, 0x10449); cv(0x10422, 0x1044A); cv(0x10423, 0x1044B); cv(0x10424, 0x1044C); cv(0x10425, 0x1044D); cv(0x10426, 0x1044E); cv(0x10427, 0x1044F); cv(0x10428, 0x10400); cv(0x10429, 0x10401); cv(0x1042A, 0x10402); cv(0x1042B, 0x10403); cv(0x1042C, 0x10404); cv(0x1042D, 0x10405); cv(0x1042E, 0x10406); cv(0x1042F, 0x10407); cv(0x10430, 0x10408); cv(0x10431, 0x10409); cv(0x10432, 0x1040A); cv(0x10433, 0x1040B); cv(0x10434, 0x1040C); cv(0x10435, 0x1040D); cv(0x10436, 0x1040E); cv(0x10437, 0x1040F); cv(0x10438, 0x10410); cv(0x10439, 0x10411); cv(0x1043A, 0x10412); cv(0x1043B, 0x10413); cv(0x1043C, 0x10414); cv(0x1043D, 0x10415); cv(0x1043E, 0x10416); cv(0x1043F, 0x10417); cv(0x10440, 0x10418); cv(0x10441, 0x10419); cv(0x10442, 0x1041A); cv(0x10443, 0x1041B); cv(0x10444, 0x1041C); cv(0x10445, 0x1041D); cv(0x10446, 0x1041E); cv(0x10447, 0x1041F); cv(0x10448, 0x10420); cv(0x10449, 0x10421); cv(0x1044A, 0x10422); cv(0x1044B, 0x10423); cv(0x1044C, 0x10424); cv(0x1044D, 0x10425); cv(0x1044E, 0x10426); cv(0x1044F, 0x10427); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/regex/SurrogateRegexTranslator.java0000644000175000017500000004566311033112257024412 0ustar eugeneeugenepackage net.sf.saxon.regex; import net.sf.saxon.om.FastStringBuffer; import net.sf.saxon.charcode.UTF16; import java.util.List; import java.util.ArrayList; /** * Abstract superclass for the JDK 1.4 and .NET regex translators, or in principle for any other * target regex dialect in which "." matches a UTF-16 16-bit code rather than a Unicode character */ public abstract class SurrogateRegexTranslator extends RegexTranslator { // TODO: could go further in terms of achieving reuse of common code between the two subclasses. // The main thing needed is a factory method for the classes that differ, e.g. Union and Subtraction, // which in turn means that static data using these classes needs to be dynamically initialized. protected static final CharClass[] categoryCharClasses = new CharClass[RegexData.categories.length()]; protected static final CharClass[] subCategoryCharClasses = new CharClass[RegexData.subCategories.length() / 2]; /** * Object representing a character class */ protected static abstract class CharClass { private final int containsBmp; // if it contains ALL and containsBmp != NONE, then the generated class for containsBmp must // contain all the high surrogates private final int containsNonBmp; /** * Create a character class * @param containsBmp NONE, SOME, or ALL, depending on whether the character class contains all * the BMP characters, some of the BMP characters, or none of the BMP characters * @param containsNonBmp NONE, SOME, or ALL, depending on whether the character class contains all * the non-BMP characters, some of the non-BMP characters, or none of the non-BMP characters */ protected CharClass(int containsBmp, int containsNonBmp) { this.containsBmp = containsBmp; this.containsNonBmp = containsNonBmp; } /** * Determine whether this character class contains NONE, SOME, or ALL of the BMP characters * @return NONE, SOME, or ALL */ public int getContainsBmp() { return containsBmp; } /** * Determine whether this character class contains NONE, SOME, or ALL of the non-BMP characters * @return NONE, SOME, or ALL */ public int getContainsNonBmp() { return containsNonBmp; } /** * Output a representation of this character class to the supplied buffer * @param buf the supplied buffer */ public final void output(FastStringBuffer buf) { switch (containsNonBmp) { case NONE: if (containsBmp == NONE) { buf.append(NOT_ALLOWED_CLASS); } else { outputBmp(buf); } break; case ALL: buf.append("(?:"); if (containsBmp == NONE) { buf.append(SURROGATES1_CLASS); buf.append(SURROGATES2_CLASS); } else { outputBmp(buf); buf.append(SURROGATES2_CLASS); buf.append('?'); } buf.append(')'); break; case SOME: buf.append("(?:"); boolean needSep = false; if (containsBmp != NONE) { needSep = true; outputBmp(buf); } List ranges = new ArrayList(10); addNonBmpRanges(ranges); sortRangeList(ranges); String hi = highSurrogateRanges(ranges); if (hi.length() > 0) { if (needSep) { buf.append('|'); } else { needSep = true; } buf.append('['); for (int i = 0, len = hi.length(); i < len; i += 2) { char min = hi.charAt(i); char max = hi.charAt(i + 1); if (min == max) { buf.append(min); } else { buf.append(min); buf.append('-'); buf.append(max); } } buf.append(']'); buf.append(SURROGATES2_CLASS); } String lo = lowSurrogateRanges(ranges); for (int i = 0, len = lo.length(); i < len; i += 3) { if (needSep) { buf.append('|'); } else { needSep = true; } buf.append(lo.charAt(i)); char min = lo.charAt(i + 1); char max = lo.charAt(i + 2); if (min == max && (i + 3 >= len || lo.charAt(i + 3) != lo.charAt(i))) { buf.append(min); } else { buf.append('['); for (; ;) { if (min == max) { buf.append(min); } else { buf.append(min); buf.append('-'); buf.append(max); } if (i + 3 >= len || lo.charAt(i + 3) != lo.charAt(i)) { break; } i += 3; min = lo.charAt(i + 1); max = lo.charAt(i + 2); } buf.append(']'); } } if (!needSep) { buf.append(NOT_ALLOWED_CLASS); } buf.append(')'); break; } } /** * Output a representation of the subset of this character class that's within the BMP, to * a supplied buffer * @param buf the supplied buffer */ public abstract void outputBmp(FastStringBuffer buf); /** * Output a representation of the complement of the subset of this character class that's within the BMP, to * a supplied buffer * @param buf the supplied buffer */ public abstract void outputComplementBmp(FastStringBuffer buf); /** * If this character class contains a single character, get that character * @return the single character matched by this character class, or -1 if it matches multiple characters */ public int getSingleChar() { return -1; } /** * Add to a supplied List, ranges of non-BMP characters that are matched by this character class. * Default implementation does nothing. * @param ranges a List to which this method will add zero or more Range objects denoting ranges * of non-BMP characters */ public void addNonBmpRanges(List ranges) { } } /** * Simple Character Class - essentially, anything other than a Union or Subtraction between two * character classes. */ public static abstract class SimpleCharClass extends CharClass { /** * Create a SimpleCharClass * @param containsBmp true if the class includes BMP characters * @param containsNonBmp true if the class includes non-BMP characters */ public SimpleCharClass(int containsBmp, int containsNonBmp) { super(containsBmp, containsNonBmp); } /** * Output a representation of the subset of this character class that's within the BMP, to * a supplied buffer * @param buf the supplied buffer */ public void outputBmp(FastStringBuffer buf) { buf.append('['); inClassOutputBmp(buf); buf.append(']'); } /** * Output a representation of the subset of this character class that's outwith the BMP, to * a supplied buffer. Must not call if containsBmp == ALL * @param buf the supplied buffer */ public void outputComplementBmp(FastStringBuffer buf) { if (getContainsBmp() == NONE) { buf.append("[\u0000-\uFFFF]"); } else { buf.append("[^"); inClassOutputBmp(buf); buf.append(']'); } } /** * Output a representation of the subset of this character class that's within the BMP, to * a supplied buffer, using regex syntax that will be valid within a character class * expression (that is, within square brackets) * @param buf the supplied buffer */ public abstract void inClassOutputBmp(FastStringBuffer buf); } /** * Character class that matches a single specific character in the BMP */ public static class SingleChar extends SimpleCharClass { private final char c; /** * Create a character class for a single BMP character * @param c the character */ public SingleChar(char c) { super(SOME, NONE); this.c = c; } /** * Get the character represented by this character class * @return the character */ public int getSingleChar() { return c; } /** * Output a representation of this character class to * a supplied buffer @param buf the supplied buffer */ public void outputBmp(FastStringBuffer buf) { inClassOutputBmp(buf); } public void inClassOutputBmp(FastStringBuffer buf) { if (isJavaMetaChar(c)) { buf.append('\\'); buf.append(c); } else { switch (c) { case '\r': buf.append("\\r"); break; case '\n': buf.append("\\n"); break; case '\t': buf.append("\\t"); break; case ' ': buf.append("\\x20"); break; default: buf.append(c); } } } } /** * Character class that matches a single specific character outside the BMP */ public static class WideSingleChar extends SimpleCharClass { private final int c; /** * Create a character class for a single non-BMP character * @param c the character */ public WideSingleChar(int c) { super(NONE, SOME); if (c <= 65535) { throw new IllegalArgumentException("Internal error: WideSingleChar handles non-BMP characters only"); } this.c = c; } public void inClassOutputBmp(FastStringBuffer buf) { throw new AssertionError("WideSingleChar handles non-BMP characters only"); } public int getSingleChar() { return c; } public void addNonBmpRanges(List ranges) { ranges.add(new Range(c, c)); } } /** * Character class that matches nothing */ public static class Empty extends SimpleCharClass { private static final Empty instance = new Empty(); private Empty() { super(NONE, NONE); } /** * Return the singular instance of this class * @return the singular instance */ public static Empty getInstance() { return instance; } public void inClassOutputBmp(FastStringBuffer buf) { throw new AssertionError("Attempt to output BMP character for empty class"); } } /** * Character class that matches any character within a range of codepoints */ public static class CharRange extends SimpleCharClass { private final int lower; private final int upper; /** * Create a character class for a range of characters * @param lower the lower end of the range * @param upper the upper end of the range */ public CharRange(int lower, int upper) { super(lower < UTF16.NONBMP_MIN ? SOME : NONE, // don't use ALL here, because that requires that the BMP class contains high surrogates upper >= UTF16.NONBMP_MIN ? SOME : NONE); this.lower = lower; this.upper = upper; } public void inClassOutputBmp(FastStringBuffer buf) { if (lower >= UTF16.NONBMP_MIN) throw new RuntimeException("BMP output botch"); if (isJavaMetaChar((char) lower)) buf.append('\\'); buf.append((char) lower); buf.append('-'); if (upper < UTF16.NONBMP_MIN) { if (isJavaMetaChar((char) upper)) buf.append('\\'); buf.append((char) upper); } else buf.append('\uFFFF'); } public void addNonBmpRanges(List ranges) { if (upper >= UTF16.NONBMP_MIN) ranges.add(new Range(lower < UTF16.NONBMP_MIN ? UTF16.NONBMP_MIN : lower, upper)); } } /** * Character class containing characters that share a given Unicode property */ public static class Property extends SimpleCharClass { private final String name; /** * Create a character class for a named property * @param name the name of the property */ public Property(String name) { super(SOME, NONE); this.name = name; } public void outputBmp(FastStringBuffer buf) { inClassOutputBmp(buf); } public void inClassOutputBmp(FastStringBuffer buf) { buf.append("\\p{"); buf.append(name); buf.append('}'); } public void outputComplementBmp(FastStringBuffer buf) { buf.append("\\P{"); buf.append(name); buf.append('}'); } } /** * Character class representing a back-reference. */ public static class BackReference extends CharClass { private final int i; /** * Create a character class representing a back reference * @param i the subexpression to which this is a backreference */ public BackReference(int i) { super(SOME, NONE); this.i = i; } public void outputBmp(FastStringBuffer buf) { inClassOutputBmp(buf); } public void outputComplementBmp(FastStringBuffer buf) { inClassOutputBmp(buf); } void inClassOutputBmp(FastStringBuffer buf) { if (i != -1) { buf.append("(?:\\" + i + ")"); // terminate the back-reference with a syntactic separator } else { buf.append("(?:)"); // matches a zero-length string, while allowing a quantifier } } } /** * Character class representing the characters matched by the XPath "." metacharacter */ public static class Dot extends CharClass { /** * Create a character class for the "." metacharacter */ public Dot() { super(SOME, NONE); // a deliberate lie } public void outputBmp(FastStringBuffer buf) { buf.append("(?:.|"); buf.append(SURROGATES1_CLASS); buf.append(SURROGATES2_CLASS); buf.append(")"); } public void outputComplementBmp(FastStringBuffer buf) { buf.append("[^\\n]"); } void inClassOutputBmp(FastStringBuffer buf) { buf.append("."); } } /** * Character class representing the complement of another character class, that is, all * characters that the other class doesn't match. */ public static class Complement extends CharClass { private final CharClass cc; /** * Create a character class representing the complement of another character class * @param cc the character class of which this is the complement */ public Complement(CharClass cc) { super(-cc.getContainsBmp(), -cc.getContainsNonBmp()); this.cc = cc; } public void outputBmp(FastStringBuffer buf) { cc.outputComplementBmp(buf); } public void outputComplementBmp(FastStringBuffer buf) { cc.outputBmp(buf); } public void addNonBmpRanges(List ranges) { List tem = new ArrayList(5); cc.addNonBmpRanges(tem); sortRangeList(tem); int c = UTF16.NONBMP_MIN; for (int i = 0, len = tem.size(); i < len; i++) { Range r = (Range) tem.get(i); if (r.getMin() > c) ranges.add(new Range(c, r.getMin() - 1)); c = r.getMax() + 1; } if (c != UTF16.NONBMP_MAX + 1) ranges.add(new Range(c, UTF16.NONBMP_MAX)); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/regex/package.html0000644000175000017500000000134411033112257020774 0ustar eugeneeugene Package overview: net.sf.saxon.regex

    This package contains the code to map XML Schema and XPath regular expressions to the regular expression engine of the underlying Java platform.

    Regular expressions are translated into the form accepted by JDK 1.5 or JDK 1.4. There are two separate versions of the translator because these two platforms differ radically in how Unicode characters outside the basic multilingual plane are handled.

    Users should not normally need to use these classes directly.

    Most of the code used in these translators was developed originally by James Clark.

    saxonb-9.1.0.8/bj/net/sf/saxon/trace/0000755000175000017500000000000012216261750016504 5ustar eugeneeugenesaxonb-9.1.0.8/bj/net/sf/saxon/trace/XSLTTraceListener.java0000644000175000017500000000374611033112257022631 0ustar eugeneeugenepackage net.sf.saxon.trace; import net.sf.saxon.om.NamespaceConstant; import net.sf.saxon.om.StandardNames; /** * A Simple trace listener for XSLT that writes messages (by default) to System.err */ public class XSLTTraceListener extends AbstractTraceListener { /** * Generate attributes to be included in the opening trace element */ protected String getOpeningAttributes() { return "xmlns:xsl=\"" + NamespaceConstant.XSLT + '\"'; } /** * Get the trace element tagname to be used for a particular construct. Return null for * trace events that are ignored by this trace listener. */ protected String tag(int construct) { if (construct < 1024) { return StandardNames.getDisplayName(construct); } switch (construct) { case Location.LITERAL_RESULT_ELEMENT: return "LRE"; case Location.LITERAL_RESULT_ATTRIBUTE: return "ATTR"; case Location.LET_EXPRESSION: return "xsl:variable"; case Location.EXTENSION_INSTRUCTION: return "extension-instruction"; case Location.TRACE_CALL: return "user-trace"; default: return null; } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none //saxonb-9.1.0.8/bj/net/sf/saxon/trace/ContextStackIterator.java0000644000175000017500000001624611033112257023475 0ustar eugeneeugenepackage net.sf.saxon.trace; import net.sf.saxon.expr.UserFunctionCall; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.instruct.*; import net.sf.saxon.om.StandardNames; import java.util.Iterator; /** * This class provides a representation of the current runtime call stack, as represented by the stack * of XPathContext objects. */ public class ContextStackIterator implements Iterator { private boolean first = true; private XPathContext next; /** * Create an iterator over the stack of XPath dynamic context objects, starting with the top-most * stackframe and working down. The objects returned by this iterator will be of class {@link ContextStackFrame} * @param context the current context */ public ContextStackIterator(XPathContext context) { next = context; } /** * Returns true if the iteration has more elements. (In other * words, returns true if next would return an element * rather than throwing an exception.) * * @return true if the iterator has more elements. */ public boolean hasNext() { return next != null; } /** * Returns the next element in the iteration. Calling this method * repeatedly until the {@link #hasNext()} method returns false will * return each element in the underlying collection exactly once. * * @return the next element in the iteration, which will always be an instance * of {@link ContextStackFrame} * @throws java.util.NoSuchElementException * iteration has no more elements. */ public Object next() { XPathContext context = next; if (context == null) { return null; } int construct = context.getOriginatingConstructType(); Object origin = context.getOrigin(); if (first) { // these constructs are only considered if they appear at the top of the stack if (construct == Location.FILTER_EXPRESSION || construct == Location.PATH_EXPRESSION || construct == Location.SORT_KEY || construct == Location.GROUPING_KEY) { } else { } } if (construct == Location.CONTROLLER) { next = context.getCaller(); return new ContextStackFrame.CallingApplication(); } else if (construct == Location.BUILT_IN_TEMPLATE) { next = context.getCaller(); return new ContextStackFrame.BuiltInTemplateRule(); } // InstructionInfo info; // if (origin instanceof Instruction) { // info = ((Instruction)origin); // } else { // next = context.getCaller(); // return next(); // } //System.err.println("Construct: " + construct); if (construct == Location.FUNCTION_CALL) { ContextStackFrame.FunctionCall sf = new ContextStackFrame.FunctionCall(); UserFunctionCall ufc = (UserFunctionCall)origin; sf.setSystemId(ufc.getSystemId()); sf.setLineNumber(ufc.getLineNumber()); sf.setContainer(ufc.getContainer()); sf.setFunctionName(ufc.getFunctionName()); sf.setContextItem(context.getContextItem()); next = context.getCaller(); return sf; } else if (construct == StandardNames.XSL_APPLY_TEMPLATES) { ContextStackFrame.ApplyTemplates sf = new ContextStackFrame.ApplyTemplates(); ApplyTemplates loc = (ApplyTemplates)origin; sf.setSystemId(loc.getSystemId()); sf.setLineNumber(loc.getLineNumber()); sf.setContainer(loc.getContainer()); sf.setContextItem(context.getContextItem()); next = context.getCaller(); return sf; } else if (construct == StandardNames.XSL_CALL_TEMPLATE) { ContextStackFrame.CallTemplate sf = new ContextStackFrame.CallTemplate(); CallTemplate loc = (CallTemplate)origin; sf.setSystemId(loc.getSystemId()); sf.setLineNumber(loc.getLineNumber()); sf.setContainer(loc.getContainer()); sf.setTemplateName(loc.getObjectName()); sf.setContextItem(context.getContextItem()); next = context.getCaller(); return sf; } else if (construct == StandardNames.XSL_VARIABLE) { ContextStackFrame.VariableEvaluation sf = new ContextStackFrame.VariableEvaluation(); GeneralVariable var = ((GeneralVariable)origin); sf.setSystemId(var.getSystemId()); sf.setLineNumber(var.getLineNumber()); sf.setContainer(var.getContainer()); sf.setContextItem(context.getContextItem()); sf.setVariableName(var.getVariableQName()); next = context.getCaller(); return sf; } else if (construct == StandardNames.XSL_FOR_EACH) { ContextStackFrame.ForEach sf = new ContextStackFrame.ForEach(); ForEach var = ((ForEach)origin); sf.setSystemId(var.getSystemId()); sf.setLineNumber(var.getLineNumber()); sf.setContainer(var.getContainer()); sf.setContextItem(context.getContextItem()); next = context.getCaller(); return sf; // } else if (construct == Location.FILTER_EXPRESSION) { // out.println(" In predicate of filter expression"); // } else if (construct == Location.PATH_EXPRESSION) { // out.println(" In step of path expression"); // } else if (construct == Location.SORT_KEY) { // out.println(" In evaluation of sort key"); // } else if (construct == Location.GROUPING_KEY) { // out.println(" In evaluation of grouping key"); } else { //other context changes are not considered significant enough to report //out.println(" In unidentified location " + construct); next = context.getCaller(); return next(); } } /** * Removes from the underlying collection the last element returned by the * iterator (optional operation). * * @throws UnsupportedOperationException as the remove * operation is not supported by this Iterator. */ public void remove() { throw new UnsupportedOperationException(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/trace/TraceListener.java0000644000175000017500000000704211033112257022107 0ustar eugeneeugenepackage net.sf.saxon.trace; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.Item; import java.util.EventListener; /** * This interface defines methods that are called by Saxon during the execution of * a stylesheet, if tracing is switched on. Tracing can be switched on by nominating * an implementation of this class using the TRACE_LISTENER feature of the TransformerFactory, * or using the addTraceListener() method of the Controller, which is Saxon's implementation * of tyhe JAXP javax.xml.transform.Transformer interface. */ public interface TraceListener extends EventListener { /** * Method called at the start of execution, that is, when the run-time transformation starts */ public void open(); /** * Method called at the end of execution, that is, when the run-time execution ends */ public void close(); /** * Method that is called when an instruction in the stylesheet gets processed. * @param instruction gives information about the instruction being * executed, and about the context in which it is executed. This object is mutable, * so if information from the InstructionInfo is to be retained, it must be copied. */ public void enter(InstructionInfo instruction, XPathContext context); /** * Method that is called after processing an instruction of the stylesheet, * that is, after any child instructions have been processed. * @param instruction gives the same information that was supplied to the * enter method, though it is not necessarily the same object. Note that the * line number of the instruction is that of the start tag in the source stylesheet, * not the line number of the end tag. */ public void leave(InstructionInfo instruction); /** * Method that is called by an instruction that changes the current item * in the source document: that is, xsl:for-each, xsl:apply-templates, xsl:for-each-group. * The method is called after the enter method for the relevant instruction, and is called * once for each item processed. * @param currentItem the new current item. Item objects are not mutable; it is safe to retain * a reference to the Item for later use. */ public void startCurrentItem(Item currentItem); /** * Method that is called when an instruction has finished processing a new current item * and is ready to select a new current item or revert to the previous current item. * The method will be called before the leave() method for the instruction that made this * item current. * @param currentItem the item that was current, whose processing is now complete. This will represent * the same underlying item as the corresponding startCurrentItem() call, though it will * not necessarily be the same actual object. */ public void endCurrentItem(Item currentItem); } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Edwin Glaser (edwin@pannenleiter.de) // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): Heavily modified by Michael Kay // saxonb-9.1.0.8/bj/net/sf/saxon/trace/TimedTraceListener.java0000644000175000017500000000710011033112257023065 0ustar eugeneeugenepackage net.sf.saxon.trace; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.Item; import net.sf.saxon.om.StandardNames; import net.sf.saxon.om.NamePool; /** * A Simple trace listener that writes messages to System.err */ public class TimedTraceListener implements TraceListener { /** * Called at start */ public void open() { System.err.println(""); } /** * Called at end */ public void close() { System.err.println(""); } /** * Called when an instruction in the stylesheet gets processed */ public void enter(InstructionInfo instruction, XPathContext context) { NamePool pool = context.getNamePool(); int loc = instruction.getConstructType(); if (loc == StandardNames.XSL_FUNCTION || loc == StandardNames.XSL_TEMPLATE) { String tag = "<"; tag += (loc==StandardNames.XSL_FUNCTION ? "function" : "template"); String name = null; if (instruction.getObjectName() != null) { name = instruction.getObjectName().getDisplayName(); } else if (instruction.getProperty("name") != null) { name = instruction.getProperty("name").toString(); } if (name != null) { tag += " name=\"" + name + "\""; } if (instruction.getProperty("match") != null) { tag += " match=\"" + instruction.getProperty("match") + "\""; } String file = instruction.getSystemId(); if (file != null) { if (file.length()>15) { file="*" + file.substring(file.length()-14); } tag += " file=\"" + file + "\""; } tag += " line=\"" + instruction.getLineNumber() + "\""; tag += " time=\"" + System.currentTimeMillis() + "\""; tag += ">"; System.err.println(tag); } } /** * Called after an instruction of the stylesheet got processed */ public void leave(InstructionInfo instruction) { int loc = instruction.getConstructType(); if (loc == StandardNames.XSL_FUNCTION || loc == StandardNames.XSL_TEMPLATE) { String tag = "" : "template>"); System.err.println(tag); } } /** * Called when an item becomes current */ public void startCurrentItem(Item item) {} /** * Called after a node of the source tree got processed */ public void endCurrentItem(Item item) {} } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none //saxonb-9.1.0.8/bj/net/sf/saxon/trace/AbstractTraceListener.java0000644000175000017500000001574611033112257023605 0ustar eugeneeugenepackage net.sf.saxon.trace; import net.sf.saxon.Version; import net.sf.saxon.expr.ExpressionLocation; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.*; import net.sf.saxon.value.Whitespace; import java.io.PrintStream; import java.util.Iterator; /** * This is the standard trace listener used when the -T option is specified on the command line. * There are two variants, represented by subclasses: one for XSLT, and one for XQuery. The two variants * differ in that they present the trace output in terms of constructs used in the relevant host language. */ public abstract class AbstractTraceListener implements TraceListener { private int indent = 0; private PrintStream out = System.err; private static StringBuffer spaceBuffer = new StringBuffer(" "); /** * Called at start */ public void open() { out.println("'); indent++; } protected abstract String getOpeningAttributes(); /** * Called at end */ public void close() { indent--; out.println(""); } /** * Called when an instruction in the stylesheet gets processed */ public void enter(InstructionInfo info, XPathContext context) { NamePool pool = context.getNamePool(); int infotype = info.getConstructType(); StructuredQName qName = info.getObjectName(); String tag = tag(infotype); if (tag==null) { // this TraceListener ignores some events to reduce the volume of output return; } String file = ExpressionLocation.truncateURI(info.getSystemId()); String msg = AbstractTraceListener.spaces(indent) + '<' + tag; String name = (String)info.getProperty("name"); if (name!=null) { msg += " name=\"" + escape(name) + '"'; } else if (qName != null) { msg += " name=\"" + escape(qName.getDisplayName()) + '"'; } Iterator props = info.getProperties(); while (props.hasNext()) { String prop = (String)props.next(); Object val = info.getProperty(prop); if (prop.startsWith("{")) { // It's a QName in Clark notation: we'll strip off the namespace int rcurly = prop.indexOf('}'); if (rcurly > 0) { prop = prop.substring(rcurly+1); } } if (val != null && !prop.equals("name") && !prop.equals("expression")) { msg += ' ' + prop + "=\"" + escape(val.toString()) + '"'; } } msg += " line=\"" + info.getLineNumber() + '"'; int col = info.getColumnNumber(); if (col >= 0) { msg += " column=\"" + info.getColumnNumber() + '"'; } msg += " module=\"" + escape(file) + "\">"; out.println(msg); indent++; } /** * Escape a string for XML output (in an attribute delimited by double quotes). * This method also collapses whitespace (since the value may be an XPath expression that * was originally written over several lines). */ public String escape(String in) { if (in==null) { return ""; } CharSequence collapsed = Whitespace.collapseWhitespace(in); StringBuffer sb = new StringBuffer(collapsed.length() + 10); for (int i=0; i') { sb.append(">"); } else if (c=='&') { sb.append("&"); } else if (c=='\"') { sb.append("""); } else if (c=='\n') { sb.append(" "); } else if (c=='\r') { sb.append(" "); } else if (c=='\t') { sb.append(" "); } else { sb.append(c); } } return sb.toString(); } /** * Called after an instruction of the stylesheet got processed */ public void leave(InstructionInfo info) { int infotype = info.getConstructType(); String tag = tag(infotype); if (tag==null) { // this TraceListener ignores some events to reduce the volume of output return; } indent--; out.println(AbstractTraceListener.spaces(indent) + "'); } protected abstract String tag(int construct); /** * Called when an item becomes the context item */ public void startCurrentItem(Item item) { if (item instanceof NodeInfo) { NodeInfo curr = (NodeInfo) item; out.println(AbstractTraceListener.spaces(indent) + ""); } indent++; } /** * Called after a node of the source tree got processed */ public void endCurrentItem(Item item) { indent--; if (item instanceof NodeInfo) { NodeInfo curr = (NodeInfo) item; out.println(AbstractTraceListener.spaces(indent) + ""); } } /** * Get n spaces */ private static String spaces(int n) { while (spaceBuffer.length() < n) { spaceBuffer.append(AbstractTraceListener.spaceBuffer); } return spaceBuffer.substring(0, n); } /** * Set the output destination (default is System.err) * @param stream the output destination for tracing output */ public void setOutputDestination(PrintStream stream) { out = stream; } /** * Get the output destination */ public PrintStream getOutputDestination() { return out; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none //saxonb-9.1.0.8/bj/net/sf/saxon/trace/InstructionInfo.java0000644000175000017500000000647711033112257022513 0ustar eugeneeugenepackage net.sf.saxon.trace; import net.sf.saxon.event.SaxonLocator; import net.sf.saxon.om.StructuredQName; import java.util.Iterator; /** * Information about an instruction in the stylesheet, made * available at run-time to a TraceListener */ public interface InstructionInfo extends SaxonLocator { /** * Get the type of construct. This will either be the fingerprint of a standard XSLT instruction name * (values in {@link net.sf.saxon.om.StandardNames}: all less than 1024) * or it will be a constant in class {@link Location}. * @return an integer identifying the kind of construct */ public int getConstructType(); /** * Get a name identifying the object of the expression, for example a function name, template name, * variable name, key name, element name, etc. This is used only where the name is known statically. * @return the QName of the object declared or manipulated by this instruction or expression */ public StructuredQName getObjectName(); /** * Get the system identifier (URI) of the source stylesheet or query module containing * the instruction. This will generally be an absolute URI. If the system * identifier is not known, the method may return null. In some cases, for example * where XML external entities are used, the correct system identifier is not * always retained. * @return the URI of the containing module */ public String getSystemId(); /** * Get the line number of the instruction in the source stylesheet module. * If this is not known, or if the instruction is an artificial one that does * not relate to anything in the source code, the value returned may be -1. * @return the line number of the expression within the containing module */ public int getLineNumber(); /** * Get the value of a particular property of the instruction. Properties * of XSLT instructions are generally known by the name of the stylesheet attribute * that defines them. * @param name The name of the required property * @return The value of the requested property, or null if the property is not available */ public Object getProperty(String name); /** * Get an iterator over all the properties available. The values returned by the iterator * will be of type String, and each string can be supplied as input to the getProperty() * method to retrieve the value of the property. The iterator may return properties whose * value is null. * @return an iterator over the properties. */ public Iterator getProperties(); } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/trace/TraceEventMulticaster.java0000644000175000017500000001253711033112257023625 0ustar eugeneeugenepackage net.sf.saxon.trace; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.Item; import java.util.EventListener; /** * A class which implements efficient and thread-safe multi-cast event * dispatching for the TraceListener evants. *

    * Grabbed from java.awt.AWTEventMulticaster */ public class TraceEventMulticaster implements TraceListener { protected final EventListener a, b; /** * Creates an event multicaster instance which chains listener-a * with listener-b. * * @param a listener-a * @param b listener-b */ protected TraceEventMulticaster(EventListener a, EventListener b) { this.a = a; this.b = b; } /** * Removes a listener from this multicaster and returns the * resulting multicast listener. * * @param oldl the listener to be removed */ protected EventListener remove(EventListener oldl) { if (oldl == a) { return b; } if (oldl == b) { return a; } EventListener a2 = removeInternal(a, oldl); EventListener b2 = removeInternal(b, oldl); if (a2 == a && b2 == b) { return this; // it's not here } return addInternal(a2, b2); } /** * Called at start */ public void open() { ((TraceListener)a).open(); ((TraceListener)b).open(); } /** * Called at end */ public void close() { ((TraceListener)a).close(); ((TraceListener)b).close(); } /** * Called when an element of the stylesheet gets processed */ public void enter(InstructionInfo element, XPathContext context) { ((TraceListener)a).enter(element, context); ((TraceListener)b).enter(element, context); } /** * Called after an element of the stylesheet got processed */ public void leave(InstructionInfo element) { ((TraceListener)a).leave(element); ((TraceListener)b).leave(element); } /** * Called when an item becomes current */ public void startCurrentItem(Item item) { ((TraceListener)a).startCurrentItem(item); ((TraceListener)b).startCurrentItem(item); } /** * Called when an item ceases to be the current item */ public void endCurrentItem(Item item) { ((TraceListener)a).endCurrentItem(item); ((TraceListener)b).endCurrentItem(item); } /** * Adds trace-listener-a with trace-listener-b and * returns the resulting multicast listener. * * @param a trace-listener-a * @param b trace-listener-b */ public static TraceListener add(TraceListener a, TraceListener b) { return (TraceListener)addInternal(a, b); } /** * Removes the old trace-listener from trace-listener-l and * returns the resulting multicast listener. * * @param l trace-listener-l * @param oldl the trace-listener being removed */ public static TraceListener remove(TraceListener l, TraceListener oldl) { return (TraceListener)removeInternal(l, oldl); } /** * Returns the resulting multicast listener from adding listener-a * and listener-b together. * If listener-a is null, it returns listener-b; * If listener-b is null, it returns listener-a * If neither are null, then it creates and returns * a new EventMulticaster instance which chains a with b. * * @param a event listener-a * @param b event listener-b */ protected static EventListener addInternal(EventListener a, EventListener b) { if (a == null) { return b; } if (b == null) { return a; } return new TraceEventMulticaster(a, b); } /** * Returns the resulting multicast listener after removing the * old listener from listener-l. * If listener-l equals the old listener OR listener-l is null, * returns null. * Else if listener-l is an instance of SaxonEventMulticaster, * then it removes the old listener from it. * Else, returns listener l. * * @param l the listener being removed from * @param oldl the listener being removed */ protected static EventListener removeInternal(EventListener l, EventListener oldl) { if (l == oldl || l == null) { return null; } else if (l instanceof TraceEventMulticaster) { return ((TraceEventMulticaster)l).remove(oldl); } else { return l; // it's not here } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Edwin Glaser (edwin@pannenleiter.de) // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): Modified by Michael Kay for Saxon 6.1 to remove "throws SAXException" from all methods // saxonb-9.1.0.8/bj/net/sf/saxon/trace/ExpressionPresenter.java0000644000175000017500000001577311033112257023404 0ustar eugeneeugenepackage net.sf.saxon.trace; import net.sf.saxon.Configuration; import net.sf.saxon.event.Receiver; import net.sf.saxon.event.SaxonOutputKeys; import net.sf.saxon.om.NamePool; import net.sf.saxon.om.StandardNames; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.TypeHierarchy; import javax.xml.transform.OutputKeys; import javax.xml.transform.stream.StreamResult; import java.io.OutputStream; import java.util.Properties; /** * This class handles the display of an abstract expression tree in an XML format * with some slight resemblence to XQueryX */ public class ExpressionPresenter { private Configuration config; private Receiver receiver; int depth = 0; /** * Make an ExpressionPresenter that writes indented output to System.err * @param config the Saxon configuration */ public ExpressionPresenter(Configuration config) { this(config, System.err); } /** * Make an ExpressionPresenter that writes indented output to a specified output stream * @param config the Saxon configuration * @param out the output stream */ public ExpressionPresenter(Configuration config, OutputStream out) { Properties props = makeDefaultProperties(); try { receiver = config.getSerializerFactory().getReceiver( new StreamResult(out), config.makePipelineConfiguration(), props); } catch (XPathException err) { err.printStackTrace(); throw new InternalError(err.getMessage()); } this.config = config; try { receiver.open(); receiver.startDocument(0); } catch (XPathException err) { err.printStackTrace(); throw new InternalError(err.getMessage()); } } /** * Make an ExpressionPresenter for a given Configuration using a user-supplied Receiver * to accept the output * @param config the Configuration * @param receiver the user-supplied Receiver */ public ExpressionPresenter(Configuration config, Receiver receiver) { this.config = config; this.receiver = receiver; try { receiver.open(); receiver.startDocument(0); } catch (XPathException err) { err.printStackTrace(); throw new InternalError(err.getMessage()); } } /** * Make a receiver, using default output properties, with serialized output going * to a specified OutputStream * @param config the Configuration * @param out the OutputStream * @return a Receiver that directs serialized output to this output stream * @throws XPathException */ public static Receiver defaultDestination(Configuration config, OutputStream out) throws XPathException { Properties props = makeDefaultProperties(); return config.getSerializerFactory().getReceiver( new StreamResult(out), config.makePipelineConfiguration(), props); } /** * Make a Properties object containing defaulted serialization attributes for the expression tree * @return a default set of properties */ private static Properties makeDefaultProperties() { Properties props = new Properties(); props.setProperty(OutputKeys.METHOD, "xml"); props.setProperty(OutputKeys.INDENT, "yes"); props.setProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); props.setProperty(SaxonOutputKeys.INDENT_SPACES, "2"); return props; } /** * Start an element * @param name the name of the element * @return the depth of the tree before this element: for diagnostics, this can be compared * with the value returned by endElement */ public int startElement(String name) { try { receiver.startElement(config.getNamePool().allocate("", "", name), StandardNames.XS_UNTYPED, 0, 0); } catch (XPathException err) { err.printStackTrace(); throw new InternalError(err.getMessage()); } return depth++; } /** * Output an attribute node * @param name the name of the attribute * @param value the value of the attribute */ public void emitAttribute(String name, String value) { try { receiver.attribute(config.getNamePool().allocate("", "", name), StandardNames.XS_UNTYPED, value, 0, 0); } catch (XPathException err) { err.printStackTrace(); throw new InternalError(err.getMessage()); } } /** * End an element in the expression tree * @return the depth of the tree after ending this element. For diagnostics, this can be compared with the * value returned by startElement() */ public int endElement() { try { receiver.endElement(); } catch (XPathException err) { err.printStackTrace(); throw new InternalError(err.getMessage()); } return --depth; } /** * Start a child element in the output * @param name the name of the child element */ public void startSubsidiaryElement(String name) { startElement(name); } /** * End a child element in the output */ public void endSubsidiaryElement() { endElement(); } /** * Close the output */ public void close() { try { receiver.endDocument(); receiver.close(); } catch (XPathException err) { err.printStackTrace(); throw new InternalError(err.getMessage()); } } /** * Get the Saxon configuration * @return the Saxon configuration */ public Configuration getConfiguration() { return config; } /** * Get the name pool * @return the name pool */ public NamePool getNamePool() { return config.getNamePool(); } /** * Get the type hierarchy cache * @return the type hierarchy cache */ public TypeHierarchy getTypeHierarchy() { return config.getTypeHierarchy(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/trace/ContextStackFrame.java0000644000175000017500000002547111033112257022736 0ustar eugeneeugenepackage net.sf.saxon.trace; import net.sf.saxon.trans.Err; import net.sf.saxon.expr.Container; import net.sf.saxon.instruct.*; import net.sf.saxon.om.*; import net.sf.saxon.trans.KeyDefinition; import java.io.PrintStream; /** * An entry on the context stack. A new entry is created every time the context changes. This is a * representation of the stack created on request; it does not hold live data. */ public abstract class ContextStackFrame { private String moduleUri; private int lineNumber; private Container container; private Item contextItem; /** * Set the system ID representing the location of the instruction that caused this new context * to be created * @param uri the system ID (base URI/module URI) of the module containing the instruction */ public void setSystemId(String uri) { this.moduleUri = uri; } /** * Get the system ID representing the location of the instruction that caused this new context * to be created * @return the system ID (base URI/module URI) of the module containing the instruction */ public String getSystemId() { return moduleUri; } /** * Set the line number of the location of the instruction that caused this new context * to be created * @param lineNumber the line number of the instruction within its containing module */ public void setLineNumber(int lineNumber) { this.lineNumber = lineNumber; } /** * Get the line number of the location of the instruction that caused this new context * to be created * @return the line number of the instruction within its containing module */ public int getLineNumber() { return lineNumber; } /** * Set the container of the instruction that caused this new context to be created. This will * generally be an object such as an XSLT Template or a user-defined function * @param container the container of the instruction */ public void setContainer(Container container) { this.container = container; } /** * Get the container of the instruction that caused this new context to be created. This will * generally be an object such as an XSLT Template or a user-defined function * @return the container of the instruction in the expression tree */ public Container getContainer() { return container; } /** * Set the value of the context item at this level of the context stack * @param contextItem the context item as it was when this new context was created */ public void setContextItem(Item contextItem) { this.contextItem = contextItem; } /** * Get the value of the context item at this level of the context stack * @return the context item as it was when this new context was created */ public Item getContextItem() { return contextItem; } /** * Display a representation of the stack frame on the specified output stream * @param out the output stream */ public abstract void print(PrintStream out); /** * Subclass of ContextStackFrame representing the outermost stack frame, * for the calling application */ public static class CallingApplication extends ContextStackFrame { public void print(PrintStream out) { //out.println(" (called from external application)"); } } /** * Subclass of ContextStackFrame representing a built-in template rule in XSLT */ public static class BuiltInTemplateRule extends ContextStackFrame { public void print(PrintStream out) { out.println(" in built-in template rule"); } } /** * Subclass of ContextStackFrame representing a call to a user-defined function * either in XSLT or XQuery */ public static class FunctionCall extends ContextStackFrame { StructuredQName functionName; /** * Get the name of the function being called * @return the name of the function being called */ public StructuredQName getFunctionName() { return functionName; } /** * Set the name of the function being called * @param functionName the name of the function being called */ public void setFunctionName(StructuredQName functionName) { this.functionName = functionName; } /** * Display a representation of the stack frame on the specified output stream * @param out the output stream */ public void print(PrintStream out) { out.println(" at " + functionName.getDisplayName() + "() " + "(" + getSystemId() + "#" + getLineNumber() + ")"); } } /** * Subclass of ContextStackFrame representing an xsl:apply-templates call in XSLT */ public static class ApplyTemplates extends ContextStackFrame { /** * Display a representation of the stack frame on the specified output stream * @param out the output stream */ public void print(PrintStream out) { out.println(" at xsl:apply-templates (" + getSystemId() + "#" + getLineNumber() + ")"); Item node = getContextItem(); if (node instanceof NodeInfo) { out.println(" processing " + Navigator.getPath((NodeInfo)node)); } } } /** * Subclass of ContextStackFrame representing an xsl:for-each instruction in XSLT */ public static class ForEach extends ContextStackFrame { /** * Display a representation of the stack frame on the specified output stream * @param out the output stream */ public void print(PrintStream out) { out.println(" at xsl:for-each (" + getSystemId() + "#" + getLineNumber() + ")"); Item item = getContextItem(); if (item instanceof NodeInfo) { out.println(" processing " + Navigator.getPath((NodeInfo)item)); } else { out.println(" processing " + Err.wrap(item.getStringValueCS(), Err.VALUE)); } } } /** * Subclass of ContextStackFrame representing an xsl:call-template instruction in XSLT */ public static class CallTemplate extends ContextStackFrame { /** * Get the name of the template being called * @return the name of the template being called. Note this may be null in the case of the * extension instruction saxon:call-template */ public StructuredQName getTemplateName() { return templateName; } /** * Set the name of the template being called * @param templateName the name of the template being called. */ public void setTemplateName(StructuredQName templateName) { this.templateName = templateName; } StructuredQName templateName; /** * Display a representation of the stack frame on the specified output stream * @param out the output stream */ public void print(PrintStream out) { String name = templateName == null ? "??" : templateName.getDisplayName(); out.println(" at xsl:call-template name=\"" + name + "\" (" + getSystemId() + "#" + getLineNumber() + ")"); } } /** * Subclass of ContextStackFrame representing the evaluation of a variable (typically a global variable) */ public static class VariableEvaluation extends ContextStackFrame { /** * Get the name of the variable * @return the name of the variable */ public StructuredQName getVariableName() { return variableName; } /** * Set the name of the variable * @param variableName the name of the variable */ public void setVariableName(StructuredQName variableName) { this.variableName = variableName; } StructuredQName variableName; /** * Display a representation of the stack frame on the specified output stream * @param out the output stream */ public void print(PrintStream out) { out.println(" in " + displayContainer(getContainer()) + " (" + getSystemId() + "#" + getLineNumber() + ")"); } } private static String displayContainer(Container container) { if (container instanceof Procedure) { StructuredQName name = ((Procedure)container).getObjectName(); String objectName = (name==null ? "" : name.getDisplayName()); if (container instanceof Template) { if (name == null) { //NamePool pool = container.getExecutable().getConfiguration().getNamePool(); return "template match=\"" + ((Template)container).getMatchPattern().toString() + "\""; } else { return "template name=\"" + objectName + "\""; } } else if (container instanceof UserFunction) { return "function " + objectName + "()"; } else if (container instanceof AttributeSet) { return "attribute-set " + objectName; } else if (container instanceof KeyDefinition) { return "key " + objectName; } } else if (container instanceof GlobalVariable) { StructuredQName qName = ((GlobalVariable)container).getVariableQName(); if (NamespaceConstant.SAXON.equals(qName.getNamespaceURI()) && "gg".equals(qName.getPrefix())) { return "optimizer-created global variable"; } else { return "variable " + qName.getDisplayName(); } } else { return ""; } return ""; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/trace/Location.java0000644000175000017500000001601511033112257021113 0ustar eugeneeugenepackage net.sf.saxon.trace; /** * This class holds constants identifying different kinds of location in a source stylesheet or query. * These constants are used in the getConstructType() method of class InstructionInfo. Some of these * locations represent points where the dynamic context changes, and they are therefore recorded as * such on the context stack. Some of the locations represent points in the evaluation of a stylesheet * (or query or XPath expression) that are notified to the trace listener. Some fulfil both roles. * *

    Any constant used in {@link net.sf.saxon.om.StandardNames} can be used as a Location. Such * names are generally used to identify XSLT instructions. They are also used for equivalent constructs * in XQuery, for example XSL_ELEMENT is used for a computed element constructor in XQuery. The constants * in StandardNames are all in the range 0-1023, so constants defined in this class are outside this * range.

    * *

    The constants in this file are annotated with Q to indicate they can appear in XQuery trace output, * T to indicate they can appear in XSLT trace output, and/or C to indicate that they can appear on the * dynamic context stack.

    */ public class Location { /** * The outer system environment, identified as the caller of a user query or stylesheet. * Usage:C */ public static final int CONTROLLER = 2000; /** * An XSLT instruction. The name of the instruction (which may be an extension instruction) can * be obtained using the fingerprint property. Usage:T */ public static final int EXTENSION_INSTRUCTION = 2005; /** * An XSLT literal result element, or an XQuery direct element constructor. Usage:QT */ public static final int LITERAL_RESULT_ELEMENT = 2006; /** * An attribute of an XSLT literal result element or of an XQuery direct element constructor. * Usage: QT */ public static final int LITERAL_RESULT_ATTRIBUTE = 2007; /** * An XSLT user-written template rule or named template. Usage: TC */ public static final int TEMPLATE = 2008; /** * An XPath function call to a user-defined function. * The "expression" property references the actual expression, of class ComputedExpression. * The "target" property references the function being called, of class UserFunction. * Usage: QTC */ public static final int FUNCTION_CALL = 2009; /** * An XSLT built-in template rule. Usage: TC */ public static final int BUILT_IN_TEMPLATE = 2010; /** * Entry point to a top-level XPath expression within an XSLT stylesheet. * Usage: TC */ public static final int XPATH_IN_XSLT = 2011; /** * An XPath or XQuery "for" clause. Usage: Q */ public static final int FOR_EXPRESSION = 2012; /** * An XQuery "let" clause, or an XSLT local variable (which compiles into a LET clause). * Usage: Q,T */ public static final int LET_EXPRESSION = 2013; /** * An XPath or XQuery "return" clause. Usage: Q */ public static final int RETURN_EXPRESSION = 2014; /** * An XPath or XQuery "if" expression. Usage: Q */ public static final int IF_EXPRESSION = 2015; /** * An XPath or XQuery "then" clause. Usage: Q */ public static final int THEN_EXPRESSION = 2016; /** * An XPath or XQuery "else" clause. Usage: Q */ public static final int ELSE_EXPRESSION = 2017; /** * A WHERE clause in a FLWOR expression. Usage: Q */ public static final int WHERE_CLAUSE = 2018; /** * An order-by clause in a FLWOR expression. Usage: Q */ public static final int ORDER_BY_CLAUSE = 2019; /** * An XPath or XQuery "typeswitch" expression. Usage: Q */ public static final int TYPESWITCH_EXPRESSION = 2020; /** * CASE clause within "typeswitch". Usage: Q */ public static final int CASE_EXPRESSION = 2021; /** * DEFAULT clause within "typeswitch". Usage: Q */ public static final int DEFAULT_EXPRESSION = 2022; /** * An XPath or XQuery "validate" expression. Usage: Q */ public static final int VALIDATE_EXPRESSION = 2023; /** * An XPath or XQuery filter expression. Usage: C */ public static final int FILTER_EXPRESSION = 2024; /** * An XPath or XQuery path expression. Usage: C */ public static final int PATH_EXPRESSION = 2025; /** * An explicit call of the fn:trace() function. Usage: QT */ public static final int TRACE_CALL = 2031; /** * An XPath expression constructed dynamically using saxon:evaluate (or saxon:expression). * Usage: QTC */ public static final int SAXON_EVALUATE = 2051; /** * A higher-order extension function such as saxon:sum, saxon:highest. Usage: C */ public static final int SAXON_HIGHER_ORDER_EXTENSION_FUNCTION = 2052; /** * The saxon:serialize() extension function. Usage: C */ public static final int SAXON_SERIALIZE = 2053; /** * A sort key (or order-by key). Usage: C */ public static final int SORT_KEY = 2061; /** * A grouping key in XSLT. Usage: C */ public static final int GROUPING_KEY = 2062; /** * Lazy evaluation of an expression (this code is used to identify a context created as a saved * copy of an existing context, to be stored in a Closure). Usage: C */ public static final int LAZY_EVALUATION = 2063; /** * An XSLT Pattern. Usage: C */ public static final int PATTERN = 2064; /** * A function declaration in XSLT or XQuery */ public static final int FUNCTION = 2065; /** * XPath expression, otherwise unclassified. The "expression" property references the actual expression, * of class ComputedExpression. Used in fallback cases only. */ public static final int XPATH_EXPRESSION = 2098; /** * Unclassified location. Used in fallback cases only. */ public static final int UNCLASSIFIED = 2099; private Location() { } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none //saxonb-9.1.0.8/bj/net/sf/saxon/trace/XQueryTraceListener.java0000644000175000017500000000665511033112257023276 0ustar eugeneeugenepackage net.sf.saxon.trace; import net.sf.saxon.om.StandardNames; import net.sf.saxon.om.StandardNames; /** * A Simple trace listener for XQuery that writes messages (by default) to System.err */ public class XQueryTraceListener extends AbstractTraceListener { /** * Generate attributes to be included in the opening trace element */ protected String getOpeningAttributes() { return ""; } /** * Get the trace element tagname to be used for a particular construct. Return null for * trace events that are ignored by this trace listener. */ protected String tag(int construct) { switch (construct) { case StandardNames.XSL_FUNCTION: return "function"; case StandardNames.XSL_VARIABLE: return "variable"; case StandardNames.XSL_ELEMENT: return "element"; case StandardNames.XSL_ATTRIBUTE: return "attribute"; case StandardNames.XSL_COMMENT: return "comment"; case StandardNames.XSL_DOCUMENT: return "document"; case StandardNames.XSL_PROCESSING_INSTRUCTION: return "processing-instruction"; case StandardNames.XSL_TEXT: return "text"; case StandardNames.XSL_NAMESPACE: return "namespace"; case Location.LITERAL_RESULT_ELEMENT: return "element"; case Location.LITERAL_RESULT_ATTRIBUTE: return "attribute"; case Location.FUNCTION_CALL: //return "function-call"; return null; case Location.FOR_EXPRESSION: return "for"; case Location.LET_EXPRESSION: return "let"; case Location.WHERE_CLAUSE: return "where"; case Location.ORDER_BY_CLAUSE: return "sort"; case Location.RETURN_EXPRESSION: return "return"; case Location.TYPESWITCH_EXPRESSION: return "typeswitch"; case Location.VALIDATE_EXPRESSION: return "validate"; case Location.IF_EXPRESSION: return "if"; case Location.THEN_EXPRESSION: return "then"; case Location.ELSE_EXPRESSION: return "else"; case Location.CASE_EXPRESSION: return "case"; case Location.DEFAULT_EXPRESSION: return "default"; case Location.TRACE_CALL: return "user-trace"; default: //return "Other"; return null; } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none //saxonb-9.1.0.8/bj/net/sf/saxon/trace/package.html0000644000175000017500000000151511033112257020760 0ustar eugeneeugene Package overview for net.sf.saxon.trace

    This package provides an interface to Saxon tracing and debugging capabilities.

    The package was originally created by Edwin Glaser.

    The package includes three tracing modules that can be optionally selected: XSLTTraceListener, XQueryTraceListener, and TimedTraceListener. These all receive notification of the same events, but select and format the events in different ways to meet different requirements. Other events are notified through the TraceListener interface that are ignored by tracing applications, but may be of interest to debuggers.


    Michael H. Kay
    Saxonica Limited
    9 February 2005

    saxonb-9.1.0.8/bj/net/sf/saxon/pull/0000755000175000017500000000000012216261752016364 5ustar eugeneeugenesaxonb-9.1.0.8/bj/net/sf/saxon/pull/NamespaceContextImpl.java0000644000175000017500000000766511033112257023317 0ustar eugeneeugenepackage net.sf.saxon.pull; import net.sf.saxon.om.NamespaceResolver; import javax.xml.namespace.NamespaceContext; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /** * This class bridges between the JAXP 1.3 NamespaceContext interface and Saxon's * equivalent NamespaceResolver interface. It allows any implementation of the Saxon * NamespaceResolver to be wrapped as a JAXP NamespaceContext. */ public class NamespaceContextImpl implements NamespaceContext, NamespaceResolver { NamespaceResolver resolver; /** * Constructor: wrap a Saxon NamespaceResolver as a JAXP NamespaceContext * @param resolver the Saxon NamespaceResolver */ public NamespaceContextImpl(NamespaceResolver resolver) { this.resolver = resolver; } /** * Get the namespace URI corresponding to a given prefix. Return null * if the prefix is not in scope. * @param prefix the namespace prefix * @param useDefault true if the default namespace is to be used when the * prefix is "" * @return the uri for the namespace, or null if the prefix is not in scope */ public String getURIForPrefix(String prefix, boolean useDefault) { return resolver.getURIForPrefix(prefix, useDefault); } /** * Get an iterator over all the prefixes declared in this namespace context. This will include * the default namespace (prefix="") and the XML namespace where appropriate */ public Iterator iteratePrefixes() { return resolver.iteratePrefixes(); } /** * Implement the JAXP getNamespaceURI() method in terms of the Saxon-specific methods * @param prefix a namespace prefix * @return the corresponding URI, if the prefix is bound, or "" otherwise */ public String getNamespaceURI(String prefix) { if (prefix.equals("xmlns")) { return "http://www.w3.org/2000/xmlns/"; } return resolver.getURIForPrefix(prefix, true); } /** * Get the prefix bound to a particular namespace URI, if there is one, or null if not (JAXP method) * @param uri the namespace URI * @return the prefix bound to the URI if there is one, or null if not */ public String getPrefix(String uri) { Iterator prefixes = iteratePrefixes(); while (prefixes.hasNext()) { String p = (String)prefixes.next(); String u = resolver.getURIForPrefix(p, true); if (u.equals(uri)) { return p; } } return null; } /** * Get all the prefixes mapped to a given namespace URI (JAXP method) * @param uri the namespace URI * @return an iterator over all the prefixes bound to this namespace URI */ public Iterator getPrefixes(String uri) { List list = new ArrayList(4); Iterator prefixes = iteratePrefixes(); while (prefixes.hasNext()) { String p = (String)prefixes.next(); String u = resolver.getURIForPrefix(p, true); if (u.equals(uri)) { list.add(p); } } return list.iterator(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none //saxonb-9.1.0.8/bj/net/sf/saxon/pull/PullFilter.java0000644000175000017500000002616111033112257021306 0ustar eugeneeugenepackage net.sf.saxon.pull; import net.sf.saxon.event.PipelineConfiguration; import net.sf.saxon.om.AttributeCollection; import net.sf.saxon.om.NamespaceDeclarations; import net.sf.saxon.om.NamePool; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.AtomicValue; import javax.xml.transform.SourceLocator; import java.util.List; /** * PullFilter is a pass-through filter class that links one PullProvider to another PullProvider * in a pipeline. This class passes all events through completely unchanged. The class is designed * so that subclasses can modify this behavior by altering some of the events. */ public class PullFilter implements PullProvider { private PullProvider base; private PipelineConfiguration pipe; protected int currentEvent; /** * Create a PullFilter * @param base the PullProvider to which requests are to be passed */ public PullFilter(PullProvider base) { this.base = base; if (base.getPipelineConfiguration() != null) { setPipelineConfiguration(base.getPipelineConfiguration()); } } /** * Set configuration information. This must only be called before any events * have been read. */ public void setPipelineConfiguration(PipelineConfiguration pipe) { this.pipe = pipe; base.setPipelineConfiguration(pipe); } /** * Get configuration information. */ public PipelineConfiguration getPipelineConfiguration() { return pipe; } /** * Helper method to get the current namePool * @return the NamePool */ public final NamePool getNamePool() { return getPipelineConfiguration().getConfiguration().getNamePool(); } /** * Get the underlying PullProvider * @return the underlying PullProvider */ public PullProvider getUnderlyingProvider() { return base; } /** * Get the next event. * *

    Note that a subclass that overrides this method is responsible for ensuring * that current() works properly. This can be achieved by setting the field * currentEvent to the event returned by any call on next().

    * * @return an integer code indicating the type of event. The code * {@link #END_OF_INPUT} is returned at the end of the sequence. */ public int next() throws XPathException { return base.next(); } /** * Get the event most recently returned by next(), or by other calls that change * the position, for example getStringValue() and skipToMatchingEnd(). This * method does not change the position of the PullProvider. * * @return the current event */ public int current() { return currentEvent; } /** * Get the attributes associated with the current element. This method must * be called only after a START_ELEMENT event has been notified. The contents * of the returned AttributeCollection are guaranteed to remain unchanged * until the next START_ELEMENT event, but may be modified thereafter. The object * should not be modified by the client. *

    *

    Attributes may be read before or after reading the namespaces of an element, * but must not be read after the first child node has been read, or after calling * one of the methods skipToEnd(), getStringValue(), or getTypedValue().

    * * @return an AttributeCollection representing the attributes of the element * that has just been notified. */ public AttributeCollection getAttributes() throws XPathException { return base.getAttributes(); } /** * Get the namespace declarations associated with the current element. This method must * be called only after a START_ELEMENT event has been notified. In the case of a top-level * START_ELEMENT event (that is, an element that either has no parent node, or whose parent * is not included in the sequence being read), the NamespaceDeclarations object returned * will contain a namespace declaration for each namespace that is in-scope for this element * node. In the case of a non-top-level element, the NamespaceDeclarations will contain * a set of namespace declarations and undeclarations, representing the differences between * this element and its parent. *

    *

    It is permissible for this method to return namespace declarations that are redundant.

    *

    *

    The NamespaceDeclarations object is guaranteed to remain unchanged until the next START_ELEMENT * event, but may then be overwritten. The object should not be modified by the client.

    *

    *

    Namespaces may be read before or after reading the attributes of an element, * but must not be read after the first child node has been read, or after calling * one of the methods skipToEnd(), getStringValue(), or getTypedValue().

    * */ public NamespaceDeclarations getNamespaceDeclarations() throws XPathException { return base.getNamespaceDeclarations(); } /** * Skip the current subtree. This method may be called only immediately after * a START_DOCUMENT or START_ELEMENT event. This call returns the matching * END_DOCUMENT or END_ELEMENT event; the next call on next() will return * the event following the END_DOCUMENT or END_ELEMENT. */ public int skipToMatchingEnd() throws XPathException { return base.skipToMatchingEnd(); } /** * Close the event reader. This indicates that no further events are required. * It is not necessary to close an event reader after {@link #END_OF_INPUT} has * been reported, but it is recommended to close it if reading terminates * prematurely. Once an event reader has been closed, the effect of further * calls on next() is undefined. */ public void close() { base.close(); } /** * Get the nameCode identifying the name of the current node. This method * can be used after the {@link #START_ELEMENT}, {@link #PROCESSING_INSTRUCTION}, * {@link #ATTRIBUTE}, or {@link #NAMESPACE} events. With some PullProvider implementations, * it can also be used after {@link #END_ELEMENT}, but this is not guaranteed: a client who * requires the information at that point (for example, to do serialization) should insert an * {@link ElementNameTracker} into the pipeline. * If called at other times, the result is undefined and may result in an IllegalStateException. * If called when the current node is an unnamed namespace node (a node representing the default namespace) * the returned value is -1. * * @return the nameCode. The nameCode can be used to obtain the prefix, local name, * and namespace URI from the name pool. */ public int getNameCode() { return base.getNameCode(); } /** * Get the fingerprint of the name of the element. This is similar to the nameCode, except that * it does not contain any information about the prefix: so two elements with the same fingerprint * have the same name, excluding prefix. This method * can be used after the {@link #START_ELEMENT}, {@link #END_ELEMENT}, {@link #PROCESSING_INSTRUCTION}, * {@link #ATTRIBUTE}, or {@link #NAMESPACE} events. * If called at other times, the result is undefined and may result in an IllegalStateException. * If called when the current node is an unnamed namespace node (a node representing the default namespace) * the returned value is -1. * * @return the fingerprint. The fingerprint can be used to obtain the local name * and namespace URI from the name pool. */ public int getFingerprint() { return base.getFingerprint(); } /** * Get the string value of the current element, text node, processing-instruction, * or top-level attribute or namespace node, or atomic value. *

    *

    In other situations the result is undefined and may result in an IllegalStateException.

    *

    *

    If the most recent event was a {@link #START_ELEMENT}, this method causes the content * of the element to be read. The next event notified will be the corresponding {@link #END_ELEMENT}.

    * * @return the String Value of the node in question, defined according to the rules in the * XPath data model. */ public CharSequence getStringValue() throws XPathException { return base.getStringValue(); } /** * Get an atomic value. This call may be used only when the last event reported was * ATOMIC_VALUE. This indicates that the PullProvider is reading a sequence that contains * a free-standing atomic value; it is never used when reading the content of a node. */ public AtomicValue getAtomicValue() { return base.getAtomicValue(); } /** * Get the type annotation of the current attribute or element node, or atomic value. * The result of this method is undefined unless the most recent event was START_ELEMENT, * ATTRIBUTE, or ATOMIC_VALUE. * * @return the type annotation. This code is the fingerprint of a type name, which may be * resolved to a {@link net.sf.saxon.type.SchemaType} by access to the Configuration. */ public int getTypeAnnotation() { return base.getTypeAnnotation(); } /** * Get the location of the current event. * For an event stream representing a real document, the location information * should identify the location in the lexical XML source. For a constructed document, it should * identify the location in the query or stylesheet that caused the node to be created. * A value of null can be returned if no location information is available. */ public SourceLocator getSourceLocator() { return base.getSourceLocator(); } /** * Get a list of unparsed entities. * * @return a list of unparsed entities, or null if the information is not available, or * an empty list if there are no unparsed entities. */ public List getUnparsedEntities() { return base.getUnparsedEntities(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/pull/StaxBridge.java0000644000175000017500000012762311142322742021270 0ustar eugeneeugenepackage net.sf.saxon.pull; import net.sf.saxon.Configuration; import net.sf.saxon.event.*; import net.sf.saxon.expr.ExpressionLocation; import net.sf.saxon.om.*; import net.sf.saxon.tinytree.CharSlice; import net.sf.saxon.tinytree.CompressedWhitespace; import net.sf.saxon.trans.SaxonErrorCode; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.AtomicValue; import net.sf.saxon.value.Whitespace; import javax.xml.stream.*; import javax.xml.stream.events.EntityDeclaration; import javax.xml.transform.SourceLocator; import javax.xml.transform.TransformerException; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.List; import java.util.Properties; /** * This class implements the Saxon PullProvider API on top of a standard StAX parser * (or any other StAX XMLStreamReader implementation) */ public class StaxBridge implements PullProvider, SaxonLocator, SourceLocationProvider { private XMLStreamReader reader; private StaxAttributes attributes = new StaxAttributes(); private StaxNamespaces namespaces = new StaxNamespaces(); private PipelineConfiguration pipe; private List unparsedEntities = null; int currentEvent = START_OF_INPUT; int depth = 0; boolean ignoreIgnorable = false; /** * Create a new instance of the class */ public StaxBridge() { } /** * Supply an input stream containing XML to be parsed. A StAX parser is created using * the JAXP XMLInputFactory. * @param systemId The Base URI of the input document * @param inputStream the stream containing the XML to be parsed * @throws XPathException if an error occurs creating the StAX parser */ public void setInputStream(String systemId, InputStream inputStream) throws XPathException { try { XMLInputFactory factory = XMLInputFactory.newInstance(); //XMLInputFactory factory = new WstxInputFactory(); factory.setXMLReporter(new StaxErrorReporter()); reader = factory.createXMLStreamReader(systemId, inputStream); } catch (XMLStreamException e) { throw new XPathException(e); } } /** * Supply an XMLStreamReader: the events reported by this XMLStreamReader will be translated * into PullProvider events * @param reader the supplier of XML events, typically an XML parser */ public void setXMLStreamReader(XMLStreamReader reader) { this.reader = reader; } /** * Set configuration information. This must only be called before any events * have been read. */ public void setPipelineConfiguration(PipelineConfiguration pipe) { this.pipe = new PipelineConfiguration(pipe); this.pipe.setLocationProvider(this); ignoreIgnorable = pipe.getConfiguration().getStripsWhiteSpace() != Whitespace.NONE; } /** * Get configuration information. */ public PipelineConfiguration getPipelineConfiguration() { return pipe; } /** * Get the XMLStreamReader used by this StaxBridge. This is available only after * setInputStream() or setXMLStreamReader() has been called * @return the instance of XMLStreamReader allocated when setInputStream() was called, * or the instance supplied directly to setXMLStreamReader() */ public XMLStreamReader getXMLStreamReader() { return reader; } /** * Get the name pool * @return the name pool */ public NamePool getNamePool() { return pipe.getConfiguration().getNamePool(); } /** * Get the next event * * @return an integer code indicating the type of event. The code * {@link #END_OF_INPUT} is returned at the end of the sequence. */ public int next() throws XPathException { if (currentEvent == START_OF_INPUT) { // StAX isn't reporting START_DOCUMENT so we supply it ourselves currentEvent = START_DOCUMENT; return currentEvent; } if (currentEvent == END_OF_INPUT || currentEvent == END_DOCUMENT) { try { reader.close(); } catch (XMLStreamException e) { // } return END_OF_INPUT; } try { if (reader.hasNext()) { int event = reader.next(); //System.err.println("Read event " + event); currentEvent = translate(event); } else { currentEvent = END_OF_INPUT; } } catch (XMLStreamException e) { String message = e.getMessage(); // Following code recognizes the messages produced by the Sun Zephyr parser if (message.startsWith("ParseError at")) { int c = message.indexOf("\nMessage: "); if (c > 0) { message = message.substring(c + 10); } } XPathException err = new XPathException("Error reported by XML parser: " + message); err.setErrorCode(SaxonErrorCode.SXXP0003); err.setLocator(translateLocation(e.getLocation())); throw err; } return currentEvent; } private int translate(int event) throws XPathException { //System.err.println("EVENT " + event); switch (event) { case XMLStreamConstants.ATTRIBUTE: return ATTRIBUTE; case XMLStreamConstants.CDATA: return TEXT; case XMLStreamConstants.CHARACTERS: if (depth == 0 && reader.isWhiteSpace()) { return next(); // } else if (reader.isWhiteSpace()) { // return next(); } else { // System.err.println("TEXT[" + new String(reader.getTextCharacters(), reader.getTextStart(), reader.getTextLength()) + "]"); // System.err.println(" ARRAY length " + reader.getTextCharacters().length + "[" + new String(reader.getTextCharacters(), 0, reader.getTextStart() + reader.getTextLength()) + "]"); // System.err.println(" START: " + reader.getTextStart() + " LENGTH " + reader.getTextLength()); return TEXT; } case XMLStreamConstants.COMMENT: return COMMENT; case XMLStreamConstants.DTD: unparsedEntities = (List)reader.getProperty("javax.xml.stream.entities"); return next(); case XMLStreamConstants.END_DOCUMENT: return END_DOCUMENT; case XMLStreamConstants.END_ELEMENT: depth--; return END_ELEMENT; case XMLStreamConstants.ENTITY_DECLARATION: return next(); case XMLStreamConstants.ENTITY_REFERENCE: return next(); case XMLStreamConstants.NAMESPACE: return NAMESPACE; case XMLStreamConstants.NOTATION_DECLARATION: return next(); case XMLStreamConstants.PROCESSING_INSTRUCTION: return PROCESSING_INSTRUCTION; case XMLStreamConstants.SPACE: if (depth == 0) { return next(); } else if (ignoreIgnorable) { // (Brave attempt, but Woodstox doesn't seem to report ignorable whitespace) return next(); } else { return TEXT; } case XMLStreamConstants.START_DOCUMENT: return next(); // we supplied the START_DOCUMENT ourselves //return START_DOCUMENT; case XMLStreamConstants.START_ELEMENT: depth++; return START_ELEMENT; default: throw new IllegalStateException("Unknown StAX event " + event); } } /** * Get the event most recently returned by next(), or by other calls that change * the position, for example getStringValue() and skipToMatchingEnd(). This * method does not change the position of the PullProvider. * * @return the current event */ public int current() { return currentEvent; } /** * Get the attributes associated with the current element. This method must * be called only after a START_ELEMENT event has been notified. The contents * of the returned AttributeCollection are guaranteed to remain unchanged * until the next START_ELEMENT event, but may be modified thereafter. The object * should not be modified by the client. *

    *

    Attributes may be read before or after reading the namespaces of an element, * but must not be read after the first child node has been read, or after calling * one of the methods skipToEnd(), getStringValue(), or getTypedValue().

    * * @return an AttributeCollection representing the attributes of the element * that has just been notified. */ public AttributeCollection getAttributes() throws XPathException { return attributes; } /** * Get the namespace declarations associated with the current element. This method must * be called only after a START_ELEMENT event has been notified. In the case of a top-level * START_ELEMENT event (that is, an element that either has no parent node, or whose parent * is not included in the sequence being read), the NamespaceDeclarations object returned * will contain a namespace declaration for each namespace that is in-scope for this element * node. In the case of a non-top-level element, the NamespaceDeclarations will contain * a set of namespace declarations and undeclarations, representing the differences between * this element and its parent. *

    *

    It is permissible for this method to return namespace declarations that are redundant.

    *

    *

    The NamespaceDeclarations object is guaranteed to remain unchanged until the next START_ELEMENT * event, but may then be overwritten. The object should not be modified by the client.

    *

    *

    Namespaces may be read before or after reading the attributes of an element, * but must not be read after the first child node has been read, or after calling * one of the methods skipToEnd(), getStringValue(), or getTypedValue().

    * */ public NamespaceDeclarations getNamespaceDeclarations() throws XPathException { return namespaces; } /** * Skip the current subtree. This method may be called only immediately after * a START_DOCUMENT or START_ELEMENT event. This call returns the matching * END_DOCUMENT or END_ELEMENT event; the next call on next() will return * the event following the END_DOCUMENT or END_ELEMENT. */ public int skipToMatchingEnd() throws XPathException { switch (currentEvent) { case START_DOCUMENT: currentEvent = END_DOCUMENT; return currentEvent; case START_ELEMENT: try { int skipDepth = 0; while (reader.hasNext()) { int event = reader.next(); if (event == XMLStreamConstants.START_ELEMENT) { skipDepth++; } else if (event == XMLStreamConstants.END_ELEMENT) { if (skipDepth-- == 0) { currentEvent = END_ELEMENT; return currentEvent; } } } } catch (XMLStreamException e) { throw new XPathException(e); } throw new IllegalStateException( "Element start has no matching element end"); default: throw new IllegalStateException( "Cannot call skipToMatchingEnd() except when at start of element or document"); } } /** * Close the event reader. This indicates that no further events are required. * It is not necessary to close an event reader after {@link #END_OF_INPUT} has * been reported, but it is recommended to close it if reading terminates * prematurely. Once an event reader has been closed, the effect of further * calls on next() is undefined. */ public void close() { try { reader.close(); } catch (XMLStreamException e) { // } } /** * Get the nameCode identifying the name of the current node. This method * can be used after the {@link #START_ELEMENT}, {@link #PROCESSING_INSTRUCTION}, * {@link #ATTRIBUTE}, or {@link #NAMESPACE} events. With some PullProvider implementations, * including this one, it can also be used after {@link #END_ELEMENT}. * If called at other times, the result is undefined and may result in an IllegalStateException. * If called when the current node is an unnamed namespace node (a node representing the default namespace) * the returned value is -1. * * @return the nameCode. The nameCode can be used to obtain the prefix, local name, * and namespace URI from the name pool. */ public int getNameCode() { if (currentEvent == START_ELEMENT || currentEvent == END_ELEMENT) { String local = reader.getLocalName(); String uri = reader.getNamespaceURI(); String prefix = reader.getPrefix(); if (prefix==null) { prefix = ""; } if (uri == null) { uri = ""; } return getNamePool().allocate(prefix, uri, local); //TODO: keep a local cache as in ReceivingContentHandler } else if (currentEvent == PROCESSING_INSTRUCTION) { String local = reader.getPITarget(); return getNamePool().allocate("", "", local); } else { throw new IllegalStateException(); } } /** * Get the fingerprint of the name of the element. This is similar to the nameCode, except that * it does not contain any information about the prefix: so two elements with the same fingerprint * have the same name, excluding prefix. This method * can be used after the {@link #START_ELEMENT}, {@link #PROCESSING_INSTRUCTION}, * {@link #ATTRIBUTE}, or {@link #NAMESPACE} events. * If called at other times, the result is undefined and may result in an IllegalStateException. * If called when the current node is an unnamed namespace node (a node representing the default namespace) * the returned value is -1. * * @return the fingerprint. The fingerprint can be used to obtain the local name * and namespace URI from the name pool. */ public int getFingerprint() { int nc = getNameCode(); if (nc == -1) { return -1; } else { return nc & NamePool.FP_MASK; } } /** * Get the string value of the current element, text node, processing-instruction, * or top-level attribute or namespace node, or atomic value. *

    *

    In other situations the result is undefined and may result in an IllegalStateException.

    *

    *

    If the most recent event was a {@link #START_ELEMENT}, this method causes the content * of the element to be read. The current event on completion of this method will be the * corresponding {@link #END_ELEMENT}. The next call of next() will return the event following * the END_ELEMENT event.

    * * @return the String Value of the node in question, defined according to the rules in the * XPath data model. */ public CharSequence getStringValue() throws XPathException { switch (currentEvent) { case TEXT: CharSlice cs = new CharSlice(reader.getTextCharacters(), reader.getTextStart(), reader.getTextLength()); return CompressedWhitespace.compress(cs); case COMMENT: return new CharSlice(reader.getTextCharacters(), reader.getTextStart(), reader.getTextLength()); case PROCESSING_INSTRUCTION: String s = reader.getPIData(); // The BEA parser includes the separator space in the value, // which isn't part of the XPath data model return Whitespace.removeLeadingWhitespace(s); case START_ELEMENT: FastStringBuffer combinedText = null; try { int depth = 0; while (reader.hasNext()) { int event = reader.next(); if (event == XMLStreamConstants.CHARACTERS) { if (combinedText == null) { combinedText = new FastStringBuffer(1024); } combinedText.append( reader.getTextCharacters(), reader.getTextStart(), reader.getTextLength()); } else if (event == XMLStreamConstants.START_ELEMENT) { depth++; } else if (event == XMLStreamConstants.END_ELEMENT) { if (depth-- == 0) { currentEvent = END_ELEMENT; if (combinedText != null) { return combinedText.condense(); } else { return ""; } } } } } catch (XMLStreamException e) { throw new XPathException(e); } default: throw new IllegalStateException("getStringValue() called when current event is " + currentEvent); } } /** * Get an atomic value. This call may be used only when the last event reported was * ATOMIC_VALUE. This indicates that the PullProvider is reading a sequence that contains * a free-standing atomic value; it is never used when reading the content of a node. */ public AtomicValue getAtomicValue() { throw new IllegalStateException(); } /** * Get the location of the current event. The location is returned as an integer. * This is a value that can be passed to the {@link net.sf.saxon.event.LocationProvider} * held by the {@link net.sf.saxon.event.PipelineConfiguration} to get real location information (line number, * system Id, etc). For an event stream representing a real document, the location information * should identify the location in the lexical XML source. For a constructed document, it should * identify the location in the query or stylesheet that caused the node to be created. * A value of zero can be returned if no location information is available. * @return the location ID */ public int getLocationId() { return 0; } /** * Get the type annotation of the current attribute or element node, or atomic value. * The result of this method is undefined unless the most recent event was START_ELEMENT, * ATTRIBUTE, or ATOMIC_VALUE. * * @return the type annotation. This code is the fingerprint of a type name, which may be * resolved to a {@link net.sf.saxon.type.SchemaType} by access to the Configuration. */ public int getTypeAnnotation() { return -1; } /** * Get the location of the current event. * For an event stream representing a real document, the location information * should identify the location in the lexical XML source. For a constructed document, it should * identify the location in the query or stylesheet that caused the node to be created. * A value of null can be returned if no location information is available. */ public SourceLocator getSourceLocator() { return translateLocation(reader.getLocation()); } /** * Translate a StAX Location object to a Saxon Locator * @param location the StAX Location object * @return a Saxon/SAX SourceLocator object */ private ExpressionLocation translateLocation(Location location) { ExpressionLocation loc = new ExpressionLocation(); if (location != null) { loc.setLineNumber(location.getLineNumber()); loc.setColumnNumber(location.getColumnNumber()); loc.setSystemId(location.getSystemId()); //loc.setPublicId(location.getPublicId()); } return loc; } /** * Implement the Saxon AttributeCollection interface over the StAX interface. */ private class StaxAttributes implements AttributeCollection { /** * Set the location provider. This must be set if the methods getSystemId() and getLineNumber() * are to be used to get location information for an attribute. * @param provider the location provider */ public void setLocationProvider(LocationProvider provider) { } /** * Return the number of attributes in the list. * * @return The number of attributes in the list. */ public int getLength() { return reader.getAttributeCount(); } /** * Get the namecode of an attribute (by position). * * @param index The position of the attribute in the list. * @return The namecode of the attribute */ public int getNameCode(int index) { String local = reader.getAttributeLocalName(index); String uri = reader.getAttributeNamespace(index); String prefix = reader.getAttributePrefix(index); if (prefix == null) { prefix = ""; } if (uri == null) { uri = ""; } return getNamePool().allocate(prefix, uri, local); // TODO: the JavaDoc for XMLStreamReader doesn't say what happens if index is out of range. // The interface definition for PullProvider states that null/-1 is returned. } /** * Get the type annotation of an attribute (by position). * * @param index The position of the attribute in the list. * @return The type annotation, as the fingerprint of the type name. * The bit {@link NodeInfo#IS_DTD_TYPE} represents a DTD-derived type. */ public int getTypeAnnotation(int index) { String type = reader.getAttributeType(index); if ("ID".equals(type)) { return StandardNames.XS_ID | NodeInfo.IS_DTD_TYPE; } return StandardNames.XS_UNTYPED_ATOMIC; } /** * Get the locationID of an attribute (by position) * * @param index The position of the attribute in the list. * @return The location identifier of the attribute. This can be supplied * to a {@link net.sf.saxon.event.LocationProvider} in order to obtain the * actual system identifier and line number of the relevant location */ public int getLocationId(int index) { return 0; } /** * Get the systemId part of the location of an attribute, at a given index. *

    *

    Attribute location information is not available from a SAX parser, so this method * is not useful for getting the location of an attribute in a source document. However, * in a Saxon result document, the location information represents the location in the * stylesheet of the instruction used to generate this attribute, which is useful for * debugging.

    * * @param index the required attribute * @return the systemId of the location of the attribute */ public String getSystemId(int index) { return reader.getLocation().getSystemId(); } /** * Get the line number part of the location of an attribute, at a given index. *

    *

    Attribute location information is not available from a SAX parser, so this method * is not useful for getting the location of an attribute in a source document. However, * in a Saxon result document, the location information represents the location in the * stylesheet of the instruction used to generate this attribute, which is useful for * debugging.

    * * @param index the required attribute * @return the line number of the location of the attribute */ public int getLineNumber(int index) { return reader.getLocation().getLineNumber(); } /** * Get the properties of an attribute (by position) * * @param index The position of the attribute in the list. * @return The properties of the attribute. This is a set * of bit-settings defined in class {@link net.sf.saxon.event.ReceiverOptions}. The * most interesting of these is {{@link net.sf.saxon.event.ReceiverOptions#DEFAULTED_ATTRIBUTE}, * which indicates an attribute that was added to an element as a result of schema validation. */ public int getProperties(int index) { int properties = 0; if (!reader.isAttributeSpecified(index)) { properties |= ReceiverOptions.DEFAULTED_ATTRIBUTE; } if (isIdref(index)) { properties |= (ReceiverOptions.IS_IDREF | ReceiverOptions.ID_IDREF_CHECKED); } return properties; } /** * Get the prefix of the name of an attribute (by position). * * @param index The position of the attribute in the list. * @return The prefix of the attribute name as a string, or null if there * is no attribute at that position. Returns "" for an attribute that * has no prefix. */ public String getPrefix(int index) { return getNamePool().getPrefix(getNameCode(index)); } /** * Get the lexical QName of an attribute (by position). * * @param index The position of the attribute in the list. * @return The lexical QName of the attribute as a string, or null if there * is no attribute at that position. */ public String getQName(int index) { return getNamePool().getDisplayName(getNameCode(index)); } /** * Get the local name of an attribute (by position). * * @param index The position of the attribute in the list. * @return The local name of the attribute as a string, or null if there * is no attribute at that position. */ public String getLocalName(int index) { return reader.getAttributeLocalName(index); } /** * Get the namespace URI of an attribute (by position). * * @param index The position of the attribute in the list. * @return The local name of the attribute as a string, or null if there * is no attribute at that position. */ public String getURI(int index) { return reader.getAttributeNamespace(index); } /** * Get the index of an attribute (by name). * * @param uri The namespace uri of the attribute. * @param localname The local name of the attribute. * @return The index position of the attribute */ public int getIndex(String uri, String localname) { for (int i=0; i *

    The return value is the public identifier of the document * entity or of the external parsed entity in which the markup * triggering the event appears.

    * * @return A string containing the public identifier, or * null if none is available. * @see #getSystemId */ public String getPublicId() { return reader.getLocation().getPublicId(); } /** * Return the system identifier for the current document event. *

    *

    The return value is the system identifier of the document * entity or of the external parsed entity in which the markup * triggering the event appears.

    *

    *

    If the system identifier is a URL, the parser must resolve it * fully before passing it to the application. For example, a file * name must always be provided as a file:... URL, and other * kinds of relative URI are also resolved against their bases.

    * * @return A string containing the system identifier, or null * if none is available. * @see #getPublicId */ public String getSystemId() { Location location = reader.getLocation(); return (location==null ? null : location.getSystemId()); } /** * Return the line number where the current document event ends. * Lines are delimited by line ends, which are defined in * the XML specification. *

    *

    Warning: The return value from the method * is intended only as an approximation for the sake of diagnostics; * it is not intended to provide sufficient information * to edit the character content of the original XML document. * In some cases, these "line" numbers match what would be displayed * as columns, and in others they may not match the source text * due to internal entity expansion.

    *

    *

    The return value is an approximation of the line number * in the document entity or external parsed entity where the * markup triggering the event appears.

    *

    *

    If possible, the SAX driver should provide the line position * of the first character after the text associated with the document * event. The first line is line 1.

    * * @return The line number, or -1 if none is available. * @see #getColumnNumber */ public int getLineNumber() { Location location = reader.getLocation(); return (location==null ? -1 : location.getLineNumber()); } /** * Return the column number where the current document event ends. * This is one-based number of Java char values since * the last line end. *

    *

    Warning: The return value from the method * is intended only as an approximation for the sake of diagnostics; * it is not intended to provide sufficient information * to edit the character content of the original XML document. * For example, when lines contain combining character sequences, wide * characters, surrogate pairs, or bi-directional text, the value may * not correspond to the column in a text editor's display.

    *

    *

    The return value is an approximation of the column number * in the document entity or external parsed entity where the * markup triggering the event appears.

    *

    *

    If possible, the SAX driver should provide the line position * of the first character after the text associated with the document * event. The first column in each line is column 1.

    * * @return The column number, or -1 if none is available. * @see #getLineNumber */ public int getColumnNumber() { return reader.getLocation().getColumnNumber(); } public String getSystemId(long locationId) { return getSystemId(); } public int getLineNumber(long locationId) { return getLineNumber(); } public int getColumnNumber(long locationId) { return getColumnNumber(); } /** * Get a list of unparsed entities. * * @return a list of unparsed entities, or null if the information is not available, or * an empty list if there are no unparsed entities. Each item in the list will * be an instance of {@link net.sf.saxon.pull.UnparsedEntity} */ public List getUnparsedEntities() { if (unparsedEntities == null) { return null; } List list = new ArrayList(unparsedEntities.size()); for (int i=0; i 1) { emitter.setOutputStream(new FileOutputStream(args[1])); } else { emitter.setOutputStream(System.out); } NamespaceReducer r = new NamespaceReducer(); r.setUnderlyingReceiver(emitter); puller.setPipelineConfiguration(pipe); r.setPipelineConfiguration(pipe); new PullPushCopier(puller, r).copy(); System.err.println("Elapsed time: " + (System.currentTimeMillis() - startTime) + "ms"); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/pull/ElementNameTracker.java0000644000175000017500000000626311033112257022733 0ustar eugeneeugenepackage net.sf.saxon.pull; import net.sf.saxon.trans.XPathException; /** * This is a filter that can be added to a pull pipeline to remember element names so that * they are available immediately after the END_ELEMENT event is notified */ public class ElementNameTracker extends PullFilter { private int[] namestack = new int[20]; int used = 0; int elementJustEnded = -1; public ElementNameTracker(PullProvider base) { super(base); } /** * Get the next event. *

    *

    Note that a subclass that overrides this method is responsible for ensuring * that current() works properly. This can be achieved by setting the field * currentEvent to the event returned by any call on next().

    * * @return an integer code indicating the type of event. The code * {@link #END_OF_INPUT} is returned at the end of the sequence. */ public int next() throws XPathException { currentEvent = super.next(); if (currentEvent == START_ELEMENT) { int nc = getNameCode(); if (used >= namestack.length) { int[] n2 = new int[used*2]; System.arraycopy(namestack, 0, n2, 0, used); namestack = n2; } namestack[used++] = nc; } else if (currentEvent == END_ELEMENT) { elementJustEnded = namestack[--used]; } return currentEvent; } /** * Get the nameCode identifying the name of the current node. This method * can be used after the {@link #START_ELEMENT}, {@link #PROCESSING_INSTRUCTION}, * {@link #ATTRIBUTE}, or {@link #NAMESPACE} events. With some PullProvider implementations, * including this one, it can also be used after {@link #END_ELEMENT}: in fact, that is the * main purpose of this class. * If called at other times, the result is undefined and may result in an IllegalStateException. * If called when the current node is an unnamed namespace node (a node representing the default namespace) * the returned value is -1. * * @return the nameCode. The nameCode can be used to obtain the prefix, local name, * and namespace URI from the name pool. */ public int getNameCode() { if (currentEvent == END_ELEMENT) { return elementJustEnded; } else { return super.getNameCode(); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/pull/PullSource.java0000644000175000017500000000516311033112257021320 0ustar eugeneeugenepackage net.sf.saxon.pull; import javax.xml.transform.Source; /** * A PullSource is a JAXP Source that encapsulates a PullProvider - that is, an object * that supplies an XML document as a sequence of events that are read under the control * of the recipient. Note that although PullSource implements the JAXP Source interface, * it is not necessarily acceptable to every JAXP implementation that accepts a Source * as input: Source is essentially a marker interface and users of Source objects need * to understand the individual implementation. */ public class PullSource implements Source { private String systemId; private PullProvider provider; /** * Create a PullSource based on a supplied PullProvider * @param provider the underlying PullProvider */ public PullSource(PullProvider provider) { this.provider = provider; if (provider.getSourceLocator() != null) { systemId = provider.getSourceLocator().getSystemId(); } } /** * Get the PullProvider * @return the underlying PullProvider */ public PullProvider getPullProvider() { return provider; } /** * Set the system identifier for this Source. *

    *

    The system identifier is optional if the source does not * get its data from a URL, but it may still be useful to provide one. * The application can use a system identifier, for example, to resolve * relative URIs and to include in error messages and warnings.

    * * @param systemId The system identifier as a URL string. */ public void setSystemId(String systemId) { this.systemId = systemId; } /** * Get the system identifier that was set with setSystemId. * * @return The system identifier that was set with setSystemId, or null * if setSystemId was not called. */ public String getSystemId() { return systemId; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/pull/UnconstructedElement.java0000644000175000017500000000545711033112257023403 0ustar eugeneeugenepackage net.sf.saxon.pull; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.instruct.ElementCreator; import net.sf.saxon.type.Type; /** * An element node whose construction is deferred. */ public class UnconstructedElement extends UnconstructedParent { private int nameCode; /** * Create an unconstructed (pending) element node * @param instruction the instruction responsible for creating the node * @param context the XPath dynamic context */ public UnconstructedElement(ElementCreator instruction, XPathContext context) { super(instruction, context); } /** * Set the name of the element node * @param nameCode the namepool code for the element name */ public void setNameCode(int nameCode) { this.nameCode = nameCode; } /** * Get name code. The name code is a coded form of the node name: two nodes * with the same name code have the same namespace URI, the same local name, * and the same prefix. By masking the name code with &0xfffff, you get a * fingerprint: two nodes with the same fingerprint have the same local name * and namespace URI. * * @return an integer name code, which may be used to obtain the actual node * name from the name pool * @see net.sf.saxon.om.NamePool#allocate allocate * @see net.sf.saxon.om.NamePool#getFingerprint getFingerprint */ public int getNameCode() { return nameCode; } public int getNodeKind() { return Type.ELEMENT; } /** * Get the Base URI for the node, that is, the URI used for resolving a relative URI contained * in the node. This will be the same as the System ID unless xml:base has been used. * * @return the base URI of the node */ public String getBaseURI() { if (node == null) { // we need to construct the element because it might have an xml:base attribute tryToConstruct(); } return node.getBaseURI(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/pull/PullPushCopier.java0000644000175000017500000000415111033112257022135 0ustar eugeneeugenepackage net.sf.saxon.pull; import net.sf.saxon.event.Receiver; import net.sf.saxon.trans.XPathException; /** * This class copies a document by using the pull interface to read the input document, * and the push interface to write the output document. */ public class PullPushCopier { private PullProvider in; private Receiver out; /** * Create a PullPushCopier * @param in a PullProvider from which events will be read * @param out a Receiver to which copies of the same events will be written */ public PullPushCopier(PullProvider in, Receiver out) { this.out = out; this.in = in; } /** * Copy the input to the output. This method will open the output Receiver before appending to * it, and will close it afterwards. * @throws XPathException */ public void copy() throws XPathException { out.open(); PullPushTee tee = new PullPushTee(in, out); new PullConsumer(tee).consume(); out.close(); } /** * Copy the input to the output. This method relies on the caller to open the output Receiver before * use and to close it afterwards. * @throws XPathException */ public void append() throws XPathException { PullPushTee tee = new PullPushTee(in, out); new PullConsumer(tee).consume(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/pull/PullProvider.java0000644000175000017500000004035011033112257021647 0ustar eugeneeugenepackage net.sf.saxon.pull; import net.sf.saxon.event.PipelineConfiguration; import net.sf.saxon.om.AttributeCollection; import net.sf.saxon.om.NamespaceDeclarations; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.AtomicValue; import javax.xml.transform.SourceLocator; import java.util.List; /** * PullProvider is Saxon's pull-based interface for reading XML documents and XDM sequences. * A PullProvider can deliver any sequence of nodes or atomic values. An atomic value * in the sequence is delivered as a single event; a node is delivered as a sequence * of events equivalent to a recursive walk of the XML tree. Within this sequence, * the start and end of a document, or of an element, are delivered as separate * events; other nodes are delivered as individual events. */ public interface PullProvider { // Start by defining the different types of event /** * START_OF_INPUT is the initial state when the PullProvider is instantiated. * This event is never notified by the next() method, but it is returned * from a call of current() prior to the first call on next(). */ public static final int START_OF_INPUT = 0; /** * ATOMIC_VALUE is notified when the PullProvider is reading a sequence of items, * and one of the items is an atomic value rather than a node. This will always * be a top-level event (it will never be nested in Start/End Document or * Start/End Element). */ public static final int ATOMIC_VALUE = 1; /** * START_DOCUMENT is notified when a document node is encountered. This will * always be a top-level event (it will never be nested in Start/End Document or * Start/End Element). Note however that multiple document nodes can occur in * a sequence, and the start and end of each one will be notified. */ public static final int START_DOCUMENT = 2; /** * END_DOCUMENT is notified at the end of processing a document node, that is, * after all the descendants of the document node have been notified. The event * will always be preceded by the corresponding START_DOCUMENT event. */ public static final int END_DOCUMENT = 3; /** * START_ELEMENT is notified when an element node is encountered. This may either * be a top-level element (an element node that participates in the sequence being * read in its own right) or a nested element (reported because it is a descendant * of an element or document node that participates in the sequence.) * *

    Following the notification of START_ELEMENT, the client may obtain information * about the element node, such as its name and type annotation. The client may also * call getAttributes() to obtain information about the attributes of the element * node, and/or getNamespaceDeclarations() to get information about the namespace * declarations. The client may then do one of the following:

    * *
      *
    • Call skipToMatchingEnd() to move straight to the corresponding END_ELEMENT event (which * will then be the current event)
    • *
    • Call next(), repeatedly, to be notified of events relating to the children and * descendants of this element node
    • *
    • Call getStringValue() to obtain the string value of the element node, after which * the next event notified will be the corresponding END_ELEMENT event
    • *
    • Call getTypedValue() to obtain the typed value of the element node, after which * the next event notified will be the corresponding END_ELEMENT event
    • *
    */ public static final int START_ELEMENT = 4; /** * END_ELEMENT is notified at the end of an element node, that is, after all the children * and descendants of the element have either been processed or skipped. It may relate to * a top-level element, or to a nested element. For an empty element (one with no children) * the END_ELEMENT event will immediately follow the corresponding START_ELEMENT event. * No information (such as the element name) is available after an END_ELEMENT event: if the * client requires such information, it must remember it, typically on a Stack. */ public static final int END_ELEMENT = 5; /** * The ATTRIBUTE event is notified only for an attribute node that appears in its own right * as a top-level item in the sequence being read. ATTRIBUTE events are not notified for * the attributes of an element that has been notified: such attributes must be read using the * {@link #getAttributes()} method. */ public static final int ATTRIBUTE = 6; /** * The NAMESPACE event is notified only for a namespace node that appears in its own right * as a top-level item in the sequence being read. NAMESPACE events are not notified for * the namespaces of an element that has been notified: such attributes must be read using the * {@link #getNamespaceDeclarations()} method. */ public static final int NAMESPACE = 7; /** * A TEXT event is notified for a text node. This may either be a top-level text * node, or a text node nested within an element or document node. At the top level, * text nodes may be zero-length and may be consecutive in the sequence being read. * Nested within an element or document node, text nodes will never be zero-length, * and adjacent text nodes will have been coalesced into one. (This might not always * be true when reading third-party data models such as a DOM.) Whitespace-only * text nodes will be notified unless something has been done (e.g. xsl:strip-space) * to remove them. */ public static final int TEXT = 8; /** * A COMMENT event is notified for a comment node, which may be either a top-level * comment or one nested within an element or document node. */ public static final int COMMENT = 9; /** * A PROCESSING_INSTRUCTION event is notified for a processing instruction node, * which may be either a top-level comment or one nested within an element or document node. * As defined in the XPath data model, the "target" of a processing instruction is represented * as the node name (which only has a local part, no prefix or URI), and the "data" of the * processing instruction is represented as the string-value of the node. */ public static final int PROCESSING_INSTRUCTION = 10; /** * The END_OF_INPUT event is returned to indicate the end of the sequence being read. * After this event, the result of any further calls on the next() method is undefined. */ public static final int END_OF_INPUT = -1; /** * Set configuration information. This must only be called before any events * have been read. * @param pipe the pipeline configuration */ public void setPipelineConfiguration(PipelineConfiguration pipe); /** * Get configuration information. * @return the pipeline configuration */ public PipelineConfiguration getPipelineConfiguration(); /** * Get the next event * @return an integer code indicating the type of event. The code * {@link #END_OF_INPUT} is returned at the end of the sequence. */ public int next() throws XPathException; /** * Get the event most recently returned by next(), or by other calls that change * the position, for example getStringValue() and skipToMatchingEnd(). This * method does not change the position of the PullProvider. * @return the current event */ public int current(); /** * Get the attributes associated with the current element. This method must * be called only after a START_ELEMENT event has been notified. The contents * of the returned AttributeCollection are guaranteed to remain unchanged * until the next START_ELEMENT event, but may be modified thereafter. The object * should not be modified by the client. * *

    Attributes may be read before or after reading the namespaces of an element, * but must not be read after the first child node has been read, or after calling * one of the methods skipToMatchingEnd(), getStringValue(), or getTypedValue().

    * * @return an AttributeCollection representing the attributes of the element * that has just been notified. */ public AttributeCollection getAttributes() throws XPathException; /** * Get the namespace declarations associated with the current element. This method must * be called only after a START_ELEMENT event has been notified. In the case of a top-level * START_ELEMENT event (that is, an element that either has no parent node, or whose parent * is not included in the sequence being read), the NamespaceDeclarations object returned * will contain a namespace declaration for each namespace that is in-scope for this element * node. In the case of a non-top-level element, the NamespaceDeclarations will contain * a set of namespace declarations and undeclarations, representing the differences between * this element and its parent. * *

    It is permissible for this method to return namespace declarations that are redundant.

    * *

    The NamespaceDeclarations object is guaranteed to remain unchanged until the next START_ELEMENT * event, but may then be overwritten. The object should not be modified by the client.

    * *

    Namespaces may be read before or after reading the attributes of an element, * but must not be read after the first child node has been read, or after calling * one of the methods skipToMatchingEnd(), getStringValue(), or getTypedValue().

    * * @return the namespace declarations associated with the current START_ELEMENT event. */ public NamespaceDeclarations getNamespaceDeclarations() throws XPathException; /** * Skip the current subtree. This method may be called only immediately after * a START_DOCUMENT or START_ELEMENT event. This call returns the matching * END_DOCUMENT or END_ELEMENT event; the next call on next() will return * the event following the END_DOCUMENT or END_ELEMENT. * @return the matching END_DOCUMENT or END_ELEMENT event * @throws IllegalStateException if the method is called at any time other than * immediately after a START_DOCUMENT or START_ELEMENT event. */ public int skipToMatchingEnd() throws XPathException; /** * Close the event reader. This indicates that no further events are required. * It is not necessary to close an event reader after {@link #END_OF_INPUT} has * been reported, but it is recommended to close it if reading terminates * prematurely. Once an event reader has been closed, the effect of further * calls on next() is undefined. */ public void close(); /** * Get the nameCode identifying the name of the current node. This method * can be used after the {@link #START_ELEMENT}, {@link #PROCESSING_INSTRUCTION}, * {@link #ATTRIBUTE}, or {@link #NAMESPACE} events. With some PullProvider implementations, * it can also be used after {@link #END_ELEMENT}, but this is not guaranteed: a client who * requires the information at that point (for example, to do serialization) should insert an * {@link ElementNameTracker} into the pipeline. * If called at other times, the result is undefined and may result in an IllegalStateException. * If called when the current node is an unnamed namespace node (a node representing the default namespace) * the returned value is -1. * @return the nameCode. The nameCode can be used to obtain the prefix, local name, * and namespace URI from the name pool. */ public int getNameCode(); /** * Get the fingerprint of the name of the element. This is similar to the nameCode, except that * it does not contain any information about the prefix: so two elements with the same fingerprint * have the same name, excluding prefix. This method * can be used after the {@link #START_ELEMENT}, {@link #END_ELEMENT}, {@link #PROCESSING_INSTRUCTION}, * {@link #ATTRIBUTE}, or {@link #NAMESPACE} events. * If called at other times, the result is undefined and may result in an IllegalStateException. * If called when the current node is an unnamed namespace node (a node representing the default namespace) * the returned value is -1. * @return the fingerprint. The fingerprint can be used to obtain the local name * and namespace URI from the name pool. */ public int getFingerprint(); /** * Get the string value of the current element, text node, processing-instruction, * or top-level attribute or namespace node, or atomic value. * *

    In other situations the result is undefined and may result in an IllegalStateException.

    * *

    If the most recent event was a {@link #START_ELEMENT}, this method causes the content * of the element to be read. The current event on completion of this method will be the * corresponding {@link #END_ELEMENT}. The next call of next() will return the event following * the END_ELEMENT event.

    * * @return the String Value of the node in question, defined according to the rules in the * XPath data model. */ public CharSequence getStringValue() throws XPathException; /** * Get the type annotation of the current attribute or element node, or atomic value. * The result of this method is undefined unless the most recent event was START_ELEMENT, * ATTRIBUTE, or ATOMIC_VALUE. In the case of an attribute node, the additional bit NodeInfo.IS_DTD_TYPE * may be set to indicate a DTD-derived ID or IDREF/S type. * * @return the type annotation. This code is the fingerprint of a type name, which may be * resolved to a {@link net.sf.saxon.type.SchemaType} by access to the Configuration. */ public int getTypeAnnotation(); /** * Get an atomic value. This call may be used only when the last event reported was * ATOMIC_VALUE. This indicates that the PullProvider is reading a sequence that contains * a free-standing atomic value; it is never used when reading the content of a node. * @return the atomic value */ public AtomicValue getAtomicValue(); /** * Get the location of the current event. * For an event stream representing a real document, the location information * should identify the location in the lexical XML source. For a constructed document, it should * identify the location in the query or stylesheet that caused the node to be created. * A value of null can be returned if no location information is available. * @return the SourceLocator giving the location of the current event, or null if * no location information is available */ public SourceLocator getSourceLocator(); /** * Get a list of unparsed entities. * @return a list of unparsed entities, or null if the information is not available, or * an empty list if there are no unparsed entities. Each item in the list will * be an instance of {@link net.sf.saxon.pull.UnparsedEntity} */ public List getUnparsedEntities(); } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/pull/UnconstructedDocument.java0000644000175000017500000001431211033112257023556 0ustar eugeneeugenepackage net.sf.saxon.pull; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.instruct.DocumentInstr; import net.sf.saxon.om.DocumentInfo; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.type.Type; import java.util.Iterator; import java.util.Collections; /** * A document node whose construction is deferred. *

    * (TODO) NOTE: this class is an exception to the general rule that for document nodes, node identity implies object identity */ public class UnconstructedDocument extends UnconstructedParent implements DocumentInfo { /** * Create an unconstructed (pending) document node * @param instruction the instruction responsible for creating the node * @param context the XPath dynamic context */ public UnconstructedDocument(DocumentInstr instruction, XPathContext context) { super(instruction, context); } /** * Get name code. The name code is a coded form of the node name: two nodes * with the same name code have the same namespace URI, the same local name, * and the same prefix. By masking the name code with &0xfffff, you get a * fingerprint: two nodes with the same fingerprint have the same local name * and namespace URI. * * @return an integer name code, which may be used to obtain the actual node * name from the name pool * @see net.sf.saxon.om.NamePool#allocate allocate * @see net.sf.saxon.om.NamePool#getFingerprint getFingerprint */ public int getNameCode() { return -1; } public int getNodeKind() { return Type.DOCUMENT; } /** * Get fingerprint. The fingerprint is a coded form of the expanded name * of the node: two nodes * with the same name code have the same namespace URI and the same local name. * A fingerprint of -1 should be returned for a node with no name. * * @return an integer fingerprint; two nodes with the same fingerprint have * the same expanded QName */ public int getFingerprint() { return -1; } /** * Get the local part of the name of this node. This is the name after the ":" if any. * * @return the local part of the name. For an unnamed node, returns "". Unlike the DOM * interface, this returns the full name in the case of a non-namespaced name. */ public String getLocalPart() { return ""; } /** * Get the URI part of the name of this node. This is the URI corresponding to the * prefix, or the URI of the default namespace if appropriate. * * @return The URI of the namespace of this node. For an unnamed node, * or for a node with an empty prefix, return an empty * string. */ public String getURI() { return ""; } /** * Get the display name of this node. For elements and attributes this is [prefix:]localname. * For unnamed nodes, it is an empty string. * * @return The display name of this node. For a node with no name, return * an empty string. */ public String getDisplayName() { return ""; } /** * Get the prefix of the name of the node. This is defined only for elements and attributes. * If the node has no prefix, or for other kinds of node, return a zero-length string. * * @return The prefix of the name of the node. */ public String getPrefix() { return ""; } /** * Get the root node, if it is a document node. * * @return the DocumentInfo representing the containing document. If this * node is part of a tree that does not have a document node as its * root, return null. */ public DocumentInfo getDocumentRoot() { return this; } /** * Get the element with a given ID, if any * * @param id the required ID value * @return the element with the given ID, or null if there is no such ID * present (or if the parser has not notified attributes as being of * type ID) * @since 8.4 */ public NodeInfo selectID(String id) { if (node == null) { tryToConstruct(); } return ((DocumentInfo)node).selectID(id); } /** * Get the list of unparsed entities defined in this document * @return an Iterator, whose items are of type String, containing the names of all * unparsed entities defined in this document. If there are no unparsed entities or if the * information is not available then an empty iterator is returned */ public Iterator getUnparsedEntityNames() { return Collections.EMPTY_LIST.iterator(); } /** * Get the unparsed entity with a given name * * @param name the name of the entity * @return if the entity exists, return an array of two Strings, the first * holding the system ID of the entity, the second holding the public * ID if there is one, or null if not. If the entity does not exist, * the method returns null. Applications should be written on the * assumption that this array may be extended in the future to provide * additional information. * @since 8.4 */ public String[] getUnparsedEntity(String name) { return null; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/pull/DocumentEventIgnorer.java0000644000175000017500000000334111033112257023325 0ustar eugeneeugenepackage net.sf.saxon.pull; import net.sf.saxon.trans.XPathException; /** * This is a filter that can be added to a pull pipeline to remove START_DOCUMENT and END_DOCUMENT * events. */ public class DocumentEventIgnorer extends PullFilter { public DocumentEventIgnorer(PullProvider base) { super(base); } /** * Get the next event. *

    *

    Note that a subclass that overrides this method is responsible for ensuring * that current() works properly. This can be achieved by setting the field * currentEvent to the event returned by any call on next().

    * * @return an integer code indicating the type of event. The code * {@link #END_OF_INPUT} is returned at the end of the sequence. */ public int next() throws XPathException { do { currentEvent = super.next(); } while (currentEvent == START_DOCUMENT || currentEvent == END_DOCUMENT); return currentEvent; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/pull/UnparsedEntity.java0000644000175000017500000000503411033112257022176 0ustar eugeneeugenepackage net.sf.saxon.pull; /** * This class is used to represent unparsed entities in the PullProvider interface */ public class UnparsedEntity { private String name; private String systemId; private String publicId; private String baseURI; /** * Get the name of the unparsed entity * @return the name of the unparsed entity */ public String getName() { return name; } /** * Set the name of the unparsed entity * @param name the name of the unparsed entity */ public void setName(String name) { this.name = name; } /** * Get the system identifier of the unparsed entity * @return the system identifier of the unparsed entity */ public String getSystemId() { return systemId; } /** * Set the system identifier of the unparsed entity * @param systemId the system identifier of the unparsed entity */ public void setSystemId(String systemId) { this.systemId = systemId; } /** * Get the public identifier of the unparsed entity * @return the public identifier of the unparsed entity */ public String getPublicId() { return publicId; } /** * Set the public identifier of the unparsed entity * @param publicId the public identifier of the unparsed entity */ public void setPublicId(String publicId) { this.publicId = publicId; } /** * Get the base URI of the unparsed entity * @return the base URI of the unparsed entity */ public String getBaseURI() { return baseURI; } /** * Set the base URI of the unparsed entity * @param baseURI the base URI of the unparsed entity */ public void setBaseURI(String baseURI) { this.baseURI = baseURI; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/pull/PullToStax.java0000644000175000017500000004375611163157015021321 0ustar eugeneeugenepackage net.sf.saxon.pull; import net.sf.saxon.expr.ExpressionLocation; import net.sf.saxon.om.AttributeCollection; import net.sf.saxon.om.FastStringBuffer; import net.sf.saxon.om.NamePool; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.Whitespace; import javax.xml.namespace.NamespaceContext; import javax.xml.namespace.QName; import javax.xml.stream.Location; import javax.xml.stream.XMLStreamConstants; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamReader; import javax.xml.transform.SourceLocator; /** * This class bridges PullProvider events to XMLStreamReader (Stax) events. That is, it acts * as an XMLStreamReader, fetching the underlying data from a PullProvider. *

    * A PullProvider may provide access to any XDM sequence, whereas an XMLStreamReader always * reads a document. The conversion of a sequence to a document follows the rules for * "normalizing" a sequence in the Serialization specification: for example, atomic values are * converted into text nodes, with adjacent atomic values being space-separated. */ public class PullToStax implements XMLStreamReader { private PullNamespaceReducer provider; private NamePool namePool; private boolean previousAtomic; private FastStringBuffer currentTextNode = new FastStringBuffer(100); private int currentStaxEvent = XMLStreamReader.START_DOCUMENT; private XPathException pendingException = null; /** * Create a PullToStax instance, which wraps a Saxon PullProvider as a Stax XMLStreamReader * @param provider the Saxon PullProvider from which the events will be read */ public PullToStax(PullProvider provider) { if (provider instanceof PullNamespaceReducer) { this.provider = (PullNamespaceReducer)provider; } else { this.provider = new PullNamespaceReducer(provider); } namePool = provider.getPipelineConfiguration().getConfiguration().getNamePool(); } public int getAttributeCount() { try { return provider.getAttributes().getLength(); } catch (XPathException e) { pendingException = e; return 0; } } public boolean isAttributeSpecified(int i) { return true; } public QName getAttributeName(int i) { try { AttributeCollection atts = provider.getAttributes(); return new QName(atts.getURI(i), atts.getLocalName(i), atts.getPrefix(i)); } catch (XPathException e) { pendingException = e; return new QName("http://saxon.sf.net/error", "error", ""); } } public String getAttributeLocalName(int i) { try { return provider.getAttributes().getLocalName(i); } catch (XPathException e) { pendingException = e; return "error"; } } public String getAttributeNamespace(int i) { try { return provider.getAttributes().getURI(i); } catch (XPathException e) { pendingException = e; return "http://saxon.sf.net/error"; } } public String getAttributePrefix(int i) { try { return provider.getAttributes().getPrefix(i); } catch (XPathException e) { pendingException = e; return ""; } } public String getAttributeType(int i) { try { AttributeCollection ac = provider.getAttributes(); if (ac.isId(i)) { return "ID"; } else if (ac.isIdref(i)) { return "IDREFS"; } else { return "CDATA"; } } catch (XPathException e) { pendingException = e; return "CDATA"; } } public String getAttributeValue(int i) { try { return provider.getAttributes().getValue(i); } catch (XPathException e) { pendingException = e; return "error"; } } public String getAttributeValue(String uri, String local) { try { return provider.getAttributes().getValue(uri, local); } catch (XPathException e) { pendingException = e; return ""; } } public int getEventType() { return currentStaxEvent; } public int getNamespaceCount() { try { return provider.getNamespaceDeclarations().getNumberOfNamespaces(); } catch (XPathException e) { pendingException = e; return 0; } } public String getText() { if (previousAtomic) { return currentTextNode.toString(); } else { try { return provider.getStringValue().toString(); } catch (XPathException e) { pendingException = e; return ""; } } } public int getTextLength() { if (previousAtomic) { return currentTextNode.length(); } else { try { return provider.getStringValue().length(); } catch (XPathException e) { pendingException = e; return 0; } } } public int getTextStart() { return 0; } public char[] getTextCharacters() { if (previousAtomic) { return currentTextNode.getCharArray(); } else { try { String stringValue = provider.getStringValue().toString(); char[] chars = new char[stringValue.length()]; stringValue.getChars(0, chars.length, chars, 0); return chars; } catch (XPathException e) { pendingException = e; return new char[0]; } } } public int getTextCharacters(int sourceStart, char[] target, int targetStart, int length) throws XMLStreamException { if (pendingException != null) { throw new XMLStreamException(pendingException); } if (previousAtomic) { int end = sourceStart + length; if (end > currentTextNode.length()) { end = currentTextNode.length(); } currentTextNode.getChars(sourceStart, end, target, targetStart); return end - sourceStart; } else { try { String stringValue = provider.getStringValue().subSequence(sourceStart, sourceStart + length).toString(); stringValue.getChars(0, length, target, targetStart); return length; } catch (XPathException e) { pendingException = e; return 0; } } } public int next() throws XMLStreamException { if (pendingException != null) { throw new XMLStreamException(pendingException); } int p; try { p = provider.next(); } catch (XPathException e) { throw new XMLStreamException(e); } switch (p) { case PullProvider.START_OF_INPUT: return next(); case PullProvider.ATOMIC_VALUE: currentTextNode.setLength(0); if (previousAtomic) { currentTextNode.append(' '); } currentTextNode.append(provider.getAtomicValue().getStringValue()); currentStaxEvent = XMLStreamConstants.CHARACTERS; break; case PullProvider.START_DOCUMENT: currentStaxEvent = XMLStreamConstants.START_DOCUMENT; return next(); case PullProvider.END_DOCUMENT: currentStaxEvent = XMLStreamConstants.END_DOCUMENT; break; case PullProvider.START_ELEMENT: currentStaxEvent = XMLStreamConstants.START_ELEMENT; break; case PullProvider.END_ELEMENT: currentStaxEvent = XMLStreamConstants.END_ELEMENT; break; case PullProvider.TEXT: currentStaxEvent = XMLStreamConstants.CHARACTERS; break; case PullProvider.COMMENT: currentStaxEvent = XMLStreamConstants.COMMENT; break; case PullProvider.PROCESSING_INSTRUCTION: currentStaxEvent = XMLStreamConstants.PROCESSING_INSTRUCTION; break; case PullProvider.END_OF_INPUT: currentStaxEvent = XMLStreamConstants.END_DOCUMENT; break; case PullProvider.ATTRIBUTE: throw new XMLStreamException("Free-standing attributes cannot be serialized"); case PullProvider.NAMESPACE: throw new XMLStreamException("Free-standing namespace nodes cannot be serialized"); default: throw new IllegalStateException("Unknown Stax event " + p); } previousAtomic = (p == PullProvider.ATOMIC_VALUE); return currentStaxEvent; } public int nextTag() throws XMLStreamException { if (pendingException != null) { throw new XMLStreamException(pendingException); } int eventType = next(); while ((eventType == XMLStreamConstants.CHARACTERS && isWhiteSpace()) // skip whitespace || (eventType == XMLStreamConstants.CDATA && isWhiteSpace()) // skip whitespace || eventType == XMLStreamConstants.SPACE || eventType == XMLStreamConstants.PROCESSING_INSTRUCTION || eventType == XMLStreamConstants.COMMENT ) { eventType = next(); } if (eventType != XMLStreamConstants.START_ELEMENT && eventType != XMLStreamConstants.END_ELEMENT) { throw new XMLStreamException("expected start or end tag", getLocation()); } return eventType; } public void close() throws XMLStreamException { if (pendingException != null) { throw new XMLStreamException(pendingException); } provider.close(); } public boolean hasName() { return currentStaxEvent == XMLStreamConstants.START_ELEMENT || currentStaxEvent == XMLStreamConstants.END_ELEMENT; } public boolean hasNext() throws XMLStreamException { if (pendingException != null) { throw new XMLStreamException(pendingException); } return currentStaxEvent != XMLStreamConstants.END_DOCUMENT; } public boolean hasText() { return currentStaxEvent == XMLStreamConstants.CHARACTERS || currentStaxEvent == XMLStreamConstants.COMMENT; } public boolean isCharacters() { return currentStaxEvent == XMLStreamConstants.CHARACTERS; } public boolean isEndElement() { return currentStaxEvent == XMLStreamConstants.END_ELEMENT; } public boolean isStandalone() { return false; } public boolean isStartElement() { return currentStaxEvent == XMLStreamConstants.START_ELEMENT; } public boolean isWhiteSpace() { try { return currentStaxEvent == XMLStreamConstants.CHARACTERS && Whitespace.isWhite(provider.getStringValue()); } catch (XPathException e) { pendingException = e; return false; } } public boolean standaloneSet() { return false; } public String getCharacterEncodingScheme() { return null; } public String getElementText() throws XMLStreamException { if (pendingException != null) { throw new XMLStreamException(pendingException); } if (getEventType() != XMLStreamConstants.START_ELEMENT) { throw new XMLStreamException("parser must be on START_ELEMENT to read next text", getLocation()); } int eventType = next(); StringBuffer content = new StringBuffer(); while (eventType != XMLStreamConstants.END_ELEMENT) { if (eventType == XMLStreamConstants.CHARACTERS || eventType == XMLStreamConstants.CDATA || eventType == XMLStreamConstants.SPACE || eventType == XMLStreamConstants.ENTITY_REFERENCE) { content.append(getText()); } else if (eventType == XMLStreamConstants.PROCESSING_INSTRUCTION || eventType == XMLStreamConstants.COMMENT) { // skipping } else if (eventType == XMLStreamConstants.END_DOCUMENT) { throw new XMLStreamException("unexpected end of document when reading element text content", getLocation()); } else if (eventType == XMLStreamConstants.START_ELEMENT) { throw new XMLStreamException("element text content may not contain START_ELEMENT", getLocation()); } else { throw new XMLStreamException("Unexpected event type " + eventType, getLocation()); } eventType = next(); } return content.toString(); } public String getEncoding() { return null; } public String getLocalName() { return namePool.getLocalName(provider.getNameCode()); } public String getNamespaceURI() { return namePool.getURI(provider.getNameCode()); } public String getPIData() { if (currentStaxEvent != XMLStreamConstants.PROCESSING_INSTRUCTION) { throw new IllegalStateException("Not positioned at a processing instruction"); } try { return provider.getStringValue().toString(); } catch (XPathException e) { pendingException = e; return ""; } } public String getPITarget() { if (currentStaxEvent != XMLStreamConstants.PROCESSING_INSTRUCTION) { throw new IllegalStateException("Not positioned at a processing instruction"); } return namePool.getLocalName(provider.getNameCode()); } public String getPrefix() { return namePool.getPrefix(provider.getNameCode()); } public String getVersion() { return "1.0"; } public String getNamespacePrefix(int i) { try { return provider.getNamespaceDeclarations().getPrefix(i); } catch (XPathException e) { pendingException = e; return ""; } } public String getNamespaceURI(int i) { try { return provider.getNamespaceDeclarations().getURI(i); } catch (XPathException e) { pendingException = e; return ""; } } public NamespaceContext getNamespaceContext() { return new NamespaceContextImpl(provider); } public QName getName() { int nc = provider.getNameCode(); return new QName(namePool.getURI(nc), namePool.getLocalName(nc), namePool.getPrefix(nc)); } public Location getLocation() { SourceLocator sourceLocator = provider.getSourceLocator(); if (sourceLocator == null) { sourceLocator = new ExpressionLocation(); } return new SourceStreamLocation(sourceLocator); } public Object getProperty(String s) throws IllegalArgumentException { return null; //TODO: implement this method } public void require(int event, String uri, String local) throws XMLStreamException { if (pendingException != null) { throw new XMLStreamException(pendingException); } if (currentStaxEvent != event) { throw new XMLStreamException("Required event type is " + event + ", actual event is " + currentStaxEvent); } if (uri != null && !uri.equals(getNamespaceURI())) { throw new XMLStreamException("Required namespace is " + uri + ", actual is " + getNamespaceURI()); } if (local != null && !local.equals(getLocalName())) { throw new XMLStreamException("Required local name is " + local + ", actual is " + getLocalName()); } } public String getNamespaceURI(String s) { return provider.getURIForPrefix(s, true); } /** * Bridge a SAX SourceLocator to a javax.xml.stream.Location */ public class SourceStreamLocation implements javax.xml.stream.Location { private SourceLocator locator; /** * Create a StAX SourceStreamLocation object based on a given SAX SourceLocator * @param locator the SAX SourceLocator */ public SourceStreamLocation(SourceLocator locator) { this.locator = locator; } public int getCharacterOffset() { return -1; } public int getColumnNumber() { return locator.getColumnNumber(); } public int getLineNumber() { return locator.getLineNumber(); } public String getPublicId() { return locator.getPublicId(); } public String getSystemId() { return locator.getSystemId(); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/pull/PullConsumer.java0000644000175000017500000000331211033112257021645 0ustar eugeneeugenepackage net.sf.saxon.pull; import net.sf.saxon.trans.XPathException; /** * A PullConsumer consumes all the events supplied by a PullProvider, doing nothing * with them. The class exists so that PullFilters on the pipeline can produce side-effects. * For example, this class can be used to validate a document, where the side effects are * error messages. */ public class PullConsumer { private PullProvider in; /** * Create a PullConsumer that swallows the events read from a given pull provider * @param in the PullProvider from which events are to be read and swallowed up */ public PullConsumer(PullProvider in) { this.in = in; } /** * Consume the input * @throws net.sf.saxon.trans.XPathException */ public void consume() throws XPathException { while (true) { if (in.next() == PullProvider.END_OF_INPUT) { return; } } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/pull/TreeWalker.java0000644000175000017500000005235111033112257021271 0ustar eugeneeugenepackage net.sf.saxon.pull; import net.sf.saxon.event.PipelineConfiguration; import net.sf.saxon.om.*; import net.sf.saxon.tinytree.TinyNodeImpl; import net.sf.saxon.tinytree.TinyTreeWalker; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.Type; import net.sf.saxon.value.AtomicValue; import javax.xml.transform.SourceLocator; import java.util.Stack; import java.util.List; /** * This implementation of the Saxon pull interface starts from any NodeInfo, * and returns the events corresponding to that node and its descendants (including * their attributes and namespaces). This works with any tree model: alternative * implementations may be available that take advantage of particular implementations * of the tree model. */ public class TreeWalker implements PullProvider, SourceLocator { private NodeInfo startNode; private NodeInfo currentNode; private int currentEvent; private Stack iteratorStack = new Stack(); private PipelineConfiguration pipe; /** * Factory method to get a tree walker starting an a given node * @param startNode the start node * @return a PullProvider that delivers events associated with the subtree starting at the given node */ public static PullProvider makeTreeWalker(NodeInfo startNode) { if (startNode instanceof UnconstructedParent) { return ((UnconstructedParent)startNode).getPuller(); } if (startNode instanceof TinyNodeImpl) { switch (startNode.getNodeKind()) { case Type.DOCUMENT: case Type.ELEMENT: return new TinyTreeWalker((TinyNodeImpl)startNode); default: return new PullFromIterator(SingletonIterator.makeIterator(startNode)); } } else { return new TreeWalker(startNode); } } /** * Private constructor: the class should be instantiated using the static factory method * @param startNode the root node of the subtree to be walked */ private TreeWalker(NodeInfo startNode) { this.startNode = startNode; } /** * Set configuration information. This must only be called before any events * have been read. */ public void setPipelineConfiguration(PipelineConfiguration pipe) { this.pipe = pipe; } /** * Get configuration information. */ public PipelineConfiguration getPipelineConfiguration() { return pipe; } /** * Get the next event * * @return an integer code indicating the type of event. The code * {@link #END_OF_INPUT} is returned if there are no more events to return. */ public int next() throws XPathException { switch(currentEvent) { case START_OF_INPUT: currentNode = startNode; switch (currentNode.getNodeKind()) { case Type.DOCUMENT: currentEvent = START_DOCUMENT; break; case Type.ELEMENT: currentEvent = START_ELEMENT; break; case Type.TEXT: currentEvent = TEXT; break; case Type.COMMENT: currentEvent = COMMENT; break; case Type.PROCESSING_INSTRUCTION: currentEvent = PROCESSING_INSTRUCTION; break; case Type.ATTRIBUTE: currentEvent = ATTRIBUTE; break; case Type.NAMESPACE: currentEvent = NAMESPACE; break; } return currentEvent; case START_DOCUMENT: case START_ELEMENT: AxisIterator kids = currentNode.iterateAxis(Axis.CHILD); iteratorStack.push(kids); currentNode = (NodeInfo)kids.next(); if (currentNode != null) { switch (currentNode.getNodeKind()) { case Type.ELEMENT: currentEvent = START_ELEMENT; break; case Type.TEXT: currentEvent = TEXT; break; case Type.COMMENT: currentEvent = COMMENT; break; case Type.PROCESSING_INSTRUCTION: currentEvent = PROCESSING_INSTRUCTION; break; } return currentEvent; } else { iteratorStack.pop(); if (iteratorStack.isEmpty()) { currentNode = startNode; } if (currentEvent == START_DOCUMENT) { currentEvent = END_DOCUMENT; } else { currentEvent = END_ELEMENT; } return currentEvent; } case TEXT: case COMMENT: case PROCESSING_INSTRUCTION: case END_ELEMENT: if (iteratorStack.isEmpty()) { if (currentNode == startNode) { currentNode = null; currentEvent = END_OF_INPUT; } else { currentNode = startNode; if (currentNode.getNodeKind() == Type.ELEMENT) { currentEvent = END_ELEMENT; } else { currentEvent = END_DOCUMENT; } } return currentEvent; } AxisIterator siblings = (AxisIterator)iteratorStack.peek(); currentNode = (NodeInfo)siblings.next(); if (currentNode == null) { iteratorStack.pop(); if (iteratorStack.isEmpty()) { currentNode = startNode; if (currentNode.getNodeKind() == Type.ELEMENT) { currentEvent = END_ELEMENT; } else { currentEvent = END_DOCUMENT; } return currentEvent; } AxisIterator uncles = (AxisIterator)iteratorStack.peek(); currentNode = (NodeInfo)uncles.current(); if (currentNode.getNodeKind() == Type.DOCUMENT) { currentEvent = END_DOCUMENT; } else { currentEvent = END_ELEMENT; } return currentEvent; } else { switch (currentNode.getNodeKind()) { case Type.ELEMENT: currentEvent = START_ELEMENT; break; case Type.TEXT: currentEvent = TEXT; break; case Type.COMMENT: currentEvent = COMMENT; break; case Type.PROCESSING_INSTRUCTION: currentEvent = PROCESSING_INSTRUCTION; break; } return currentEvent; } case ATTRIBUTE: case NAMESPACE: case END_DOCUMENT: currentEvent = END_OF_INPUT; return currentEvent; case END_OF_INPUT: throw new IllegalStateException("Cannot call next() when input is exhausted"); default: throw new IllegalStateException("Unrecognized event " + currentEvent); } } /** * Get the event most recently returned by next(), or by other calls that change * the position, for example getStringValue() and skipToMatchingEnd(). This * method does not change the position of the PullProvider. * * @return the current event */ public int current() { return currentEvent; } /** * Get the attributes associated with the current element. This method must * be called only after a START_ELEMENT event has been notified. The contents * of the returned AttributeCollection are guaranteed to remain unchanged * until the next START_ELEMENT event, but may be modified thereafter. The object * should not be modified by the client. *

    *

    Attributes may be read before or after reading the namespaces of an element, * but must not be read after the first child node has been read, or after calling * one of the methods skipToEnd(), getStringValue(), or getTypedValue().

    * * @return an AttributeCollection representing the attributes of the element * that has just been notified. */ public AttributeCollection getAttributes() throws XPathException { if (currentNode.getNodeKind() == Type.ELEMENT) { AttributeCollectionImpl atts = new AttributeCollectionImpl(startNode.getConfiguration()); SequenceIterator iter = currentNode.iterateAxis(Axis.ATTRIBUTE); while (true) { NodeInfo node = (NodeInfo)iter.next(); if (node == null) { break; } atts.addAttribute(node.getNameCode(), node.getTypeAnnotation(), node.getStringValue(), 0, 0); } return atts; } else { throw new IllegalStateException("getAttributes() called when current event is not ELEMENT_START"); } } /** * Get the namespace declarations associated with the current element. This method must * be called only after a START_ELEMENT event has been notified. In the case of a top-level * START_ELEMENT event (that is, an element that either has no parent node, or whose parent * is not included in the sequence being read), the NamespaceDeclarations object returned * will contain a namespace declaration for each namespace that is in-scope for this element * node. In the case of a non-top-level element, the NamespaceDeclarations will contain * a set of namespace declarations and undeclarations, representing the differences between * this element and its parent. *

    *

    It is permissible for this method to return namespace declarations that are redundant.

    *

    *

    The NamespaceDeclarations object is guaranteed to remain unchanged until the next START_ELEMENT * event, but may then be overwritten. The object should not be modified by the client.

    *

    *

    Namespaces may be read before or after reading the attributes of an element, * but must not be read after the first child node has been read, or after calling * one of the methods skipToEnd(), getStringValue(), or getTypedValue().

    * */ public NamespaceDeclarations getNamespaceDeclarations() throws XPathException { if (currentNode.getNodeKind() == Type.ELEMENT) { if (iteratorStack.isEmpty()) { // get all inscope namespaces for a top-level element in the sequence. int[] codes = NamespaceIterator.getInScopeNamespaceCodes(currentNode); return new NamespaceDeclarationsImpl(getNamePool(), codes); } else { // only namespace declarations (and undeclarations) on this element are required return new NamespaceDeclarationsImpl(getNamePool(), currentNode.getDeclaredNamespaces(nsBuffer)); } } throw new IllegalStateException("getNamespaceDeclarations() called when current event is not ELEMENT_START"); } private int[] nsBuffer = new int[10]; /** * Skip the current subtree. This method may be called only immediately after * a START_DOCUMENT or START_ELEMENT event. This call returns the matching * END_DOCUMENT or END_ELEMENT event; the next call on next() will return * the event following the END_DOCUMENT or END_ELEMENT. */ public int skipToMatchingEnd() throws XPathException { // For this implementation, we simply leave the current node unchanged, and change // the current event switch (currentEvent) { case START_DOCUMENT: currentEvent = END_DOCUMENT; return currentEvent; case START_ELEMENT: currentEvent = END_ELEMENT; return currentEvent; default: throw new IllegalStateException( "Cannot call skipToMatchingEnd() except when at start of element or document"); } } /** * Close the event reader. This indicates that no further events are required. * It is not necessary to close an event reader after {@link #END_OF_INPUT} has * been reported, but it is recommended to close it if reading terminates * prematurely. Once an event reader has been closed, the effect of further * calls on next() is undefined. */ public void close() { // no action } /** * Get the namePool used to lookup all name codes and namespace codes * * @return the namePool */ public NamePool getNamePool() { return pipe.getConfiguration().getNamePool(); } /** * Get the nameCode identifying the name of the current node. This method * can be used after the {@link #START_ELEMENT}, {@link #PROCESSING_INSTRUCTION}, * {@link #ATTRIBUTE}, or {@link #NAMESPACE} events. With some PullProvider implementations, * including this one, it can also be used after {@link #END_ELEMENT}. * If called at other times, the result is undefined and may result in an IllegalStateException. * If called when the current node is an unnamed namespace node (a node representing the default namespace) * the returned value is -1. * @return the nameCode. The nameCode can be used to obtain the prefix, local name, * and namespace URI from the name pool. */ public int getNameCode() { return currentNode.getNameCode(); } /** * Get the fingerprint of the name of the element. This is similar to the nameCode, except that * it does not contain any information about the prefix: so two elements with the same fingerprint * have the same name, excluding prefix. This method * can be used after the {@link #START_ELEMENT}, {@link #END_ELEMENT}, {@link #PROCESSING_INSTRUCTION}, * {@link #ATTRIBUTE}, or {@link #NAMESPACE} events. * If called at other times, the result is undefined and may result in an IllegalStateException. * If called when the current node is an unnamed namespace node (a node representing the default namespace) * the returned value is -1. * * @return the fingerprint. The fingerprint can be used to obtain the local name * and namespace URI from the name pool. */ public int getFingerprint() { return currentNode.getFingerprint(); } /** * Get the string value of the current attribute, text node, processing-instruction, * or atomic value. * This method cannot be used to obtain the string value of an element, or of a namespace * node. If the most recent event was anything other than {@link #START_ELEMENT}, {@link #TEXT}, * {@link #PROCESSING_INSTRUCTION}, or {@link #ATOMIC_VALUE}, the result is undefined. */ public CharSequence getStringValue() throws XPathException { if (currentNode.getNodeKind() == Type.ELEMENT) { skipToMatchingEnd(); } return currentNode.getStringValueCS(); } /** * Get the type annotation of the current attribute or element node, or atomic value. * The result of this method is undefined unless the most recent event was START_ELEMENT, * START_CONTENT, ATTRIBUTE, or ATOMIC_VALUE. * * @return the type code. This code is the fingerprint of a type name, which may be * resolved to a {@link net.sf.saxon.type.SchemaType} by access to the Configuration. */ public int getTypeAnnotation() { return currentNode.getTypeAnnotation(); } /** * Get an atomic value. This call may be used only when the last event reported was * ATOMIC_VALUE. This indicates that the PullProvider is reading a sequence that contains * a free-standing atomic value; it is never used when reading the content of a node. */ public AtomicValue getAtomicValue() { throw new IllegalStateException(); } /** * Get the location of the current event. * For an event stream representing a real document, the location information * should identify the location in the lexical XML source. For a constructed document, it should * identify the location in the query or stylesheet that caused the node to be created. * A value of null can be returned if no location information is available. */ public SourceLocator getSourceLocator() { return this; } /** * Return the public identifier for the current document event. *

    *

    The return value is the public identifier of the document * entity or of the external parsed entity in which the markup that * triggered the event appears.

    * * @return A string containing the public identifier, or * null if none is available. * @see #getSystemId */ public String getPublicId() { return null; } /** * Return the system identifier for the current document event. *

    *

    The return value is the system identifier of the document * entity or of the external parsed entity in which the markup that * triggered the event appears.

    *

    *

    If the system identifier is a URL, the parser must resolve it * fully before passing it to the application.

    * * @return A string containing the system identifier, or null * if none is available. * @see #getPublicId */ public String getSystemId() { return currentNode.getSystemId(); } /** * Return the line number where the current document event ends. *

    *

    Warning: The return value from the method * is intended only as an approximation for the sake of error * reporting; it is not intended to provide sufficient information * to edit the character content of the original XML document.

    *

    *

    The return value is an approximation of the line number * in the document entity or external parsed entity where the * markup that triggered the event appears.

    * * @return The line number, or -1 if none is available. * @see #getColumnNumber */ public int getLineNumber() { return currentNode.getLineNumber(); } /** * Return the character position where the current document event ends. *

    *

    Warning: The return value from the method * is intended only as an approximation for the sake of error * reporting; it is not intended to provide sufficient information * to edit the character content of the original XML document.

    *

    *

    The return value is an approximation of the column number * in the document entity or external parsed entity where the * markup that triggered the event appears.

    * * @return The column number, or -1 if none is available. * @see #getLineNumber */ public int getColumnNumber() { return -1; } /** * Get a list of unparsed entities. * * @return a list of unparsed entities, or null if the information is not available, or * an empty list if there are no unparsed entities. */ public List getUnparsedEntities() { return null; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. //saxonb-9.1.0.8/bj/net/sf/saxon/pull/PullPushTee.java0000644000175000017500000001611711033112257021436 0ustar eugeneeugenepackage net.sf.saxon.pull; import net.sf.saxon.event.Receiver; import net.sf.saxon.event.SequenceReceiver; import net.sf.saxon.om.AttributeCollection; import net.sf.saxon.om.NamespaceDeclarations; import net.sf.saxon.om.Orphan; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.Type; import java.util.List; /** * PullPushTee is a pass-through filter class that links one PullProvider to another PullProvider * in a pipeline, copying all events that are read into a push pipeline, supplied in the form * of a Receiver. * *

    This class can be used to insert a schema validator into a pull pipeline, since Saxon's schema * validation is push-based. It could also be used to insert a serializer into the pipeline, allowing * the XML document being "pulled" to be displayed for diagnostic purposes.

    */ public class PullPushTee extends PullFilter { private Receiver branch; boolean previousAtomic = false; /** * Create a PullPushTee * @param base the PullProvider to which requests are to be passed * @param branch the Receiver to which all events are to be copied, as "push" events. * This Receiver must already be open before use */ public PullPushTee(PullProvider base, Receiver branch) throws XPathException { super(base); this.branch = branch; //branch.open(); } /** * Get the Receiver to which events are being tee'd. * @return the Receiver */ public Receiver getReceiver() { return branch; } /** * Get the next event. This implementation gets the next event from the underlying PullProvider, * copies it to the branch Receiver, and then returns the event to the caller. * * @return an integer code indicating the type of event. The code * {@link #END_OF_INPUT} is returned at the end of the sequence. */ public int next() throws XPathException { currentEvent = super.next(); copyEvent(currentEvent); return currentEvent; } /** * Copy a pull event to a Receiver * @param event the pull event to be copied */ private void copyEvent(int event) throws XPathException { PullProvider in = getUnderlyingProvider(); Receiver out = branch; switch (event) { case START_DOCUMENT: out.startDocument(0); break; case START_ELEMENT: out.startElement(in.getNameCode(), in.getTypeAnnotation(), 0, 0); NamespaceDeclarations decl = in.getNamespaceDeclarations(); for (int i=0; i * Note that this may throw an UncheckedXPathException. This is because many of the methods on the * NodeInfo class are exception-free; we can't throw an XPathException on these interfaces, but may need * to in this case because lazy computation of expressions may throw errors. * * @throws UncheckedXPathException */ void tryToConstruct() { try { construct(); } catch (XPathException err) { throw new UncheckedXPathException(err); } } /** * Determine whether this is the same node as another node. * Note: a.isSameNodeInfo(b) if and only if generateId(a)==generateId(b). * This method has the same semantics as isSameNode() in DOM Level 3, but * works on Saxon NodeInfo objects rather than DOM Node objects. * * @param other the node to be compared with this node * @return true if this NodeInfo object and the supplied NodeInfo object represent * the same node in the tree. */ public boolean isSameNodeInfo(NodeInfo other) { return this == other || !(other instanceof UnconstructedParent) && node != null && node.isSameNodeInfo(other); } /** * The equals() method compares nodes for identity. It is defined to give the same result * as isSameNodeInfo(). * @param other the node to be compared with this node * @return true if this NodeInfo object and the supplied NodeInfo object represent * the same node in the tree. * @since 8.7 Previously, the effect of the equals() method was not defined. Callers * should therefore be aware that third party implementations of the NodeInfo interface may * not implement the correct semantics. It is safer to use isSameNodeInfo() for this reason. * The equals() method has been defined because it is useful in contexts such as a Java Set or HashMap. */ public boolean equals(Object other) { return other instanceof NodeInfo && isSameNodeInfo((NodeInfo)other); } /** * The hashCode() method obeys the contract for hashCode(): that is, if two objects are equal * (represent the same node) then they must have the same hashCode() * @since 8.7 Previously, the effect of the equals() and hashCode() methods was not defined. Callers * should therefore be aware that third party implementations of the NodeInfo interface may * not implement the correct semantics. */ public int hashCode() { if (node != null) { return node.hashCode(); } else { return super.hashCode(); } } /** * Get the System ID for the node (that is, the document URI of the containing document node). * * @return the System Identifier of the source document * containing the node, or null if not known. Note this is not the * same as the base URI: the base URI can be modified by xml:base, but * the system ID cannot. */ public String getSystemId() { return null; // if (node == null) { // tryToConstruct(); // } // return node.getSystemId(); } /** * Get the Base URI for the node, that is, the URI used for resolving a relative URI contained * in the node. This will be the same as the System ID unless xml:base has been used. * * @return the base URI of the node */ public String getBaseURI() { if (node == null) { // the base URI of a constructed parentless document or element node is the static base URI of the // instruction/expression that created it PipelineConfiguration pipe = savedXPathContext.getController().makePipelineConfiguration(); return pipe.getLocationProvider().getSystemId(instruction.getLocationId()); } else { return node.getBaseURI(); } } /** * Get line number * * @return the line number of the node in its original source document; or * -1 if not available */ public int getLineNumber() { return -1; } /** * Get column number * @return the column number of the node in its original source document; or -1 if not available */ public int getColumnNumber() { return -1; } /** * Determine the relative position of this node and another node, in document order. * The other node will always be in the same document. * * @param other The other node, whose position is to be compared with this * node * @return -1 if this node precedes the other node, +1 if it follows the * other node, or 0 if they are the same node. (In this case, * isSameNode() will always return true, and the two nodes will * produce the same result for generateId()) */ public int compareOrder(NodeInfo other) { if (node == null) { tryToConstruct(); } return node.compareOrder(other); } /** * Return the string value of the node. The interpretation of this depends on the type * of node. For an element it is the accumulated character content of the element, * including descendant elements. * * @return the string value of the node */ public String getStringValue() { return getStringValueCS().toString(); } /** * Get fingerprint. The fingerprint is a coded form of the expanded name * of the node: two nodes * with the same name code have the same namespace URI and the same local name. * A fingerprint of -1 should be returned for a node with no name. * * @return an integer fingerprint; two nodes with the same fingerprint have * the same expanded QName */ public int getFingerprint() { int nc = getNameCode(); if (nc == -1) { return -1; } return nc & NamePool.FP_MASK; } /** * Get the local part of the name of this node. This is the name after the ":" if any. * * @return the local part of the name. For an unnamed node, returns "". Unlike the DOM * interface, this returns the full name in the case of a non-namespaced name. */ public String getLocalPart() { return getNamePool().getLocalName(getNameCode()); } /** * Get the URI part of the name of this node. This is the URI corresponding to the * prefix, or the URI of the default namespace if appropriate. * * @return The URI of the namespace of this node. For an unnamed node, * or for a node with an empty prefix, return an empty * string. */ public String getURI() { return getNamePool().getURI(getNameCode()); } /** * Get the display name of this node. For elements and attributes this is [prefix:]localname. * For unnamed nodes, it is an empty string. * * @return The display name of this node. For a node with no name, return * an empty string. */ public String getDisplayName() { return getNamePool().getDisplayName(getNameCode()); } /** * Get the prefix of the name of the node. This is defined only for elements and attributes. * If the node has no prefix, or for other kinds of node, return a zero-length string. * * @return The prefix of the name of the node. */ public String getPrefix() { return getNamePool().getPrefix(getNameCode()); } /** * Get the configuration */ public Configuration getConfiguration() { return savedXPathContext.getConfiguration(); } /** * Get the NamePool that holds the namecode for this node * * @return the namepool */ public NamePool getNamePool() { return getConfiguration().getNamePool(); } /** * Get the type annotation of this node, if any. * Returns -1 for kinds of nodes that have no annotation * * @return the type annotation of the node. * @see net.sf.saxon.type.Type */ public int getTypeAnnotation() { return StandardNames.XS_UNTYPED; } /** * Get the NodeInfo object representing the parent of this node * * @return the parent of this node; null if this node has no parent */ public NodeInfo getParent() { return null; } /** * Return an iteration over all the nodes reached by the given axis from this node * * @param axisNumber an integer identifying the axis; one of the constants * defined in class net.sf.saxon.om.Axis * @return an AxisIterator that scans the nodes reached by the axis in * turn. * @throws UnsupportedOperationException if the namespace axis is * requested and this axis is not supported for this implementation. * @see net.sf.saxon.om.Axis */ public AxisIterator iterateAxis(byte axisNumber) { if (node == null) { tryToConstruct(); } return node.iterateAxis(axisNumber); } /** * Return an iteration over all the nodes reached by the given axis from this node * that match a given NodeTest * * @param axisNumber an integer identifying the axis; one of the constants * defined in class net.sf.saxon.om.Axis * @param nodeTest A pattern to be matched by the returned nodes; nodes * that do not match this pattern are not included in the result * @return a NodeEnumeration that scans the nodes reached by the axis in * turn. * @throws UnsupportedOperationException if the namespace axis is * requested and this axis is not supported for this implementation. * @see net.sf.saxon.om.Axis */ public AxisIterator iterateAxis(byte axisNumber, NodeTest nodeTest) { if (node == null) { tryToConstruct(); } return node.iterateAxis(axisNumber, nodeTest); } /** * Get the value of a given attribute of this node * * @param fingerprint The fingerprint of the attribute name * @return the attribute value if it exists or null if not */ public String getAttributeValue(int fingerprint) { if (node == null) { tryToConstruct(); } return node.getAttributeValue(fingerprint); } /** * Get the root node of the tree containing this node * * @return the NodeInfo representing the top-level ancestor of this node. * This will not necessarily be a document node */ public NodeInfo getRoot() { return this; } /** * Get the root node, if it is a document node. * * @return the DocumentInfo representing the containing document. If this * node is part of a tree that does not have a document node as its * root, return null. */ public DocumentInfo getDocumentRoot() { return null; } /** * Determine whether the node has any children.
    * Note: the result is equivalent to
    * getEnumeration(Axis.CHILD, AnyNodeTest.getInstance()).hasNext() * * @return True if the node has one or more children */ public boolean hasChildNodes() { if (node == null) { tryToConstruct(); } return node.hasChildNodes(); } /** * Get a character string that uniquely identifies this node. * Note: a.isSameNode(b) if and only if generateId(a)==generateId(b) * * @param buffer a buffer, into which will be placed * a string that uniquely identifies this node, across all * documents. */ public void generateId(FastStringBuffer buffer) { if (node == null) { tryToConstruct(); } node.generateId(buffer); } /** * Get the document number of the document containing this node. For a free-standing * orphan node, just return the hashcode. */ public int getDocumentNumber() { if (node == null) { tryToConstruct(); } return node.getDocumentNumber(); } /** * Copy this node to a given outputter * * @param out the Receiver to which the node should be copied * @param whichNamespaces in the case of an element, controls * which namespace nodes should be copied. Values are {@link #NO_NAMESPACES}, * {@link #LOCAL_NAMESPACES}, {@link #ALL_NAMESPACES} * @param copyAnnotations indicates whether the type annotations * of element and attribute nodes should be copied * @param locationId If non-zero, identifies the location of the instruction * that requested this copy. If zero, indicates that the location information * for the original node is to be copied; in this case the Receiver must be * a LocationCopier * @throws net.sf.saxon.trans.XPathException * */ public void copy(Receiver out, int whichNamespaces, boolean copyAnnotations, int locationId) throws XPathException { if (node == null) { if (whichNamespaces == NodeInfo.ALL_NAMESPACES && copyAnnotations) { PullProvider pull = new VirtualTreeWalker(instruction, savedXPathContext); pull.setPipelineConfiguration(out.getPipelineConfiguration()); PullPushCopier copier = new PullPushCopier(pull, out); copier.append(); return; } else { construct(); } } node.copy(out, whichNamespaces, copyAnnotations, locationId); } /** * Get all namespace undeclarations and undeclarations defined on this element. * * @param buffer If this is non-null, and the result array fits in this buffer, then the result * may overwrite the contents of this array, to avoid the cost of allocating a new array on the heap. * @return An array of integers representing the namespace declarations and undeclarations present on * this element. For a node other than an element, return null. Otherwise, the returned array is a * sequence of namespace codes, whose meaning may be interpreted by reference to the name pool. The * top half word of each namespace code represents the prefix, the bottom half represents the URI. * If the bottom half is zero, then this is a namespace undeclaration rather than a declaration. * The XML namespace is never included in the list. If the supplied array is larger than required, * then the first unused entry will be set to -1. *

    *

    For a node other than an element, the method returns null.

    */ public int[] getDeclaredNamespaces(int[] buffer) { if (node == null) { tryToConstruct(); } return node.getDeclaredNamespaces(buffer); } /** * Set the system identifier for this Source. *

    *

    The system identifier is optional if the source does not * get its data from a URL, but it may still be useful to provide one. * The application can use a system identifier, for example, to resolve * relative URIs and to include in error messages and warnings.

    * * @param systemId The system identifier as a URL string. */ public void setSystemId(String systemId) { // } /** * Get the value of the item as a CharSequence. This is in some cases more efficient than * the version of the method that returns a String. */ public CharSequence getStringValueCS() { if (node == null) { //construct(); try { PullProvider puller = getPuller(); puller.next(); // assert: it's a START_DOCUMENT or START_ELEMENT return puller.getStringValue(); } catch (XPathException e) { throw new UncheckedXPathException(e); } } return node.getStringValueCS(); } /** * Get the typed value of the item * * @return the typed value of the item. In general this will be a sequence * @throws net.sf.saxon.trans.XPathException * where no typed value is available, e.g. for * an element with complex content */ public SequenceIterator getTypedValue() throws XPathException { if (node == null) { construct(); } return node.getTypedValue(); } /** * Get the typed value. The result of this method will always be consistent with the method * {@link net.sf.saxon.om.Item#getTypedValue()}. However, this method is often more convenient and may be * more efficient, especially in the common case where the value is expected to be a singleton. * * @return the typed value. If requireSingleton is set to true, the result will always be an * AtomicValue. In other cases it may be a Value representing a sequence whose items are atomic * values. * @since 8.5 */ public Value atomize() throws XPathException { if (node == null) { construct(); } return node.atomize(); } /** * Determine whether this node has the is-id property * * @return true if the node is an ID */ public boolean isId() { return false; } /** * Determine whether this node has the is-idref property * * @return true if the node is an IDREF or IDREFS element or attribute */ public boolean isIdref() { return false; } /** * Determine whether the node has the is-nilled property * * @return true if the node has the is-nilled property */ public boolean isNilled() { return false; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/pull/PullNamespaceReducer.java0000644000175000017500000005425111033112257023270 0ustar eugeneeugenepackage net.sf.saxon.pull; import net.sf.saxon.om.*; import net.sf.saxon.trans.XPathException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /** * PullNamespaceReducer is a PullFilter responsible for removing duplicate namespace * declarations. It also performs namespace fixup: that is, it ensures that the * namespaces used in element and attribute names are all declared. *

    *

    This class is derived from, and contains much common code with, the NamespaceReducer * in the push pipeline. (In the push version, however, namespace fixup is not * performed by the NamespaceReducer, but by the ComplexContentOutputter).

    * * @see net.sf.saxon.event.NamespaceReducer */ public class PullNamespaceReducer extends PullFilter implements NamespaceResolver { // As well as keeping track of namespaces, this class keeps a stack of element names, // so that the current element name is available to the caller after an endElement event private int[] namestack = new int[50]; // stack of element name codes int elementJustEnded = -1; // namecode of the element that has just ended // We keep track of namespaces to avoid outputting duplicate declarations. The namespaces // vector holds a list of all namespaces currently declared (organised as integer namespace codes). // The countStack contains an entry for each element currently open; the // value on the countStack is an Integer giving the number of namespaces added to the main // namespace stack by that element. private int[] allNamespaces = new int[50]; // all namespace codes currently declared private int allNamespacesSize = 0; // all namespaces currently declared private int[] namespaceCountStack = new int[50]; // one entry per started element, holding the number // of namespaces declared at that level private int depth = 0; // current depth of element nesting private int[] localNamespaces; // namespaces declared on the current start element private int localNamespacesSize = 0; private int nameCode; // the namecode of the current element private NamespaceDeclarations declaredNamespaces; private AttributeCollection attributeCollection; // Creating an element does not automatically inherit the namespaces of the containing element. // TODO: disinheriting namespaces is not yet supported by the pull pipeline //private boolean[] disinheritStack = new boolean[50]; private int[] pendingUndeclarations = null; /** * Create a namespace reducer for a pull pipeline * @param base the next stage in the pipeline, from which events are read */ public PullNamespaceReducer(PullProvider base) { super(base); } /** * next(): handle next event. * The START_ELEMENT event removes redundant namespace declarations, and * possibly adds an xmlns="" undeclaration. */ public int next() throws XPathException { currentEvent = super.next(); switch (currentEvent) { case START_ELEMENT: startElement(); break; case END_ELEMENT: endElement(); break; case PROCESSING_INSTRUCTION: case ATTRIBUTE: case NAMESPACE: nameCode = super.getNameCode(); break; default: nameCode = -1; } return currentEvent; } private void startElement() throws XPathException { // If the parent element specified inherit=no, keep a list of namespaces that need to be // undeclared // if (depth>0 && disinheritStack[depth-1]) { // pendingUndeclarations = new int[namespacesSize]; // System.arraycopy(namespaces, 0, pendingUndeclarations, 0, namespacesSize); // } else { // pendingUndeclarations = null; // } // Record the current height of the namespace list so it can be reset at endElement time namespaceCountStack[depth] = 0; //disinheritStack[depth] = (properties & ReceiverOptions.DISINHERIT_NAMESPACES) != 0; if (++depth >= namespaceCountStack.length) { int[] newstack = new int[depth * 2]; System.arraycopy(namespaceCountStack, 0, newstack, 0, depth); //boolean[] disStack2 = new boolean[depth*2]; //System.arraycopy(disinheritStack, 0, disStack2, 0, depth); namespaceCountStack = newstack; //disinheritStack = disStack2; int[] name2 = new int[depth * 2]; System.arraycopy(namestack, 0, name2, 0, depth); namestack = name2; } // Get the list of namespaces associated with this element NamespaceDeclarations declarations = super.getNamespaceDeclarations(); localNamespaces = declarations.getNamespaceCodes(nsBuffer); localNamespacesSize = 0; for (int i = 0; i < localNamespaces.length; i++) { if (localNamespaces[i] == -1) { break; } else { if (isNeeded(localNamespaces[i])) { addGlobalNamespace(localNamespaces[i]); namespaceCountStack[depth - 1]++; localNamespaces[localNamespacesSize++] = localNamespaces[i]; } } } // Namespace fixup: ensure that the element namespace is output nameCode = checkProposedPrefix(super.getNameCode(), 0); namestack[depth - 1] = nameCode; // int elementNS = getNamePool().allocateNamespaceCode(getNameCode()); // if (isNeeded(elementNS)) { // appendNamespace(elementNS); // } // Namespace fixup: ensure that all namespaces used in attribute names are declared attributeCollection = super.getAttributes(); boolean modified = false; for (int i = 0; i < attributeCollection.getLength(); i++) { int nc = attributeCollection.getNameCode(i); if ((nc & ~NamePool.FP_MASK) != 0) { // Only need to do checking for an attribute that's namespaced int newnc = checkProposedPrefix(nc, i + 1); if (nc != newnc) { if (!modified) { attributeCollection = copyAttributeCollection(attributeCollection); modified = true; } ((AttributeCollectionImpl) attributeCollection).setAttribute(i, newnc, attributeCollection.getTypeAnnotation(i), attributeCollection.getValue(i), attributeCollection.getLocationId(i), attributeCollection.getProperties(i)); } } } if (localNamespacesSize < localNamespaces.length) { localNamespaces[localNamespacesSize] = -1; // add a terminator } declaredNamespaces = new NamespaceDeclarationsImpl(getNamePool(), localNamespaces); // TODO: defer construction of this object until the user asks for it namespaceCountStack[depth - 1] = localNamespacesSize; } private int[] nsBuffer = new int[20]; private void addLocalNamespace(int nc) { if (localNamespacesSize < localNamespaces.length) { localNamespaces[localNamespacesSize++] = nc; } else { if (localNamespacesSize == 0) { localNamespaces = new int[10]; } else { int[] nc2 = new int[localNamespacesSize * 2]; System.arraycopy(localNamespaces, 0, nc2, 0, localNamespacesSize); localNamespaces = nc2; localNamespaces[localNamespacesSize++] = nc; } } addGlobalNamespace(nc); } /** * Determine whether a namespace declaration is needed * @param nscode the namespace code of the declaration (prefix plus uri) * @return true if the namespace declaration is needed */ private boolean isNeeded(int nscode) { if (nscode == NamespaceConstant.XML_NAMESPACE_CODE) { // Ignore the XML namespace return false; } // First cancel any pending undeclaration of this namespace prefix (there may be more than one) if (pendingUndeclarations != null) { for (int p = 0; p < pendingUndeclarations.length; p++) { if ((nscode >> 16) == (pendingUndeclarations[p] >> 16)) { pendingUndeclarations[p] = -1; //break; } } } for (int i = allNamespacesSize - 1; i >= 0; i--) { if (allNamespaces[i] == nscode) { // it's a duplicate so we don't need it return false; } if ((allNamespaces[i] >> 16) == (nscode >> 16)) { // same prefix, different URI, so we do need it return true; } } // we need it unless it's a redundant xmlns="" return (nscode != NamespaceConstant.NULL_NAMESPACE_CODE); // startContent: Add any namespace undeclarations needed to stop // namespaces being inherited from parent elements // if (pendingUndeclarations != null) { // for (int i=0; i> 16; for (int i = allNamespacesSize - 1; i >= 0; i--) { if (nsprefix == (allNamespaces[i] >> 16)) { // same prefix if ((nscode & 0xffff) == (allNamespaces[i] & 0xffff)) { // same URI return nameCode; // all is well } else { // same prefix is bound to a different URI. Action depends on whether the declaration // is local to this element or at an outer level if (i + localNamespacesSize >= allNamespacesSize) { // the prefix is already defined locally, so allocate a new one String prefix = getSubstitutePrefix(nscode, seq); int newNameCode = namePool.allocate(prefix, namePool.getURI(nameCode), namePool.getLocalName(nameCode)); int newNSCode = namePool.allocateNamespaceCode(newNameCode); addLocalNamespace(newNSCode); return newNameCode; } else { // the prefix has been used on an outer level, but we can reuse it here addLocalNamespace(nscode); return nameCode; } } } } // there is no declaration of this prefix: declare it now if (nscode != NamespaceConstant.NULL_NAMESPACE_CODE) { addLocalNamespace(nscode); } return nameCode; } /** * It is possible for a single output element to use the same prefix to refer to different * namespaces. In this case we have to generate an alternative prefix for uniqueness. The * one we generate is based on the sequential position of the element/attribute: this is * designed to ensure both uniqueness (with a high probability) and repeatability * @param nscode the namespace code * @param seq sequence number to help in making the generated prefix unique * @return the invented prefix */ private String getSubstitutePrefix(int nscode, int seq) { String prefix = getNamePool().getPrefixFromNamespaceCode(nscode); return prefix + '_' + seq; } /** * Add a namespace declaration to the stack * @param nscode the namespace code representing the namespace declaration */ private void addGlobalNamespace(int nscode) { // expand the stack if necessary if (allNamespacesSize + 1 >= allNamespaces.length) { int[] newlist = new int[allNamespacesSize * 2]; System.arraycopy(allNamespaces, 0, newlist, 0, allNamespacesSize); allNamespaces = newlist; } allNamespaces[allNamespacesSize++] = nscode; } /** * Get the nameCode identifying the name of the current node. This method * can be used after the {@link #START_ELEMENT}, {@link #PROCESSING_INSTRUCTION}, * {@link #ATTRIBUTE}, or {@link #NAMESPACE} events. With some PullProvider implementations, * including this one, it can also be used after {@link #END_ELEMENT} * If called at other times, the result is undefined and may result in an IllegalStateException. * If called when the current node is an unnamed namespace node (a node representing the default namespace) * the returned value is -1. * * @return the nameCode. The nameCode can be used to obtain the prefix, local name, * and namespace URI from the name pool. */ public int getNameCode() { if (currentEvent == END_ELEMENT) { return elementJustEnded; } else { return nameCode; } } /** * Get the attributes associated with the current element. This method must * be called only after a START_ELEMENT event has been notified. The contents * of the returned AttributeCollection are guaranteed to remain unchanged * until the next START_ELEMENT event, but may be modified thereafter. The object * should not be modified by the client. *

    *

    Attributes may be read before or after reading the namespaces of an element, * but must not be read after the first child node has been read, or after calling * one of the methods skipToEnd(), getStringValue(), or getTypedValue().

    * * @return an AttributeCollection representing the attributes of the element * that has just been notified. */ public AttributeCollection getAttributes() throws XPathException { return attributeCollection; } private AttributeCollectionImpl copyAttributeCollection(AttributeCollection in) { AttributeCollectionImpl out = new AttributeCollectionImpl(getPipelineConfiguration().getConfiguration()); for (int i = 0; i < in.getLength(); i++) { out.addAttribute(in.getNameCode(i), in.getTypeAnnotation(i), in.getValue(i), in.getLocationId(i), in.getProperties(i)); } return out; } /** * Get the namespace declarations associated with the current element. This method must * be called only after a START_ELEMENT event has been notified. In the case of a top-level * START_ELEMENT event (that is, an element that either has no parent node, or whose parent * is not included in the sequence being read), the NamespaceDeclarations object returned * will contain a namespace declaration for each namespace that is in-scope for this element * node. In the case of a non-top-level element, the NamespaceDeclarations will contain * a set of namespace declarations and undeclarations, representing the differences between * this element and its parent. *

    *

    This class extends the semantics of the PullProvider interface by allowing this method * to be called also after an END_ELEMENT event. This is to support PullToStax, which requires * this functionality. In this situation it returns the namespaces declared on the startElement * associated with the element that has just ended.

    *

    It is permissible for this method to return namespace declarations that are redundant.

    *

    *

    The NamespaceDeclarations object is guaranteed to remain unchanged until the next START_ELEMENT * event, but may then be overwritten. The object should not be modified by the client.

    *

    *

    Namespaces may be read before or after reading the attributes of an element, * but must not be read after the first child node has been read, or after calling * one of the methods skipToEnd(), getStringValue(), or getTypedValue().

    * */ public NamespaceDeclarations getNamespaceDeclarations() throws XPathException { if (currentEvent == END_ELEMENT) { // this case is sufficiently rare that we don't worry about its efficiency. // The namespaces that are needed are still on the namespace stack, even though the // top-of-stack pointer has already been decremented. int nscount = namespaceCountStack[depth]; int[] namespaces = new int[nscount]; System.arraycopy(allNamespaces, allNamespacesSize, namespaces, 0, nscount); return new NamespaceDeclarationsImpl(getNamePool(), namespaces); } else { return declaredNamespaces; } } /** * endElement: Discard the namespaces declared on this element. Note, however, that for the * benefit of PullToStax, the namespaces that go out of scope on this endElement are available * so long as the endElement is the current event */ public void endElement() throws XPathException { if (depth-- == 0) { throw new IllegalStateException("Attempt to output end tag with no matching start tag"); } elementJustEnded = namestack[depth]; allNamespacesSize -= namespaceCountStack[depth]; } /** * Get the URI code corresponding to a given prefix code, by searching the * in-scope namespaces. This is a service provided to subclasses. * * @param prefixCode the 16-bit prefix code required * @return the 16-bit URI code, or -1 if the prefix is not found */ protected short getURICode(short prefixCode) { for (int i = allNamespacesSize - 1; i >= 0; i--) { if ((allNamespaces[i] >> 16) == (prefixCode)) { return (short) (allNamespaces[i] & 0xffff); } } if (prefixCode == 0) { return 0; // by default, no prefix means no namespace URI } else { return -1; } } /** * Get the namespace URI corresponding to a given prefix. Return null * if the prefix is not in scope. * * @param prefix the namespace prefix * @param useDefault true if the default namespace is to be used when the * prefix is "" * @return the uri for the namespace, or null if the prefix is not in scope */ public String getURIForPrefix(String prefix, boolean useDefault) { NamePool pool = getNamePool(); if ((prefix == null || prefix.length() == 0) && !useDefault) { return ""; } else if ("xml".equals(prefix)) { return NamespaceConstant.XML; } else { short prefixCode = pool.getCodeForPrefix(prefix); short uriCode = getURICode(prefixCode); if (uriCode == -1) { return null; } return pool.getURIFromURICode(uriCode); } } /** * Get an iterator over all the prefixes declared in this namespace context. This will include * the default namespace (prefix="") and the XML namespace where appropriate */ public Iterator iteratePrefixes() { NamePool pool = getNamePool(); List prefixes = new ArrayList(allNamespacesSize); for (int i = allNamespacesSize - 1; i >= 0; i--) { String prefix = pool.getPrefixFromNamespaceCode(allNamespaces[i]); if (!prefixes.contains(prefix)) { prefixes.add(prefix); } } prefixes.add("xml"); return prefixes.iterator(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/pull/PullFromIterator.java0000644000175000017500000003460411033112257022477 0ustar eugeneeugenepackage net.sf.saxon.pull; import net.sf.saxon.event.PipelineConfiguration; import net.sf.saxon.om.*; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.AtomicType; import net.sf.saxon.type.Type; import net.sf.saxon.type.TypeHierarchy; import net.sf.saxon.value.AtomicValue; import javax.xml.transform.SourceLocator; import java.util.List; /** * This class delivers any XPath sequence through the pull interface. Atomic values * in the sequence are supplied unchanged, as are top-level text, comment, attribute, * namespace, and processing-instruction nodes. Elements and documents appearing in * the input sequence are supplied as a sequence of events that walks recursively * down the subtree rooted at that node. The input is supplied in the form of a * SequenceIterator. */ public class PullFromIterator implements PullProvider { private SequenceIterator base; private PullProvider treeWalker = null; private PipelineConfiguration pipe; private int currentEvent = START_OF_INPUT; /** * Create a PullProvider that wraps a supplied SequenceIterator * @param base the sequence iterator to be wrapped */ public PullFromIterator(SequenceIterator base) { this.base = base; } /** * Set configuration information. This must only be called before any events * have been read. */ public void setPipelineConfiguration(PipelineConfiguration pipe) { this.pipe = pipe; } /** * Get configuration information. */ public PipelineConfiguration getPipelineConfiguration() { return pipe; } /** * Get the next event * * @return an integer code indicating the type of event. The code * {@link #END_OF_INPUT} is returned at the end of the sequence. */ public int next() throws XPathException { if (treeWalker == null) { Item item = base.next(); if (item == null) { currentEvent = END_OF_INPUT; return currentEvent; } else if (item instanceof UnconstructedParent) { // this represents a lazily-evaluated element or document node constructor treeWalker = ((UnconstructedParent)item).getPuller(); //treeWalker.setPipelineConfiguration(pipe); currentEvent = treeWalker.next(); return currentEvent; } else if (item instanceof AtomicValue) { currentEvent = ATOMIC_VALUE; return currentEvent; } else { switch (((NodeInfo)item).getNodeKind()) { case Type.TEXT: currentEvent = TEXT; return currentEvent; case Type.COMMENT: currentEvent = COMMENT; return currentEvent; case Type.PROCESSING_INSTRUCTION: currentEvent = PROCESSING_INSTRUCTION; return currentEvent; case Type.ATTRIBUTE: currentEvent = ATTRIBUTE; return currentEvent; case Type.NAMESPACE: currentEvent = NAMESPACE; return currentEvent; case Type.ELEMENT: case Type.DOCUMENT: treeWalker = TreeWalker.makeTreeWalker((NodeInfo)item); treeWalker.setPipelineConfiguration(pipe); currentEvent = treeWalker.next(); return currentEvent; default: throw new IllegalStateException(); } } } else { // there is an active TreeWalker: just return its next event int event = treeWalker.next(); if (event == END_OF_INPUT) { treeWalker = null; currentEvent = next(); } else { currentEvent = event; } return currentEvent; } } /** * Get the event most recently returned by next(), or by other calls that change * the position, for example getStringValue() and skipToMatchingEnd(). This * method does not change the position of the PullProvider. * * @return the current event */ public int current() { return currentEvent; } /** * Get the attributes associated with the current element. This method must * be called only after a START_ELEMENT event has been notified. The contents * of the returned AttributeCollection are guaranteed to remain unchanged * until the next START_ELEMENT event, but may be modified thereafter. The object * should not be modified by the client. *

    *

    Attributes may be read before or after reading the namespaces of an element, * but must not be read after the first child node has been read, or after calling * one of the methods skipToEnd(), getStringValue(), or getTypedValue().

    * * @return an AttributeCollection representing the attributes of the element * that has just been notified. */ public AttributeCollection getAttributes() throws XPathException { if (treeWalker != null) { return treeWalker.getAttributes(); } else { throw new IllegalStateException(); } } /** * Get the namespace declarations associated with the current element. This method must * be called only after a START_ELEMENT event has been notified. In the case of a top-level * START_ELEMENT event (that is, an element that either has no parent node, or whose parent * is not included in the sequence being read), the NamespaceDeclarations object returned * will contain a namespace declaration for each namespace that is in-scope for this element * node. In the case of a non-top-level element, the NamespaceDeclarations will contain * a set of namespace declarations and undeclarations, representing the differences between * this element and its parent. *

    *

    It is permissible for this method to return namespace declarations that are redundant.

    *

    *

    The NamespaceDeclarations object is guaranteed to remain unchanged until the next START_ELEMENT * event, but may then be overwritten. The object should not be modified by the client.

    *

    *

    Namespaces may be read before or after reading the attributes of an element, * but must not be read after the first child node has been read, or after calling * one of the methods skipToEnd(), getStringValue(), or getTypedValue().

    * */ public NamespaceDeclarations getNamespaceDeclarations() throws XPathException { if (treeWalker != null) { return treeWalker.getNamespaceDeclarations(); } else { throw new IllegalStateException(); } } /** * Skip the current subtree. This method may be called only immediately after * a START_DOCUMENT or START_ELEMENT event. This call returns the matching * END_DOCUMENT or END_ELEMENT event; the next call on next() will return * the event following the END_DOCUMENT or END_ELEMENT. */ public int skipToMatchingEnd() throws XPathException { if (treeWalker != null) { return treeWalker.skipToMatchingEnd(); } else { throw new IllegalStateException(); } } /** * Close the event reader. This indicates that no further events are required. * It is not necessary to close an event reader after {@link #END_OF_INPUT} has * been reported, but it is recommended to close it if reading terminates * prematurely. Once an event reader has been closed, the effect of further * calls on next() is undefined. */ public void close() { if (treeWalker != null) { treeWalker.close(); } } /** * Get the nameCode identifying the name of the current node. This method * can be used after the {@link #START_ELEMENT}, {@link #PROCESSING_INSTRUCTION}, * {@link #ATTRIBUTE}, or {@link #NAMESPACE} events. With some PullProvider implementations, * including this one, it can also be used after {@link #END_ELEMENT}. * If called at other times, the result is undefined and may result in an IllegalStateException. * If called when the current node is an unnamed namespace node (a node representing the default namespace) * the returned value is -1. * * @return the nameCode. The nameCode can be used to obtain the prefix, local name, * and namespace URI from the name pool. */ public int getNameCode() { if (treeWalker != null) { return treeWalker.getNameCode(); } else { Item item = base.current(); if (item instanceof NodeInfo) { return ((NodeInfo)item).getNameCode(); } else { throw new IllegalStateException(); } } } /** * Get the fingerprint of the name of the element. This is similar to the nameCode, except that * it does not contain any information about the prefix: so two elements with the same fingerprint * have the same name, excluding prefix. This method * can be used after the {@link #START_ELEMENT}, {@link #END_ELEMENT}, {@link #PROCESSING_INSTRUCTION}, * {@link #ATTRIBUTE}, or {@link #NAMESPACE} events. * If called at other times, the result is undefined and may result in an IllegalStateException. * If called when the current node is an unnamed namespace node (a node representing the default namespace) * the returned value is -1. * * @return the fingerprint. The fingerprint can be used to obtain the local name * and namespace URI from the name pool. */ public int getFingerprint() { int nc = getNameCode(); if (nc == -1) { return -1; } else { return nc & NamePool.FP_MASK; } } /** * Get the string value of the current element, text node, processing-instruction, * or top-level attribute or namespace node, or atomic value. *

    *

    In other situations the result is undefined and may result in an IllegalStateException.

    *

    *

    If the most recent event was a {@link #START_ELEMENT}, this method causes the content * of the element to be read. The current event on completion of this method will be the * corresponding {@link #END_ELEMENT}. The next call of next() will return the event following * the END_ELEMENT event.

    * * @return the String Value of the node in question, defined according to the rules in the * XPath data model. */ public CharSequence getStringValue() throws XPathException { if (treeWalker != null) { return treeWalker.getStringValue(); } else { Item item = base.current(); return item.getStringValueCS(); } } /** * Get an atomic value. This call may be used only when the last event reported was * ATOMIC_VALUE. This indicates that the PullProvider is reading a sequence that contains * a free-standing atomic value; it is never used when reading the content of a node. */ public AtomicValue getAtomicValue() { if (currentEvent == ATOMIC_VALUE) { return (AtomicValue)base.current(); } else { throw new IllegalStateException(); } } /** * Get the type annotation of the current attribute or element node, or atomic value. * The result of this method is undefined unless the most recent event was START_ELEMENT, * ATTRIBUTE, or ATOMIC_VALUE. * * @return the type annotation. This code is the fingerprint of a type name, which may be * resolved to a {@link net.sf.saxon.type.SchemaType} by access to the Configuration. */ public int getTypeAnnotation() { if (treeWalker != null) { return treeWalker.getTypeAnnotation(); } else { Item item = base.current(); if (item instanceof NodeInfo) { return ((NodeInfo)item).getTypeAnnotation(); } else { final TypeHierarchy th = pipe.getConfiguration().getTypeHierarchy(); return ((AtomicType)((AtomicValue)item).getItemType(th)).getFingerprint(); } } } /** * Get the location of the current event. * For an event stream representing a real document, the location information * should identify the location in the lexical XML source. For a constructed document, it should * identify the location in the query or stylesheet that caused the node to be created. * A value of null can be returned if no location information is available. */ public SourceLocator getSourceLocator() { if (treeWalker != null) { return treeWalker.getSourceLocator(); } else { return null; } } /** * Get a list of unparsed entities. * * @return a list of unparsed entities, or null if the information is not available, or * an empty list if there are no unparsed entities. */ public List getUnparsedEntities() { return null; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. //saxonb-9.1.0.8/bj/net/sf/saxon/pull/VirtualTreeWalker.java0000644000175000017500000011113511033112257022634 0ustar eugeneeugenepackage net.sf.saxon.pull; import net.sf.saxon.Configuration; import net.sf.saxon.sort.IntArraySet; import net.sf.saxon.event.PipelineConfiguration; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.instruct.DocumentInstr; import net.sf.saxon.instruct.ElementCreator; import net.sf.saxon.instruct.ParentNodeConstructor; import net.sf.saxon.om.*; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.Type; import net.sf.saxon.value.AtomicValue; import javax.xml.transform.SourceLocator; import java.util.ArrayList; import java.util.List; import java.util.Stack; /** * A virtual tree walker provides a sequence of pull events describing the structure and content of a tree * that is conceptually being constructed by expressions in a query or stylesheet; in fact the tree is * not necessarily constructed in memory, and exists only as this stream of pull events. *

    * The tree is physically constructed if operations are requested that depend on the identity of the nodes * in the tree, or that navigate within the tree. Operations such as copying or atomizing the tree can be done * directly, without building it in memory. (Note however that if such operations are done more than once, the * underlying instructions may be evaluated repeatedly.) */ public class VirtualTreeWalker implements PullProvider, NamespaceDeclarations { private PipelineConfiguration pipe; private int currentEvent = START_OF_INPUT; private int nameCode; private int nextNameCode; private ParentNodeConstructor instruction; private XPathContext context; private Stack constructorStack = new Stack(); private Stack iteratorStack = new Stack(); private PullProvider subordinateTreeWalker = null; // The subordinateTreeWalker is used if the tree construction expression pulls in references // to document or element nodes in an existing source document. When this happens, tree walking // events generated by walking the source document are copied into to the stream of events // generated by this class. private boolean alreadyRead = false; private boolean allowAttributes = false; private int stripDepth = -1; // If this is >0, it indicates that instructions on the constructor stack with depth < stripDepth // specify validation=preserve, while those at greater depth effectively specify validation=strip // (It doesn't matter if they actually say validation=preserve, the stripping takes priority) private AttributeCollectionImpl attributes; private boolean foundAttributes; private int[] activeNamespaces; private ArrayList additionalNamespaces = new ArrayList(10); // array of namespace nodes /** * Create a VirtualTreeWalker to navigate the tree constructed by evaluating a given instruction * in a given dyamic context * @param instruction the instruction (this will always be an instruction that creates element or * document nodes) * @param context the dynamic evaluation context */ public VirtualTreeWalker(ParentNodeConstructor instruction, XPathContext context) { this.instruction = instruction; this.context = context; } /** * Set configuration information. This must only be called before any events * have been read. */ public void setPipelineConfiguration(PipelineConfiguration pipe) { this.pipe = pipe; } /** * Get configuration information. * @return the pipeline configuration */ public PipelineConfiguration getPipelineConfiguration() { return pipe; } /** * Get the namepool * @return the NamePool */ public NamePool getNamePool() { return pipe.getConfiguration().getNamePool(); } /** * Get the next event * * @return an integer code indicating the type of event. The code * {@link #END_OF_INPUT} is returned at the end of the sequence. */ public int next() throws XPathException { try { // First see if we are currently walking some other tree that has been logically // copied into this tree. if (subordinateTreeWalker != null) { currentEvent = subordinateTreeWalker.next(); if (currentEvent == END_OF_INPUT) { subordinateTreeWalker = null; return next(); } return currentEvent; } // On the first call, produce a START_ELEMENT or START_DOCUMENT event depending on the instruction if (currentEvent == START_OF_INPUT) { constructorStack.push(instruction); if (stripDepth < 0 && instruction.getValidationMode() == Validation.STRIP) { stripDepth = constructorStack.size(); } SequenceIterator content = instruction.getContentExpression().iterate(context); iteratorStack.push(content); if (instruction instanceof DocumentInstr) { currentEvent = START_DOCUMENT; nameCode = -1; } else { currentEvent = START_ELEMENT; nameCode = ((ElementCreator)instruction).getNameCode(context); allowAttributes = true; // look ahead to generate all the attributes and namespaces of the element processAttributesAndNamespaces((ElementCreator)instruction, content); // remember that we've read one event too many allowAttributes = false; alreadyRead = true; } return currentEvent; } if (iteratorStack.isEmpty()) { // if we're at the top level, see if we've just started, or are about to finish if (currentEvent == START_DOCUMENT || currentEvent == START_ELEMENT) { // we've just started: start processing the content of the instruction SequenceIterator iter = instruction.getContentExpression().iterate(context); constructorStack.push(instruction); if (stripDepth < 0 && instruction.getValidationMode() == Validation.STRIP) { stripDepth = constructorStack.size(); } iteratorStack.push(iter); } else if (currentEvent == END_DOCUMENT || currentEvent == END_ELEMENT) { // we're about to finish currentEvent = END_OF_INPUT; return currentEvent; } else { // we're going to finish soon, but must first generate the last END_DOCUMENT or END_ELEMENT event currentEvent = ((instruction instanceof DocumentInstr) ? END_DOCUMENT : END_ELEMENT); return currentEvent; } } // Read the next item from the current content iterator SequenceIterator iterator = ((SequenceIterator)iteratorStack.peek()); if (alreadyRead) { Item item = iterator.current(); alreadyRead = false; nameCode = nextNameCode; return processItem(iterator, item); } else { return processItem(iterator, iterator.next()); } } catch (XPathException e) { // report any dynamic errors unless already reported context.getController().reportFatalError(e); throw e; } } private FastStringBuffer textNodeBuffer = new FastStringBuffer(100); private CharSequence currentTextValue = null; /** * Process an item in the content of an element or document node * @param iterator the iterator over the contents of the element or document * @param item the current item to be processed, or null if the end of the content * iterator has been reached * @return the next event code * @throws XPathException if a dynamic error occurs */ private int processItem(SequenceIterator iterator, Item item) throws XPathException { if (item == null) { // we've reached the end of the children if (stripDepth == constructorStack.size()) { stripDepth = -1; } ParentNodeConstructor inst = (ParentNodeConstructor)constructorStack.pop(); if (inst instanceof DocumentInstr) { iteratorStack.pop(); if (iteratorStack.isEmpty()) { currentEvent = END_DOCUMENT; nameCode = -1; return currentEvent; } // skip the END_DOCUMENT event for a nested document node return next(); } else { currentEvent = END_ELEMENT; nameCode = -1; iteratorStack.pop(); return currentEvent; } } else if (item instanceof UnconstructedParent) { // this represents a nested element or document node constructor UnconstructedParent parent = (UnconstructedParent)item; ParentNodeConstructor inst = parent.getInstruction(); constructorStack.push(inst); if (stripDepth < 0 && inst.getValidationMode() == Validation.STRIP) { stripDepth = constructorStack.size(); } SequenceIterator content = inst.getContentExpression().iterate(parent.getXPathContext()); if (inst instanceof DocumentInstr) { iteratorStack.push(content); // skip the START_DOCUMENT event return next(); } else { currentEvent = START_ELEMENT; nameCode = ((UnconstructedElement)item).getNameCode(); processAttributesAndNamespaces((ElementCreator)inst, content); alreadyRead = true; iteratorStack.push(content); return currentEvent; } } else if (item instanceof AtomicValue) { currentTextValue = textNodeBuffer; textNodeBuffer.setLength(0); textNodeBuffer.append(item.getStringValueCS()); while (true) { Item next = iterator.next(); if (next instanceof AtomicValue) { textNodeBuffer.append(' '); textNodeBuffer.append(next.getStringValueCS()); //continue; } else { currentEvent = TEXT; nameCode = -1; alreadyRead = true; return currentEvent; } } } else { nameCode = ((NodeInfo)item).getNameCode(); switch (((NodeInfo)item).getNodeKind()) { case Type.TEXT: currentEvent = TEXT; currentTextValue = item.getStringValueCS(); return currentEvent; case Type.COMMENT: currentEvent = COMMENT; return currentEvent; case Type.PROCESSING_INSTRUCTION: currentEvent = PROCESSING_INSTRUCTION; return currentEvent; case Type.ATTRIBUTE: if (!allowAttributes) { XPathException de; if (constructorStack.peek() instanceof DocumentInstr) { de = new XPathException( "Attributes cannot be attached to a document node"); if (pipe.getHostLanguage() == Configuration.XQUERY) { de.setErrorCode("XQTY0004"); } else { de.setErrorCode("XTDE0420"); } } else { de = new XPathException( "Attributes in the content of an element must come before the child nodes"); if (pipe.getHostLanguage() == Configuration.XQUERY) { de.setErrorCode("XQDY0024"); } else { de.setErrorCode("XTDE0410"); } } de.setXPathContext(context); de.setLocator(getSourceLocator()); throw de; } currentEvent = ATTRIBUTE; return currentEvent; case Type.NAMESPACE: if (!allowAttributes) { XPathException de = new XPathException("Namespace nodes in the content of an element must come before the child nodes"); de.setErrorCode("XTDE0410"); de.setXPathContext(context); de.setLocator(getSourceLocator()); throw de; } currentEvent = NAMESPACE; return currentEvent; case Type.ELEMENT: subordinateTreeWalker = TreeWalker.makeTreeWalker((NodeInfo)item); subordinateTreeWalker.setPipelineConfiguration(pipe); currentEvent = subordinateTreeWalker.next(); nameCode = subordinateTreeWalker.getNameCode(); return currentEvent; case Type.DOCUMENT: subordinateTreeWalker = TreeWalker.makeTreeWalker((NodeInfo)item); subordinateTreeWalker.setPipelineConfiguration(pipe); subordinateTreeWalker = new DocumentEventIgnorer(subordinateTreeWalker); subordinateTreeWalker.setPipelineConfiguration(pipe); currentEvent = subordinateTreeWalker.next(); nameCode = -1; return currentEvent; default: throw new IllegalStateException(); } } } /** * Following a START_ELEMENT event, evaluate the contents of the element to obtain all attributes and namespaces. * This process stops when the first event other than an attribute or namespace is read. We then remember the * extra event, which will be the next event returned in the normal sequence. Note that the relative order * of attributes and namespaces is undefined. * @param inst The instruction that creates the element node * @param content Iterator over the expression that generates the attributes, namespaces, and content of the * element * @throws XPathException if any dynamic error occurs */ private void processAttributesAndNamespaces(ElementCreator inst, SequenceIterator content) throws XPathException { foundAttributes = false; additionalNamespaces.clear(); activeNamespaces = inst.getActiveNamespaces(); if (activeNamespaces == null) { activeNamespaces = IntArraySet.EMPTY_INT_ARRAY; } // if the namespace of the element name itself is not one of the active namespaces, make sure // a namespace node is created for it // NamePool pool = context.getNamePool(); // int nscode = pool.allocateNamespaceCode(nameCode); // boolean found = false; // for (int i=0; i= 0) { // Attribute already exists. In XQuery this is an error. In XSLT, the last attribute wins if (context.getController().getExecutable().getHostLanguage() == Configuration.XSLT) { attributes.setAttribute(index, node.getNameCode(), preserve ? node.getTypeAnnotation() : StandardNames.XS_UNTYPED_ATOMIC, node.getStringValue(), 0, 0); } else { XPathException de = new XPathException("The attributes of an element must have distinct names"); de.setErrorCode("XQDY0025"); de.setXPathContext(context); de.setLocator(getSourceLocator()); throw de; } } else { attributes.addAttribute( node.getNameCode(), preserve ? node.getTypeAnnotation() : StandardNames.XS_UNTYPED_ATOMIC, node.getStringValue(), 0, 0); } // if the namespace of the attribute name itself has not already been declared, make sure // a namespace node is created for it // int anc = node.getNameCode(); // if ((anc >> 20) != 0) { // // the attribute name is prefixed // // int anscode = pool.allocateNamespaceCode(anc); // boolean afound = false; // for (int i=0; i *

    Attributes may be read before or after reading the namespaces of an element, * but must not be read after the first child node has been read, or after calling * one of the methods skipToEnd(), getStringValue(), or getTypedValue().

    * * @return an AttributeCollection representing the attributes of the element * that has just been notified. */ public AttributeCollection getAttributes() throws XPathException { if (subordinateTreeWalker != null) { return subordinateTreeWalker.getAttributes(); } else { if (foundAttributes) { return attributes; } else { return AttributeCollectionImpl.EMPTY_ATTRIBUTE_COLLECTION; } } } /** * Get the namespace declarations associated with the current element. This method must * be called only after a START_ELEMENT event has been notified. In the case of a top-level * START_ELEMENT event (that is, an element that either has no parent node, or whose parent * is not included in the sequence being read), the NamespaceDeclarations object returned * will contain a namespace declaration for each namespace that is in-scope for this element * node. In the case of a non-top-level element, the NamespaceDeclarations will contain * a set of namespace declarations and undeclarations, representing the differences between * this element and its parent. *

    *

    It is permissible for this method to return namespace declarations that are redundant.

    *

    *

    The NamespaceDeclarations object is guaranteed to remain unchanged until the next START_ELEMENT * event, but may then be overwritten. The object should not be modified by the client.

    *

    *

    Namespaces may be read before or after reading the attributes of an element, * but must not be read after the first child node has been read, or after calling * one of the methods skipToEnd(), getStringValue(), or getTypedValue().

    * */ public NamespaceDeclarations getNamespaceDeclarations() throws XPathException { if (subordinateTreeWalker != null) { return subordinateTreeWalker.getNamespaceDeclarations(); } else { return this; } } /** * Skip the current subtree. This method may be called only immediately after * a START_DOCUMENT or START_ELEMENT event. This call returns the matching * END_DOCUMENT or END_ELEMENT event; the next call on next() will return * the event following the END_DOCUMENT or END_ELEMENT. * @throws IllegalStateException if the method is called at any time other than * immediately after a START_DOCUMENT or START_ELEMENT event. */ public int skipToMatchingEnd() throws XPathException { if (currentEvent != START_DOCUMENT && currentEvent != START_ELEMENT) { throw new IllegalStateException(); } if (subordinateTreeWalker != null) { return subordinateTreeWalker.skipToMatchingEnd(); } else { SequenceIterator content = (SequenceIterator)iteratorStack.peek(); if (alreadyRead) { alreadyRead = false; } while (true) { Item next = content.next(); if (next == null) { break; } } return (currentEvent == START_DOCUMENT ? END_DOCUMENT : END_ELEMENT); } } /** * Close the event reader. This indicates that no further events are required. * It is not necessary to close an event reader after {@link #END_OF_INPUT} has * been reported, but it is recommended to close it if reading terminates * prematurely. Once an event reader has been closed, the effect of further * calls on next() is undefined. */ public void close() { if (subordinateTreeWalker != null) { subordinateTreeWalker.close(); } else { // do nothing } } /** * Set the initial nameCode * @param nameCode the nameCode of the node at the root of the tree being walked */ public void setNameCode(int nameCode) { this.nameCode = nameCode; } /** * Get the nameCode identifying the name of the current node. This method * can be used after the {@link #START_ELEMENT}, {@link #END_ELEMENT}, {@link #PROCESSING_INSTRUCTION}, * {@link #ATTRIBUTE}, or {@link #NAMESPACE} events. With some PullProvider implementations, * but not this one, it can also be used after {@link #END_ELEMENT}. * If called at other times, the result is undefined and may result in an IllegalStateException. * If called when the current node is an unnamed namespace node (a node representing the default namespace) * the returned value is -1. * * @return the nameCode. The nameCode can be used to obtain the prefix, local name, * and namespace URI from the name pool. */ public int getNameCode() { if (subordinateTreeWalker != null) { return subordinateTreeWalker.getNameCode(); } return nameCode; } /** * Get the fingerprint of the name of the element. This is similar to the nameCode, except that * it does not contain any information about the prefix: so two elements with the same fingerprint * have the same name, excluding prefix. This method * can be used after the {@link #START_ELEMENT}, {@link #END_ELEMENT}, {@link #PROCESSING_INSTRUCTION}, * {@link #ATTRIBUTE}, or {@link #NAMESPACE} events. * If called at other times, the result is undefined and may result in an IllegalStateException. * If called when the current node is an unnamed namespace node (a node representing the default namespace) * the returned value is -1. * * @return the fingerprint. The fingerprint can be used to obtain the local name * and namespace URI from the name pool. */ public int getFingerprint() { int nc = getNameCode(); if (nc == -1) { return -1; } else { return nc & NamePool.FP_MASK; } } /** * Get the string value of the current element, text node, processing-instruction, * or top-level attribute or namespace node, or atomic value. *

    *

    In other situations the result is undefined and may result in an IllegalStateException.

    *

    *

    If the most recent event was a {@link #START_ELEMENT}, this method causes the content * of the element to be read. The current event on completion of this method will be the * corresponding {@link #END_ELEMENT}. The next call of next() will return the event following * the END_ELEMENT event.

    * * @return the String Value of the node in question, defined according to the rules in the * XPath data model. */ public CharSequence getStringValue() throws XPathException { if (subordinateTreeWalker != null) { return subordinateTreeWalker.getStringValue(); } else if (currentEvent == TEXT) { return currentTextValue; } else if (currentEvent != START_ELEMENT && currentEvent != START_DOCUMENT) { SequenceIterator content = (SequenceIterator)iteratorStack.peek(); if (content.current() == null) { return ""; } return content.current().getStringValue(); } else { FastStringBuffer sb = new FastStringBuffer(100); SequenceIterator content = (SequenceIterator)iteratorStack.peek(); boolean previousAtomic = false; if (alreadyRead) { Item current = content.current(); if (current == null) { return ""; } processText(current, sb); previousAtomic = (current instanceof AtomicValue); alreadyRead = false; } while (true) { Item next = content.next(); if (next == null) { break; } boolean atomic = (next instanceof AtomicValue); if (atomic && previousAtomic) { sb.append(' '); } processText(next, sb); previousAtomic = atomic; } return sb; } } /** * Add the string value of a child item to a string buffer that is used to accumulate the * string value of a document or element node * @param item the child item * @param sb the string buffer where the content is accumulated */ private void processText(Item item, FastStringBuffer sb) { if (item instanceof UnconstructedParent) { sb.append(item.getStringValueCS()); } else if (item instanceof AtomicValue) { sb.append(item.getStringValueCS()); } else { NodeInfo node = (NodeInfo)item; switch (node.getNodeKind()) { case Type.DOCUMENT: case Type.ELEMENT: case Type.TEXT: sb.append(node.getStringValueCS()); default: // do nothing } } } /** * Get an atomic value. This call may be used only when the last event reported was * ATOMIC_VALUE. This indicates that the PullProvider is reading a sequence that contains * a free-standing atomic value; it is never used when reading the content of a node. */ public AtomicValue getAtomicValue() { throw new IllegalStateException(); } /** * Get the type annotation of the current attribute or element node, or atomic value. * The result of this method is undefined unless the most recent event was START_ELEMENT, * ATTRIBUTE, or ATOMIC_VALUE. * * @return the type annotation. This code is the fingerprint of a type name, which may be * resolved to a {@link net.sf.saxon.type.SchemaType} by access to the Configuration. */ public int getTypeAnnotation() { if (subordinateTreeWalker != null && stripDepth < 0) { return subordinateTreeWalker.getTypeAnnotation(); } else { return -1; } } /** * Get the location of the current event. * For an event stream representing a real document, the location information * should identify the location in the lexical XML source. For a constructed document, it should * identify the location in the query or stylesheet that caused the node to be created. * A value of null can be returned if no location information is available. */ public SourceLocator getSourceLocator() { return instruction; } /** * Get the number of declarations (and undeclarations) in this list. */ public int getNumberOfNamespaces() { return activeNamespaces.length + additionalNamespaces.size(); } /** * Get the prefix of the n'th declaration (or undeclaration) in the list, * counting from zero. * * @param index the index identifying which declaration is required. * @return the namespace prefix. For a declaration or undeclaration of the * default namespace, this is the zero-length string. * @throws IndexOutOfBoundsException if the index is out of range. */ public String getPrefix(int index) { if (index < activeNamespaces.length) { return getNamePool().getPrefixFromNamespaceCode(activeNamespaces[index]); } else { return ((NodeInfo)additionalNamespaces.get(index - activeNamespaces.length)).getLocalPart(); } } /** * Get the namespace URI of the n'th declaration (or undeclaration) in the list, * counting from zero. * * @param index the index identifying which declaration is required. * @return the namespace URI. For a namespace undeclaration, this is the * zero-length string. * @throws IndexOutOfBoundsException if the index is out of range. */ public String getURI(int index) { if (index < activeNamespaces.length) { return getNamePool().getURIFromNamespaceCode(activeNamespaces[index]); } else { return ((NodeInfo)additionalNamespaces.get(index - activeNamespaces.length)).getStringValue(); } } /** * Get the n'th declaration in the list in the form of a namespace code. Namespace * codes can be translated into a prefix and URI by means of methods in the * NamePool * * @param index the index identifying which declaration is required. * @return the namespace code. This is an integer whose upper half indicates * the prefix (0 represents the default namespace), and whose lower half indicates * the URI (0 represents an undeclaration). * @throws IndexOutOfBoundsException if the index is out of range. * @see net.sf.saxon.om.NamePool#getPrefixFromNamespaceCode(int) * @see net.sf.saxon.om.NamePool#getURIFromNamespaceCode(int) */ public int getNamespaceCode(int index) { if (index < activeNamespaces.length) { return activeNamespaces[index]; } else { return getNamePool().allocateNamespaceCode(getPrefix(index), getURI(index)); } } /** * Get all the namespace codes, as an array. * * @param buffer a sacrificial array that the method is free to use to contain the result. * May be null. * @return an integer array containing namespace codes. The array may be filled completely * with namespace codes, or it may be incompletely filled, in which case a -1 integer acts * as a terminator. */ public int[] getNamespaceCodes(int[] buffer) { if (buffer.length < getNumberOfNamespaces()) { buffer = new int[getNumberOfNamespaces()]; } else { buffer[getNumberOfNamespaces()] = -1; } for (int i=0; i Package overview for net.sf.saxon.pull

    This package provides an experimental pull API for Saxon: that is, it allows an application to read serially through a document, reading "events" such as the start and end of elements, text nodes, comments, and processing instructions, in the order in which they appear. In fact, the API allows access not just to a single document, but to any sequence consisting of nodes and atomic values: when a node is encountered, the pull API does a traversal of the subtree rooted at that node, before moving on to the next item in the sequence.

    The API, defined in class PullProvider, is loosely modelled on the StAX XMLReader API. It is not identical, because it is designed as an intimate and efficient interface that integrates with Saxon concepts such as the SequenceIterator and the NamePool. A class StaxBridge is available that provides the PullProvider interface on top of a StAX pull parser; however, because pull parsing is not yet a standard feature of the Java platform, and because at the time of writing the available StAX parsers appear to be buggy, StaxBridge is not included in the saxon.jar distribution, but is instead supplied as a sample application in the samples directory.

    The three main kinds of PullProvider are:

    • StaxBridge, which is an interface to a pull-mode XML parser

    • TreeWalker, which delivers events based on an in-memory tree. There is one general-purpose TreeWalker that can handle any Saxon tree (any tree that implements the NodeInfo interface) and aother that is optimized to the TinyTree implementation.

    • VirtualTreeWalker, which delivers events representing the nodes constructed by a stylesheet or query, without actually constructing the nodes in memory. (Note that this doesn't currently work if the constructed nodes need to be schema-validated).

    Some examples of application code using the pull interface with Saxon are provided in the PullExamples.java file in the samples directory.

    Michael H. Kay
    Saxonica Limited
    30 March 2005

    saxonb-9.1.0.8/bj/net/sf/saxon/type/0000755000175000017500000000000012216261742016370 5ustar eugeneeugenesaxonb-9.1.0.8/bj/net/sf/saxon/type/BuiltInListType.java0000644000175000017500000004030511033112257022271 0ustar eugeneeugenepackage net.sf.saxon.type; import net.sf.saxon.expr.*; import net.sf.saxon.om.*; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.SequenceExtent; import net.sf.saxon.value.StringValue; import net.sf.saxon.value.Value; import net.sf.saxon.value.Whitespace; import java.io.Serializable; /** *

    This class is used to implement the built-in * list types NMTOKENS, ENTITIES, IDREFS. It is also used to represent the anonymous type of the * xsi:schemaLocation attribute (a list of xs:anyURI values).

    * **/ public class BuiltInListType implements ListType, Serializable { private int fingerprint; public static BuiltInListType ENTITIES = makeListType(NamespaceConstant.SCHEMA, "ENTITIES"); public static BuiltInListType IDREFS = makeListType(NamespaceConstant.SCHEMA, "IDREFS"); public static BuiltInListType NMTOKENS = makeListType(NamespaceConstant.SCHEMA, "NMTOKENS"); public static BuiltInListType ANY_URIS = makeListType(NamespaceConstant.SCHEMA_INSTANCE, "anonymous_schemaLocationType"); /** * Return true if this is an external object type, that is, a Saxon-defined type for external * Java or .NET objects */ public boolean isExternalType() { return false; } /** * Determine whether this is a built-in type or a user-defined type */ public boolean isBuiltInType() { return true; } /** * Get the URI of the schema document containing the definition of this type * @return null for a built-in type */ public String getSystemId() { return null; } /** * Determine how values of this simple type are whitespace-normalized. * * @return one of {@link net.sf.saxon.value.Whitespace#PRESERVE}, {@link net.sf.saxon.value.Whitespace#COLLAPSE}, * {@link net.sf.saxon.value.Whitespace#REPLACE}. * @param th the type hierarchy cache */ public int getWhitespaceAction(TypeHierarchy th) { return Whitespace.COLLAPSE; } /** * The SimpleType of the items in the list. */ private BuiltInAtomicType itemType = null; /** * Get the most specific possible atomic type that all items in this SimpleType belong to * * @return the lowest common supertype of all member types */ public AtomicType getCommonAtomicType() { return itemType; } /** * Create a new ListType. * @param fingerprint identifies the name of the type */ public BuiltInListType(int fingerprint) { this.fingerprint = fingerprint; switch (fingerprint) { case StandardNames.XS_ENTITIES: itemType = BuiltInAtomicType.ENTITY; break; case StandardNames.XS_IDREFS: itemType = BuiltInAtomicType.IDREF; break; case StandardNames.XS_NMTOKENS: itemType = BuiltInAtomicType.NMTOKEN; break; case StandardNames.XSI_SCHEMA_LOCATION_TYPE: itemType = BuiltInAtomicType.ANY_URI; break; } } /** * Get the validation status - always valid */ public int getValidationStatus() { return VALIDATED; } /** * Returns the base type that this type inherits from. * If this type is a Simpletype that is a built in primitive type then null is returned. * @return the base type. */ public SchemaType getBaseType() { return AnySimpleType.getInstance(); } /** * Test whether this Simple Type is an atomic type * @return false, this is not an atomic type */ public boolean isAtomicType() { return false; } /** * Returns true if this type is derived by list, or if it is derived by restriction * from a list type, or if it is a union that contains a list as one of its members */ public boolean isListType() { return true; } public boolean isUnionType() { return false; } /** * Test whether this is an anonymous type * @return true if this SchemaType is an anonymous type */ public boolean isAnonymousType() { return false; } public SchemaType getBuiltInBaseType() { return this; } public boolean isNamespaceSensitive() { return false; } /** * Get the local name of this type * * @return the local name of this type definition, if it has one. Return null in the case of an * anonymous type. */ public String getName() { return StandardNames.getLocalName(fingerprint); } /** * Get the target namespace of this type * * @return the target namespace of this type definition, if it has one. Return null in the case * of an anonymous type, and in the case of a global type defined in a no-namespace schema. */ public String getTargetNamespace() { return NamespaceConstant.SCHEMA; } /** * Get the fingerprint of the name of this type * @return the fingerprint. Returns an invented fingerprint for an anonymous type. */ public int getFingerprint() { return fingerprint; } /** * Get the namecode of the name of this type. Because built-in types don't depend on the namePool, * this actually returns the fingerprint, which contains no information about the namespace prefix */ public int getNameCode() { return fingerprint; } /** * Get the display name of the type: that is, a lexical QName with an arbitrary prefix * * @return a lexical QName identifying the type */ public String getDisplayName() { return StandardNames.getDisplayName(fingerprint); } /** * Test whether this SchemaType is a complex type * * @return true if this SchemaType is a complex type */ public boolean isComplexType() { return false; } /** * Test whether this SchemaType is a simple type * @return true if this SchemaType is a simple type */ public boolean isSimpleType() { return true; } /** * Returns the value of the 'block' attribute for this type, as a bit-signnificant * integer with fields such as {@link SchemaType#DERIVATION_LIST} and {@link SchemaType#DERIVATION_EXTENSION} * * @return the value of the 'block' attribute for this type */ public int getBlock() { return 0; } /** * Returns the base type that this type inherits from. This method can be used to get the * base type of a type that is known to be valid. * If this type is a Simpletype that is a built in primitive type then null is returned. * * @return the base type. * @throws IllegalStateException if this type is not valid. */ public SchemaType getKnownBaseType() throws IllegalStateException { return AnySimpleType.getInstance(); } /** * Gets the integer code of the derivation method used to derive this type from its * parent. Returns zero for primitive types. * * @return a numeric code representing the derivation method, for example {@link SchemaType#DERIVATION_RESTRICTION} */ public int getDerivationMethod() { return SchemaType.DERIVATION_LIST; } /** * Determines whether derivation (of a particular kind) * from this type is allowed, based on the "final" property * * @param derivation the kind of derivation, for example {@link SchemaType#DERIVATION_LIST} * @return true if this kind of derivation is allowed */ public boolean allowsDerivation(int derivation) { return true; } /** * Get the typed value of a node that is annotated with this schema type. This method must be called * only for a valid type. * * @param node the node whose typed value is required * @return a SequenceIterator over the atomic values making up the typed value of the specified * node. The objects returned by this iterator are of type {@link net.sf.saxon.value.AtomicValue} */ public SequenceIterator getTypedValue(NodeInfo node) throws XPathException { try { return getTypedValue(node.getStringValue(), new InscopeNamespaceResolver(node), node.getConfiguration().getNameChecker()); } catch (ValidationException err) { throw new XPathException("Internal error: value doesn't match its type annotation. " + err.getMessage()); } } /** * Get the typed value of a node that is annotated with this schema type. The result of this method will always be consistent with the method * {@link #getTypedValue}. However, this method is often more convenient and may be * more efficient, especially in the common case where the value is expected to be a singleton. * * @param node the node whose typed value is required * @return the typed value. * @since 8.5 */ public Value atomize(NodeInfo node) throws XPathException { return new SequenceExtent(getTypedValue(node)).simplify(); } /** * Test whether this is the same type as another type. They are considered to be the same type * if they are derived from the same type definition in the original XML representation (which * can happen when there are multiple includes of the same file) */ public boolean isSameType(SchemaType other) { return other.getFingerprint() == getFingerprint(); } public String getDescription() { return getDisplayName(); } /** * Check that this type is validly derived from a given type * * @param type the type from which this type is derived * @param block the derivations that are blocked by the relevant element declaration * @throws SchemaException * if the derivation is not allowed */ public void checkTypeDerivationIsOK(SchemaType type, int block) throws SchemaException { // } /** * Get the local name of this type * @return the local part of the name, or null if the type is anonymous */ public String getLocalName() { return getDisplayName().substring(3); } /** * Returns the simpleType of the items in this ListType. * @return the simpleType of the items in this ListType. */ public SimpleType getItemType() { return itemType; } /** * Apply the whitespace normalization rules for this simple type * @param value the string before whitespace normalization * @return the string after whitespace normalization */ public String applyWhitespaceNormalization(String value) { return Whitespace.collapseWhitespace(value).toString(); } /** * Analyze an expression to see whether the expression is capable of delivering a value of this * type. * * @param expression the expression that delivers the content * @param kind the node kind whose content is being delivered: {@link Type#ELEMENT}, * {@link Type#ATTRIBUTE}, or {@link Type#DOCUMENT} * @param env the XPath static context * @throws net.sf.saxon.trans.XPathException * if the expression will never deliver a value of the correct type */ public void analyzeContentExpression(Expression expression, int kind, StaticContext env) throws XPathException { BuiltInAtomicType.analyzeContentExpression(this, expression, env, kind); } /** * Check whether a given input string is valid according to this SimpleType * @param value the input string to be checked * @param nsResolver a namespace resolver used to resolve namespace prefixes if the type * is namespace sensitive. The value supplied may be null; in this case any namespace-sensitive * content will throw an UnsupportedOperationException. * @param nameChecker XML 1.0 or 1.1 name checker, for types such as xs:NCName * @throws UnsupportedOperationException if the type is namespace-sensitive and no namespace * resolver is supplied */ public ValidationFailure validateContent(CharSequence value, NamespaceResolver nsResolver, NameChecker nameChecker) { SimpleType base = getItemType(); StringTokenIterator iter = new StringTokenIterator(value.toString()); ValidationFailure result = null; int count = 0; //try { while (true) { StringValue val = (StringValue)iter.next(); if (val == null) break; count++; ValidationFailure v = base.validateContent(val.getStringValue(), nsResolver, nameChecker); if (v != null) { return v; } } // } catch (ValidationException err) { // result = err; // } catch (XPathException err) { // result = new ValidationException(err); // } if (count == 0) { result = new ValidationFailure("The built-in list type " + StandardNames.getDisplayName(fingerprint) + " does not allow a zero-length list"); } return result; } /** * Get the typed value of a given input string. This method assumes that the input value * is valid according to this SimpleType * @param value the string whose typed value is required * @param resolver namespace resolver for namespace-sensitive content * @param nameChecker name checker for XML-version sensitive content */ public SequenceIterator getTypedValue(CharSequence value, NamespaceResolver resolver, NameChecker nameChecker) throws ValidationException { UnfailingIterator iter = new StringTokenIterator(value.toString()); ListTypeMappingFunction map = new ListTypeMappingFunction(); map.resolver = resolver; map.atomicType = (AtomicType)getItemType(); map.nameChecker = nameChecker; return new MappingIterator(iter, map); } private static BuiltInListType makeListType(String namespace, String lname) { BuiltInListType t = new BuiltInListType(StandardNames.getFingerprint(namespace, lname)); BuiltInType.register(t.getFingerprint(), t); return t; } private static class ListTypeMappingFunction implements MappingFunction { public NamespaceResolver resolver; public AtomicType atomicType; public NameChecker nameChecker; /** * The typed value of a list-valued node is obtained by tokenizing the string value and * applying a mapping function to the sequence of tokens. * This method implements the mapping function. It is for internal use only. * For details see {@link net.sf.saxon.expr.MappingFunction} */ public SequenceIterator map(Item item) throws XPathException { try { return atomicType.getTypedValue(item.getStringValue(), resolver, nameChecker); } catch (ValidationException err) { throw new XPathException(err); } } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Saxonica Limited. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/type/SchemaDeclaration.java0000644000175000017500000000343011033112257022571 0ustar eugeneeugenepackage net.sf.saxon.type; import net.sf.saxon.pattern.NodeTest; /** * This is a marker interface that acts as a surrogate for an object representing * a global element or attribute declaration. * The real implementation of these declarations is available in the schema-aware * version of the Saxon product. */ public interface SchemaDeclaration { /** * Get the simple or complex type associated with the element or attribute declaration * @return the simple or complex type */ public SchemaType getType(); /** * Create a NodeTest that implements the semantics of schema-element(name) or * schema-attribute(name) applied to this element or attribute declaration. */ public NodeTest makeSchemaNodeTest(); /** * Determine, in the case of an Element Declaration, whether it is nillable. */ public boolean isNillable(); /** * Determine, in the case of an Element Declaration, whether the declaration is abstract */ public boolean isAbstract(); } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Saxonica Limited // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none //saxonb-9.1.0.8/bj/net/sf/saxon/type/Untyped.java0000644000175000017500000003672111270626650020676 0ustar eugeneeugenepackage net.sf.saxon.type; import net.sf.saxon.expr.Expression; import net.sf.saxon.expr.StaticContext; import net.sf.saxon.expr.StaticProperty; import net.sf.saxon.om.*; import net.sf.saxon.sort.IntHashSet; import net.sf.saxon.value.UntypedAtomicValue; import net.sf.saxon.value.Value; import java.io.Serializable; /** * This class has a singleton instance which represents the complex type xdt:untyped, * used for elements that have not been validated. */ public final class Untyped implements ComplexType, Serializable { private static Untyped theInstance = new Untyped(); /** * Private constructor */ private Untyped() { } /** * Get the validation status - always valid */ public int getValidationStatus() { return VALIDATED; } /** * Get the local name of this type * * @return the local name of this type definition, if it has one. Return null in the case of an * anonymous type. */ public String getName() { return "untyped"; } /** * Get the target namespace of this type * * @return the target namespace of this type definition, if it has one. Return null in the case * of an anonymous type, and in the case of a global type defined in a no-namespace schema. */ public String getTargetNamespace() { return NamespaceConstant.SCHEMA; } /** * Get the URI of the schema document containing the definition of this type * @return null for a built-in type */ public String getSystemId() { return null; } /** * Returns the value of the 'block' attribute for this type, as a bit-signnificant * integer with fields such as {@link SchemaType#DERIVATION_LIST} and {@link SchemaType#DERIVATION_EXTENSION} * * @return the value of the 'block' attribute for this type */ public int getBlock() { return 0; } /** * Gets the integer code of the derivation method used to derive this type from its * parent. Returns zero for primitive types. * * @return a numeric code representing the derivation method, for example {@link SchemaType#DERIVATION_RESTRICTION} */ public int getDerivationMethod() { return 0; } /** * Determines whether derivation (of a particular kind) * from this type is allowed, based on the "final" property * * @param derivation the kind of derivation, for example {@link SchemaType#DERIVATION_LIST} * @return true if this kind of derivation is allowed */ public boolean allowsDerivation(int derivation) { return false; } /** * Check that this type is validly derived from a given type * * @param type the type from which this type is derived * @param block the derivations that are blocked by the relevant element declaration */ public void checkTypeDerivationIsOK(SchemaType type, int block) { } /** * Get the fingerprint of the name of this type * * @return the fingerprint. Returns an invented fingerprint for an anonymous type. */ public int getFingerprint() { return StandardNames.XS_UNTYPED; } /** * Get the namecode of the name of this type. This includes the prefix from the original * type declaration: in the case of built-in types, there may be a conventional prefix * or there may be no prefix. */ public int getNameCode() { return StandardNames.XS_UNTYPED; } /** * Get the display name of the type: that is, a lexical QName with an arbitrary prefix * * @return a lexical QName identifying the type */ public String getDisplayName() { return "xs:untyped"; } /** * Test whether this SchemaType is a complex type * * @return true if this SchemaType is a complex type */ public boolean isComplexType() { return true; } /** * Test whether this is an anonymous type * * @return true if this SchemaType is an anonymous type */ public boolean isAnonymousType() { return false; } /** * Returns the base type that this type inherits from. This method can be used to get the * base type of a type that is known to be valid. * If this type is a Simpletype that is a built in primitive type then null is returned. * * @return the base type. * @throws IllegalStateException if this type is not valid. */ public SchemaType getKnownBaseType() throws IllegalStateException { return AnyType.getInstance(); } /** * Test whether this is the same type as another type. They are considered to be the same type * if they are derived from the same type definition in the original XML representation (which * can happen when there are multiple includes of the same file) */ public boolean isSameType(SchemaType other) { return (other instanceof Untyped); } /** * Returns the base type that this type inherits from. * If this type is a Simpletype that is a built in primitive type then null is returned. * * @return the base type. */ public SchemaType getBaseType() { return AnyType.getInstance(); } /** * Get the singular instance of this class * * @return the singular object representing xs:anyType */ public static Untyped getInstance() { return theInstance; } /** * Test whether this ComplexType has been marked as abstract. * * @return false: this class is not abstract. */ public boolean isAbstract() { return false; } /** * Test whether this SchemaType is a simple type * * @return true if this SchemaType is a simple type */ public boolean isSimpleType() { return false; } /** * Test whether this SchemaType is an atomic type * * @return true if this SchemaType is an atomic type */ public boolean isAtomicType() { return false; } /** * Test whether this complex type has complex content * * @return true: this complex type has complex content */ public boolean isComplexContent() { return true; } /** * Test whether this complex type has simple content * * @return false: this complex type has complex content */ public boolean isSimpleContent() { return false; } /** * Test whether this complex type has "all" content, that is, a content model * using an xs:all compositor * * @return false: this complex type does not use an "all" compositor */ public boolean isAllContent() { return false; } /** * For a complex type with simple content, return the simple type of the content. * Otherwise, return null. * * @return null: this complex type does not have simple content */ public SimpleType getSimpleContentType() { return null; } /** * Test whether this complex type is derived by restriction * * @return true: this type is treated as a restriction of xs:anyType */ public boolean isRestricted() { return true; } /** * Test whether the content type of this complex type is empty * * @return false: the content model is not empty */ public boolean isEmptyContent() { return false; } /** * Test whether the content model of this complexType allows empty content * * @return true: the content is allowed to be empty */ public boolean isEmptiable() { return true; } /** * Test whether this complex type allows mixed content * * @return true: mixed content is allowed */ public boolean isMixedContent() { return true; } /** * Get a description of this type for use in diagnostics * * @return the string "xs:anyType" */ public String getDescription() { return "xs:untyped"; } /** * Analyze an expression to see whether the expression is capable of delivering a value of this * type. * * @param expression the expression that delivers the content * @param kind the node kind whose content is being delivered: {@link Type#ELEMENT}, * {@link Type#ATTRIBUTE}, or {@link Type#DOCUMENT} * @param env the static context */ public void analyzeContentExpression(Expression expression, int kind, StaticContext env) { //return; } /** * Get the typed value of a node that is annotated with this schema type * * @param node the node whose typed value is required * @return an iterator returning a single untyped atomic value, equivalent to the string value of the node. This * follows the standard rules for elements with mixed content. */ public SequenceIterator getTypedValue(NodeInfo node) { return SingletonIterator.makeIterator(new UntypedAtomicValue(node.getStringValueCS())); } /** * Get the typed value of a node that is annotated with this schema type. The result of this method will always be consistent with the method * {@link #getTypedValue}. However, this method is often more convenient and may be * more efficient, especially in the common case where the value is expected to be a singleton. * * @param node the node whose typed value is required * @return the typed value. * @since 8.5 */ public Value atomize(NodeInfo node) { return new UntypedAtomicValue(node.getStringValue()); } /** * Test whether this complex type subsumes another complex type. The algorithm * used is as published by Thompson and Tobin, XML Europe 2003. * * @param sub the other type (the type that is derived by restriction, validly or otherwise) * @param compiler used for error reporting * @return null indicating that this type does indeed subsume the other; or a string indicating * why it doesn't. */ // public String subsumes(ComplexType sub, ISchemaCompiler compiler) { // return null; // } /** * Find an element particle within this complex type definition having a given element name * (identified by fingerprint), and return the schema type associated with that element particle. * If there is no such particle, return null. If the fingerprint matches an element wildcard, * return the type of the global element declaration with the given name if one exists, or AnyType * if none exists and lax validation is permitted by the wildcard. * * @param fingerprint Identifies the name of the child element within this content model * @param considerExtensions */ public SchemaType getElementParticleType(int fingerprint, boolean considerExtensions) { return this; } /** * Find an element particle within this complex type definition having a given element name * (identified by fingerprint), and return the cardinality associated with that element particle, * that is, the number of times the element can occur within this complex type. The value is one of * {@link net.sf.saxon.expr.StaticProperty#EXACTLY_ONE}, {@link net.sf.saxon.expr.StaticProperty#ALLOWS_ZERO_OR_ONE}, * {@link net.sf.saxon.expr.StaticProperty#ALLOWS_ZERO_OR_MORE}, {@link net.sf.saxon.expr.StaticProperty#ALLOWS_ONE_OR_MORE}, * If there is no such particle, return zero. * * @param fingerprint Identifies the name of the child element within this content model * @param searchExtensionTypes */ public int getElementParticleCardinality(int fingerprint, boolean searchExtensionTypes) { return StaticProperty.ALLOWS_ZERO_OR_MORE; } /** * Find an attribute use within this complex type definition having a given attribute name * (identified by fingerprint), and return the schema type associated with that attribute. * If there is no such attribute use, return null. If the fingerprint matches an attribute wildcard, * return the type of the global attribute declaration with the given name if one exists, or AnySimpleType * if none exists and lax validation is permitted by the wildcard. * * @param fingerprint Identifies the name of the child element within this content model */ public SchemaType getAttributeUseType(int fingerprint) { return BuiltInAtomicType.UNTYPED_ATOMIC; } /** * Return true if this type (or any known type derived from it by extension) allows the element * to have one or more attributes. * @return true if attributes are allowed */ public boolean allowsAttributes() { return true; } /** * Get a list of all the names of elements that can appear as children of an element having this * complex type, as integer fingerprints. If the list is unbounded (because of wildcards or the use * of xs:anyType), return null. * * @param children an integer set, initially empty, which on return will hold the fingerprints of all permitted * child elements; if the result contains the value -1, this indicates that it is not possible to enumerate * all the children, typically because of wildcards. In this case the other contents of the set should * be ignored. */ public void gatherAllPermittedChildren(IntHashSet children) throws SchemaException { children.add(-1); } /** * Get a list of all the names of elements that can appear as descendants of an element having this * complex type, as integer fingerprints. If the list is unbounded (because of wildcards or the use * of xs:anyType), return null. * * @param descendants an integer set, initially empty, which on return will hold the fingerprints of all permitted * descendant elements; if the result contains the value -1, this indicates that it is not possible to enumerate * all the descendants, typically because of wildcards. In this case the other contents of the set should * be ignored. */ public void gatherAllPermittedDescendants(IntHashSet descendants) throws SchemaException { descendants.add(-1); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Saxonica Limited // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none //saxonb-9.1.0.8/bj/net/sf/saxon/type/ComplexType.java0000644000175000017500000002160211270626650021507 0ustar eugeneeugenepackage net.sf.saxon.type; import net.sf.saxon.sort.IntHashSet; /** * A complex type as defined in XML Schema: either a user-defined complex type, or xs:anyType, or xs:untyped. * In the non-schema-aware version of the Saxon product, the only complex type encountered is xs:untyped. */ public interface ComplexType extends SchemaType { /** * Test whether this complex type has been marked as abstract. This corresponds to * the {abstract} property in the schema component model. * * @return true if this complex type is abstract. */ public boolean isAbstract(); /** * Test whether this complex type has complex content. This represents one aspect of the * {content type} property in the schema component model. * * @return true if this complex type has a complex content model, false if it has a simple content model */ public boolean isComplexContent(); /** * Test whether this complexType has simple content. This represents one aspect of the * {content type} property in the schema component model. * * @return true if this complex type has a simple content model, false if it has a complex content model */ public boolean isSimpleContent(); /** * Test whether this complex type has "all" content, that is, a content model * using an xs:all compositor * @return true if the type has an "all" content model */ public boolean isAllContent(); /** * Get the simple content type. This represents one aspect of the * {content type} property in the schema component model. * * @return For a complex type with simple content, returns the simple type of the content. * Otherwise, returns null. */ public SimpleType getSimpleContentType(); /** * Test whether this complex type is derived by restriction. This corresponds to one * aspect of the {derivation method} property in the schema component model. * * @return true if this complex type is derived by restriction */ public boolean isRestricted(); /** * Test whether the content model of this complex type is empty. This represents one aspect of the * {content type} property in the schema component model. * * @return true if the content model is defined as empty */ public boolean isEmptyContent(); /** * Test whether the content model of this complex type allows empty content. This property applies only if * this is a complex type with complex content. * * @return true if empty content is valid */ public boolean isEmptiable() throws SchemaException; /** * Test whether this complex type allows mixed content. This represents one aspect of the * {content type} property in the schema component model. This property applies only if * this is a complex type with complex content. * * @return true if mixed content is allowed */ public boolean isMixedContent(); /** * Test whether this complex type subsumes another complex type. The algorithm * used is as published by Thompson and Tobin, XML Europe 2003. * @param sub the other type (the type that is derived by restriction, validly or otherwise) * @param compiler used for error reporting * @return null indicating that this type does indeed subsume the other; or a string indicating * why it doesn't. */ //public String subsumes(ComplexType sub, ISchemaCompiler compiler) throws SchemaException; /** * Find an element particle within this complex type definition having a given element name * (identified by fingerprint), and return the schema type associated with that element particle. * If there is no such particle, return null. If the fingerprint matches an element wildcard, * return the type of the global element declaration with the given name if one exists, or AnyType * if none exists and lax validation is permitted by the wildcard. * @param fingerprint Identifies the name of the child element within this content model * @param considerExtensions * @return the schema type associated with the child element particle with the given name. * If there is no such particle, return null. */ public SchemaType getElementParticleType(int fingerprint, boolean considerExtensions) throws SchemaException, ValidationException; /** * Find an element particle within this complex type definition having a given element name * (identified by fingerprint), and return the cardinality associated with that element particle, * that is, the number of times the element can occur within this complex type. The value is one of * {@link net.sf.saxon.expr.StaticProperty#EXACTLY_ONE}, {@link net.sf.saxon.expr.StaticProperty#ALLOWS_ZERO_OR_ONE}, * {@link net.sf.saxon.expr.StaticProperty#ALLOWS_ZERO_OR_MORE}, {@link net.sf.saxon.expr.StaticProperty#ALLOWS_ONE_OR_MORE}, * If there is no such particle, return {@link net.sf.saxon.expr.StaticProperty#EMPTY}. * @param fingerprint Identifies the name of the child element within this content model * @param searchExtensionTypes * @return the cardinality associated with the child element particle with the given name. * If there is no such particle, return {@link net.sf.saxon.expr.StaticProperty#EMPTY}. */ public int getElementParticleCardinality(int fingerprint, boolean searchExtensionTypes) throws SchemaException, ValidationException; /** * Find an attribute use within this complex type definition having a given attribute name * (identified by fingerprint), and return the schema type associated with that attribute. * If there is no such attribute use, return null. If the fingerprint matches an attribute wildcard, * return the type of the global attribute declaration with the given name if one exists, or AnySimpleType * if none exists and lax validation is permitted by the wildcard. *

    * If there are types derived from this type by extension, search those too. * @param fingerprint Identifies the name of the child element within this content model * @return the schema type associated with the attribute use identified by the fingerprint. * If there is no such attribute use, return null. */ public SchemaType getAttributeUseType(int fingerprint) throws SchemaException, ValidationException; /** * Return true if this type (or any known type derived from it by extension) allows the element * to have one or more attributes. * @return true if attributes are allowed */ public boolean allowsAttributes(); /** * Get a list of all the names of elements that can appear as children of an element having this * complex type, as integer fingerprints. If the list is unbounded (because of wildcards or the use * of xs:anyType), return null. * @param children an integer set, initially empty, which on return will hold the fingerprints of all permitted * child elements; if the result contains the value -1, this indicates that it is not possible to enumerate * all the children, typically because of wildcards. In this case the other contents of the set should * be ignored. */ public void gatherAllPermittedChildren(IntHashSet children) throws SchemaException; /** * Get a list of all the names of elements that can appear as descendants of an element having this * complex type, as integer fingerprints. If the list is unbounded (because of wildcards or the use * of xs:anyType), include a -1 in the result. * @param descendants an integer set, initially empty, which on return will hold the fingerprints of all permitted * descendant elements; if the result contains the value -1, this indicates that it is not possible to enumerate * all the descendants, typically because of wildcards. In this case the other contents of the set should * be ignored. */ public void gatherAllPermittedDescendants(IntHashSet descendants) throws SchemaException; } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Saxonica Limited // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none //saxonb-9.1.0.8/bj/net/sf/saxon/type/AnyItemType.java0000644000175000017500000000602211033112257021433 0ustar eugeneeugenepackage net.sf.saxon.type; import net.sf.saxon.Configuration; import net.sf.saxon.om.Item; import net.sf.saxon.om.NamePool; import java.io.Serializable; /** * An implementation of ItemType that matches any item (node or atomic value) */ public class AnyItemType implements ItemType, Serializable { private AnyItemType(){}; private static AnyItemType theInstance = new AnyItemType(); /** * Factory method to get the singleton instance */ public static AnyItemType getInstance() { return theInstance; } /** * Determine whether this item type is atomic (that is, whether it can ONLY match * atomic values) * * @return false: this type can match nodes or atomic values */ public boolean isAtomicType() { return false; } /** * Test whether a given item conforms to this type * @param item The item to be tested * @param allowURIPromotion * @param config * @return true if the item is an instance of this type; false otherwise */ public boolean matchesItem(Item item, boolean allowURIPromotion, Configuration config) { return true; } public ItemType getSuperType(TypeHierarchy th) { return null; } /** * Get the primitive item type corresponding to this item type. For item(), * this is Type.ITEM. For node(), it is Type.NODE. For specific node kinds, * it is the value representing the node kind, for example Type.ELEMENT. * For anyAtomicValue it is Type.ATOMIC_VALUE. For numeric it is Type.NUMBER. * For other atomic types it is the primitive type as defined in XML Schema, * except that INTEGER is considered to be a primitive type. */ public ItemType getPrimitiveItemType() { return this; } public int getPrimitiveType() { return Type.ITEM; } public AtomicType getAtomizedItemType() { return BuiltInAtomicType.ANY_ATOMIC; } public String toString() { return "item()"; } public String toString(NamePool pool) { return "item()"; } /** * Returns a hash code value for the object. */ public int hashCode() { return "AnyItemType".hashCode(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/type/SimpleType.java0000644000175000017500000001235011033112257021317 0ustar eugeneeugenepackage net.sf.saxon.type; import net.sf.saxon.om.NameChecker; import net.sf.saxon.om.NamespaceResolver; import net.sf.saxon.om.SequenceIterator; /** * This interface represents a simple type, which may be a built-in simple type, or * a user-defined simple type. */ public interface SimpleType extends SchemaType { /** * Test whether this Simple Type is an atomic type * @return true if this is an atomic type */ boolean isAtomicType(); /** * Test whether this Simple Type is a list type * @return true if this is a list type */ boolean isListType(); /** * Test whether this Simple Type is a union type * @return true if this is a union type */ boolean isUnionType(); /** * Return true if this is an external object type, that is, a Saxon-defined type for external * Java or .NET objects * @return true if this is an external type */ boolean isExternalType(); /** * Get the most specific possible atomic type that all items in this SimpleType belong to * @return the lowest common supertype of all member types */ AtomicType getCommonAtomicType(); /** * Determine whether this is a built-in type or a user-defined type * @return true if this is a built-in type */ boolean isBuiltInType(); /** * Get the built-in type from which this type is derived by restriction * @return the built-in type from which this type is derived by restriction. This will not necessarily * be a primitive type. */ SchemaType getBuiltInBaseType(); /** * Get the typed value corresponding to a given string value, assuming it is * valid against this type * @param value the string value * @param resolver a namespace resolver used to resolve any namespace prefixes appearing * in the content of values. Can supply null, in which case any namespace-sensitive content * will be rejected. * @param nameChecker a NameChecker used in the case of types that are defined in terms of the * XML NCName syntax: this is used to check conformance to XML 1.0 or XML 1.1 naming rules, as * appropriate * @return an iterator over the atomic sequence comprising the typed value. The objects * returned by this SequenceIterator will all be of type {@link net.sf.saxon.value.AtomicValue}, * The next() method on the iterator throws no checked exceptions, although it is not actually * declared as an UnfailingIterator. * @throws ValidationException if the supplied value is not in the lexical space of the data type */ public SequenceIterator getTypedValue(CharSequence value, NamespaceResolver resolver, NameChecker nameChecker) throws ValidationException; /** * Check whether a given input string is valid according to this SimpleType * @param value the input string to be checked * @param nsResolver a namespace resolver used to resolve namespace prefixes if the type * is namespace sensitive. The value supplied may be null; in this case any namespace-sensitive * content will throw an UnsupportedOperationException. * @param nameChecker XML 1.0 or 1.1 name checker, needed when types such as xs:NCName are used * @return null if validation succeeds; return a ValidationFailure describing the validation failure * if validation fails. Note that the exception is returned rather than being thrown. * @throws UnsupportedOperationException if the type is namespace-sensitive and no namespace * resolver is supplied */ ValidationFailure validateContent(CharSequence value, NamespaceResolver nsResolver, NameChecker nameChecker); /** * Test whether this type is namespace sensitive, that is, if a namespace context is needed * to translate between the lexical space and the value space. This is true for types derived * from, or containing, QNames and NOTATIONs * @return true if the type is namespace-sensitive */ boolean isNamespaceSensitive(); /** * Determine how values of this simple type are whitespace-normalized. * @return one of {@link net.sf.saxon.value.Whitespace#PRESERVE}, {@link net.sf.saxon.value.Whitespace#COLLAPSE}, * {@link net.sf.saxon.value.Whitespace#REPLACE}. * @param th the type hierarchy cache. Not needed in the case of a built-in type */ public int getWhitespaceAction(TypeHierarchy th); } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/type/AnySimpleType.java0000644000175000017500000002753111033112257021776 0ustar eugeneeugenepackage net.sf.saxon.type; import net.sf.saxon.expr.Expression; import net.sf.saxon.expr.StaticContext; import net.sf.saxon.om.*; import net.sf.saxon.om.StandardNames; import net.sf.saxon.value.UntypedAtomicValue; import net.sf.saxon.value.Value; import net.sf.saxon.value.Whitespace; /** * This class has a singleton instance which represents the XML Schema built-in type xs:anySimpleType */ public final class AnySimpleType implements SimpleType { private static AnySimpleType theInstance = new AnySimpleType(); /** * Private constructor */ private AnySimpleType() { } /** * Get the local name of this type * * @return the local name of this type definition, if it has one. Return null in the case of an * anonymous type. */ public String getName() { return "anySimpleType"; } /** * Get the target namespace of this type * * @return the target namespace of this type definition, if it has one. Return null in the case * of an anonymous type, and in the case of a global type defined in a no-namespace schema. */ public String getTargetNamespace() { return NamespaceConstant.SCHEMA; } /** * Return true if this is an external object type, that is, a Saxon-defined type for external * Java or .NET objects */ public boolean isExternalType() { return false; } /** * Determine whether this is a built-in type or a user-defined type */ public boolean isBuiltInType() { return true; } /** * Get the URI of the schema document containing the definition of this type * @return null for a built-in type */ public String getSystemId() { return null; } /** * Get the most specific possible atomic type that all items in this SimpleType belong to * @return the lowest common supertype of all member types */ public AtomicType getCommonAtomicType() { return BuiltInAtomicType.ANY_ATOMIC; } /** * Get the singular instance of this class * @return the singular object representing xs:anyType */ public static AnySimpleType getInstance() { return theInstance; } /** * Get the validation status - always valid */ public int getValidationStatus() { return VALIDATED; } /** * Get the base type * @return AnyType */ public SchemaType getBaseType() { return AnyType.getInstance(); } /** * Returns the base type that this type inherits from. This method can be used to get the * base type of a type that is known to be valid. * @return the base type. */ public SchemaType getKnownBaseType() throws IllegalStateException { return getBaseType(); } /** * Test whether this SchemaType is a complex type * * @return true if this SchemaType is a complex type */ public boolean isComplexType() { return false; } /** * Test whether this SchemaType is a simple type * @return true if this SchemaType is a simple type */ public boolean isSimpleType() { return true; } /** * Get the fingerprint of the name of this type * @return the fingerprint. */ public int getFingerprint() { return StandardNames.XS_ANY_SIMPLE_TYPE; } /** * Get the namecode of the name of this type. This includes the prefix from the original * type declaration: in the case of built-in types, there may be a conventional prefix * or there may be no prefix. */ public int getNameCode() { return StandardNames.XS_ANY_SIMPLE_TYPE; } /** * Get a description of this type for use in diagnostics * @return the string "xs:anyType" */ public String getDescription() { return "xs:anySimpleType"; } /** * Get the display name of the type: that is, a lexical QName with an arbitrary prefix * * @return a lexical QName identifying the type */ public String getDisplayName() { return "xs:anySimpleType"; } /** * Test whether this is the same type as another type. They are considered to be the same type * if they are derived from the same type definition in the original XML representation (which * can happen when there are multiple includes of the same file) */ public boolean isSameType(SchemaType other) { return (other instanceof AnySimpleType); } /** * Get the typed value of a node that is annotated with this schema type. This shouldn't happen: nodes * are never annotated as xs:anySimpleType; but if it does happen, we treat it as if it were * untypedAtomic. * @param node the node whose typed value is required * @return an iterator returning a single untyped atomic value, equivalent to the string value of the node. */ public SequenceIterator getTypedValue(NodeInfo node) { return SingletonIterator.makeIterator(new UntypedAtomicValue(node.getStringValueCS())); } /** * Get the typed value of a node that is annotated with this schema type. The result of this method will always be consistent with the method * {@link #getTypedValue}. However, this method is often more convenient and may be * more efficient, especially in the common case where the value is expected to be a singleton. * * @param node the node whose typed value is required * @return the typed value. * @since 8.5 */ public Value atomize(NodeInfo node) { return new UntypedAtomicValue(node.getStringValueCS()); } /** * Check that this type is validly derived from a given type * * @param type the type from which this type is derived * @param block the derivations that are blocked by the relevant element declaration * @throws SchemaException * if the derivation is not allowed */ public void checkTypeDerivationIsOK(SchemaType type, int block) throws SchemaException { if (type == this) { return; } throw new SchemaException("Cannot derive xs:anySimpleType from another type"); } /** * Test whether this Simple Type is an atomic type * @return false, this is not (necessarily) an atomic type */ public boolean isAtomicType() { return false; } public boolean isAnonymousType() { return false; } /** * Determine whether this is a list type * @return false (it isn't a list type) */ public boolean isListType() { return false; } /** * Determin whether this is a union type * @return false (it isn't a union type) */ public boolean isUnionType() { return false; } /** * Get the built-in ancestor of this type in the type hierarchy * @return this type itself */ public SchemaType getBuiltInBaseType() { return this; } /** * Get the typed value corresponding to a given string value, assuming it is * valid against this type * * @param value the string value * @param resolver a namespace resolver used to resolve any namespace prefixes appearing * in the content of values. Can supply null, in which case any namespace-sensitive content * will be rejected. * @param nameChecker * @return an iterator over the atomic sequence comprising the typed value. The objects * returned by this SequenceIterator will all be of type {@link net.sf.saxon.value.AtomicValue} */ public SequenceIterator getTypedValue(CharSequence value, NamespaceResolver resolver, NameChecker nameChecker) { return SingletonIterator.makeIterator(new UntypedAtomicValue(value)); } /** * Check whether a given input string is valid according to this SimpleType * @param value the input string to be checked * @param nsResolver a namespace resolver used to resolve namespace prefixes if the type * is namespace sensitive. The value supplied may be null; in this case any namespace-sensitive * content will throw an UnsupportedOperationException. * @param nameChecker * @return null if validation succeeds (which it always does for this implementation) * @throws UnsupportedOperationException if the type is namespace-sensitive and no namespace * resolver is supplied */ public ValidationFailure validateContent(CharSequence value, NamespaceResolver nsResolver, NameChecker nameChecker) { return null; } /** * Test whether this type represents namespace-sensitive content * @return false */ public boolean isNamespaceSensitive() { return false; } /** * Returns the value of the 'block' attribute for this type, as a bit-signnificant * integer with fields such as {@link SchemaType#DERIVATION_LIST} and {@link SchemaType#DERIVATION_EXTENSION} * * @return the value of the 'block' attribute for this type */ public int getBlock() { return 0; } /** * Gets the integer code of the derivation method used to derive this type from its * parent. Returns zero for primitive types. * * @return a numeric code representing the derivation method, for example {@link SchemaType#DERIVATION_RESTRICTION} */ public int getDerivationMethod() { return SchemaType.DERIVATION_RESTRICTION; } /** * Determines whether derivation (of a particular kind) * from this type is allowed, based on the "final" property * * @param derivation the kind of derivation, for example {@link SchemaType#DERIVATION_LIST} * @return true if this kind of derivation is allowed */ public boolean allowsDerivation(int derivation) { return true; } /** * Determine how values of this simple type are whitespace-normalized. * * @return one of {@link net.sf.saxon.value.Whitespace#PRESERVE}, {@link net.sf.saxon.value.Whitespace#COLLAPSE}, * {@link net.sf.saxon.value.Whitespace#REPLACE}. * @param th the type hierarchy cache */ public int getWhitespaceAction(TypeHierarchy th) { return Whitespace.COLLAPSE; } /** * Analyze an expression to see whether the expression is capable of delivering a value of this * type. * * @param expression the expression that delivers the content * @param kind the node kind whose content is being delivered: {@link net.sf.saxon.type.Type#ELEMENT}, * {@link net.sf.saxon.type.Type#ATTRIBUTE}, or {@link net.sf.saxon.type.Type#DOCUMENT} * @param env */ public void analyzeContentExpression(Expression expression, int kind, StaticContext env) { //return; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Saxonica Limited // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none //saxonb-9.1.0.8/bj/net/sf/saxon/type/AtomicType.java0000644000175000017500000000620111033112257021300 0ustar eugeneeugenepackage net.sf.saxon.type; import net.sf.saxon.om.NameChecker; import net.sf.saxon.value.AtomicValue; /** * Interface for atomic types (these are either built-in atomic types * or user-defined atomic types). An AtomicType is both an ItemType (a possible type * for items in a sequence) and a SchemaType (a possible type for validating and * annotating nodes). */ public interface AtomicType extends SimpleType, ItemType { /** * Validate that a primitive atomic value is a valid instance of a type derived from the * same primitive type. * @param primValue the value in the value space of the primitive type. * @param lexicalValue the value in the lexical space. If null, the string value of primValue * is used. This value is checked against the pattern facet (if any) * @param checker Used for checking names against XML 1.0 or XML 1.1 rules * @return null if the value is valid; otherwise, a ValidationFailure object indicating * the nature of the error. * @throws UnsupportedOperationException in the case of an external object type */ public ValidationFailure validate(AtomicValue primValue, CharSequence lexicalValue, NameChecker checker); /** * Determine whether the atomic type is ordered, that is, whether less-than and greater-than comparisons * are permitted * @return true if ordering operations are permitted */ public boolean isOrdered(); /** * Determine whether the type is abstract, that is, whether it cannot have instances that are not also * instances of some concrete subtype */ public boolean isAbstract(); /** * Determine whether the atomic type is a primitive type. The primitive types are * the 19 primitive types of XML Schema, plus xs:integer, xs:dayTimeDuration and xs:yearMonthDuration; * xs:untypedAtomic; and all supertypes of these (xs:anyAtomicType, xs:numeric, ...) * @return true if the type is considered primitive under the above rules */ public boolean isPrimitiveType(); /** * Determine whether the atomic type is a built-in type. The built-in atomic types are the 41 atomic types * defined in XML Schema, plus xs:dayTimeDuration and xs:yearMonthDuration, * xs:untypedAtomic, and all supertypes of these (xs:anyAtomicType, xs:numeric, ...) */ public boolean isBuiltInType(); } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/type/SchemaComponent.java0000644000175000017500000000416211033112257022311 0ustar eugeneeugenepackage net.sf.saxon.type; import java.io.Serializable; /** * This is a marker interface that represents any "schema component" as defined in the XML Schema * specification. This may be a user-defined schema component or a built-in schema component. */ public interface SchemaComponent extends Serializable { /** * Get the validation status of this component. * @return one of the values {@link #UNVALIDATED}, {@link #VALIDATING}, * {@link #VALIDATED}, {@link #INVALID}, {@link #INCOMPLETE} */ public int getValidationStatus(); /** * Validation status: not yet validated */ public static final int UNVALIDATED = 0; /** * Validation status: fixed up (all references to other components have been resolved) */ public static final int FIXED_UP = 1; /** * Validation status: currently being validated */ public static final int VALIDATING = 2; /** * Validation status: successfully validated */ public static final int VALIDATED = 3; /** * Validation status: validation attempted and failed with fatal errors */ public static final int INVALID = 4; /** * Validation status: validation attempted, component contains references to * other components that are not (yet) available */ public static final int INCOMPLETE = 5; } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Saxonica Limited // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none //saxonb-9.1.0.8/bj/net/sf/saxon/type/ItemType.java0000644000175000017500000001063011033112257020763 0ustar eugeneeugenepackage net.sf.saxon.type; import net.sf.saxon.Configuration; import net.sf.saxon.om.Item; import net.sf.saxon.om.NamePool; import java.io.Serializable; /** * ItemType is an interface that allows testing of whether an Item conforms to an * expected type. ItemType represents the types in the type hierarchy in the XPath model, * as distinct from the schema model: an item type is either item() (matches everything), * a node type (matches nodes), an atomic type (matches atomic values), or empty() * (matches nothing). Atomic types, represented by the class AtomicType, are also * instances of SimpleType in the schema type heirarchy. Node Types, represented by * the class NodeTest, are also Patterns as used in XSLT. * @see net.sf.saxon.type.AtomicType * @see net.sf.saxon.pattern.NodeTest */ public interface ItemType extends Serializable { /** * Determine whether this item type is atomic (that is, whether it can ONLY match * atomic values) * @return true if this is ANY_ATOMIC_TYPE or a subtype thereof */ public boolean isAtomicType(); /** * Test whether a given item conforms to this type * @param item The item to be tested * @param allowURIPromotion * @param config * @return true if the item is an instance of this type; false otherwise */ public boolean matchesItem(Item item, boolean allowURIPromotion, Configuration config); /** * Get the type from which this item type is derived by restriction. This * is the supertype in the XPath type heirarchy, as distinct from the Schema * base type: this means that the supertype of xs:boolean is xs:anyAtomicType, * whose supertype is item() (rather than xs:anySimpleType). *

    * In fact the concept of "supertype" is not really well-defined, because the types * form a lattice rather than a hierarchy. The only real requirement on this function * is that it returns a type that strictly subsumes this type, ideally as narrowly * as possible. * @return the supertype, or null if this type is item() * @param th the type hierarchy cache */ public ItemType getSuperType(TypeHierarchy th); /** * Get the primitive item type corresponding to this item type. For item(), * this is Type.ITEM. For node(), it is Type.NODE. For specific node kinds, * it is the value representing the node kind, for example Type.ELEMENT. * For anyAtomicValue it is Type.ATOMIC_VALUE. For numeric it is Type.NUMBER. * For other atomic types it is the primitive type as defined in XML Schema, * except that integer, xs:dayTimeDuration, and xs:yearMonthDuration * are considered to be primitive types. */ public ItemType getPrimitiveItemType(); /** * Get the primitive type corresponding to this item type. For item(), * this is Type.ITEM. For node(), it is Type.NODE. For specific node kinds, * it is the value representing the node kind, for example Type.ELEMENT. * For anyAtomicValue it is Type.ATOMIC_VALUE. For numeric it is Type.NUMBER. * For other atomic types it is the primitive type as defined in XML Schema, * except that INTEGER is considered to be a primitive type. */ public int getPrimitiveType(); /** * Produce a representation of this type name for use in error messages. * Where this is a QName, it will use conventional prefixes */ public String toString(NamePool pool); /** * Get the item type of the atomic values that will be produced when an item * of this type is atomized */ public AtomicType getAtomizedItemType(); } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/type/ISchemaCompiler.java0000644000175000017500000000145011033112257022227 0ustar eugeneeugenepackage net.sf.saxon.type; /** * Marker interface: the only instance of this class is the SchemaCompiler object in Saxon-SA */ public interface ISchemaCompiler { } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/type/ListType.java0000644000175000017500000000231011033112257020774 0ustar eugeneeugenepackage net.sf.saxon.type; /** * Interface representing a simple type of variety List */ public interface ListType extends SimpleType { /** * Returns the simpleType of the items in this ListType. This method assumes that the * item type has been fully resolved * @return the simpleType of the items in this ListType. * @throws IllegalStateException if the item type has not been fully resolved */ SimpleType getItemType(); } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/type/SchemaURIResolver.java0000644000175000017500000000500011033112257022520 0ustar eugeneeugenepackage net.sf.saxon.type; import net.sf.saxon.trans.XPathException; import javax.xml.transform.Source; import java.io.Serializable; /** * A SchemaURIResolver is used when resolving references to * schema documents. It takes as input the target namespace of the schema to be loaded, and a set of * location hints as input, and returns one or more Source obects containing the schema documents * to be imported. * @author Michael H. Kay */ public interface SchemaURIResolver extends Serializable { /** * Resolve a URI identifying a schema document, given the target namespace URI and * a set of associated location hints. * @param targetNamespace the target namespaces of the schema to be imported. The "null namesapce" * is identified by a zero-length string. In the case of an xsd:include directive, where no * target namespace is specified, the parameter is null. * @param baseURI The base URI of the module containing the "import schema" declaration; * null if no base URI is known * @param locations The set of URIs identified as schema location hints. In most cases (xsd:include, xsd:import, * xsi:schemaLocation, xsl:import-schema) there is only one URI in this list. With an XQuery "import module" * declaration, however, a list of URIs may be specified. * @return an array of Source objects each identifying a schema document to be loaded. * These need not necessarily correspond one-to-one with the location hints provided. * @throws net.sf.saxon.trans.XPathException if the module cannot be located, and if delegation to the default * module resolver is not required. */ public Source[] resolve(String targetNamespace, String baseURI, String[] locations) throws XPathException; } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/type/SchemaException.java0000644000175000017500000000411311033112257022301 0ustar eugeneeugene package net.sf.saxon.type; import javax.xml.transform.SourceLocator; import javax.xml.transform.TransformerConfigurationException; /** * An exception that identifies an error in reading, parsing, or * validating a schema. */ public class SchemaException extends TransformerConfigurationException { /** * Creates a new XMLException with no message * or nested Exception. */ public SchemaException() { super(); } public SchemaException(String message, SourceLocator locator) { super(message, locator); } /** * Creates a new XMLException with the given message. * * @param message the message for this Exception */ public SchemaException(String message) { super(message); } /** * Creates a new XMLException with the given nested * exception. * * @param exception the nested exception */ public SchemaException(Throwable exception) { super(exception); } /** * Creates a new XMLException with the given message * and nested exception. * * @param message the detail message for this exception * @param exception the nested exception */ public SchemaException(String message, Throwable exception) { super(message, exception); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Saxonica Limited // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none //saxonb-9.1.0.8/bj/net/sf/saxon/type/TypeHierarchy.java0000644000175000017500000004344011033112257022010 0ustar eugeneeugenepackage net.sf.saxon.type; import net.sf.saxon.Configuration; import net.sf.saxon.om.NamePool; import net.sf.saxon.om.StandardNames; import net.sf.saxon.pattern.AnyNodeTest; import net.sf.saxon.pattern.DocumentNodeTest; import net.sf.saxon.pattern.EmptySequenceTest; import net.sf.saxon.pattern.NodeTest; import net.sf.saxon.sort.IntHashSet; import java.io.Serializable; import java.util.Collections; import java.util.HashMap; import java.util.Map; /** * This class exists to provide answers to questions about the type hierarchy. Because * such questions are potentially expensive, it caches the answers. There is one instance of * this class for a Configuration. */ public class TypeHierarchy implements Serializable { private Map map; private Configuration config; /** * Constant denoting relationship between two types: A is the same type as B */ public static final int SAME_TYPE = 0; /** * Constant denoting relationship between two types: A subsumes B */ public static final int SUBSUMES = 1; /** * Constant denoting relationship between two types: A is subsumed by B */ public static final int SUBSUMED_BY = 2; /** * Constant denoting relationship between two types: A overlaps B */ public static final int OVERLAPS = 3; /** * Constant denoting relationship between two types: A is disjoint from B */ public static final int DISJOINT = 4; //private String[] relnames = {"SAME", "SUBSUMES", "SUBSUMED_BY", "OVERLAPS", "DISJOINT"}; /** * Create the type hierarchy cache for a configuration * @param config the configuration */ public TypeHierarchy(Configuration config){ this.config = config; try { // J2SE 5.0 path Class concurrentHashMapClass = config.getClass("java.util.concurrent.ConcurrentHashMap", false, null); map = (Map)concurrentHashMapClass.newInstance(); } catch (Exception e) { // JDK 1.4 path map = Collections.synchronizedMap(new HashMap(100)); } } /** * Get the Saxon configuration to which this type hierarchy belongs * @return the configuration */ public Configuration getConfiguration() { return config; } /** * Determine whether type A is type B or one of its subtypes, recursively * * @param subtype identifies the first type * @param supertype identifies the second type * @return true if the first type is the second type or a (direct or * indirect) subtype of the second type */ public boolean isSubType(ItemType subtype, ItemType supertype) { int relation = relationship(subtype, supertype); return (relation==SAME_TYPE || relation==SUBSUMED_BY); } /** * Determine the relationship of one item type to another. * @param t1 the first item type * @param t2 the second item type * @return {@link #SAME_TYPE} if the types are the same; {@link #SUBSUMES} if the first * type subsumes the second (that is, all instances of the second type are also instances * of the first); {@link #SUBSUMED_BY} if the second type subsumes the first; * {@link #OVERLAPS} if the two types overlap (have a non-empty intersection, but neither * subsumes the other); {@link #DISJOINT} if the two types are disjoint (have an empty intersection) */ public int relationship(ItemType t1, ItemType t2) { if (t1 == null) { throw new NullPointerException(); } if (t1.equals(t2)) { return SAME_TYPE; } ItemTypePair pair = new ItemTypePair(t1, t2); Integer result = (Integer)map.get(pair); if (result == null) { final int r = computeRelationship(t1, t2); result = new Integer(r); map.put(pair, result); } return result.intValue(); } /** * Determine the relationship of one item type to another. * @param t1 the first item type * @param t2 the second item type * @return {@link #SAME_TYPE} if the types are the same; {@link #SUBSUMES} if the first * type subsumes the second (that is, all instances of the second type are also instances * of the first); {@link #SUBSUMED_BY} if the second type subsumes the first; * {@link #OVERLAPS} if the two types overlap (have a non-empty intersection, but neither * subsumes the other); {@link #DISJOINT} if the two types are disjoint (have an empty intersection) */ private int computeRelationship(ItemType t1, ItemType t2) { //System.err.println("computeRelationship " + t1 + ", " + t2); if (t1 == t2) { return SAME_TYPE; } if (t1 instanceof AnyItemType) { if (t2 instanceof AnyItemType) { return SAME_TYPE; } else { return SUBSUMES; } } else if (t2 instanceof AnyItemType) { return SUBSUMED_BY; } else if (t1.isAtomicType()) { if (t2 instanceof NodeTest) { return DISJOINT; } else if (t1 instanceof ExternalObjectType) { if (t2 instanceof ExternalObjectType) { return ((ExternalObjectType)t1).getRelationship((ExternalObjectType)t2); } else if (((AtomicType)t2).getFingerprint() == StandardNames.XS_ANY_ATOMIC_TYPE) { return SUBSUMED_BY; } else { return DISJOINT; } } else if (t2 instanceof ExternalObjectType) { if (((AtomicType)t1).getFingerprint() == StandardNames.XS_ANY_ATOMIC_TYPE) { return SUBSUMES; } else { return DISJOINT; } } else { if (((AtomicType)t1).getFingerprint() == ((AtomicType)t2).getFingerprint()) { return SAME_TYPE; } ItemType t = t2; while (t.isAtomicType()) { if (((AtomicType)t1).getFingerprint() == ((AtomicType)t).getFingerprint()) { return SUBSUMES; } t = t.getSuperType(this); } t = t1; while (t.isAtomicType()) { if (((AtomicType)t).getFingerprint() == ((AtomicType)t2).getFingerprint()) { return SUBSUMED_BY; } t = t.getSuperType(this); } return DISJOINT; } } else { // t1 is a NodeTest if (t2.isAtomicType()) { return DISJOINT; } else { // both types are NodeTests if (t1 instanceof AnyNodeTest) { if (t2 instanceof AnyNodeTest) { return SAME_TYPE; } else { return SUBSUMES; } } else if (t2 instanceof AnyNodeTest) { return SUBSUMED_BY; } else if (t1 instanceof EmptySequenceTest) { return DISJOINT; } else if (t2 instanceof EmptySequenceTest) { return DISJOINT; } else { // first find the relationship between the node kinds allowed int nodeKindRelationship; int m1 = ((NodeTest)t1).getNodeKindMask(); int m2 = ((NodeTest)t2).getNodeKindMask(); if ((m1 & m2) == 0) { return DISJOINT; } else if (m1 == m2) { nodeKindRelationship = SAME_TYPE; } else if ((m1 & m2) == m1) { nodeKindRelationship = SUBSUMED_BY; } else if ((m1 & m2) == m2) { nodeKindRelationship = SUBSUMES; } else { nodeKindRelationship = OVERLAPS; } // now find the relationship between the node names allowed. Note that although // NamespaceTest and LocalNameTest are NodeTests, they do not occur in SequenceTypes, // so we don't need to consider them. int nodeNameRelationship; IntHashSet n1 = ((NodeTest)t1).getRequiredNodeNames(); // null means all names allowed IntHashSet n2 = ((NodeTest)t2).getRequiredNodeNames(); // null means all names allowed if (n1 == null) { if (n2 == null) { nodeNameRelationship = SAME_TYPE; } else { nodeNameRelationship = SUBSUMES; } } else if (n2 == null) { nodeNameRelationship = SUBSUMED_BY; } else if (n1.containsAll(n2)) { if (n1.size() == n2.size()) { nodeNameRelationship = SAME_TYPE; } else { nodeNameRelationship = SUBSUMES; } } else if (n2.containsAll(n1)) { nodeNameRelationship = SUBSUMED_BY; } else if (n1.containsSome(n2)) { nodeNameRelationship = OVERLAPS; } else { nodeNameRelationship = DISJOINT; } // now find the relationship between the content types allowed int contentRelationship; if (t1 instanceof DocumentNodeTest) { if (t2 instanceof DocumentNodeTest) { contentRelationship = relationship(((DocumentNodeTest)t1).getElementTest(), ((DocumentNodeTest)t2).getElementTest()); } else { contentRelationship = SUBSUMED_BY; } } else if (t2 instanceof DocumentNodeTest) { contentRelationship = SUBSUMES; } else { SchemaType s1 = ((NodeTest)t1).getContentType(); SchemaType s2 = ((NodeTest)t2).getContentType(); contentRelationship = schemaTypeRelationship(s1, s2); } // now analyse the three different relationsships if (nodeKindRelationship == SAME_TYPE && nodeNameRelationship == SAME_TYPE && contentRelationship == SAME_TYPE) { return SAME_TYPE; } else if ((nodeKindRelationship == SAME_TYPE || nodeKindRelationship == SUBSUMES) && (nodeNameRelationship == SAME_TYPE || nodeNameRelationship == SUBSUMES) && (contentRelationship == SAME_TYPE || contentRelationship == SUBSUMES)) { return SUBSUMES; } else if ((nodeKindRelationship == SAME_TYPE || nodeKindRelationship == SUBSUMED_BY) && (nodeNameRelationship == SAME_TYPE || nodeNameRelationship == SUBSUMED_BY) && (contentRelationship == SAME_TYPE || contentRelationship == SUBSUMED_BY)) { return SUBSUMED_BY; } else if (nodeKindRelationship == DISJOINT || nodeNameRelationship == DISJOINT || contentRelationship == DISJOINT) { return DISJOINT; } else { return OVERLAPS; } } } } } /** * Test whether a type annotation code represents the type xs:ID or one of its subtypes * @param typeCode the type annotation to be tested * @return true if the type annotation represents an xs:ID */ public boolean isIdCode(int typeCode) { typeCode &= NamePool.FP_MASK; if (typeCode == StandardNames.XS_ID) { return true; } else if (typeCode < 1024) { // No other built-in type is an ID return false; } else { SchemaType type = config.getSchemaType(typeCode); if (type == null) { return false; // this shouldn't happen, but there's no need to crash right here } if (type.isAtomicType()) { return isSubType((AtomicType)type, BuiltInAtomicType.ID); } if (type instanceof ComplexType && ((ComplexType)type).isSimpleContent()) { SimpleType contentType = ((ComplexType)type).getSimpleContentType(); if (contentType.isAtomicType()) { return isSubType((AtomicType)contentType, BuiltInAtomicType.ID); } } return false; } } /** * Test whether a type annotation code represents the type xs:IDREF, xs:IDREFS or one of their subtypes * @param typeCode the type annotation to be tested * @return true if the type annotation represents an xs:IDREF or xs:IDREFS or a subtype thereof */ public boolean isIdrefsCode(int typeCode) { typeCode &= NamePool.FP_MASK; if (typeCode == StandardNames.XS_IDREF || typeCode == StandardNames.XS_IDREFS) { return true; } else if (typeCode < 1024) { // No other built-in type is an IDREF or IDREFS return false; } else { SchemaType type = config.getSchemaType(typeCode); if (type == null) { // shouldn't happen, but we don't need to crash right now return false; } if (type.isAtomicType()) { return isSubType((AtomicType)type, BuiltInAtomicType.IDREF); } if (type instanceof ListType) { return ((ListType)type).getBuiltInBaseType().getFingerprint() == StandardNames.XS_IDREFS; } if (type.isComplexType() && ((ComplexType)type).isSimpleContent()) { SimpleType contentType = ((ComplexType)type).getSimpleContentType(); if (contentType.isAtomicType()) { return isSubType((AtomicType)contentType, BuiltInAtomicType.IDREF); } else if (contentType instanceof ListType) { return contentType.getBuiltInBaseType().getFingerprint() == StandardNames.XS_IDREFS; } } return false; } } /** * Get the relationship of two schema types to each other * @param s1 the first type * @param s2 the second type * @return the relationship of the two types, as one of the constants * {@link net.sf.saxon.type.TypeHierarchy#SAME_TYPE}, {@link net.sf.saxon.type.TypeHierarchy#SUBSUMES}, * {@link net.sf.saxon.type.TypeHierarchy#SUBSUMED_BY}, {@link net.sf.saxon.type.TypeHierarchy#DISJOINT} */ public static int schemaTypeRelationship(SchemaType s1, SchemaType s2) { if (s1.isSameType(s2)) { return SAME_TYPE; } if (s1 instanceof AnyType) { return SUBSUMES; } if (s2 instanceof AnyType) { return SUBSUMED_BY; } SchemaType t1 = s1; while (true) { t1 = t1.getBaseType(); if (t1 == null) { break; } if (t1.isSameType(s2)) { return SUBSUMED_BY; } } SchemaType t2 = s2; while (true) { t2 = t2.getBaseType(); if (t2 == null) { break; } if (t2.isSameType(s1)) { return SUBSUMES; } } return DISJOINT; } private class ItemTypePair implements Serializable { ItemType s; ItemType t; public ItemTypePair(ItemType s, ItemType t) { this.s = s; this.t = t; } /** * Returns a hash code value for the object. * @return a hash code value for this object. * @see Object#equals(Object) * @see java.util.Hashtable */ public int hashCode() { return s.hashCode() ^ t.hashCode(); } /** * Indicates whether some other object is "equal to" this one. */ public boolean equals(Object obj) { final ItemTypePair pair = (ItemTypePair)obj; return s.equals(pair.s) && t.equals(pair.t); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/type/ConversionResult.java0000644000175000017500000000357511033112257022561 0ustar eugeneeugenepackage net.sf.saxon.type; import net.sf.saxon.value.AtomicValue; /** * This is a marker interface used as the result methods that convert or cast values from one type * to another. It is implemented by AtomicValue, which indicates a successful conversion, and by * ValidationFailure, which indicates an unsuccessful conversion. An unsuccessful conversion does not * throw an exception because exceptions are expensive and should not be used on success paths. For example * when validating a union, conversion failures are to be expected. */ public interface ConversionResult { /** * Calling this method on a ConversionResult returns the AtomicValue that results * from the conversion if the conversion was successful, and throws a ValidationException * explaining the conversion error otherwise. * *

    Use this method if you are calling a conversion method that returns a ConversionResult, * and if you want to throw an exception if the conversion fails.

    * * @return the atomic value that results from the conversion if the conversion was successful * @throws ValidationException if the conversion was not successful */ public AtomicValue asAtomic() throws ValidationException; } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/type/AnyType.java0000644000175000017500000003653711270626650020644 0ustar eugeneeugenepackage net.sf.saxon.type; import net.sf.saxon.expr.Expression; import net.sf.saxon.expr.StaticContext; import net.sf.saxon.expr.StaticProperty; import net.sf.saxon.om.*; import net.sf.saxon.value.UntypedAtomicValue; import net.sf.saxon.value.Value; import net.sf.saxon.sort.IntHashSet; import java.io.Serializable; /** * This class has a singleton instance which represents the XML Schema built-in type xs:anyType, * also known as the urtype. */ public final class AnyType implements ComplexType, Serializable { private static AnyType theInstance = new AnyType(); /** * Private constructor */ private AnyType() { super(); } /** * Get the singular instance of this class * @return the singular object representing xs:anyType */ public static AnyType getInstance() { return theInstance; } /** * Get the local name of this type * * @return the local name of this type definition, if it has one. Return null in the case of an * anonymous type. */ public String getName() { return "anyType"; } /** * Get the target namespace of this type * * @return the target namespace of this type definition, if it has one. Return null in the case * of an anonymous type, and in the case of a global type defined in a no-namespace schema. */ public String getTargetNamespace() { return NamespaceConstant.SCHEMA; } /** * Get the validation status - always valid */ public int getValidationStatus() { return VALIDATED; } /** * Get the base type * @return null (this is the root of the type hierarchy) */ public SchemaType getBaseType() { return null; } /** * Returns the base type that this type inherits from. This method can be used to get the * base type of a type that is known to be valid. * If this type is a Simpletype that is a built in primitive type then null is returned. * * @return the base type. * @throws IllegalStateException if this type is not valid. */ public SchemaType getKnownBaseType() throws IllegalStateException { return null; } /** * Gets the integer code of the derivation method used to derive this type from its * parent. Returns zero for primitive types. * * @return a numeric code representing the derivation method, for example * {@link SchemaType#DERIVATION_RESTRICTION} */ public int getDerivationMethod() { return 0; } /** * Determines whether derivation (of a particular kind) * from this type is allowed, based on the "final" property * * @param derivation the kind of derivation, for example {@link SchemaType#DERIVATION_LIST} * @return true if this kind of derivation is allowed */ public boolean allowsDerivation(int derivation) { return true; } /** * Test whether this ComplexType has been marked as abstract. * @return false: this class is not abstract. */ public boolean isAbstract() { return false; } /** * Test whether this SchemaType is a complex type * * @return true if this SchemaType is a complex type */ public boolean isComplexType() { return true; } /** * Test whether this is an anonymous type * @return true if this SchemaType is an anonymous type */ public boolean isAnonymousType() { return false; } /** * Test whether this SchemaType is a simple type * @return true if this SchemaType is a simple type */ public boolean isSimpleType() { return false; } /** * Test whether this SchemaType is an atomic type * @return true if this SchemaType is an atomic type */ public boolean isAtomicType() { return false; } /** * Returns the value of the 'block' attribute for this type, as a bit-signnificant * integer with fields such as {@link SchemaType#DERIVATION_LIST} and {@link SchemaType#DERIVATION_EXTENSION} * * @return the value of the 'block' attribute for this type */ public int getBlock() { return 0; } /** * Test whether this complex type has complex content * @return true: this complex type has complex content */ public boolean isComplexContent() { return true; } /** * Test whether this complex type has simple content * @return false: this complex type has complex content */ public boolean isSimpleContent() { return false; } /** * Test whether this complex type has "all" content, that is, a content model * using an xs:all compositor * @return false: this complex type does not use an "all" compositor */ public boolean isAllContent() { return false; } /** * For a complex type with simple content, return the simple type of the content. * Otherwise, return null. * @return null: this complex type does not have simple content */ public SimpleType getSimpleContentType() { return null; } /** * Test whether this complex type is derived by restriction * @return false: this type is not a restriction */ public boolean isRestricted() { return false; } /** * Test whether the content type of this complex type is empty * @return false: the content model is not empty */ public boolean isEmptyContent() { return false; } /** * Test whether the content model of this complexType allows empty content * @return true: the content is allowed to be empty */ public boolean isEmptiable() { return true; } /** * Test whether this complex type allows mixed content * @return true: mixed content is allowed */ public boolean isMixedContent() { return true; } /** * Get the fingerprint of the name of this type * @return the fingerprint. */ public int getFingerprint() { return StandardNames.XS_ANY_TYPE; } /** * Get the namecode of the name of this type. This includes the prefix from the original * type declaration: in the case of built-in types, there may be a conventional prefix * or there may be no prefix. */ public int getNameCode() { return StandardNames.XS_ANY_TYPE; } /** * Get a description of this type for use in diagnostics * @return the string "xs:anyType" */ public String getDescription() { return "xs:anyType"; } /** * Get the display name of the type: that is, a lexical QName with an arbitrary prefix * * @return a lexical QName identifying the type */ public String getDisplayName() { return "xs:anyType"; } /** * Get the URI of the schema document containing the definition of this type * @return null for a built-in type */ public String getSystemId() { return null; } /** * Test whether this is the same type as another type. They are considered to be the same type * if they are derived from the same type definition in the original XML representation (which * can happen when there are multiple includes of the same file) */ public boolean isSameType(SchemaType other) { return (other instanceof AnyType); } /** * Analyze an expression to see whether the expression is capable of delivering a value of this * type. * @param expression the expression that delivers the content * @param kind the node kind whose content is being delivered: {@link net.sf.saxon.type.Type#ELEMENT}, * {@link net.sf.saxon.type.Type#ATTRIBUTE}, or {@link net.sf.saxon.type.Type#DOCUMENT} * @param env */ public void analyzeContentExpression(Expression expression, int kind, StaticContext env) { return; } /** * Get the typed value of a node that is annotated with this schema type * @param node the node whose typed value is required * @return an iterator returning a single untyped atomic value, equivalent to the string value of the node. This * follows the standard rules for elements with mixed content. */ public SequenceIterator getTypedValue(NodeInfo node) { return SingletonIterator.makeIterator(new UntypedAtomicValue(node.getStringValue())); } /** * Get the typed value of a node that is annotated with this schema type. The result of this method will always be consistent with the method * {@link #getTypedValue}. However, this method is often more convenient and may be * more efficient, especially in the common case where the value is expected to be a singleton. * * @param node the node whose typed value is required * @return the typed value. * @since 8.5 */ public Value atomize(NodeInfo node) { return new UntypedAtomicValue(node.getStringValue()); } /** * Test whether this complex type subsumes another complex type. The algorithm * used is as published by Thompson and Tobin, XML Europe 2003. * @param sub the other type (the type that is derived by restriction, validly or otherwise) * @param compiler * @return null indicating that this type does indeed subsume the other; or a string indicating * why it doesn't. */ // public String subsumes(ComplexType sub, ISchemaCompiler compiler) { // return null; // } /** * Check that this type is validly derived from a given type * * @param type the type from which this type is derived * @param block the derivations that are blocked by the relevant element declaration * @throws SchemaException * if the derivation is not allowed */ public void checkTypeDerivationIsOK(SchemaType type, int block) throws SchemaException { if (!(type instanceof AnyType)) { throw new SchemaException("Cannot derive xs:anyType from another type"); } } /** * Find an element particle within this complex type definition having a given element name * (identified by fingerprint), and return the schema type associated with that element particle. * If there is no such particle, return null. If the fingerprint matches an element wildcard, * return the type of the global element declaration with the given name if one exists, or AnyType * if none exists and lax validation is permitted by the wildcard. * * @param fingerprint Identifies the name of the child element within this content model * @param considerExtensions */ public SchemaType getElementParticleType(int fingerprint, boolean considerExtensions) { return this; } /** * Find an element particle within this complex type definition having a given element name * (identified by fingerprint), and return the cardinality associated with that element particle, * that is, the number of times the element can occur within this complex type. The value is one of * {@link net.sf.saxon.expr.StaticProperty#EXACTLY_ONE}, {@link net.sf.saxon.expr.StaticProperty#ALLOWS_ZERO_OR_ONE}, * {@link net.sf.saxon.expr.StaticProperty#ALLOWS_ZERO_OR_MORE}, {@link net.sf.saxon.expr.StaticProperty#ALLOWS_ONE_OR_MORE}, * If there is no such particle, return zero. * * @param fingerprint Identifies the name of the child element within this content model * @param searchExtensionTypes */ public int getElementParticleCardinality(int fingerprint, boolean searchExtensionTypes) { return StaticProperty.ALLOWS_ZERO_OR_MORE; } /** * Find an attribute use within this complex type definition having a given attribute name * (identified by fingerprint), and return the schema type associated with that attribute. * If there is no such attribute use, return null. If the fingerprint matches an attribute wildcard, * return the type of the global attribute declaration with the given name if one exists, or AnySimpleType * if none exists and lax validation is permitted by the wildcard. * * @param fingerprint Identifies the name of the child element within this content model */ public SchemaType getAttributeUseType(int fingerprint) { return AnySimpleType.getInstance(); } /** * Return true if this type (or any known type derived from it by extension) allows the element * to have one or more attributes. * @return true if attributes are allowed */ public boolean allowsAttributes() { return true; } /** * Get a list of all the names of elements that can appear as children of an element having this * complex type, as integer fingerprints. If the list is unbounded (because of wildcards or the use * of xs:anyType), return null. * * @param children an integer set, initially empty, which on return will hold the fingerprints of all permitted * child elements; if the result contains the value -1, this indicates that it is not possible to enumerate * all the children, typically because of wildcards. In this case the other contents of the set should * be ignored. */ public void gatherAllPermittedChildren(IntHashSet children) throws SchemaException { children.add(-1); } /** * Get a list of all the names of elements that can appear as descendants of an element having this * complex type, as integer fingerprints. If the list is unbounded (because of wildcards or the use * of xs:anyType), return null. * * @param descendants an integer set, initially empty, which on return will hold the fingerprints of all permitted * descendant elements; if the result contains the value -1, this indicates that it is not possible to enumerate * all the descendants, typically because of wildcards. In this case the other contents of the set should * be ignored. */ public void gatherAllPermittedDescendants(IntHashSet descendants) throws SchemaException { descendants.add(-1); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Saxonica Limited // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none //saxonb-9.1.0.8/bj/net/sf/saxon/type/UnresolvedReferenceException.java0000644000175000017500000000247711033112257025061 0ustar eugeneeugenepackage net.sf.saxon.type; /** * This exception occurs when an attempt is made to dereference a reference from one * schema component to another, if the target of the reference cannot be found. Note that * an unresolved reference is not necessarily an error: a schema containing unresolved * references may be used for validation, provided the components containing the * unresolved references are not actually used. */ public abstract class UnresolvedReferenceException extends RuntimeException { public UnresolvedReferenceException(String ref) { super(ref); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/type/BuiltInType.java0000644000175000017500000000557111033112257021443 0ustar eugeneeugenepackage net.sf.saxon.type; import net.sf.saxon.om.StandardNames; import net.sf.saxon.sort.IntHashMap; import java.io.Serializable; /** * This non-instantiable class acts as a register of Schema objects containing all the built-in types: * that is, the types defined in the "xs" namespace. * *

    Previously called BuiltInSchemaFactory; but its original function has largely been moved to the two * classes {@link BuiltInAtomicType} and {@link BuiltInListType} */ public abstract class BuiltInType implements Serializable { /** * Table of all built in types */ private static IntHashMap lookup = new IntHashMap(100); /** * Class is never instantiated */ private BuiltInType() { } static { register(StandardNames.XS_ANY_SIMPLE_TYPE, AnySimpleType.getInstance()); register(StandardNames.XS_ANY_TYPE, AnyType.getInstance()); register(StandardNames.XS_UNTYPED, Untyped.getInstance()); } /** * Get the schema type with a given fingerprint * @param fingerprint the fingerprint representing the name of the required type * @return the SchemaType object representing the given type, if known, otherwise null */ public static SchemaType getSchemaType(int fingerprint) { SchemaType st = (SchemaType)lookup.get(fingerprint); if (st == null) { // this means the method has been called before doing the static initialization of BuiltInAtomicType // or BuiltInListType. So force it now if (BuiltInAtomicType.DOUBLE == null || BuiltInListType.NMTOKENS == null) { // no action, except to force the initialization to run } st = (SchemaType)lookup.get(fingerprint); } return st; } /** * Method for internal use to register a built in type with this class * @param fingerprint the fingerprint of the type name * @param type the SchemaType representing the built in type */ static void register(int fingerprint, SchemaType type) { lookup.put(fingerprint, type); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/type/ValidationException.java0000644000175000017500000002164611033112257023205 0ustar eugeneeugenepackage net.sf.saxon.type; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.trans.XPathException; import org.xml.sax.Locator; import javax.xml.transform.SourceLocator; /** * This exception indicates a failure when validating an instance against a type * defined in a schema. */ public class ValidationException extends XPathException implements SourceLocator, Locator { private String systemId; private String publicId; private int lineNumber = -1; private int columnNumber = -1; private NodeInfo node; private int schemaPart = -1; private String constraintName; private String constraintClauseNumber; // TODO: during output validation, it would sometimes be useful to know what the position in the input file was. /** * Creates a new ValidationException with the given message. * @param message the message for this Exception */ public ValidationException(String message) { super(message); setIsTypeError(true); } /** * Creates a new ValidationException with the given nested * exception. * @param exception the nested exception */ public ValidationException(Exception exception) { super(exception); setIsTypeError(true); } /** * Creates a new ValidationException with the given message * and nested exception. * @param message the detail message for this exception * @param exception the nested exception */ public ValidationException(String message, Exception exception) { super(message, exception); setIsTypeError(true); } /** * Create a new ValidationException from a message and a Locator. * @param message The error or warning message. * @param locator The locator object for the error or warning. */ public ValidationException(String message, SourceLocator locator) { super(message, locator); setIsTypeError(true); // With Xerces, it's enough to store the locator as part of the exception. But with Crimson, // the locator is destroyed when the parse terminates, which means the location information // will not be available in the final error message. So we copy the location information now, // as part of the exception object itself. setSourceLocator(locator); } /** * Set a reference to the constraint in XML Schema that is not satisfied * @param schemaPart - 1 or 2, depending whether the constraint is in XMLSchema part 1 or part 2 * @param constraintName - the short name of the constraint in XMLSchema, as a fragment identifier in the * HTML of the XML Schema Part 1 specification * @param clause - the clause number within the description of that constraint */ public void setConstraintReference(int schemaPart, String constraintName, String clause) { this.schemaPart = schemaPart; this.constraintName = constraintName; this.constraintClauseNumber = clause; } /** * Copy the constraint reference from another exception object * @param e the other exception object from which to copy the information */ public void setConstraintReference(ValidationException e) { schemaPart = e.schemaPart; constraintName = e.constraintName; constraintClauseNumber = e.constraintClauseNumber; } /** * Get the constraint reference as a string for inserting into an error message. * @return the reference as a message, or null if no information is available */ public String getConstraintReferenceMessage() { if (schemaPart == -1) { return null; } return "See http://www.w3.org/TR/xmlschema-" + schemaPart + "/#" + constraintName + " clause " + constraintClauseNumber; } /** * Get the "schema part" component of the constraint reference * @return 1 or 2 depending on whether the violated constraint is in XML Schema Part 1 or Part 2; * or -1 if there is no constraint reference */ public int getConstraintSchemaPart() { return schemaPart; } /** * Get the constraint name * @return the name of the violated constraint, in the form of a fragment identifier within * the published XML Schema specification; or null if the information is not available. */ public String getConstraintName() { return constraintName; } /** * Get the constraint clause number * @return the section number of the clause containing the constraint that has been violated. * Generally a decimal number in the form n.n.n; possibly a sequence of such numbers separated * by semicolons. Or null if the information is not available. */ public String getConstraintClauseNumber() { return constraintClauseNumber; } /** * Get the constraint name and clause in the format defined in XML Schema Part C (Outcome Tabulations). * This mandates the format validation-rule-name.clause-number * @return the constraint reference, for example "cos-ct-extends.1.2"; or null if the reference * is not known. */ public String getConstraintReference() { return constraintName + '.' + constraintClauseNumber; } /** * Returns the String representation of this Exception * @return the String representation of this Exception **/ public String toString() { StringBuffer sb = new StringBuffer("ValidationException: "); String message = getMessage(); if (message != null) { sb.append(message); } return sb.toString(); } public String getPublicId() { SourceLocator loc = getLocator(); if (publicId == null && loc != null && loc != this) { return loc.getPublicId(); } else{ return publicId; } } public String getSystemId() { SourceLocator loc = getLocator(); if (systemId == null && loc != null && loc != this) { return loc.getSystemId(); } else{ return systemId; } } public int getLineNumber() { SourceLocator loc = getLocator(); if (lineNumber == -1 && loc != null && loc != this) { return loc.getLineNumber(); } else{ return lineNumber; } } public int getColumnNumber() { SourceLocator loc = getLocator(); if (columnNumber == -1 && loc != null && loc != this) { return loc.getColumnNumber(); } else{ return columnNumber; } } public NodeInfo getNode() { return node; } public void setPublicId(String id) { publicId = id; } public void setSystemId(String id) { systemId = id; } public void setLineNumber(int line) { lineNumber = line; } public void setColumnNumber(int column) { columnNumber = column; } public void setLocator(Locator locator) { if (locator != null) { setPublicId(locator.getPublicId()); setSystemId(locator.getSystemId()); setLineNumber(locator.getLineNumber()); setColumnNumber(locator.getColumnNumber()); if (locator instanceof NodeInfo) { node = ((NodeInfo)locator); } } super.setLocator(null); } public void setSourceLocator(SourceLocator locator) { if (locator != null) { setPublicId(locator.getPublicId()); setSystemId(locator.getSystemId()); setLineNumber(locator.getLineNumber()); setColumnNumber(locator.getColumnNumber()); if (locator instanceof NodeInfo) { node = ((NodeInfo)locator); } } super.setLocator(null); } public SourceLocator getLocator() { SourceLocator loc = super.getLocator(); if (loc != null) { return loc; } else { return this; } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Saxonica Limited // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none //saxonb-9.1.0.8/bj/net/sf/saxon/type/ExternalObjectType.java0000644000175000017500000005145111062271504023007 0ustar eugeneeugenepackage net.sf.saxon.type; import net.sf.saxon.Configuration; import net.sf.saxon.expr.Expression; import net.sf.saxon.expr.StaticContext; import net.sf.saxon.expr.Literal; import net.sf.saxon.instruct.ValueOf; import net.sf.saxon.om.*; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.AtomicValue; import net.sf.saxon.value.ObjectValue; import net.sf.saxon.value.Value; import net.sf.saxon.value.Whitespace; import java.io.Serializable; /** * This class represents the type of an external Java object returned by * an extension function, or supplied as an external variable/parameter. */ public class ExternalObjectType implements AtomicType, Serializable { private Class javaClass; private Configuration config; int fingerprint; int baseFingerprint = -1; /** * Create an external object type * @param javaClass the Java class to which this type corresponds * @param config the Saxon configuration */ public ExternalObjectType(Class javaClass, Configuration config) { this.javaClass = javaClass; this.config = config; final String localName = javaClass.getName().replace('$', '_'); fingerprint = config.getNamePool().allocate("", NamespaceConstant.JAVA_TYPE, localName); } /** * Get the local name of this type * * @return the local name of this type definition, if it has one. Return null in the case of an * anonymous type. */ public String getName() { return config.getNamePool().getLocalName(fingerprint); } /** * Get the target namespace of this type * * @return the target namespace of this type definition, if it has one. Return null in the case * of an anonymous type, and in the case of a global type defined in a no-namespace schema. */ public String getTargetNamespace() { return config.getNamePool().getURI(fingerprint); } /** * Return true if this is an external object type, that is, a Saxon-defined type for external * Java or .NET objects */ public boolean isExternalType() { return true; } /** * Determine whether this is a built-in type or a user-defined type * @return false - external types are not built in */ public boolean isBuiltInType() { return false; } /** * Determine whether the type is abstract, that is, whether it cannot have instances that are not also * instances of some concrete subtype * @return false - external types are not abstract */ public boolean isAbstract() { return false; } /** * Determine whether the atomic type is a primitive type. The primitive types are * the 19 primitive types of XML Schema, plus xs:integer, xs:dayTimeDuration and xs:yearMonthDuration; * xs:untypedAtomic; and all supertypes of these (xs:anyAtomicType, xs:numeric, ...) * * @return true if the type is considered primitive under the above rules */ public boolean isPrimitiveType() { return false; } /** * Get the most specific possible atomic type that all items in this SimpleType belong to * @return the lowest common supertype of all member types */ public AtomicType getCommonAtomicType() { return this; } /** * Determine whether the atomic type is ordered, that is, whether less-than and greater-than comparisons * are permitted * * @return true if ordering operations are permitted */ public boolean isOrdered() { return false; } /** * Get the URI of the schema document where the type was originally defined. * * @return the URI of the schema document. Returns null if the information is unknown or if this * is a built-in type */ public String getSystemId() { return null; //AUTO } /** * Get the validation status - always valid */ public final int getValidationStatus() { return VALIDATED; } /** * Returns the value of the 'block' attribute for this type, as a bit-signnificant * integer with fields such as {@link SchemaType#DERIVATION_LIST} and {@link SchemaType#DERIVATION_EXTENSION} * * @return the value of the 'block' attribute for this type */ public final int getBlock() { return 0; } /** * Gets the integer code of the derivation method used to derive this type from its * parent. Returns zero for primitive types. * * @return a numeric code representing the derivation method, for example {@link SchemaType#DERIVATION_RESTRICTION} */ public final int getDerivationMethod() { return SchemaType.DERIVATION_RESTRICTION; } /** * Determines whether derivation (of a particular kind) * from this type is allowed, based on the "final" property * * @param derivation the kind of derivation, for example {@link SchemaType#DERIVATION_LIST} * @return true if this kind of derivation is allowed */ public final boolean allowsDerivation(int derivation) { return true; } /** * Get the namecode of the name of this type. This includes the prefix from the original * type declaration: in the case of built-in types, there may be a conventional prefix * or there may be no prefix. */ public int getNameCode() { return fingerprint; } /** * Test whether this SchemaType is a complex type * * @return true if this SchemaType is a complex type */ public final boolean isComplexType() { return false; } /** * Returns the base type that this type inherits from. This method can be used to get the * base type of a type that is known to be valid. * If this type is a Simpletype that is a built in primitive type then null is returned. * * @return the base type. * @throws IllegalStateException if this type is not valid. */ public final SchemaType getBaseType() { return BuiltInAtomicType.ANY_ATOMIC; } /** * Get the primitive item type corresponding to this item type. For item(), * this is Type.ITEM. For node(), it is Type.NODE. For specific node kinds, * it is the value representing the node kind, for example Type.ELEMENT. * For anyAtomicValue it is Type.ATOMIC_VALUE. For numeric it is Type.NUMBER. * For other atomic types it is the primitive type as defined in XML Schema, * except that INTEGER is considered to be a primitive type. */ public ItemType getPrimitiveItemType() { return this; } /** * Get the primitive type corresponding to this item type. For item(), * this is Type.ITEM. For node(), it is Type.NODE. For specific node kinds, * it is the value representing the node kind, for example Type.ELEMENT. * For anyAtomicValue it is Type.ATOMIC. For numeric it is Type.NUMBER. * For other atomic types it is the primitive type as defined in XML Schema, * except that INTEGER is considered to be a primitive type. */ public int getPrimitiveType() { return StandardNames.XS_ANY_ATOMIC_TYPE; } /** * Produce a representation of this type name for use in error messages. * Where this is a QName, it will use conventional prefixes */ public String toString(NamePool pool) { return getDisplayName(); } /** * Get the item type of the atomic values that will be produced when an item * of this type is atomized */ public AtomicType getAtomizedItemType() { return this; } /** * Returns the base type that this type inherits from. This method can be used to get the * base type of a type that is known to be valid. * If this type is a Simpletype that is a built in primitive type then null is returned. * * @return the base type. * @throws IllegalStateException if this type is not valid. */ public SchemaType getKnownBaseType() { return getBaseType(); } /** * Test whether this is the same type as another type. They are considered to be the same type * if they are derived from the same type definition in the original XML representation (which * can happen when there are multiple includes of the same file) */ public boolean isSameType(SchemaType other) { return (other.getFingerprint() == getFingerprint()); } /** * Get the relationship of this external object type to another external object type * @param other the other external object type * @return the relationship of this external object type to another external object type, * as one of the constants in class {@link TypeHierarchy}, for example {@link TypeHierarchy#SUBSUMES} */ public int getRelationship(ExternalObjectType other) { Class j2 = other.javaClass; if (javaClass.equals(j2)) { return TypeHierarchy.SAME_TYPE; } else if (javaClass.isAssignableFrom(j2)) { return TypeHierarchy.SUBSUMES; } else if (j2.isAssignableFrom(javaClass)) { return TypeHierarchy.SUBSUMED_BY; } else if (javaClass.isInterface() || j2.isInterface()) { return TypeHierarchy.OVERLAPS; // there may be an overlap, we play safe } else { return TypeHierarchy.DISJOINT; } } public String getDescription() { return getDisplayName(); } /** * Check that this type is validly derived from a given type * * @param type the type from which this type is derived * @param block the derivations that are blocked by the relevant element declaration * @throws SchemaException if the derivation is not allowed */ public void checkTypeDerivationIsOK(SchemaType type, int block) throws SchemaException { //return; } /** * Returns true if this SchemaType is a SimpleType * * @return true (always) */ public final boolean isSimpleType() { return true; } /** * Test whether this Simple Type is an atomic type * @return true, this is considered to be an atomic type */ public boolean isAtomicType() { return true; } /** * Returns true if this type is derived by list, or if it is derived by restriction * from a list type, or if it is a union that contains a list as one of its members * * @return true if this is a list type */ public boolean isListType() { return false; } /** * Return true if this type is a union type (that is, if its variety is union) * * @return true for a union type */ public boolean isUnionType() { return false; } /** * Determine the whitespace normalization required for values of this type * * @return one of PRESERVE, REPLACE, COLLAPSE * @param th the type hierarchy cache */ public int getWhitespaceAction(TypeHierarchy th) { return Whitespace.PRESERVE; } /** * Apply the whitespace normalization rules for this simple type * * @param value the string before whitespace normalization * @return the string after whitespace normalization */ public CharSequence applyWhitespaceNormalization(CharSequence value) throws ValidationException { return value; } /** * Returns the built-in base type this type is derived from. * * @return the first built-in type found when searching up the type hierarchy */ public SchemaType getBuiltInBaseType() { return this; } /** * Test whether this simple type is namespace-sensitive, that is, whether * it is derived from xs:QName or xs:NOTATION * * @return true if this type is derived from xs:QName or xs:NOTATION */ public boolean isNamespaceSensitive() { return false; } /** * Test whether this is an anonymous type * @return true if this SchemaType is an anonymous type */ public boolean isAnonymousType() { return false; } /** * Get the typed value of a node that is annotated with this schema type * * @param node the node whose typed value is required * @return an iterator over the items making up the typed value of this node. The objects * returned by this SequenceIterator will all be of type {@link net.sf.saxon.value.AtomicValue} */ public final SequenceIterator getTypedValue(NodeInfo node) { throw new IllegalStateException("The type annotation of a node cannot be an external object type"); } /** * Get the typed value of a node that is annotated with this schema type. The result of this method will always be consistent with the method * {@link #getTypedValue}. However, this method is often more convenient and may be * more efficient, especially in the common case where the value is expected to be a singleton. * * @param node the node whose typed value is required * @return the typed value. * @since 8.5 */ public Value atomize(NodeInfo node) throws XPathException { throw new IllegalStateException("The type annotation of a node cannot be an external object type"); } /** * Get the typed value corresponding to a given string value, assuming it is * valid against this type * * @param value the string value * @param resolver a namespace resolver used to resolve any namespace prefixes appearing * in the content of values. Can supply null, in which case any namespace-sensitive content * will be rejected. * @param nameChecker checks names against XML 1.0 or XML 1.1 syntax rules * @return an iterator over the atomic sequence comprising the typed value. The objects * returned by this SequenceIterator will all be of type {@link net.sf.saxon.value.AtomicValue} */ public SequenceIterator getTypedValue(CharSequence value, NamespaceResolver resolver, NameChecker nameChecker) throws ValidationException { throw new ValidationException("Cannot validate a string against an external object type"); } /** * Validate that a primitive atomic value is a valid instance of a type derived from the * same primitive type. * * @param primValue the value in the value space of the primitive type. * @param lexicalValue the value in the lexical space. If null, the string value of primValue * is used. This value is checked against the pattern facet (if any) * @param checker * @return null if the value is valid; otherwise, a ValidationFailure object indicating * the nature of the error. * @throws UnsupportedOperationException in the case of an external object type */ public ValidationFailure validate(AtomicValue primValue, CharSequence lexicalValue, NameChecker checker) { throw new UnsupportedOperationException("validate"); } /** * Analyze an expression to see whether the expression is capable of delivering a value of this * type. * * @param expression the expression that delivers the content * @param kind the node kind whose content is being delivered: {@link Type#ELEMENT}, * {@link Type#ATTRIBUTE}, or {@link Type#DOCUMENT} * @param env the static evaluation context * @throws net.sf.saxon.trans.XPathException * if the expression will never deliver a value of the correct type */ public void analyzeContentExpression(Expression expression, int kind, StaticContext env) throws XPathException { analyzeContentExpression(this, expression, env, kind); } /** * Analyze an expression to see whether the expression is capable of delivering a value of this * type. * @param simpleType the simple type against which the expression is to be checked * @param expression the expression that delivers the content * @param env the static evaluation context * @param kind the node kind whose content is being delivered: {@link Type#ELEMENT}, * {@link Type#ATTRIBUTE}, or {@link Type#DOCUMENT} * @throws net.sf.saxon.trans.XPathException * if the expression will never deliver a value of the correct type */ public static void analyzeContentExpression(SimpleType simpleType, Expression expression, StaticContext env, int kind) throws XPathException { if (kind == Type.ELEMENT) { expression.checkPermittedContents(simpleType, env, true); } else if (kind == Type.ATTRIBUTE) { // for attributes, do a check only for text nodes and atomic values: anything else gets atomized if (expression instanceof ValueOf || expression instanceof Literal) { expression.checkPermittedContents(simpleType, env, true); } } } /** * Get the Java class to which this external object type corresponds * @return the corresponding Java class */ public Class getJavaClass() { return javaClass; } public boolean matchesItem(Item item, boolean allowURIPromotion, Configuration config) { if (item instanceof ObjectValue) { Object obj = ((ObjectValue)item).getObject(); return javaClass.isAssignableFrom(obj.getClass()); } return false; } /** * Check whether a given input string is valid according to this SimpleType * @param value the input string to be checked * @param nsResolver a namespace resolver used to resolve namespace prefixes if the type * is namespace sensitive. The value supplied may be null; in this case any namespace-sensitive * content will throw an UnsupportedOperationException. * @param nameChecker used to check names against XML 1.0 or XML 1.1 syntax rules * @return null if validation succeeds; return a ValidationException describing the validation failure * if validation fails, unless throwException is true, in which case the exception is thrown rather than * being returned. * @throws UnsupportedOperationException if the type is namespace-sensitive and no namespace * resolver is supplied */ public ValidationFailure validateContent(CharSequence value, NamespaceResolver nsResolver, NameChecker nameChecker) { throw new UnsupportedOperationException("Cannot use an external object type for validation"); } public ItemType getSuperType(TypeHierarchy th) { if (javaClass == Object.class) { return BuiltInAtomicType.ANY_ATOMIC; } Class javaSuper = javaClass.getSuperclass(); if (javaSuper == null) { // this happens for an interface return BuiltInAtomicType.ANY_ATOMIC; } return new ExternalObjectType(javaSuper, config); } public int getFingerprint() { return fingerprint; } public String toString() { String name = javaClass.getName(); name = name.replace('$', '-'); return "java:" + name; } public String getDisplayName() { return toString(); } /** * Returns a hash code value for the object. */ public int hashCode() { return fingerprint; } /** * Test whether two ExternalObjectType objects represent the same type * @param obj the other ExternalObjectType * @return */ public boolean equals(Object obj) { return obj instanceof ExternalObjectType && fingerprint == ((ExternalObjectType)obj).fingerprint; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Saxonica Limited // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none //saxonb-9.1.0.8/bj/net/sf/saxon/type/ValidationFailure.java0000644000175000017500000002145511033112257022634 0ustar eugeneeugenepackage net.sf.saxon.type; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.AtomicValue; import org.xml.sax.Locator; import javax.xml.transform.SourceLocator; /** * This exception indicates a failure when validating an instance against a type * defined in a schema. * *

    This class holds the same information as a ValidationException, except that it is not an exception, * and does not carry system overheads such as a stack trace. It is used because operations such as "castable", * and validation of values in a union, cause validation failures on a success path and it is costly to throw, * or even to create, exception objects on a success path.

    */ public class ValidationFailure implements SourceLocator, Locator, ConversionResult { private String message; private String systemId; private String publicId; private int lineNumber = -1; private int columnNumber = -1; private int schemaPart = -1; private String constraintName; private String clause; private String errorCode; /** * Creates a new ValidationException with the given message. * @param message the message for this Exception **/ public ValidationFailure(String message) { this.message = message; } /** * Creates a new ValidationFailure with the given nested * exception. * @param exception the nested exception **/ public ValidationFailure(Exception exception) { message = exception.getMessage(); if (exception instanceof XPathException) { errorCode = ((XPathException)exception).getErrorCodeLocalPart(); } } /** * Set a reference to the constraint in XML Schema that is not satisfied * @param schemaPart - 1 or 2, depending whether the constraint is in XMLSchema part 1 or part 2 * @param constraintName - the short name of the constraint in XMLSchema, as a fragment identifier in the * HTML of the XML Schema Part 1 specification * @param clause - the clause number within the description of that constraint */ public void setConstraintReference(int schemaPart, String constraintName, String clause) { this.schemaPart = schemaPart; this.constraintName = constraintName; this.clause = clause; } /** * Copy the constraint reference from another exception object * @param e the other exception object from which to copy the information */ public void setConstraintReference(ValidationFailure e) { schemaPart = e.schemaPart; constraintName = e.constraintName; clause = e.clause; } /** * Get the constraint reference as a string for inserting into an error message. * @return the reference as a message, or null if no information is available */ public String getConstraintReferenceMessage() { if (schemaPart == -1) { return null; } return "See http://www.w3.org/TR/xmlschema-" + schemaPart + "/#" + constraintName + " clause " + clause; } /** * Get the "schema part" component of the constraint reference * @return 1 or 2 depending on whether the violated constraint is in XML Schema Part 1 or Part 2; * or -1 if there is no constraint reference */ public int getConstraintSchemaPart() { return schemaPart; } /** * Get the constraint name * @return the name of the violated constraint, in the form of a fragment identifier within * the published XML Schema specification; or null if the information is not available. */ public String getConstraintName() { return constraintName; } /** * Get the constraint clause number * @return the section number of the clause containing the constraint that has been violated. * Generally a decimal number in the form n.n.n; possibly a sequence of such numbers separated * by semicolons. Or null if the information is not available. */ public String getConstraintClauseNumber() { return clause; } /** * Get the constraint name and clause in the format defined in XML Schema Part C (Outcome Tabulations). * This mandates the format validation-rule-name.clause-number * @return the constraint reference, for example "cos-ct-extends.1.2"; or null if the reference * is not known. */ public String getConstraintReference() { return constraintName + '.' + clause; } public String getMessage() { return message; } /** * Returns the String representation of this Exception * @return the String representation of this Exception **/ public String toString() { StringBuffer sb = new StringBuffer("ValidationException: "); String message = getMessage(); if (message != null) { sb.append(message); } return sb.toString(); } public String getPublicId() { SourceLocator loc = getLocator(); if (publicId == null && loc != null && loc != this) { return loc.getPublicId(); } else{ return publicId; } } public String getSystemId() { SourceLocator loc = getLocator(); if (systemId == null && loc != null && loc != this) { return loc.getSystemId(); } else{ return systemId; } } public int getLineNumber() { SourceLocator loc = getLocator(); if (lineNumber == -1 && loc != null && loc != this) { return loc.getLineNumber(); } else{ return lineNumber; } } public int getColumnNumber() { SourceLocator loc = getLocator(); if (columnNumber == -1 && loc != null && loc != this) { return loc.getColumnNumber(); } else{ return columnNumber; } } public void setPublicId(String id) { publicId = id; } public void setSystemId(String id) { systemId = id; } public void setLineNumber(int line) { lineNumber = line; } public void setColumnNumber(int column) { columnNumber = column; } public void setLocator(SourceLocator locator) { if (locator != null) { setPublicId(locator.getPublicId()); setSystemId(locator.getSystemId()); setLineNumber(locator.getLineNumber()); setColumnNumber(locator.getColumnNumber()); } } public void setSourceLocator(SourceLocator locator) { if (locator != null) { setPublicId(locator.getPublicId()); setSystemId(locator.getSystemId()); setLineNumber(locator.getLineNumber()); setColumnNumber(locator.getColumnNumber()); } } public SourceLocator getLocator() { return this; } public void setErrorCode(String errorCode) { this.errorCode = errorCode; } public String getErrorCode() { return errorCode; } public ValidationException makeException() { ValidationException ve = new ValidationException(message); ve.setConstraintReference(schemaPart, constraintName, clause); ve.setErrorCode(errorCode == null ? "FORG0001" : errorCode); return ve; } /** * Calling this method on a ConversionResult returns the AtomicValue that results * from the conversion if the conversion was successful, and throws a ValidationException * explaining the conversion error otherwise. *

    *

    Use this method if you are calling a conversion method that returns a ConversionResult, * and if you want to throw an exception if the conversion fails.

    * * @return the atomic value that results from the conversion if the conversion was successful * @throws net.sf.saxon.type.ValidationException * if the conversion was not successful */ public AtomicValue asAtomic() throws ValidationException { throw makeException(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/type/Type.java0000644000175000017500000002706211033112257020153 0ustar eugeneeugenepackage net.sf.saxon.type; import net.sf.saxon.om.Item; import net.sf.saxon.om.NamePool; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.om.StandardNames; import net.sf.saxon.pattern.AnyNodeTest; import net.sf.saxon.pattern.EmptySequenceTest; import net.sf.saxon.pattern.NodeKindTest; import net.sf.saxon.pattern.NodeTest; import net.sf.saxon.value.AtomicValue; import net.sf.saxon.value.ObjectValue; import java.io.Serializable; /** * This class contains static information about types and methods for constructing type codes. * The class is never instantiated. * *

    The constant integers used for type names in earlier versions of this class have been replaced * by constants in {@link StandardNames}. The constants representing {@link AtomicType} objects are now * available through the {@link BuiltInAtomicType} class.

    * */ public abstract class Type implements Serializable { // Note that the integer codes representing node kinds are the same as // the codes allocated in the DOM interface, while the codes for built-in // atomic types are fingerprints allocated in StandardNames. These two sets of // codes must not overlap! /** * Type representing an element node - element() */ public static final short ELEMENT = 1; /** * Item type representing an attribute node - attribute() */ public static final short ATTRIBUTE = 2; /** * Item type representing a text node - text() */ public static final short TEXT = 3; /** * Item type representing a text node stored in the tiny tree as compressed whitespace */ public static final short WHITESPACE_TEXT = 4; /** * Item type representing a processing-instruction node */ public static final short PROCESSING_INSTRUCTION = 7; /** * Item type representing a comment node */ public static final short COMMENT = 8; /** * Item type representing a document node */ public static final short DOCUMENT = 9; /** * Item type representing a namespace node */ public static final short NAMESPACE = 13; /** * Dummy node kind used in the tiny tree to mark the end of the tree */ public static final short STOPPER = 11; /** * Dummy node kind used in the tiny tree to contain a parent pointer */ public static final short PARENT_POINTER = 12; /** * An item type that matches any node */ public static final short NODE = 0; public static final ItemType NODE_TYPE = AnyNodeTest.getInstance(); /** * An item type that matches any item */ public static final short ITEM = 88; public static final ItemType ITEM_TYPE = AnyItemType.getInstance(); public static final short MAX_NODE_TYPE = 13; /** * Item type that matches no items (corresponds to SequenceType empty()) */ public static final short EMPTY = 15; // a test for this type will never be satisfied private Type() { } /** * Test whether a given type is (some subtype of) node() * * @param type The type to be tested * @return true if the item type is node() or a subtype of node() */ public static boolean isNodeType(ItemType type) { return type instanceof NodeTest; } /** * Get the ItemType of an Item * @param item the item whose type is required * @param th the type hierarchy cache * @return the item type of the item */ public static ItemType getItemType(Item item, TypeHierarchy th) { if (item instanceof AtomicValue) { return ((AtomicValue)item).getItemType(th); } else { return NodeKindTest.makeNodeKindTest(((NodeInfo)item).getNodeKind()); // We could return a more precise type than this, for example one that includes // a ContentTypeTest for the type annotation of the nodes. However, given the way in which // this method is used, this wouldn't be very useful } } /** * Output (for diagnostics) a representation of the type of an item. This * does not have to be the most specific type * @param item the item whose type is to be displayed * @return a string representation of the type of the item */ public static String displayTypeName(Item item) { if (item instanceof NodeInfo) { NodeInfo node = (NodeInfo)item; switch (node.getNodeKind()) { case DOCUMENT: return "document-node()"; case ELEMENT: NamePool pool = node.getNamePool(); int annotation = node.getTypeAnnotation(); return "element(" + ((NodeInfo)item).getDisplayName() + ", " + (annotation == -1 ? "xs:untyped)" : pool.getDisplayName(annotation) + ')'); case ATTRIBUTE: NamePool pool2 = node.getNamePool(); int annotation2 = node.getTypeAnnotation() & NamePool.FP_MASK; return "attribute(" + ((NodeInfo)item).getDisplayName()+ ", " + (annotation2 == -1 ? "xs:untypedAtomic)" : pool2.getDisplayName(annotation2) + ')'); case TEXT: return "text()"; case COMMENT: return "comment()"; case PROCESSING_INSTRUCTION: return "processing-instruction()"; case NAMESPACE: return "namespace()"; default: return ""; } } else if (item instanceof ObjectValue) { return ((ObjectValue)item).displayTypeName(); } else { return ((AtomicValue)item).getItemType(null).toString(); } } /** * Get the ItemType object for a built-in type * @param namespace the namespace URI of the type * @param localName the local name of the type * @return the ItemType, or null if not found */ public static ItemType getBuiltInItemType(String namespace, String localName) { SchemaType t = BuiltInType.getSchemaType( StandardNames.getFingerprint(namespace, localName)); if (t instanceof ItemType) { return (ItemType)t; } else { return null; } } /** * Get a type that is a common supertype of two given item types * * @param t1 the first item type * @param t2 the second item type * @param th the type hierarchy cache * @return the item type that is a supertype of both * the supplied item types */ public static ItemType getCommonSuperType(ItemType t1, ItemType t2, TypeHierarchy th) { if (t1 instanceof EmptySequenceTest) { return t2; } if (t2 instanceof EmptySequenceTest) { return t1; } int r = th.relationship(t1, t2); if (r == TypeHierarchy.SAME_TYPE) { return t1; } else if (r == TypeHierarchy.SUBSUMED_BY) { return t2; } else if (r == TypeHierarchy.SUBSUMES) { return t1; } else { return getCommonSuperType(t2.getSuperType(th), t1, th); // eventually we will hit a type that is a supertype of t2. We reverse // the arguments so we go up each branch of the tree alternately. // If we hit the root of the tree, one of the earlier conditions will be satisfied, // so the recursion will stop. } } /** * Determine whether this type is a primitive type. The primitive types are * the 19 primitive types of XML Schema, plus xs:integer, xs:dayTimeDuration and xs:yearMonthDuration; * xs:untypedAtomic; the 7 node kinds; and all supertypes of these (item(), node(), xs:anyAtomicType, * xs:numeric, ...) * @param code the item type code to be tested * @return true if the type is considered primitive under the above rules */ public static boolean isPrimitiveType(int code) { return code >= 0 && (code <= StandardNames.XS_INTEGER || code == StandardNames.XS_NUMERIC || code == StandardNames.XS_UNTYPED_ATOMIC || code == StandardNames.XS_ANY_ATOMIC_TYPE || code == StandardNames.XS_DAY_TIME_DURATION || code == StandardNames.XS_YEAR_MONTH_DURATION || code == StandardNames.XS_ANY_SIMPLE_TYPE); } /** * Determine whether two primitive atomic types are comparable * @param t1 the first type to compared. * This must be a primitive atomic type as defined by {@link ItemType#getPrimitiveType} * @param t2 the second type to compared. * This must be a primitive atomic type as defined by {@link ItemType#getPrimitiveType} * @param ordered true if testing for an ordering comparison (lt, gt, le, ge). False * if testing for an equality comparison (eq, ne) * @return true if the types are comparable, as defined by the rules of the "eq" operator */ public static boolean isComparable(BuiltInAtomicType t1, BuiltInAtomicType t2, boolean ordered) { if (t1.equals(BuiltInAtomicType.ANY_ATOMIC) || t2.equals(BuiltInAtomicType.ANY_ATOMIC)) { return true; // meaning we don't actually know at this stage } if (t1.equals(BuiltInAtomicType.UNTYPED_ATOMIC)) { t1 = BuiltInAtomicType.STRING; } if (t2.equals(BuiltInAtomicType.UNTYPED_ATOMIC)) { t2 = BuiltInAtomicType.STRING; } if (t1.equals(BuiltInAtomicType.ANY_URI)) { t1 = BuiltInAtomicType.STRING; } if (t2.equals(BuiltInAtomicType.ANY_URI)) { t2 = BuiltInAtomicType.STRING; } if (t1.isPrimitiveNumeric()) { t1 = BuiltInAtomicType.NUMERIC; } if (t2.isPrimitiveNumeric()) { t2 = BuiltInAtomicType.NUMERIC; } if (!ordered) { if (t1.equals(BuiltInAtomicType.DAY_TIME_DURATION)) { t1 = BuiltInAtomicType.DURATION; } if (t2.equals(BuiltInAtomicType.DAY_TIME_DURATION)) { t2 = BuiltInAtomicType.DURATION; } if (t1.equals(BuiltInAtomicType.YEAR_MONTH_DURATION)) { t1 = BuiltInAtomicType.DURATION; } if (t2.equals(BuiltInAtomicType.YEAR_MONTH_DURATION)) { t2 = BuiltInAtomicType.DURATION; } } return t1 == t2; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/type/SchemaType.java0000644000175000017500000003044111033112257021267 0ustar eugeneeugenepackage net.sf.saxon.type; import net.sf.saxon.expr.Expression; import net.sf.saxon.expr.StaticContext; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.Value; /** * SchemaType is an interface implemented by all schema types: simple and complex types, built-in and * user-defined types. * *

    There is a hierarchy of interfaces that extend SchemaType, representing the top levels of the schema * type system: SimpleType and ComplexType, with SimpleType further subdivided into List, Union, and Atomic * types.

    * *

    The implementations of these interfaces are organized into a different hierarchy: on the one side, * built-in types such as AnyType, AnySimpleType, and the built-in atomic types and list types; on the other * side, user-defined types defined in a schema.

    */ public interface SchemaType extends SchemaComponent { // DerivationMethods. These constants are copied from org.w3.dom.TypeInfo. They are redefined here to avoid // creating a dependency on the TypeInfo class, which is only available when JAXP 1.3 is available. /** * If the document's schema is an XML Schema [XML Schema Part 1] * , this constant represents the derivation by * restriction if complex types are involved, or a * restriction if simple types are involved. *
    The reference type definition is derived by restriction from the * other type definition if the other type definition is the same as the * reference type definition, or if the other type definition can be * reached recursively following the {base type definition} property * from the reference type definition, and all the derivation methods involved are restriction. */ public static final int DERIVATION_RESTRICTION = 0x00000001; /** * If the document's schema is an XML Schema [XML Schema Part 1] * , this constant represents the derivation by * extension. *
    The reference type definition is derived by extension from the * other type definition if the other type definition can be reached * recursively following the {base type definition} property from the * reference type definition, and at least one of the derivation methods involved is an extension. */ public static final int DERIVATION_EXTENSION = 0x00000002; /** * If the document's schema is an XML Schema [XML Schema Part 1] * , this constant represents the * union if simple types are involved. *
    The reference type definition is derived by union from the other * type definition if there exists two type definitions T1 and T2 such * as the reference type definition is derived from T1 by * DERIVATION_RESTRICTION or * DERIVATION_EXTENSION, T2 is derived from the other type * definition by DERIVATION_RESTRICTION, T1 has {variety} union, and one of the {member type definitions} is T2. Note that T1 could be * the same as the reference type definition, and T2 could be the same * as the other type definition. */ public static final int DERIVATION_UNION = 0x00000004; /** * If the document's schema is an XML Schema [XML Schema Part 1] * , this constant represents the list. *
    The reference type definition is derived by list from the other * type definition if there exists two type definitions T1 and T2 such * as the reference type definition is derived from T1 by * DERIVATION_RESTRICTION or * DERIVATION_EXTENSION, T2 is derived from the other type * definition by DERIVATION_RESTRICTION, T1 has {variety} list, and T2 is the {item type definition}. Note that T1 could be the same as * the reference type definition, and T2 could be the same as the other * type definition. */ public static final int DERIVATION_LIST = 0x00000008; /** * Derivation by substitution. * This constant, unlike the others, is NOT defined in the DOM level 3 TypeInfo interface. */ public static final int DERIVE_BY_SUBSTITUTION = 16; /** * Get the local name of this type * @return the local name of this type definition, if it has one. Return null in the case of an * anonymous type. */ public String getName(); /** * Get the target namespace of this type * @return the target namespace of this type definition, if it has one. Return null in the case * of an anonymous type, and in the case of a global type defined in a no-namespace schema. */ public String getTargetNamespace(); /** * Get the namecode of the name of this type. This includes the prefix from the original * type declaration: in the case of built-in types, there may be a conventional prefix * or there may be no prefix. * @return the namecode. Returns an invented namecode for an anonymous type. */ int getNameCode(); /** * Get the fingerprint of the name of this type * @return the fingerprint. Returns an invented fingerprint for an anonymous type. */ int getFingerprint(); /** * Get the display name of the type: that is, a lexical QName with an arbitrary prefix * @return a lexical QName identifying the type */ String getDisplayName(); /** * Test whether this SchemaType is a complex type * @return true if this SchemaType is a complex type */ boolean isComplexType(); /** * Test whether this SchemaType is a simple type * @return true if this SchemaType is a simple type */ boolean isSimpleType(); /** * Test whether this SchemaType is an atomic type * @return true if this SchemaType is an atomic type */ boolean isAtomicType(); /** * Test whether this is an anonymous type * @return true if this SchemaType is an anonymous type */ boolean isAnonymousType(); /** * Returns the value of the 'block' attribute for this type, as a bit-signnificant * integer with fields such as {@link SchemaType#DERIVATION_LIST} and {@link SchemaType#DERIVATION_EXTENSION} * @return the value of the 'block' attribute for this type */ int getBlock(); /** * Returns the base type that this type inherits from. This method can be used to get the * base type of a type that is known to be valid. * If this type is a Simpletype that is a built in primitive type then null is returned. * @return the base type. * @throws IllegalStateException if this type is not valid. */ SchemaType getBaseType() throws UnresolvedReferenceException; /** * Gets the integer code of the derivation method used to derive this type from its * parent. Returns zero for primitive types. * @return a numeric code representing the derivation method, for example {@link SchemaType#DERIVATION_RESTRICTION} */ int getDerivationMethod(); /** * Determines whether derivation (of a particular kind) * from this type is allowed, based on the "final" property * @param derivation the kind of derivation, for example {@link SchemaType#DERIVATION_LIST} * @return true if this kind of derivation is allowed */ boolean allowsDerivation(int derivation); /** * Analyze an expression to see whether the expression is capable of delivering a value of this * type. * @param expression the expression that delivers the content * @param kind the node kind whose content is being delivered: {@link Type#ELEMENT}, * {@link Type#ATTRIBUTE}, or {@link Type#DOCUMENT} * @param env The static evaluation context for the query or stylesheet * @throws XPathException if the expression will never deliver a value of the correct type */ void analyzeContentExpression(Expression expression, int kind, StaticContext env) throws XPathException; /** * Get the typed value of a node that is annotated with this schema type. The results of this method * are consistent with the {@link #atomize} method, but this version returns a SequenceIterator which may * be more efficient when handling long lists. * @param node the node whose typed value is required * @return a SequenceIterator over the atomic values making up the typed value of the specified * node. The objects returned by this iterator are of type {@link net.sf.saxon.value.AtomicValue} */ SequenceIterator getTypedValue(NodeInfo node) throws XPathException; /** * Get the typed value of a node that is annotated with this schema type. The result of this method will always be consistent with the method * {@link #getTypedValue}. However, this method is often more convenient and may be * more efficient, especially in the common case where the value is expected to be a singleton. * @param node the node whose typed value is required * @return the typed value. * @since 8.5 */ Value atomize(NodeInfo node) throws XPathException; /** * Test whether this is the same type as another type. They are considered to be the same type * if they are derived from the same type definition in the original XML representation (which * can happen when there are multiple includes of the same file) * @param other the other type * @return true if this is the same type as other */ boolean isSameType(SchemaType other); /** * Get a description of this type for use in error messages. This is the same as the display name * in the case of named types; for anonymous types it identifies the type by its position in a source * schema document. * @return text identifing the type, for use in a phrase such as "the type XXXX". */ String getDescription(); /** * Check that this type is validly derived from a given type, following the rules for the Schema Component * Constraint "Is Type Derivation OK (Simple)" (3.14.6) or "Is Type Derivation OK (Complex)" (3.4.6) as * appropriate. * @param base the base type; the algorithm tests whether derivation from this type is permitted * @param block the derivations that are blocked by the relevant element declaration * @throws SchemaException if the derivation is not allowed */ public void checkTypeDerivationIsOK(SchemaType base, int block) throws SchemaException; /** * Get the URI of the schema document where the type was originally defined. * @return the URI of the schema document. Returns null if the information is unknown or if this * is a built-in type */ public String getSystemId(); } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/type/BuiltInAtomicType.java0000644000175000017500000012203111033112257022567 0ustar eugeneeugenepackage net.sf.saxon.type; import net.sf.saxon.Configuration; import net.sf.saxon.trans.Err; import net.sf.saxon.expr.Expression; import net.sf.saxon.expr.Literal; import net.sf.saxon.expr.StaticContext; import net.sf.saxon.instruct.ValueOf; import net.sf.saxon.om.*; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.*; import java.io.Serializable; /** * This class represents a built-in atomic type, which may be either a primitive type * (such as xs:decimal or xs:anyURI) or a derived type (such as xs:ID or xs:dayTimeDuration). */ public class BuiltInAtomicType implements AtomicType, Serializable { int fingerprint; int baseFingerprint; int primitiveFingerprint; boolean ordered = false; //private static boolean initialized = false; public static BuiltInAtomicType ANY_ATOMIC = makeAtomicType(StandardNames.XS_ANY_ATOMIC_TYPE, AnySimpleType.getInstance(), true); public static BuiltInAtomicType NUMERIC = makeAtomicType(StandardNames.XS_NUMERIC, ANY_ATOMIC, true); public static BuiltInAtomicType STRING = makeAtomicType(StandardNames.XS_STRING, ANY_ATOMIC, true); public static BuiltInAtomicType BOOLEAN = makeAtomicType(StandardNames.XS_BOOLEAN, ANY_ATOMIC, true); public static BuiltInAtomicType DURATION = makeAtomicType(StandardNames.XS_DURATION, ANY_ATOMIC, false); public static BuiltInAtomicType DATE_TIME = makeAtomicType(StandardNames.XS_DATE_TIME, ANY_ATOMIC, true); public static BuiltInAtomicType DATE = makeAtomicType(StandardNames.XS_DATE, ANY_ATOMIC, true); public static BuiltInAtomicType TIME = makeAtomicType(StandardNames.XS_TIME, ANY_ATOMIC, true); public static BuiltInAtomicType G_YEAR_MONTH = makeAtomicType(StandardNames.XS_G_YEAR_MONTH, ANY_ATOMIC, false); public static BuiltInAtomicType G_MONTH = makeAtomicType(StandardNames.XS_G_MONTH, ANY_ATOMIC, false); public static BuiltInAtomicType G_MONTH_DAY = makeAtomicType(StandardNames.XS_G_MONTH_DAY, ANY_ATOMIC, false); public static BuiltInAtomicType G_YEAR = makeAtomicType(StandardNames.XS_G_YEAR, ANY_ATOMIC, false); public static BuiltInAtomicType G_DAY = makeAtomicType(StandardNames.XS_G_DAY, ANY_ATOMIC, false); public static BuiltInAtomicType HEX_BINARY = makeAtomicType(StandardNames.XS_HEX_BINARY, ANY_ATOMIC, false); public static BuiltInAtomicType BASE64_BINARY = makeAtomicType(StandardNames.XS_BASE64_BINARY, ANY_ATOMIC, false); public static BuiltInAtomicType ANY_URI = makeAtomicType(StandardNames.XS_ANY_URI, ANY_ATOMIC, true);; public static BuiltInAtomicType QNAME = makeAtomicType(StandardNames.XS_QNAME, ANY_ATOMIC, false); public static BuiltInAtomicType NOTATION = makeAtomicType(StandardNames.XS_NOTATION, ANY_ATOMIC, false); public static BuiltInAtomicType UNTYPED_ATOMIC = makeAtomicType(StandardNames.XS_UNTYPED_ATOMIC, ANY_ATOMIC, true); public static BuiltInAtomicType DECIMAL = makeAtomicType(StandardNames.XS_DECIMAL, NUMERIC, true); public static BuiltInAtomicType FLOAT = makeAtomicType(StandardNames.XS_FLOAT, NUMERIC, true); public static BuiltInAtomicType DOUBLE = makeAtomicType(StandardNames.XS_DOUBLE, NUMERIC, true); public static BuiltInAtomicType INTEGER = makeAtomicType(StandardNames.XS_INTEGER, DECIMAL, true); public static BuiltInAtomicType NON_POSITIVE_INTEGER = makeAtomicType(StandardNames.XS_NON_POSITIVE_INTEGER, INTEGER, true); public static BuiltInAtomicType NEGATIVE_INTEGER = makeAtomicType(StandardNames.XS_NEGATIVE_INTEGER, NON_POSITIVE_INTEGER, true); public static BuiltInAtomicType LONG = makeAtomicType(StandardNames.XS_LONG, INTEGER, true); public static BuiltInAtomicType INT = makeAtomicType(StandardNames.XS_INT, LONG, true); public static BuiltInAtomicType SHORT = makeAtomicType(StandardNames.XS_SHORT, INT, true); public static BuiltInAtomicType BYTE = makeAtomicType(StandardNames.XS_BYTE, SHORT, true); public static BuiltInAtomicType NON_NEGATIVE_INTEGER = makeAtomicType(StandardNames.XS_NON_NEGATIVE_INTEGER, INTEGER, true); public static BuiltInAtomicType POSITIVE_INTEGER = makeAtomicType(StandardNames.XS_POSITIVE_INTEGER, NON_NEGATIVE_INTEGER, true); public static BuiltInAtomicType UNSIGNED_LONG = makeAtomicType(StandardNames.XS_UNSIGNED_LONG, NON_NEGATIVE_INTEGER, true); public static BuiltInAtomicType UNSIGNED_INT = makeAtomicType(StandardNames.XS_UNSIGNED_INT, UNSIGNED_LONG, true); public static BuiltInAtomicType UNSIGNED_SHORT = makeAtomicType(StandardNames.XS_UNSIGNED_SHORT, UNSIGNED_INT, true); public static BuiltInAtomicType UNSIGNED_BYTE = makeAtomicType(StandardNames.XS_UNSIGNED_BYTE, UNSIGNED_SHORT, true); public static BuiltInAtomicType YEAR_MONTH_DURATION = makeAtomicType(StandardNames.XS_YEAR_MONTH_DURATION, DURATION, true); public static BuiltInAtomicType DAY_TIME_DURATION = makeAtomicType(StandardNames.XS_DAY_TIME_DURATION, DURATION, true); public static BuiltInAtomicType NORMALIZED_STRING = makeAtomicType(StandardNames.XS_NORMALIZED_STRING, STRING, true); public static BuiltInAtomicType TOKEN = makeAtomicType(StandardNames.XS_TOKEN, NORMALIZED_STRING, true); public static BuiltInAtomicType LANGUAGE = makeAtomicType(StandardNames.XS_LANGUAGE, TOKEN, true); public static BuiltInAtomicType NAME = makeAtomicType(StandardNames.XS_NAME, TOKEN, true); public static BuiltInAtomicType NMTOKEN = makeAtomicType(StandardNames.XS_NMTOKEN, TOKEN, true); public static BuiltInAtomicType NCNAME = makeAtomicType(StandardNames.XS_NCNAME, NAME, true); public static BuiltInAtomicType ID = makeAtomicType(StandardNames.XS_ID, NCNAME, true); public static BuiltInAtomicType IDREF = makeAtomicType(StandardNames.XS_IDREF, NCNAME, true); public static BuiltInAtomicType ENTITY = makeAtomicType(StandardNames.XS_ENTITY, NCNAME, true); /** * Static initialization */ // public static void init() { // if (initialized) { // return; // } // initialized = true; // // DECIMAL = makeAtomicType(StandardNames.XS_DECIMAL, NUMERIC); // FLOAT = makeAtomicType(StandardNames.XS_FLOAT, NUMERIC); // DOUBLE = makeAtomicType(StandardNames.XS_DOUBLE, NUMERIC); // INTEGER = makeAtomicType(StandardNames.XS_INTEGER, DECIMAL); // NON_POSITIVE_INTEGER = makeAtomicType(StandardNames.XS_NON_POSITIVE_INTEGER, INTEGER); // NEGATIVE_INTEGER = makeAtomicType(StandardNames.XS_NEGATIVE_INTEGER, NON_POSITIVE_INTEGER); // LONG = makeAtomicType(StandardNames.XS_LONG, INTEGER); // INT = makeAtomicType(StandardNames.XS_INT, LONG); // SHORT = makeAtomicType(StandardNames.XS_SHORT, INT); // BYTE = makeAtomicType(StandardNames.XS_BYTE, SHORT); // NON_NEGATIVE_INTEGER = makeAtomicType(StandardNames.XS_NON_NEGATIVE_INTEGER, INTEGER); // POSITIVE_INTEGER = makeAtomicType(StandardNames.XS_POSITIVE_INTEGER, NON_NEGATIVE_INTEGER); // UNSIGNED_LONG = makeAtomicType(StandardNames.XS_UNSIGNED_LONG, NON_NEGATIVE_INTEGER); // UNSIGNED_INT = makeAtomicType(StandardNames.XS_UNSIGNED_INT, UNSIGNED_LONG); // UNSIGNED_SHORT = makeAtomicType(StandardNames.XS_UNSIGNED_SHORT, UNSIGNED_INT); // UNSIGNED_BYTE = makeAtomicType(StandardNames.XS_UNSIGNED_BYTE, UNSIGNED_SHORT); // YEAR_MONTH_DURATION = makeAtomicType(StandardNames.XS_YEAR_MONTH_DURATION, DURATION); // YEAR_MONTH_DURATION.ordered = true; // DAY_TIME_DURATION = makeAtomicType(StandardNames.XS_DAY_TIME_DURATION, DURATION); // DAY_TIME_DURATION.ordered = true; // NORMALIZED_STRING = makeAtomicType(StandardNames.XS_NORMALIZED_STRING, STRING); // TOKEN = makeAtomicType(StandardNames.XS_TOKEN, NORMALIZED_STRING); // LANGUAGE = makeAtomicType(StandardNames.XS_LANGUAGE, TOKEN); // NAME = makeAtomicType(StandardNames.XS_NAME, TOKEN); // NMTOKEN = makeAtomicType(StandardNames.XS_NMTOKEN, TOKEN); // NCNAME = makeAtomicType(StandardNames.XS_NCNAME, NAME); // ID = makeAtomicType(StandardNames.XS_ID, NCNAME); // IDREF = makeAtomicType(StandardNames.XS_IDREF, NCNAME); // ENTITY = makeAtomicType(StandardNames.XS_ENTITY, NCNAME); // // ANY_ATOMIC.ordered = true; // give it the benefit of the doubt: used only for static types // // } private BuiltInAtomicType(int fingerprint) { this.fingerprint = fingerprint; } /** * Get the local name of this type * * @return the local name of this type definition, if it has one. Return null in the case of an * anonymous type. */ public String getName() { if (fingerprint == StandardNames.XS_NUMERIC) { return "numeric"; } else { return StandardNames.getLocalName(fingerprint); } } /** * Get the target namespace of this type * * @return the target namespace of this type definition, if it has one. Return null in the case * of an anonymous type, and in the case of a global type defined in a no-namespace schema. */ public String getTargetNamespace() { return NamespaceConstant.SCHEMA; } /** * Determine whether the type is abstract, that is, whether it cannot have instances that are not also * instances of some concrete subtype */ public boolean isAbstract() { switch (fingerprint) { case StandardNames.XS_NOTATION: case StandardNames.XS_ANY_ATOMIC_TYPE: case StandardNames.XS_NUMERIC: case StandardNames.XS_ANY_SIMPLE_TYPE: return true; default: return false; } } /** * Return true if this is an external object type, that is, a Saxon-defined type for external * Java or .NET objects */ public boolean isExternalType() { return false; } /** * Determine whether this is a built-in type or a user-defined type */ public boolean isBuiltInType() { return true; } /** * Determine whether the atomic type is ordered, that is, whether less-than and greater-than comparisons * are permitted * * @return true if ordering operations are permitted */ public boolean isOrdered() { return ordered; } /** * Get the URI of the schema document where the type was originally defined. * * @return the URI of the schema document. Returns null if the information is unknown or if this * is a built-in type */ public String getSystemId() { return null; } /** * Determine whether the atomic type is numeric * * @return true if the type is a built-in numeric type */ public boolean isPrimitiveNumeric() { switch (fingerprint) { case StandardNames.XS_INTEGER: case StandardNames.XS_DECIMAL: case StandardNames.XS_DOUBLE: case StandardNames.XS_FLOAT: case StandardNames.XS_NUMERIC: return true; default: return false; } } /** * Get the most specific possible atomic type that all items in this SimpleType belong to * * @return the lowest common supertype of all member types */ public AtomicType getCommonAtomicType() { return this; } /** * Get the validation status - always valid */ public final int getValidationStatus() { return VALIDATED; } /** * Returns the value of the 'block' attribute for this type, as a bit-significant * integer with fields such as {@link SchemaType#DERIVATION_LIST} and {@link SchemaType#DERIVATION_EXTENSION} * * @return the value of the 'block' attribute for this type */ public final int getBlock() { return 0; } /** * Gets the integer code of the derivation method used to derive this type from its * parent. Returns zero for primitive types. * * @return a numeric code representing the derivation method, for example {@link SchemaType#DERIVATION_RESTRICTION} */ public final int getDerivationMethod() { return SchemaType.DERIVATION_RESTRICTION; } /** * Determines whether derivation (of a particular kind) * from this type is allowed, based on the "final" property * * @param derivation the kind of derivation, for example {@link SchemaType#DERIVATION_LIST} * @return true if this kind of derivation is allowed */ public final boolean allowsDerivation(int derivation) { return true; } /** * Set the base type of this type * * @param baseFingerprint the namepool fingerprint of the name of the base type */ public final void setBaseTypeFingerprint(int baseFingerprint) { this.baseFingerprint = baseFingerprint; } /** * Get the fingerprint of the name of this type * * @return the fingerprint. Returns an invented fingerprint for an anonymous type. */ public int getFingerprint() { return fingerprint; } /** * Get the namecode of the name of this type. This includes the prefix from the original * type declaration: in the case of built-in types, there may be a conventional prefix * or there may be no prefix. */ public int getNameCode() { return fingerprint; } /** * Get the name of the type as a QName * * @return a StructuredQName containing the name of the type. The conventional prefix "xs" is used * to represent the XML Schema namespace */ public StructuredQName getQualifiedName() { return new StructuredQName("xs", NamespaceConstant.SCHEMA, StandardNames.getLocalName(fingerprint)); } /** * Get the display name of the type: that is, a lexical QName with an arbitrary prefix * * @return a lexical QName identifying the type */ public String getDisplayName() { if (fingerprint == StandardNames.XS_NUMERIC) { return "numeric"; } else { return StandardNames.getDisplayName(fingerprint); } } /** * Determine whether the atomic type is a primitive type. The primitive types are * the 19 primitive types of XML Schema, plus xs:integer, xs:dayTimeDuration and xs:yearMonthDuration; * xs:untypedAtomic; and all supertypes of these (xs:anyAtomicType, xs:numeric, ...) * * @return true if the type is considered primitive under the above rules */ public boolean isPrimitiveType() { return Type.isPrimitiveType(fingerprint); } /** * Test whether this SchemaType is a complex type * * @return true if this SchemaType is a complex type */ public final boolean isComplexType() { return false; } /** * Test whether this is an anonymous type * * @return true if this SchemaType is an anonymous type */ public boolean isAnonymousType() { return false; } /** * Returns the base type that this type inherits from. This method can be used to get the * base type of a type that is known to be valid. * If this type is a Simpletype that is a built in primitive type then null is returned. * * @return the base type. * @throws IllegalStateException if this type is not valid. */ public final SchemaType getBaseType() { if (baseFingerprint == -1) { return null; } else { return BuiltInType.getSchemaType(baseFingerprint); } } /** * Test whether a given item conforms to this type * * @param item The item to be tested * @param allowURIPromotion true if we regard a URI as effectively a subtype of String * @param config the Saxon configuration (used to locate the type hierarchy cache) * @return true if the item is an instance of this type; false otherwise */ public boolean matchesItem(Item item, boolean allowURIPromotion, Configuration config) { if (item instanceof AtomicValue) { AtomicValue value = (AtomicValue)item; // Try to match primitive types first if (value.getPrimitiveType() == this) { return true; } AtomicType type = value.getTypeLabel(); if (type.getFingerprint() == getFingerprint()) { // note, with compiled stylesheets one can have two objects representing // the same type, so comparing identity is not safe return true; } final TypeHierarchy th = config.getTypeHierarchy(); boolean ok = th.isSubType(type, this); if (ok) { return true; } if (allowURIPromotion && getFingerprint() == StandardNames.XS_STRING && th.isSubType(type, BuiltInAtomicType.ANY_URI)) { // allow promotion from anyURI to string return true; } } return false; } /** * Get the type from which this item type is derived by restriction. This * is the supertype in the XPath type heirarchy, as distinct from the Schema * base type: this means that the supertype of xs:boolean is xs:anyAtomicType, * whose supertype is item() (rather than xs:anySimpleType). * * @param th the type hierarchy cache, not used in this implementation * @return the supertype, or null if this type is item() */ public ItemType getSuperType(TypeHierarchy th) { SchemaType base = getBaseType(); if (base instanceof AnySimpleType) { return AnyItemType.getInstance(); } else { return (ItemType)base; } } /** * Get the primitive item type corresponding to this item type. For item(), * this is Type.ITEM. For node(), it is Type.NODE. For specific node kinds, * it is the value representing the node kind, for example Type.ELEMENT. * For anyAtomicValue it is Type.ATOMIC_VALUE. For numeric it is Type.NUMBER. * For other atomic types it is the primitive type as defined in XML Schema, * except that INTEGER is considered to be a primitive type. */ public ItemType getPrimitiveItemType() { if (isPrimitiveType()) { return this; } else { ItemType s = (ItemType)getBaseType(); if (s.isAtomicType()) { return s.getPrimitiveItemType(); } else { return this; } } } /** * Get the primitive type corresponding to this item type. For item(), * this is Type.ITEM. For node(), it is Type.NODE. For specific node kinds, * it is the value representing the node kind, for example Type.ELEMENT. * For anyAtomicValue it is Type.ATOMIC_VALUE. For numeric it is Type.NUMBER. * For other atomic types it is the primitive type as defined in XML Schema, * except that INTEGER is considered to be a primitive type. */ public int getPrimitiveType() { return primitiveFingerprint; } /** * Determine whether this type is supported in a basic XSLT processor * * @return true if this type is permitted in a basic XSLT processor */ public boolean isAllowedInBasicXSLT() { return (isPrimitiveType() && getFingerprint() != StandardNames.XS_NOTATION); } /** * Produce a representation of this type name for use in error messages. * Where this is a QName, it will use conventional prefixes */ public String toString(NamePool pool) { return getDisplayName(); } /** * Get the item type of the atomic values that will be produced when an item * of this type is atomized */ public AtomicType getAtomizedItemType() { return this; } /** * Returns the base type that this type inherits from. This method can be used to get the * base type of a type that is known to be valid. * If this type is a Simpletype that is a built in primitive type then null is returned. * * @return the base type. * @throws IllegalStateException if this type is not valid. */ public SchemaType getKnownBaseType() { return getBaseType(); } /** * Test whether this is the same type as another type. They are considered to be the same type * if they are derived from the same type definition in the original XML representation (which * can happen when there are multiple includes of the same file) */ public boolean isSameType(SchemaType other) { return other.getFingerprint() == getFingerprint(); } public String getDescription() { return getDisplayName(); } public String toString() { return getDisplayName(); } /** * Check that this type is validly derived from a given type * * @param type the type from which this type is derived * @param block the derivations that are blocked by the relevant element declaration * @throws SchemaException if the derivation is not allowed */ public void checkTypeDerivationIsOK(SchemaType type, int block) throws SchemaException { if (type == AnySimpleType.getInstance()) { // OK } else if (isSameType(type)) { // OK } else { SchemaType base = getBaseType(); if (base == null) { throw new SchemaException("Type " + getDescription() + " is not validly derived from " + type.getDescription()); } try { base.checkTypeDerivationIsOK(type, block); } catch (SchemaException se) { throw new SchemaException("Type " + getDescription() + " is not validly derived from " + type.getDescription()); } } } /** * Returns true if this SchemaType is a SimpleType * * @return true (always) */ public final boolean isSimpleType() { return true; } /** * Test whether this Simple Type is an atomic type * * @return true, this is an atomic type */ public boolean isAtomicType() { return true; } /** * Returns true if this type is derived by list, or if it is derived by restriction * from a list type, or if it is a union that contains a list as one of its members * * @return true if this is a list type */ public boolean isListType() { return false; } /** * Return true if this type is a union type (that is, if its variety is union) * * @return true for a union type */ public boolean isUnionType() { return false; } /** * Determine the whitespace normalization required for values of this type * * @param th the type hierarchy cache * @return one of PRESERVE, REPLACE, COLLAPSE */ public int getWhitespaceAction(TypeHierarchy th) { switch (getFingerprint()) { case StandardNames.XS_STRING: return Whitespace.PRESERVE; case StandardNames.XS_NORMALIZED_STRING: return Whitespace.REPLACE; default: return Whitespace.COLLAPSE; } } /** * Returns the built-in base type this type is derived from. * * @return the first built-in type found when searching up the type hierarchy */ public SchemaType getBuiltInBaseType() { BuiltInAtomicType base = this; while ((base != null) && (base.getFingerprint() > 1023)) { base = (BuiltInAtomicType)base.getBaseType(); } return base; } /** * Test whether this simple type is namespace-sensitive, that is, whether * it is derived from xs:QName or xs:NOTATION * * @return true if this type is derived from xs:QName or xs:NOTATION */ public boolean isNamespaceSensitive() { BuiltInAtomicType base = this; int fp = base.getFingerprint(); while (fp > 1023) { base = (BuiltInAtomicType)base.getBaseType(); fp = base.getFingerprint(); } return fp == StandardNames.XS_QNAME || fp == StandardNames.XS_NOTATION; } /** * Check whether a given input string is valid according to this SimpleType * * @param value the input string to be checked * @param nsResolver a namespace resolver used to resolve namespace prefixes if the type * is namespace sensitive. The value supplied may be null; in this case any namespace-sensitive * content will throw an UnsupportedOperationException. * @param nameChecker XML 1.0 or 1.1 name checker. Must not be null. * @return XPathException if the value is invalid. Note that the exception is returned rather than being thrown. * Returns null if the value is valid. * @throws UnsupportedOperationException if the type is namespace-sensitive and no namespace * resolver is supplied */ public ValidationFailure validateContent(CharSequence value, NamespaceResolver nsResolver, NameChecker nameChecker) { int f = getFingerprint(); if (f == StandardNames.XS_STRING || f == StandardNames.XS_ANY_SIMPLE_TYPE || f == StandardNames.XS_UNTYPED_ATOMIC || f == StandardNames.XS_ANY_ATOMIC_TYPE) { return null; } ValidationFailure result = null; if (isNamespaceSensitive()) { if (nsResolver == null) { throw new UnsupportedOperationException("Cannot validate a QName without a namespace resolver"); } try { String[] parts = nameChecker.getQNameParts(Whitespace.trimWhitespace(value)); String uri = nsResolver.getURIForPrefix(parts[0], true); if (uri == null) { result = new ValidationFailure("Namespace prefix " + Err.wrap(parts[0]) + " has not been declared"); } new QNameValue(parts[0], uri, parts[1], BuiltInAtomicType.QNAME, nameChecker); } catch (QNameException err) { result = new ValidationFailure("Invalid lexical QName " + Err.wrap(value)); } catch (XPathException err) { result = new ValidationFailure(err.getMessage()); } } else { ConversionResult v = StringValue.convertStringToBuiltInType(value, this, nameChecker); if (v instanceof ValidationFailure) { result = (ValidationFailure)v; } } return result; } /** * Get the typed value of a node that is annotated with this schema type * * @param node the node whose typed value is required * @return an iterator over the items making up the typed value of this node. The objects * returned by this SequenceIterator will all be of type {@link net.sf.saxon.value.AtomicValue} */ public final SequenceIterator getTypedValue(NodeInfo node) throws XPathException { try { CharSequence stringValue = node.getStringValueCS(); if (stringValue.length() == 0 && node.isNilled()) { return EmptyIterator.getInstance(); } return getTypedValue(stringValue, new InscopeNamespaceResolver(node), node.getConfiguration().getNameChecker()); } catch (ValidationException err) { throw new XPathException("Internal error: value doesn't match its type annotation. " + err.getMessage()); } } /** * Get the typed value of a node that is annotated with this schema type. * The result of this method will always be consistent with the method * {@link #getTypedValue}. However, this method is often more convenient and may be * more efficient, especially in the common case where the value is expected to be a singleton. * * @param node the node whose typed value is required * @return the typed value. * @since 8.5 */ public Value atomize(NodeInfo node) throws XPathException { // Fast path for common cases CharSequence stringValue = node.getStringValueCS(); if (stringValue.length() == 0 && node.isNilled()) { return EmptySequence.getInstance(); } if (fingerprint == StandardNames.XS_STRING) { return StringValue.makeStringValue(stringValue); } else if (fingerprint == StandardNames.XS_UNTYPED_ATOMIC) { return new UntypedAtomicValue(stringValue); } final NameChecker checker = node.getConfiguration().getNameChecker(); if (isNamespaceSensitive()) { try { NamespaceResolver resolver = new InscopeNamespaceResolver(node); String[] parts = checker.getQNameParts(Whitespace.trimWhitespace(stringValue)); String uri = resolver.getURIForPrefix(parts[0], true); if (uri == null) { throw new ValidationException("Namespace prefix " + Err.wrap(parts[0]) + " has not been declared"); } return new QNameValue(parts[0], uri, parts[1], BuiltInAtomicType.QNAME, checker); } catch (QNameException err) { throw new ValidationException("Invalid lexical QName " + Err.wrap(stringValue)); } catch (XPathException err) { throw new ValidationException(err.getMessage()); } } return StringValue.convertStringToBuiltInType(stringValue, this, checker).asAtomic(); } /** * Get the typed value corresponding to a given string value, assuming it is * valid against this type (and that the containing node is not nilled) * * @param value the string value * @param resolver a namespace resolver used to resolve any namespace prefixes appearing * in the content of values. Can supply null, in which case any namespace-sensitive content * will be rejected. * @param nameChecker XML 1.0 or 1.1 name checker. May be null if name checking is not required * @return an iterator over the atomic sequence comprising the typed value. The objects * returned by this SequenceIterator will all be of type {@link AtomicValue} */ public SequenceIterator getTypedValue(CharSequence value, NamespaceResolver resolver, NameChecker nameChecker) throws ValidationException { // Fast path for common cases if (fingerprint == StandardNames.XS_STRING) { return SingletonIterator.makeIterator(StringValue.makeStringValue(value)); } else if (fingerprint == StandardNames.XS_UNTYPED_ATOMIC) { return SingletonIterator.makeIterator(new UntypedAtomicValue(value)); } else if (fingerprint == StandardNames.XS_QNAME || fingerprint == StandardNames.XS_NOTATION) { try { String[] parts = nameChecker.getQNameParts(Whitespace.trimWhitespace(value)); String uri = resolver.getURIForPrefix(parts[0], true); if (uri == null) { throw new ValidationException("Namespace prefix " + Err.wrap(parts[0]) + " has not been declared"); } return SingletonIterator.makeIterator( fingerprint == StandardNames.XS_QNAME ? (QualifiedNameValue)new QNameValue(parts[0], uri, parts[1], this, nameChecker) : (QualifiedNameValue)new NotationValue(parts[0], uri, parts[1], nameChecker)); } catch (QNameException err) { throw new ValidationException("Invalid lexical QName " + Err.wrap(value)); } catch (XPathException err) { throw new ValidationException(err.getMessage()); } } // TODO: if we really can assume validity, we should set nameChecker to null in the following call AtomicValue val = StringValue.convertStringToBuiltInType(value, this, nameChecker).asAtomic(); return SingletonIterator.makeIterator(val); } /** * Two types are equal if they have the same fingerprint. * Note: it is normally safe to use ==, because we always use the static constants, one instance * for each built in atomic type. However, after serialization and deserialization a different instance * can appear. */ public boolean equals(Object obj) { return obj instanceof BuiltInAtomicType && getFingerprint() == ((BuiltInAtomicType)obj).getFingerprint(); } /** * The fingerprint can be used as a hashcode */ public int hashCode() { return getFingerprint(); } /** * Validate that a primitive atomic value is a valid instance of a type derived from the * same primitive type. * * @param primValue the value in the value space of the primitive type. * @param lexicalValue the value in the lexical space. If null, the string value of primValue * is used. This value is checked against the pattern facet (if any) * @param checker Used to check names against XML 1.0 or XML 1.1 syntax rules * @return null if the value is valid; otherwise, a ValidationFailure object indicating * the nature of the error. * @throws UnsupportedOperationException in the case of an external object type */ public ValidationFailure validate(AtomicValue primValue, CharSequence lexicalValue, NameChecker checker) { switch (fingerprint) { case StandardNames.XS_NUMERIC: case StandardNames.XS_STRING: case StandardNames.XS_BOOLEAN: case StandardNames.XS_DURATION: case StandardNames.XS_DATE_TIME: case StandardNames.XS_DATE: case StandardNames.XS_TIME: case StandardNames.XS_G_YEAR_MONTH: case StandardNames.XS_G_MONTH: case StandardNames.XS_G_MONTH_DAY: case StandardNames.XS_G_YEAR: case StandardNames.XS_G_DAY: case StandardNames.XS_HEX_BINARY: case StandardNames.XS_BASE64_BINARY: case StandardNames.XS_ANY_URI: case StandardNames.XS_QNAME: case StandardNames.XS_NOTATION: case StandardNames.XS_UNTYPED_ATOMIC: case StandardNames.XS_DECIMAL: case StandardNames.XS_FLOAT: case StandardNames.XS_DOUBLE: case StandardNames.XS_INTEGER: return null; case StandardNames.XS_NON_POSITIVE_INTEGER: case StandardNames.XS_NEGATIVE_INTEGER: case StandardNames.XS_LONG: case StandardNames.XS_INT: case StandardNames.XS_SHORT: case StandardNames.XS_BYTE: case StandardNames.XS_NON_NEGATIVE_INTEGER: case StandardNames.XS_POSITIVE_INTEGER: case StandardNames.XS_UNSIGNED_LONG: case StandardNames.XS_UNSIGNED_INT: case StandardNames.XS_UNSIGNED_SHORT: case StandardNames.XS_UNSIGNED_BYTE: return ((IntegerValue)primValue).validateAgainstSubType(this); case StandardNames.XS_YEAR_MONTH_DURATION: case StandardNames.XS_DAY_TIME_DURATION: return null; // treated as primitive case StandardNames.XS_NORMALIZED_STRING: case StandardNames.XS_TOKEN: case StandardNames.XS_LANGUAGE: case StandardNames.XS_NAME: case StandardNames.XS_NMTOKEN: case StandardNames.XS_NCNAME: case StandardNames.XS_ID: case StandardNames.XS_IDREF: case StandardNames.XS_ENTITY: return StringValue.validate( this, primValue.getStringValueCS(), checker); default: throw new IllegalArgumentException(); } } /** * Analyze an expression to see whether the expression is capable of delivering a value of this * type. * * @param expression the expression that delivers the content * @param kind the node kind whose content is being delivered: {@link Type#ELEMENT}, * {@link Type#ATTRIBUTE}, or {@link Type#DOCUMENT} * @param env the static context * @throws net.sf.saxon.trans.XPathException * if the expression will never deliver a value of the correct type */ public void analyzeContentExpression(Expression expression, int kind, StaticContext env) throws XPathException { analyzeContentExpression(this, expression, env, kind); } /** * Analyze an expression to see whether the expression is capable of delivering a value of this * type. * * @param simpleType the simple type against which the expression is to be checked * @param expression the expression that delivers the content * @param env the static context of the expression * @param kind the node kind whose content is being delivered: {@link Type#ELEMENT}, * {@link Type#ATTRIBUTE}, or {@link Type#DOCUMENT} * @throws net.sf.saxon.trans.XPathException * if the expression will never deliver a value of the correct type */ public static void analyzeContentExpression(SimpleType simpleType, Expression expression, StaticContext env, int kind) throws XPathException { if (kind == Type.ELEMENT) { expression.checkPermittedContents(simpleType, env, true); // // if we are building the content of an element or document, no atomization will take // // place, and therefore the presence of any element or attribute nodes in the content will // // cause a validity error, since only simple content is allowed // if (Type.isSubType(itemType, NodeKindTest.makeNodeKindTest(Type.ELEMENT))) { // throw new XPathException("The content of an element with a simple type must not include any element nodes"); // } // if (Type.isSubType(itemType, NodeKindTest.makeNodeKindTest(Type.ATTRIBUTE))) { // throw new XPathException("The content of an element with a simple type must not include any attribute nodes"); // } } else if (kind == Type.ATTRIBUTE) { // for attributes, do a check only for text nodes and atomic values: anything else gets atomized if (expression instanceof ValueOf || expression instanceof Literal) { expression.checkPermittedContents(simpleType, env, true); } } } /** * Internal factory method to create a BuiltInAtomicType. There is one instance for each of the * built-in atomic types * * @param fingerprint The name of the type * @param baseType The base type from which this type is derived * @return the newly constructed built in atomic type */ private static BuiltInAtomicType makeAtomicType(int fingerprint, SimpleType baseType, boolean ordered) { BuiltInAtomicType t = new BuiltInAtomicType(fingerprint); t.setBaseTypeFingerprint(baseType.getFingerprint()); if (t.isPrimitiveType()) { t.primitiveFingerprint = fingerprint; } else { t.primitiveFingerprint = ((AtomicType)baseType).getPrimitiveType(); } t.ordered = ordered; BuiltInType.register(fingerprint, t); return t; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Saxonica Limited // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none //saxonb-9.1.0.8/bj/net/sf/saxon/type/package.html0000644000175000017500000000304711033112257020645 0ustar eugeneeugene Package overview for net.sf.saxon.type

    This package contains classes that implement the XPath 2.0 type system. It contains that part of the functionality relevant to a non-schema-aware implementation: that is, the overall structure of the type system, together with representations of the built-in types.

    The hierarchy of schema types is represented by the interfaces SchemaType, ComplexType, SimpleType, ListType, and AtomicType. (Union types never arise in non-schema-aware processing). There are concrete classes representing built-in types such as AnyType, BuiltInAtomicType, and BuiltInListType: the corresponding classes for user-defined types are in the com.saxonica.schema package.

    The class SequenceType ought logically to be in this package but is actually in net.sf.saxon.value. A sequence type contains an ItemType which may be an AtomicType or a NodeTest: NodeTests are found in the package net.sf.saxon.pattern.

    The logic for performing type checking is partly in the singleton class Type (which also contains many useful constants), and partly in the class TypeChecker found in package net.sf.saxon.expr.

    Michael H. Kay
    Saxonica Limited
    9 February 2005

    saxonb-9.1.0.8/bj/net/sf/saxon/query/0000755000175000017500000000000012216261743016555 5ustar eugeneeugenesaxonb-9.1.0.8/bj/net/sf/saxon/query/XQueryFunctionBinder.java0000644000175000017500000000327111033112257023501 0ustar eugeneeugenepackage net.sf.saxon.query; import net.sf.saxon.functions.FunctionLibrary; import net.sf.saxon.expr.Expression; import net.sf.saxon.om.StructuredQName; /** * XQueryFunctionBinder is an extension of the FunctionLibrary interface used for function libraries * that contain user-written XQuery functions. It provides a method that allows the XQueryFunction * with a given name and arity to be located. */ public interface XQueryFunctionBinder extends FunctionLibrary { /** * Get the function declaration corresponding to a given function name and arity * @param functionName the name of the function as a QName * @param staticArgs the expressions supplied as arguments in the function call (typically, * we only need to know the number of arguments) * @return the XQueryFunction if there is one, or null if not. */ public XQueryFunction getDeclaration(StructuredQName functionName, Expression[] staticArgs); } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/query/ModuleURIResolver.java0000644000175000017500000000525211033112257022742 0ustar eugeneeugenepackage net.sf.saxon.query; import net.sf.saxon.trans.XPathException; import javax.xml.transform.stream.StreamSource; import java.io.Serializable; /** * A ModuleURIResolver is used when resolving references to * query modules. It takes as input a URI that identifies the module to be loaded, and a set of * location hints as input, and returns one or more StreamSource obects containing the queries * to be imported. * @author Michael H. Kay */ public interface ModuleURIResolver extends Serializable { /** * Resolve a identifying a query module, given the identifying URI and * a set of associated location hints. * @param moduleURI the module URI of the module to be imported; or null when * loading a non-library module. * @param baseURI The base URI of the module containing the "import module" declaration; * null if no base URI is known * @param locations The set of URIs specified in the "at" clause of "import module", * which serve as location hints for the module * @return an array of StreamSource objects each identifying the contents of a query module to be * imported. Each StreamSource must contain a * non-null absolute System ID which will be used as the base URI of the imported module, * and either an {@link java.io.InputStream} or an {@link java.io.Reader} representing the text of the module. * The method may also return null, in which case the system attempts to resolve the URI using the * standard module URI resolver. The contained InputStream or Reader must be positioned at the start of the * content to be read; it will be consumed by the system and will be closed after use. * @throws XPathException if the module cannot be located, and if delegation to the default * module resolver is not required. */ public StreamSource[] resolve(String moduleURI, String baseURI, String[] locations) throws XPathException; } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/query/ImportedFunctionLibrary.java0000644000175000017500000001573311033112257024236 0ustar eugeneeugenepackage net.sf.saxon.query; import net.sf.saxon.expr.Expression; import net.sf.saxon.expr.StaticContext; import net.sf.saxon.functions.FunctionLibrary; import net.sf.saxon.om.StructuredQName; import net.sf.saxon.trans.XPathException; import java.util.HashSet; import java.util.Iterator; /** * This implementation of FunctionLibrary contains all the functions imported into a Query Module. * It is implemented as a view of the "global" XQueryFunctionLibrary for the whole query, selecting * only those functions that are in an imported namespace. */ public class ImportedFunctionLibrary implements FunctionLibrary, XQueryFunctionBinder { QueryModule importingModule; XQueryFunctionLibrary baseLibrary; HashSet namespaces = new HashSet(5); /** * Create an imported function library * @param importingModule the module importing the library * @param baseLibrary the function library of which this is a subset view */ public ImportedFunctionLibrary(QueryModule importingModule, XQueryFunctionLibrary baseLibrary) { this.importingModule = importingModule; this.baseLibrary = baseLibrary; } /** * Add an imported namespace * @param namespace the imported namespace */ public void addImportedNamespace(String namespace) { namespaces.add(namespace); } /** * Bind an extension function, given the URI and local parts of the function name, * and the list of expressions supplied as arguments. This method is called at compile * time. * * @param functionName the name of the function to be bound * @param staticArgs The expressions supplied statically in arguments to the function call. * The length of this array represents the arity of the function. The intention is * that the static type of the arguments (obtainable via getItemType() and getCardinality()) may * be used as part of the binding algorithm. In some cases it may be possible for the function * to be pre-evaluated at compile time, for example if these expressions are all constant values. *

    * The conventions of the XPath language demand that the results of a function depend only on the * values of the expressions supplied as arguments, and not on the form of those expressions. For * example, the result of f(4) is expected to be the same as f(2+2). The actual expression is supplied * here to enable the binding mechanism to select the most efficient possible implementation (including * compile-time pre-evaluation where appropriate). * @param env * @return An object representing the function to be called, if one is found; * null if no function was found matching the required name and arity. * @throws net.sf.saxon.trans.XPathException * if a function is found with the required name and arity, but * the implementation of the function cannot be loaded or used; or if an error occurs * while searching for the function. */ public Expression bind(StructuredQName functionName, Expression[] staticArgs, StaticContext env) throws XPathException { final String uri = functionName.getNamespaceURI(); if (namespaces.contains(uri)) { Expression call = baseLibrary.bind(functionName, staticArgs, env); if (call != null) { // Check that the result type and all the argument types are in the static context of the // calling module XQueryFunction def = baseLibrary.getDeclaration(functionName, staticArgs); importingModule.checkImportedFunctionSignature(def); } return call; } else { return null; } } /** * Get the function declaration corresponding to a given function name and arity * @return the XQueryFunction if there is one, or null if not. */ public XQueryFunction getDeclaration(StructuredQName functionName, Expression[] staticArgs) { if (namespaces.contains(functionName.getNamespaceURI())) { return baseLibrary.getDeclaration(functionName, staticArgs); } else { return null; } } /** * This method creates a copy of a FunctionLibrary: if the original FunctionLibrary allows * new functions to be added, then additions to this copy will not affect the original, or * vice versa. * * @return a copy of this function library. This must be an instance of the original class. */ public FunctionLibrary copy() { ImportedFunctionLibrary lib = new ImportedFunctionLibrary(importingModule, baseLibrary); Iterator iter = namespaces.iterator(); while (iter.hasNext()) { String ns = (String)iter.next(); lib.addImportedNamespace(ns); } return lib; } /** * Set the module that imports this function libary * @param importingModule the importing module */ public void setImportingModule(QueryModule importingModule) { this.importingModule = importingModule; } /** * Test whether an extension function with a given name and arity is available. This supports * the function-available() function in XSLT. This method may be called either at compile time * or at run time. If the function library is to be used only in an XQuery or free-standing XPath * environment, this method may throw an UnsupportedOperationException. * * @param functionName the name of the function in question * @param arity The number of arguments. This is set to -1 in the case of the single-argument * function-available() function; in this case the method should return true if there is some */ public boolean isAvailable(StructuredQName functionName, int arity) { return namespaces.contains(functionName.getNamespaceURI()) && baseLibrary.isAvailable(functionName, arity); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/query/Declaration.java0000644000175000017500000000175011033112257021637 0ustar eugeneeugenepackage net.sf.saxon.query; import javax.xml.transform.SourceLocator; /** * This interface represents the union of global variable declarations and function declarations in XQuery * modules */ public interface Declaration extends SourceLocator { } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none // saxonb-9.1.0.8/bj/net/sf/saxon/query/StaticQueryContext.java0000644000175000017500000011125411047007544023244 0ustar eugeneeugenepackage net.sf.saxon.query; import net.sf.saxon.Configuration; import net.sf.saxon.StandardErrorListener; import net.sf.saxon.expr.CollationMap; import net.sf.saxon.expr.Literal; import net.sf.saxon.instruct.Executable; import net.sf.saxon.om.*; import net.sf.saxon.sort.NamedCollation; import net.sf.saxon.sort.StringCollator; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.AnyItemType; import net.sf.saxon.type.ItemType; import net.sf.saxon.value.SequenceType; import net.sf.saxon.value.Value; import javax.xml.transform.ErrorListener; import javax.xml.transform.Source; import java.io.IOException; import java.io.InputStream; import java.io.Reader; import java.util.*; /** * StaticQueryContext contains information used to build a StaticContext for use when processing XQuery * expressions. * *

    Despite its name, StaticQueryContext no longer implements the StaticContext * interface, which means it cannot be used directly by Saxon when parsing a query. Instead it is first copied * to create a QueryModule object, which does implement the StaticContext interface. * *

    The application constructs a StaticQueryContext * and initializes it with information about the context, for example, default namespaces, base URI, and so on. * When a query is compiled using this StaticQueryContext, the query parser makes a copy of the StaticQueryContext * and uses this internally, modifying it with information obtained from the query prolog, as well as information * such as namespace and variable declarations that can occur at any point in the query. The query parser does * not modify the original StaticQueryContext supplied by the calling application, which may therefore be used * for compiling multiple queries, serially or even in multiple threads.

    * *

    This class forms part of Saxon's published XQuery API. Methods that * are considered stable are labelled with the JavaDoc "since" tag. * The value 8.4 indicates a method introduced at or before Saxon 8.4; other * values indicate the version at which the method was introduced.

    * *

    In the longer term, this entire API may at some stage be superseded by a proposed * standard Java API for XQuery.

    * * @since 8.4 */ public class StaticQueryContext { private Configuration config; private NamePool namePool; private String baseURI; private HashMap userDeclaredNamespaces; private Set userDeclaredVariables; private Executable executable; private boolean inheritNamespaces = true; private boolean preserveNamespaces = true; private int constructionMode = Validation.PRESERVE; private NamespaceResolver externalNamespaceResolver = null; private CollationMap collations; private String defaultFunctionNamespace; private String defaultElementNamespace; private ItemType requiredContextItemType = AnyItemType.getInstance(); private boolean preserveSpace = false; private boolean defaultEmptyLeast = true; private ModuleURIResolver moduleURIResolver; private ErrorListener errorListener; private boolean tracing; private boolean generateCode = false; private boolean isUpdating = false; /** * Private constructor used when copying a context */ protected StaticQueryContext() { } /** * Create a StaticQueryContext using a given Configuration. This creates a StaticQueryContext for a main module * (that is, a module that is not a library module). * @param config the Saxon Configuration * * @since 8.4 */ public StaticQueryContext(Configuration config) { this.config = config; namePool = config.getNamePool(); errorListener = config.getErrorListener(); moduleURIResolver = config.getModuleURIResolver(); if (errorListener instanceof StandardErrorListener) { errorListener = ((StandardErrorListener)errorListener).makeAnother(Configuration.XQUERY); ((StandardErrorListener)errorListener).setRecoveryPolicy(Configuration.DO_NOT_RECOVER); } collations = new CollationMap(config); reset(); } /** * Reset the state of this StaticQueryContext to an uninitialized state * * @since 8.4 */ public void reset() { userDeclaredNamespaces = new HashMap(10); externalNamespaceResolver = null; collations = new CollationMap(config); errorListener = config.getErrorListener(); if (errorListener instanceof StandardErrorListener) { errorListener = ((StandardErrorListener)errorListener).makeAnother(Configuration.XQUERY); ((StandardErrorListener)errorListener).setRecoveryPolicy(Configuration.DO_NOT_RECOVER); } constructionMode = getConfiguration().isSchemaAware(Configuration.XQUERY) ? Validation.PRESERVE : Validation.STRIP; preserveSpace = false; defaultEmptyLeast = true; requiredContextItemType = AnyItemType.getInstance(); defaultFunctionNamespace = NamespaceConstant.FN; defaultElementNamespace = NamespaceConstant.NULL; moduleURIResolver = config.getModuleURIResolver(); collations.setDefaultCollationName(NamespaceConstant.CODEPOINT_COLLATION_URI); clearNamespaces(); generateCode = false; } /** * Set the Configuration options * @param config the Saxon Configuration * @throws IllegalArgumentException if the configuration supplied is different from the existing * configuration * @since 8.4 */ public void setConfiguration(Configuration config) { if (this.config != null && this.config != config) { throw new IllegalArgumentException("Configuration cannot be changed dynamically"); } this.config = config; namePool = config.getNamePool(); } /** * Get the Configuration options * @return the Saxon configuration * @since 8.4 */ public Configuration getConfiguration() { return config; } /** * Set the Executable to contain this query. Normally a query constitutes its own Executable, * and the executable will then be created automatically. This method is used when the query is to * share the same executable as a host program, specifically, an XSLT stylesheet that imports the * query. * @param executable the executable */ public void setExecutable(Executable executable) { this.executable = executable; } /** * Get the executable containing this query * @return the executable (or null if not set) */ public Executable getExecutable() { return executable; } /** * Set the Base URI of the query * @param baseURI the base URI of the query * @since 8.4 */ public void setBaseURI(String baseURI) { this.baseURI = baseURI; } /** * Convenience method for building Saxon's internal representation of a source XML * document. The document will be built using Configuration (and NamePool) associated * with this StaticQueryContext. * *

    This method is retained for backwards compatibility; however, it is merely a wrapper * around the method {@link Configuration#buildDocument}, which should be called in preference.

    * * @param source Any javax.xml.transform.Source object representing the document against * which queries will be executed. Note that a Saxon {@link net.sf.saxon.om.DocumentInfo DocumentInfo} * (indeed any {@link net.sf.saxon.om.NodeInfo NodeInfo}) * can be used as a Source. To use a third-party DOM Document as a source, create an instance of * {@link javax.xml.transform.dom.DOMSource DOMSource} to wrap it. *

    For additional control over the way in which the source document is processed, * supply an {@link net.sf.saxon.AugmentedSource AugmentedSource} object and set appropriate * options on the object.

    * @return the DocumentInfo representing the root node of the resulting document object. * @since 8.4 */ public DocumentInfo buildDocument(Source source) throws XPathException { return config.buildDocument(source); } /** * Ask whether compile-time generation of trace code was requested * @since 9.0 * @return true if compile-time generation of code was requested */ public boolean isCompileWithTracing() { return tracing; } /** * Request compile-time generation of trace code (or not) * @param trace true if compile-time generation of trace code is required * @since 9.0 */ public void setCompileWithTracing(boolean trace) { tracing = trace; } /** * Indicate that the query should be optimized with a view to generating Java code. * This inhibits some rewrites to constructs for which code generation is not possible. * @param generateCode true if Java code is to be generated as the final output */ public void setGeneratingJavaCode(boolean generateCode) { this.generateCode = generateCode; } /** * Ask whether this query is to be optimized with a view to generating Java code. * This inhibits some rewrites to constructs for which code generation is not possible. * @return true if Java code is to be generated as the final output */ public boolean isGeneratingJavaCode() { return generateCode; } /** * Set the namespace inheritance mode * * @param inherit true if namespaces are inherited, false if not * @since 8.4 */ public void setInheritNamespaces(boolean inherit) { inheritNamespaces = inherit; } /** * Get the namespace inheritance mode * * @return true if namespaces are inherited, false if not * @since 8.4 */ public boolean isInheritNamespaces() { return inheritNamespaces; } /** * Set the namespace copy mode * * @param inherit true if namespaces are preserved, false if not * @since 8.4 */ public void setPreserveNamespaces(boolean inherit) { preserveNamespaces = inherit; } /** * Get the namespace copy mode * * @return true if namespaces are preserved, false if not * @since 8.4 */ public boolean isPreserveNamespaces() { return preserveNamespaces; } /** * Set the construction mode for this module * * @param mode one of {@link net.sf.saxon.om.Validation#STRIP}, {@link net.sf.saxon.om.Validation#PRESERVE} * @since 8.4 */ public void setConstructionMode(int mode) { constructionMode = mode; } /** * Get the current construction mode * * @return one of {@link net.sf.saxon.om.Validation#STRIP}, {@link net.sf.saxon.om.Validation#PRESERVE} * @since 8.4 */ public int getConstructionMode() { return constructionMode; } /** * Prepare an XQuery query for subsequent evaluation. The source text of the query * is supplied as a String. The base URI of the query is taken from the static context, * and defaults to the current working directory. * *

    Note that this interface makes the caller responsible for decoding the query and * presenting it as a string of characters. This means it is likely that any encoding * specified in the query prolog will be ignored.

    * * @param query The XQuery query to be evaluated, supplied as a string. * @return an XQueryExpression object representing the prepared expression * @throws net.sf.saxon.trans.XPathException * if the syntax of the expression is wrong, * or if it references namespaces, variables, or functions that have not been declared, * or contains other static errors. * @since 8.4 */ public XQueryExpression compileQuery(String query) throws XPathException { QueryParser qp = getConfiguration().newQueryParser(isUpdating); qp.setCompileWithTracing(isCompileWithTracing() || config.isCompileWithTracing()); QueryModule mainModule = new QueryModule(this); mainModule.setExecutable(executable); return qp.makeXQueryExpression(query, mainModule, config); } /** * Prepare an XQuery query for subsequent evaluation. The Query is supplied * in the form of a Reader. The base URI of the query is taken from the static context, * and defaults to the current working directory. * *

    Note that this interface makes the Reader responsible for decoding the query and * presenting it as a stream of characters. This means it is likely that any encoding * specified in the query prolog will be ignored. Also, some implementations of Reader * cannot handle a byte order mark.

    * * @param source A Reader giving access to the text of the XQuery query to be compiled. * @return an XPathExpression object representing the prepared expression. * @throws net.sf.saxon.trans.XPathException * if the syntax of the expression is wrong, or if it references namespaces, * variables, or functions that have not been declared, or any other static error is reported. * @throws java.io.IOException if a failure occurs reading the supplied input. * @since 8.4 */ public XQueryExpression compileQuery(Reader source) throws XPathException, IOException { char[] buffer = new char[4096]; StringBuffer sb = new StringBuffer(4096); while (true) { int n = source.read(buffer); if (n > 0) { sb.append(buffer, 0, n); } else { break; } } return compileQuery(sb.toString()); } /** * Prepare an XQuery query for subsequent evaluation. The Query is supplied * in the form of a InputStream, with an optional encoding. If the encoding is not specified, * the query parser attempts to obtain the encoding by inspecting the input stream: it looks specifically * for a byte order mark, and for the encoding option in the version declaration of an XQuery prolog. * The encoding defaults to UTF-8. * The base URI of the query is taken from the static context, * and defaults to the current working directory. * * @param source An InputStream giving access to the text of the XQuery query to be compiled, as a stream * of octets * @param encoding The encoding used to translate characters to octets in the query source. The parameter * may be null: in this case the query parser attempts to infer the encoding by inspecting the source, * and if that fails, it assumes UTF-8 encoding * @return an XPathExpression object representing the prepared expression. * @throws net.sf.saxon.trans.XPathException * if the syntax of the expression is wrong, or if it references namespaces, * variables, or functions that have not been declared, or any other static error is reported. * @throws java.io.IOException if a failure occurs reading the supplied input. * @since 8.5 */ public XQueryExpression compileQuery(InputStream source, String encoding) throws XPathException, IOException { String query = QueryReader.readInputStream(source, encoding, config.getNameChecker()); return compileQuery(query); } /** * Declare a namespace whose prefix can be used in expressions. This is * equivalent to declaring a prefix in the Query prolog. * Any namespace declared in the Query prolog overrides a namespace declared using * this API. * * @param prefix The namespace prefix. Must not be null. Setting this to "" means that the * namespace will be used as the default namespace for elements and types. * @param uri The namespace URI. Must not be null. The value "" (zero-length string) is used * to undeclare a namespace; it is not an error if there is no existing binding for * the namespace prefix. * @throws NullPointerException if either the prefix or URI is null * @throws IllegalArgumentException if the prefix is "xml" and the namespace is not the XML namespace, or vice * versa. * @since 9.0 */ public void declareNamespace(String prefix, String uri) { if (prefix == null) { throw new NullPointerException("Null prefix supplied to declareNamespace()"); } if (uri == null) { throw new NullPointerException("Null namespace URI supplied to declareNamespace()"); } if ((prefix.equals("xml") != uri.equals(NamespaceConstant.XML))) { throw new IllegalArgumentException("Misdeclaration of XML namespace"); } if (prefix.length() == 0) { defaultElementNamespace = (uri==null ? "" : uri); } if (uri.length() == 0 && prefix.length() != 0) { userDeclaredNamespaces.remove(prefix); } else { userDeclaredNamespaces.put(prefix, uri); namePool.allocateNamespaceCode(prefix, uri); } } /** * Declare a namespace whose prefix can be used in expressions. This is * equivalent to declaring a prefix in the Query prolog. The term "passive" * was a term from a draft XQuery proposal indicating a namespace that won't * be copied into the result tree. Passive namespaces are never undeclared. * Any namespace declared in the Query prolog overrides a namespace declared using * this API. * * @param prefix The namespace prefix. Must not be null. * @param uri The namespace URI. Must not be null. The value "" (zero-length string) is used * to undeclare a namespace; it is not an error if there is no existing binding for * the namespace prefix. * @param explicit Must be false (the value true was previously reserved for internal use, but is * no longer permitted) * @since 8.4 * @deprecated since 9.0. Use {@link #declareNamespace} */ public void declarePassiveNamespace(String prefix, String uri, boolean explicit) throws XPathException { if (explicit) { throw new IllegalArgumentException("explicit must be false"); } declareNamespace(prefix, uri); } /** * Clear all the user-declared namespaces * * @since 9.0 */ public void clearNamespaces() { userDeclaredNamespaces.clear(); declareNamespace("xml", NamespaceConstant.XML); declareNamespace("xs", NamespaceConstant.SCHEMA); declareNamespace("xsi", NamespaceConstant.SCHEMA_INSTANCE); declareNamespace("fn", NamespaceConstant.FN); declareNamespace("local", NamespaceConstant.LOCAL); declareNamespace("saxon", NamespaceConstant.SAXON); declareNamespace("", ""); } /** * Get the map of user-declared namespaces * @return the user-declared namespaces */ protected HashMap getUserDeclaredNamespaces() { return userDeclaredNamespaces; } /** * Clear all the declared passive namespaces, except for the standard ones (xml, saxon, etc) * * @since 8.4 * @deprecated since 9.0 - use {@link #clearNamespaces} */ public void clearPassiveNamespaces() { clearNamespaces(); } /** * Get the namespace prefixes that have been declared using the method {@link #declareNamespace} * @return an iterator that returns the namespace prefixes that have been explicitly declared, as * strings. The default namespace for elements and types will be included, using the prefix "". * @since 9.0 */ public Iterator iterateDeclaredPrefixes() { return userDeclaredNamespaces.keySet().iterator(); } /** * Get the namespace URI for a given prefix, which must have been declared using the method * {@link #declareNamespace}. Note that this method will not call the external namespace resolver * to resolve the prefix. * @param prefix the namespace prefix, or "" to represent the null prefix * @return the namespace URI. Returns "" to represent the non-namespace, * null to indicate that the prefix has not been declared */ public String getNamespaceForPrefix(String prefix) { return (String)userDeclaredNamespaces.get(prefix); } /** * Set an external namespace resolver. If a namespace prefix cannot be resolved using any * other mechanism, then as a last resort the external namespace resolver is called to * obtain a URI for the given prefix. * *

    Changed in Saxon 9.0 so that the namespaces resolved by the external namespace resolver * are available at run-time, just like namespaces declared in the query prolog. In consequence, * the supplied NamespaceResolver must now implement the * {@link net.sf.saxon.om.NamespaceResolver#iteratePrefixes()} method.

    * * @param resolver the external namespace resolver */ public void setExternalNamespaceResolver(NamespaceResolver resolver) { externalNamespaceResolver = resolver; } /** * Get the external namespace resolver that has been registered using * setExternalNamespaceResolver(), if any. * @return the external namespace resolver */ public NamespaceResolver getExternalNamespaceResolver() { return externalNamespaceResolver; } /** * Get the default function namespace * * @return the default function namespace (defaults to the fn: namespace) * @since 8.4 */ public String getDefaultFunctionNamespace() { return defaultFunctionNamespace; } /** * Set the default function namespace * * @param defaultFunctionNamespace The namespace to be used for unprefixed function calls * @since 8.4 */ public void setDefaultFunctionNamespace(String defaultFunctionNamespace) { this.defaultFunctionNamespace = defaultFunctionNamespace; } /** * Set the default element namespace * @param uri the namespace URI to be used as the default namespace for elements and types * @since 8.4 */ public void setDefaultElementNamespace(String uri) { defaultElementNamespace = uri; declareNamespace("", uri); } /** * Get the default namespace for elements and types * @return the namespace URI to be used as the default namespace for elements and types * @since 8.9 Modified in 8.9 to return the namespace URI as a string rather than an integer code */ public String getDefaultElementNamespace() { return defaultElementNamespace; } /** * Declare a global variable. This has the same effect as including a global variable declaration * in the Query Prolog of the main query module. A static error occurs when compiling the query if the * query prolog contains a declaration of the same variable. * @param qName the qualified name of the variable * @param type the declared type of the variable * @param value the initial value of the variable. May be null if the variable is external. * @param external true if the variable is external, that is, if its value may be set at run-time. * @throws NullPointerException if the value is null, unless the variable is external * @throws XPathException if the value of the variable is not consistent with its type. * @since 9.1 */ public void declareGlobalVariable( StructuredQName qName, SequenceType type, ValueRepresentation value, boolean external) throws XPathException { if (value == null && !external) { throw new NullPointerException("No initial value for declared variable"); } Value val = Value.asValue(value); if (!type.matches(val, getConfiguration())) { throw new XPathException("Value of declared variable does not match its type"); } GlobalVariableDefinition var = new GlobalVariableDefinition(); var.setVariableQName(qName); var.setRequiredType(type); var.setValueExpression(Literal.makeLiteral(val)); var.setIsParameter(external); if (userDeclaredVariables == null) { userDeclaredVariables = new HashSet(); } userDeclaredVariables.add(var); } /** * Iterate over all the declared global variables * @return an iterator over all the global variables that have been declared. They are returned * as instances of class {@link GlobalVariableDefinition} * @since 9.1 */ public Iterator iterateDeclaredGlobalVariables() { if (userDeclaredVariables == null) { return Collections.EMPTY_LIST.iterator(); } else { return userDeclaredVariables.iterator(); } } /** * Clear all declared global variables * @since 9.1 */ public void clearDeclaredGlobalVariables() { userDeclaredVariables = null; } /** * Set a user-defined ModuleURIResolver for resolving URIs used in "import module" * declarations in the XQuery prolog. * This will be used for resolving URIs in XQuery "import module" declarations, overriding * any ModuleURIResolver that was specified as part of the configuration. * @param resolver the ModuleURIResolver to be used */ public void setModuleURIResolver(ModuleURIResolver resolver) { moduleURIResolver = resolver; } /** * Get the user-defined ModuleURIResolver for resolving URIs used in "import module" * declarations in the XQuery prolog; returns null if none has been explicitly set either * on the StaticQueryContext or on the Configuration. * @return the registered ModuleURIResolver */ public ModuleURIResolver getModuleURIResolver() { return moduleURIResolver; } /** * Declare a named collation. Collations are only available in a query if this method * has been called externally to declare the collation and associate it with an * implementation, in the form of a Java Comparator. The default collation is the * Unicode codepoint collation, unless otherwise specified. * * @param name The name of the collation (technically, a URI) * @param comparator The Java Comparator used to implement the collating sequence * @since 8.4. */ public void declareCollation(String name, Comparator comparator) { declareCollation(name, new NamedCollation(name, comparator)); } /** * Declare a named collation. Collations are only available in a query if this method * has been called externally to declare the collation and associate it with an * implementation, in the form of a Java StringCollator. The default collation is the * Unicode codepoint collation, unless otherwise specified. * * @param name The name of the collation (technically, a URI) * @param comparator The Java Comparator used to implement the collating sequence * @since 8.9. */ public void declareCollation(String name, StringCollator comparator) { collations.setNamedCollation(name, comparator); } /** * Set the default collation. * @param name The collation name, as specified in the query prolog. The name * is not validated until it is used. * @since 8.4. Changed in 8.6 so it no longer validates the collation name: this is * because the base URI is not necessarily known at the point where the default * collation is declared. */ public void declareDefaultCollation(String name) { collations.setDefaultCollationName(name); } /** * Get a named collation. * @param name the name of the collation, as an absolute URI * @return the collation identified by the given name, as set previously using declareCollation. * If no collation with this name has been declared, the method calls the CollationURIResolver * to locate a collation with this name. * Return null if no collation with this name is found. * @since 8.4 */ public StringCollator getCollation(String name) { return collations.getNamedCollation(name); } /** * Get the collation map * @return the collation map, which identifies all the known collations */ public CollationMap getCollationMap() { return collations; } /** * Get the name of the default collation. * * @return the name of the default collation; or the name of the codepoint collation * if no default collation has been defined. The name is returned in the form * it was specified; that is, it is not yet resolved against the base URI. (This * is because the base URI declaration can follow the default collation declaration * in the query prolog.) If no default collation has been specified, the "default default" * (that is, the Unicode codepoint collation) is returned. * @since 8.4 */ public String getDefaultCollationName() { return collations.getDefaultCollationName(); } /** * Get a HashMap that maps all registered collations to Comparators. * Note that this returns a snapshot copy of the data held by the static context. * This method is provided for internal use by the query processor. *

    * This method is intended for internal use. * @return the CollationMap containing all the collations defined in this static context */ public CollationMap getAllCollations() { return new CollationMap(collations); } /** * Declare the static type of the context item. If this type is declared, and if a context item * is supplied when the query is invoked, then the context item must conform to this type (no * type conversion will take place to force it into this type). * @param type the required type of the context item */ public void setRequiredContextItemType(ItemType type) { requiredContextItemType = type; } /** * Get the required type of the context item. If no type has been explicitly declared for the context * item, an instance of AnyItemType (representing the type item()) is returned. * @return the required type of the context item */ public ItemType getRequiredContextItemType() { return requiredContextItemType; } /** * Get the NamePool used for compiling expressions * @return the name pool * @since 8.4 */ public NamePool getNamePool() { return namePool; } /** * Get the system ID of the container of the expression. Used to construct error messages. * Note that the systemID and the Base URI are currently identical, but they might be distinguished * in the future. * * @return the Base URI * @since 8.4 */ public String getSystemId() { return baseURI; } /** * Get the Base URI of the query, for resolving any relative URI's used * in the expression. * Note that the systemID and the Base URI are currently identical, but they might be distinguished * in the future. * Used by the document() function. * * @return the base URI of the query * @since 8.4 */ public String getBaseURI() { return baseURI; } /** * Set the policy for preserving boundary space * @param preserve true if boundary space is to be preserved, false if it is to be stripped * @since 9.0 */ public void setPreserveBoundarySpace(boolean preserve) { preserveSpace = preserve; } /** * Ask whether the policy for boundary space is "preserve" or "strip" * @return true if the policy is to preserve boundary space, false if it is to strip it * @since 9.0 */ public boolean isPreserveBoundarySpace() { return preserveSpace; } /** * Set the option for where an empty sequence appears in the collation order, if not otherwise * specified in the "order by" clause * @param least true if the empty sequence is considered less than any other value (the default), * false if it is considered greater than any other value * @since 9.0 */ public void setEmptyLeast(boolean least) { defaultEmptyLeast = least; } /** * Ask what is the option for where an empty sequence appears in the collation order, if not otherwise * specified in the "order by" clause * @return true if the empty sequence is considered less than any other value (the default), * false if it is considered greater than any other value * @since 9.0 */ public boolean isEmptyLeast() { return defaultEmptyLeast; } /** * Set the ErrorListener to be used to report compile-time errors in a query. This will also * be the default for the run-time error listener used to report dynamic errors * @param listener the ErrorListener to be used */ public void setErrorListener(ErrorListener listener) { errorListener = listener; } /** * Get the ErrorListener in use for this static context * @return the registered ErrorListener */ public ErrorListener getErrorListener() { if (errorListener == null) { errorListener = config.getErrorListener(); } return errorListener; } /** * Say whether the query is allowed to be updating. XQuery update syntax will be rejected * during query compilation unless this flag is set. * @param updating true if the query is allowed to use the XQuery Update facility * (requires Saxon-SA). If set to false, the query must not be an updating query. If set * to true, it may be either an updating or a non-updating query. * @since 9.1 */ public void setUpdatingEnabled(boolean updating) { isUpdating = updating; } /** * Ask whether the query is allowed to be updating * @return true if the query is allowed to use the XQuery Update facility. Note that this * does not necessarily mean that the query is an updating query; but if the value is false, * the it must definitely be non-updating. * @since 9.1 */ public boolean isUpdatingEnabled() { return isUpdating; } // public static void main(String[] args) throws Exception { // StaticQueryContext c = new StaticQueryContext(new Configuration()); // c.declareGlobalVariable( // new StructuredQName("", "", "ping"), // SequenceType.SINGLE_STRING, // new StringValue("pong"), // true // ); // XQueryExpression exp = c.compileQuery("$ping"); // DynamicQueryContext env = new DynamicQueryContext(c.getConfiguration()); // //env.setParameterValue("ping", new StringValue("pang")); // exp.run(env, new StreamResult(System.out), null); // // } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/query/GlobalVariableDefinition.java0000644000175000017500000002724511033112257024300 0ustar eugeneeugenepackage net.sf.saxon.query; import net.sf.saxon.Configuration; import net.sf.saxon.expr.*; import net.sf.saxon.instruct.Executable; import net.sf.saxon.instruct.GlobalParam; import net.sf.saxon.instruct.GlobalVariable; import net.sf.saxon.instruct.SlotManager; import net.sf.saxon.om.StructuredQName; import net.sf.saxon.trace.ExpressionPresenter; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.TypeHierarchy; import net.sf.saxon.type.AnyItemType; import net.sf.saxon.value.SequenceType; import net.sf.saxon.value.Value; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /** * Class to hold compile-time information about an XQuery global variable * or parameter */ public class GlobalVariableDefinition implements VariableDeclaration, Declaration { protected List references = new ArrayList(10); // Note that variableReferences on this list might be dormant; // that is, they might be disconnected from the live expression tree. private SequenceType requiredType; private Expression value; private boolean isParameter; private StructuredQName variableName; private String systemId; // identifies the module where the variable declaration occurred private int lineNumber; // identifies the line number of the variable declaration private GlobalVariable compiledVar; /** * Set the required type of the variable * @param type the declared type, from the "as" clause if present */ public void setRequiredType(SequenceType type) { requiredType = type; } /** * Get the required type of the variable * @return the declared type, from the "as" clause if present */ public SequenceType getRequiredType() { return requiredType; } /** * Set the variable name * @param qName the variable name */ public void setVariableQName(StructuredQName qName) { variableName = qName; } /** * Get the variable name * @return the variable name */ public StructuredQName getVariableQName() { return variableName; } /** * Set the line number where the variable declaration appears in the source * @param lineNumber the line number */ public void setLineNumber(int lineNumber) { this.lineNumber = lineNumber; } /** * Get the line number where the declaration appears */ public int getLineNumber() { return lineNumber; } /** * Get column number * @return -1 always */ public int getColumnNumber() { return -1; } /** * Get public identifier * @return null always */ public String getPublicId() { return null; } /** * Set the system ID of the module where the variable declaration appears * @param systemId the System ID (base URI) */ public void setSystemId(String systemId) { this.systemId = systemId; } /** * Get the system ID of the module containing the variable declaration * @return the System ID (base URI) */ public String getSystemId() { return systemId; } /** * Set the expression used to define the value of the variable * @param val the initializing expression */ public void setValueExpression(Expression val) { value = val; } /** * Indicate whether this global variable is a "parameter" (an external variable, in XQuery terminology) * @param b true if this variable is external */ public void setIsParameter(boolean b) { isParameter = b; } /** * Register a variable reference that refers to this global variable * @param ref the variable reference */ public void registerReference(BindingReference ref) { references.add(ref); } /** * Iterate over the references to this variable * @return an iterator over the references: returns objects of class {@link VariableReference} */ public Iterator iterateReferences() { return references.iterator(); } /** * Create a compiled representation of this global variable * @param exec the executable * @param slot the slot number allocated to this variable * @return the compiled representation * @throws XPathException if compile-time errors are found. */ public GlobalVariable compile(Executable exec, int slot) throws XPathException { TypeHierarchy th = exec.getConfiguration().getTypeHierarchy(); GlobalVariable var; if (isParameter) { var = new GlobalParam(); var.setExecutable(exec); var.setRequiredParam(value==null); } else { var = new GlobalVariable(); var.setExecutable(exec); } var.setHostLanguage(Configuration.XQUERY); var.setSelectExpression(value); var.setRequiredType(requiredType); var.setVariableQName(variableName); var.setSlotNumber(slot); int loc = exec.getLocationMap().allocateLocationId(systemId, lineNumber); var.setLocationId(loc); var.setContainer(var); Iterator iter = references.iterator(); while (iter.hasNext()) { BindingReference binding = (BindingReference)iter.next(); fixupReference(binding, th); //binding.setStaticType(requiredType, null, 0); binding.fixup(var); } exec.registerGlobalVariable(var); // int referenceCount = RangeVariable.getReferenceCount(references, true); // if (referenceCount < 10) { // // allow for the fact that the references may be in functions that are executed repeatedly // referenceCount = 10; // } // var.setReferenceCount(referenceCount); var.setReferenceCount(10); // TODO: temporary! compiledVar = var; return var; } /** * Notify a reference to this variable of the data type * @param ref the variable reference * @param th the type hierarchy cache */ public void fixupReference(BindingReference ref, TypeHierarchy th) throws XPathException { final SequenceType type = getRequiredType(); Value constantValue = null; int properties = 0; Expression select = value; if (select instanceof Literal && !isParameter) { // we can't rely on the constant value because it hasn't yet been type-checked, // which could change it (eg by numeric promotion). Rather than attempt all the type-checking // now, we do a quick check. See test bug64 int relation = th.relationship(select.getItemType(th), type.getPrimaryType()); if (relation == TypeHierarchy.SAME_TYPE || relation == TypeHierarchy.SUBSUMED_BY) { constantValue = ((Literal)select).getValue(); } } if (select != null) { properties = select.getSpecialProperties(); } ref.setStaticType(type, constantValue, properties); } /** * Type check the compiled representation of this global variable * @param visitor an expression visitor * @throws XPathException if compile-time errors are found. */ // TODO: watch bug 5224: is the context item defined for use in the body expression? public void typeCheck(ExpressionVisitor visitor) throws XPathException { GlobalVariable var = getCompiledVariable(); Expression value = var.getSelectExpression(); if (value != null) { value.checkForUpdatingSubexpressions(); if (value.isUpdatingExpression()) { throw new XPathException( "Initializing expression for global variable must not be an updating expression", "XUST0001"); } value.setContainer(var); RoleLocator role = new RoleLocator( RoleLocator.VARIABLE, var.getVariableQName(), 0); Expression value2 = TypeChecker.strictTypeCheck( visitor.typeCheck(visitor.simplify(value), AnyItemType.getInstance()), var.getRequiredType(), role, visitor.getStaticContext()); value2 = value2.optimize(visitor, AnyItemType.getInstance()); var.setSelectExpression(value2); value2.setContainer(var); // the value expression may declare local variables SlotManager map = visitor.getConfiguration().makeSlotManager(); int slots = ExpressionTool.allocateSlots(value2, 0, map); if (slots > 0) { var.setContainsLocals(map); } if (var.getRequiredType() == SequenceType.ANY_SEQUENCE && !(var instanceof GlobalParam)) { // no type was declared; try to deduce a type from the value try { final TypeHierarchy th = visitor.getConfiguration().getTypeHierarchy(); final ItemType itemType = value.getItemType(th); final int cardinality = value.getCardinality(); var.setRequiredType(SequenceType.makeSequenceType(itemType, cardinality)); Value constantValue = null; if (value2 instanceof Literal) { constantValue = ((Literal)value2).getValue(); } for (Iterator iter = references.iterator(); iter.hasNext(); ) { BindingReference ref = ((BindingReference)iter.next()); if (ref instanceof VariableReference) { ((VariableReference)ref).refineVariableType( itemType, cardinality, constantValue, value.getSpecialProperties(), visitor); } } } catch (Exception err) { // exceptions can happen because references to variables and functions are still unbound } } } } /** * Get the compiled variable if the definition has been compiled * @return the compiled global variable */ public GlobalVariable getCompiledVariable() { return compiledVar; } /** * Produce diagnostic output showing the compiled and optimized expression tree for a function * @param out the destination to be used */ public void explain(ExpressionPresenter out) { out.startElement("declareVariable"); out.emitAttribute("name", variableName.getDisplayName()); if (value != null) { value.explain(out); } out.endElement(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none //saxonb-9.1.0.8/bj/net/sf/saxon/query/UndeclaredVariable.java0000644000175000017500000000363611033112257023133 0ustar eugeneeugenepackage net.sf.saxon.query; import net.sf.saxon.expr.BindingReference; import net.sf.saxon.expr.VariableDeclaration; import net.sf.saxon.instruct.GlobalVariable; import net.sf.saxon.instruct.Executable; import net.sf.saxon.trans.XPathException; import java.util.Collections; import java.util.Iterator; /** * An UndeclaredVariable object is created when a reference is encountered to a variable * that has not yet been declared. This can happen as a result of recursive module imports. * These references are resolved at the end of query parsing. */ public class UndeclaredVariable extends GlobalVariableDefinition { public UndeclaredVariable(){} public void transferReferences(VariableDeclaration var) { Iterator iter = references.iterator(); while (iter.hasNext()) { BindingReference ref = (BindingReference)iter.next(); var.registerReference(ref); } references = Collections.EMPTY_LIST; } public GlobalVariable compile(Executable exec, int slot) throws XPathException { throw new UnsupportedOperationException("Attempt to compile a place-holder for an undeclared variable"); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none // saxonb-9.1.0.8/bj/net/sf/saxon/query/XQueryFunctionLibrary.java0000644000175000017500000002717211033112257023710 0ustar eugeneeugenepackage net.sf.saxon.query; import net.sf.saxon.Configuration; import net.sf.saxon.expr.Expression; import net.sf.saxon.expr.ExpressionVisitor; import net.sf.saxon.expr.UserFunctionCall; import net.sf.saxon.expr.StaticContext; import net.sf.saxon.functions.FunctionLibrary; import net.sf.saxon.instruct.UserFunction; import net.sf.saxon.om.StructuredQName; import net.sf.saxon.trace.ExpressionPresenter; import net.sf.saxon.trans.XPathException; import java.util.HashMap; import java.util.Iterator; /** * An XQueryFunctionLibrary is a function library containing all the user-defined functions available for use within a * particular XQuery module: that is, the functions declared in that module, and the functions imported from other * modules. It also contains (transiently during compilation) a list of function calls within the module that have not * yet been bound to a specific function declaration. */ public class XQueryFunctionLibrary implements FunctionLibrary, XQueryFunctionBinder { private Configuration config; // The functions in this library are represented using a HashMap // The key of the hashmap is a Long whose two halves hold (a) the fingerprint, and (b) the arity // The value in the hashmap is an XQueryFunction private HashMap functions = new HashMap(20); /** * Create an XQueryFunctionLibrary * @param config the Saxon configuration */ public XQueryFunctionLibrary(Configuration config) { this.config = config; } /** * Set the Configuration options * @param config the Saxon configuration */ public void setConfiguration(Configuration config) { this.config = config; } /** * Get the Configuration options * @return the Saxon configuration */ public Configuration getConfiguration() { return config; } /** * Register a user-defined XQuery function * @param function the function to be registered * @throws XPathException if there is an existing function with the same name and arity */ public void declareFunction(XQueryFunction function) throws XPathException { String keyObj = function.getIdentificationKey(); XQueryFunction existing = (XQueryFunction)functions.get(keyObj); if (existing != null) { XPathException err = new XPathException("Duplicate definition of function " + function.getDisplayName() + " (see line " + existing.getLineNumber() + " in " + existing.getSystemId() + ')'); err.setErrorCode("XQST0034"); err.setIsStaticError(true); err.setLocator(function); throw err; } functions.put(keyObj, function); } /** * Test whether a function with a given name and arity is available. This supports * the function-available() function in XSLT. This method may be called either at compile time * or at run time. * @param functionName the QName identifying the function * @param arity The number of arguments. This is set to -1 in the case of the single-argument * function-available() function; in this case the method should return true if there is some */ public boolean isAvailable(StructuredQName functionName, int arity) { if (arity == -1) { // we'll just test arity 0..20. Since this method is supporting an XSLT-only interrogative // on an XQuery function library, the outcome isn't too important. for (int i=0; i<20; i++) { if (isAvailable(functionName, i)) { return true; } } return false; } return (functions.get(XQueryFunction.getIdentificationKey(functionName, arity)) != null); } /** * Identify a (namespace-prefixed) function appearing in the expression. This * method is called by the XQuery parser to resolve function calls found within * the query. *

    Note that a function call may appear earlier in the query than the definition * of the function to which it is bound. Unlike XSLT, we cannot search forwards to * find the function definition. Binding of function calls is therefore a two-stage * process; at the time the function call is parsed, we simply register it as * pending; subsequently at the end of query parsing all the pending function * calls are resolved. Another consequence of this is that we cannot tell at the time * a function call is parsed whether it is a call to an internal (XSLT or XQuery) * function or to an extension function written in Java. * @return an Expression representing the function call. This will normally be * a FunctionCall, but it may be rewritten as some other expression. * @throws XPathException if the function call is invalid, either because it is * an unprefixed call to a non-system function, or because it is calling a system * function that is available in XSLT only. A prefixed function call that cannot * be recognized at this stage is assumed to be a forwards reference, and is bound * later when bindUnboundFunctionCalls() is called. */ public Expression bind(StructuredQName functionName, Expression[] arguments, StaticContext env) throws XPathException { String functionKey = XQueryFunction.getIdentificationKey( functionName, arguments.length); XQueryFunction fd = (XQueryFunction)functions.get(functionKey); if (fd != null) { UserFunctionCall ufc = new UserFunctionCall(); ufc.setFunctionName(fd.getFunctionName()); ufc.setArguments(arguments); ufc.setStaticType(fd.getResultType()); UserFunction fn = fd.getUserFunction(); if (fn == null) { // not yet compiled fd.registerReference(ufc); ufc.setConfirmed(true); } else { ufc.setFunction(fn); ExpressionVisitor visitor = ExpressionVisitor.make(fd.getStaticContext()); visitor.setExecutable(fd.getExecutable()); ufc.checkFunctionCall(fn, visitor); } return ufc; } else { return null; } } /** * Get the function declaration corresponding to a given function name and arity * @return the XQueryFunction if there is one, or null if not. */ public XQueryFunction getDeclaration(StructuredQName functionName, Expression[] staticArgs) { String functionKey = XQueryFunction.getIdentificationKey( functionName, staticArgs.length); return (XQueryFunction)functions.get(functionKey); } /** * Get the function declaration corresponding to a given function name and arity, supplied * in the form "{uri}local/arity" * @param functionKey a string in the form "{uri}local/arity" identifying the required function * @return the XQueryFunction if there is one, or null if not. */ public XQueryFunction getDeclarationByKey(String functionKey) { return (XQueryFunction)functions.get(functionKey); } /** * Get an iterator over the Functions defined in this module * @return an Iterator, whose items are {@link XQueryFunction} objects. It returns * all function known to this module including those imported from elsewhere; they * can be distinguished by their namespace. */ public Iterator getFunctionDefinitions() { return functions.values().iterator(); } /** * Fixup all references to global functions. This method is called * on completion of query parsing. Each XQueryFunction is required to * bind all references to that function to the object representing the run-time * executable code of the function. *

    * This method is for internal use. * @param env the static context for the main query body. */ protected void fixupGlobalFunctions(QueryModule env) throws XPathException { ExpressionVisitor visitor = ExpressionVisitor.make(env); Iterator iter = functions.values().iterator(); while (iter.hasNext()) { XQueryFunction fn = (XQueryFunction)iter.next(); fn.compile(); } iter = functions.values().iterator(); while (iter.hasNext()) { XQueryFunction fn = (XQueryFunction)iter.next(); visitor.setExecutable(fn.getExecutable()); fn.checkReferences(visitor); } } /** * Optimize the body of all global functions. This may involve inlining functions calls */ protected void optimizeGlobalFunctions() throws XPathException { Iterator iter = functions.values().iterator(); while (iter.hasNext()) { XQueryFunction fn = (XQueryFunction)iter.next(); fn.optimize(); } } /** * Output "explain" information about each declared function * @param out the ExpressionPresenter that renders the output */ public void explainGlobalFunctions(ExpressionPresenter out) { Iterator iter = functions.values().iterator(); while (iter.hasNext()) { XQueryFunction fn = (XQueryFunction)iter.next(); fn.explain(out); } } /** * Get the function with a given name and arity. This method is provided so that XQuery functions * can be called directly from a Java application. Note that there is no type checking or conversion * of arguments when this is done: the arguments must be provided in exactly the form that the function * signature declares them. * @param uri the uri of the function name * @param localName the local part of the function name * @param arity the number of arguments. * @return the function identified by the URI, local name, and arity; or null if there is no such function */ public UserFunction getUserDefinedFunction(String uri, String localName, int arity) { String functionKey = XQueryFunction.getIdentificationKey(uri, localName, arity); XQueryFunction fd = (XQueryFunction)functions.get(functionKey); if (fd==null) { return null; } return fd.getUserFunction(); } /** * This method creates a copy of a FunctionLibrary: if the original FunctionLibrary allows * new functions to be added, then additions to this copy will not affect the original, or * vice versa. * * @return a copy of this function library. This must be an instance of the original class. */ public FunctionLibrary copy() { XQueryFunctionLibrary qfl = new XQueryFunctionLibrary(config); qfl.functions = new HashMap(functions); return qfl; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/query/DynamicQueryContext.java0000644000175000017500000002767011033112257023402 0ustar eugeneeugenepackage net.sf.saxon.query; import net.sf.saxon.Configuration; import net.sf.saxon.StandardErrorListener; import net.sf.saxon.trace.TraceListener; import net.sf.saxon.functions.Component; import net.sf.saxon.om.Item; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.om.ValueRepresentation; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.DateTimeValue; import javax.xml.transform.ErrorListener; import javax.xml.transform.URIResolver; import java.util.HashMap; import java.io.PrintStream; /** * This object represents a dynamic context for query execution. This class is used * by the application writer to set up aspects of the dynamic context; it is not used * operationally (or modified) by the XQuery processor itself, which copies all required * information into its own internal representation. */ public class DynamicQueryContext { private Item contextItem; private HashMap parameters; private Configuration config; private URIResolver uriResolver; private ErrorListener errorListener; private TraceListener traceListener; private DateTimeValue currentDateTime; private PrintStream traceFunctionDestination = System.err; /** * Create the dynamic context for a query * @param config the Saxon configuration * @since 8.4. */ public DynamicQueryContext(Configuration config) { this.config = config; uriResolver = config.getURIResolver(); errorListener = config.getErrorListener(); try { traceListener = config.makeTraceListener(); } catch (XPathException err) { throw new IllegalStateException(err.getMessage()); } if (errorListener instanceof StandardErrorListener) { errorListener = ((StandardErrorListener)errorListener).makeAnother(Configuration.XQUERY); ((StandardErrorListener)errorListener).setRecoveryPolicy(Configuration.DO_NOT_RECOVER); } } /** * Set the context item for evaluating the expression to be a node. If this method is not called, * the context node will be undefined. The context node is available as the value of * the expression ".". * To obtain a NodeInfo by parsing a source document, see the method * {@link net.sf.saxon.Configuration#buildDocument buildDocument} * in class QueryProcessor. * * @param node The node that is to be the context node for the query * @since 8.4 * @deprecated From Saxon 8.7, the method {@link #setContextItem(Item)} is preferred */ public void setContextNode(NodeInfo node) { if (node==null) { throw new NullPointerException("Context node cannot be null"); } setContextItem(node); } /** * Set the context item for evaluating the expression. If this method is not called, * the context node will be undefined. The context item is available as the value of * the expression ".",. * To obtain a node by parsing a source document, see the method * {@link net.sf.saxon.Configuration#buildDocument buildDocument} * in class QueryProcessor. * @param item The item that is to be the context item for the query * @throws IllegalArgumentException if the supplied item is a node that was built under the wrong * Saxon Configuration * @since 8.4 */ public void setContextItem(Item item) { if (item==null) { throw new NullPointerException("Context item cannot be null"); } if (item instanceof NodeInfo) { if (!((NodeInfo)item).getConfiguration().isCompatible(config)) { throw new IllegalArgumentException( "Supplied node must be built using the same or a compatible Configuration"); } } contextItem = item; } /** * Get the context item for the query, as set using setContextItem() or setContextNode(). * @return the context item if set, or null otherwise. * @since 8.4 */ public Item getContextItem() { return contextItem; } /** * Set a parameter for the query. * * @param expandedName The name of the parameter in "{uri}local-name" format. * It is not an error to supply a value for a parameter that has not been * declared, the parameter will simply be ignored. If the parameter has * been declared in the query (as an external global variable) then it * will be initialized with the value supplied. * @param value The value of the parameter. This can be any valid Java * object. It follows the same conversion rules as a value returned * from a Saxon extension function. An error will occur at query * execution time if the supplied value cannot be converted to the required * type as declared in the query. For precise control of the type of the * value, instantiate one of the classes in the net.sf.saxon.value package, * for example net.sf.saxon.value.DayTimeDuration. * @since 8.4 */ public void setParameter(String expandedName, Object value) { if (parameters==null) { parameters = new HashMap(10); } parameters.put(expandedName, value); } /** * Set a parameter for the query. * * @param expandedName The name of the parameter in "{uri}local-name" format. * It is not an error to supply a value for a parameter that has not been * declared, the parameter will simply be ignored. If the parameter has * been declared in the query (as an external global variable) then it * will be initialized with the value supplied. * @param value The value of the parameter. This must be an XPath value in its Saxon * representation: no conversion occurs. * @since 8.8 */ public void setParameterValue(String expandedName, ValueRepresentation value) { if (parameters==null) { parameters = new HashMap(10); } parameters.put(expandedName, value); } /** * Reset the parameters to an empty list. */ public void clearParameters() { parameters = null; } /** * Get the actual value of a parameter to the query. * * @param expandedName the name of the required parameter, in * "{uri}local-name" format * @return the value of the parameter, if it exists, or null otherwise */ public Object getParameter(String expandedName) { if (parameters==null) return null; return parameters.get(expandedName); } /** * Get all the supplied parameters as a HashMap. The key is the expanded QName in Clark notation, * the value is the value as supplied to setParameterValue * @return a HashMap containing all the parameters */ public HashMap getParameters() { if (parameters == null) { return new HashMap(4); } return parameters; } /** * Set an object that will be used to resolve URIs used in * fn:document() and related functions. * * @param resolver An object that implements the URIResolver interface, or * null. * @since 8.4 */ public void setURIResolver(URIResolver resolver) { // System.err.println("Setting uriresolver to " + resolver + " on " + this); uriResolver = resolver; } /** * Get the URI resolver. * * @return the user-supplied URI resolver if there is one, or the * system-defined one otherwise * @since 8.4 */ public URIResolver getURIResolver() { return uriResolver; } /** * Set the error listener. The error listener receives reports of all run-time * errors and can decide how to report them. * * @param listener the ErrorListener to be used * @since 8.4 */ public void setErrorListener(ErrorListener listener) { errorListener = listener; } /** * Get the error listener. * * @return the ErrorListener in use * @since 8.4 */ public ErrorListener getErrorListener() { return errorListener; } /** * Set the trace listener. The trace listener receives reports of all run-time * expression evaluation. * * @param listener the TraceListener to be used * @since 9.0 */ public void setTraceListener(TraceListener listener) { traceListener = listener; } /** * Get the trace listener. * * @return the TraceListener in use, or null if none is in use * @since 9.0 */ public TraceListener getTraceListener() { return traceListener; } /** * Set the destination for output from the fn:trace() function. * By default, the destination is System.err. If a TraceListener is in use, * this is ignored, and the trace() output is sent to the TraceListener. * @param stream the PrintStream to which trace output will be sent. If set to * null, trace output is suppressed entirely. It is the caller's responsibility * to close the stream after use. * @since 9.1 */ public void setTraceFunctionDestination(PrintStream stream) { traceFunctionDestination = stream; } /** * Get the destination for output from the fn:trace() function. * @return the PrintStream to which trace output will be sent. If no explicitly * destination has been set, returns System.err. If the destination has been set * to null to suppress trace output, returns null. * @since 9.1 */ public PrintStream getTraceFunctionDestination() { return traceFunctionDestination; } /** * Get the date and time set previously using {@link #setCurrentDateTime(net.sf.saxon.value.DateTimeValue)} * or null if none has been set. * @return the current date and time, if it has been set. * @since 8.5 */ public DateTimeValue getCurrentDateTime() { return currentDateTime; } /** * Set a value to be used as the current date and time for the query. By default, the "real" current date and * time are used. The main purpose of this method is that it allows repeatable results to be achieved when * testing queries. *

    This method also has the effect of setting the implicit timezone.

    * @param dateTime The value to be used as the current date and time. This must include a timezone. The timezone * from this value will also be used as the implicit timezone * @since 8.5 */ public void setCurrentDateTime(DateTimeValue dateTime) throws XPathException { currentDateTime = dateTime; if (dateTime.getComponent(Component.TIMEZONE) == null) { throw new XPathException("Supplied date/time must include a timezone"); } } /** * Get the Configuration associated with this dynamic query context * @return the Configuration * @since 8.8 */ public Configuration getConfiguration() { return config; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none //saxonb-9.1.0.8/bj/net/sf/saxon/query/UpdateAgent.java0000644000175000017500000000335011061437247021623 0ustar eugeneeugenepackage net.sf.saxon.query; import net.sf.saxon.Controller; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.trans.XPathException; /** * An UpdateAgent is a callback class that is called to handle a document after it has been updated. * Typically the UpdateAgent might take responsibility for writing the updated document back to * persistent storage. */ public interface UpdateAgent { /** * Handle an updated document. * This method is called by {@link XQueryExpression#runUpdate(DynamicQueryContext, UpdateAgent)} * once for each document (or more generally, for the root of each tree) that has been modified * by the update query. * @param node the root of the tree that has been updated * @param controller the Controller that was used for executing the query * @throws XPathException if the callback code cannot handle the updated document */ public void update(NodeInfo node, Controller controller) throws XPathException; } // // The contents of this file are subject to the Mozilla Public License Version // 1.0 (the "License"); // you may not use this file except in compliance with the License. You may // obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations // under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All // Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/query/QueryParser.java0000644000175000017500000047130611223076765021722 0ustar eugeneeugenepackage net.sf.saxon.query; import net.sf.saxon.Configuration; import net.sf.saxon.trans.Err; import net.sf.saxon.Platform; import net.sf.saxon.charcode.UTF16; import net.sf.saxon.event.PipelineConfiguration; import net.sf.saxon.expr.*; import net.sf.saxon.functions.*; import net.sf.saxon.instruct.*; import net.sf.saxon.om.*; import net.sf.saxon.pattern.NodeTest; import net.sf.saxon.sort.*; import net.sf.saxon.style.AttributeValueTemplate; import net.sf.saxon.sxpath.IndependentContext; import net.sf.saxon.trace.Location; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.*; import net.sf.saxon.value.*; import javax.xml.transform.OutputKeys; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.stream.StreamSource; import java.net.URI; import java.net.URISyntaxException; import java.util.*; import java.util.regex.Pattern; import java.io.IOException; /** * This class defines extensions to the XPath parser to handle the additional * syntax supported in XQuery */ public class QueryParser extends ExpressionParser { private boolean memoFunction = false; private boolean disableCycleChecks = false; private int errorCount = 0; private XPathException firstError = null; protected Executable executable; private boolean foundCopyNamespaces = false; private boolean foundBoundarySpaceDeclaration = false; private boolean foundOrderingDeclaration = false; private boolean foundEmptyOrderingDeclaration = false; private boolean foundDefaultCollation = false; private boolean foundConstructionDeclaration = false; private boolean foundDefaultFunctionNamespace = false; private boolean foundDefaultElementNamespace = false; private boolean foundBaseURIDeclaration = false; private boolean preambleProcessed = false; public Set importedModules = new HashSet(5); List namespacesToBeSealed = new ArrayList(10); List schemaImports = new ArrayList(5); List moduleImports = new ArrayList(5); private Expression defaultValue = null; /** * Constructor for internal use: this class should be instantiated via the QueryModule */ public QueryParser() { } /** * Create an XQueryExpression * @param query the source text of the query * @param staticContext the static context of the query * @param config the Saxon configuration * @return the compiled XQuery expression */ public XQueryExpression makeXQueryExpression(String query, QueryModule staticContext, Configuration config) throws XPathException { try { if (config.getXMLVersion() == Configuration.XML10) { query = normalizeLineEndings10(query); } else { query = normalizeLineEndings11(query); } Executable exec = staticContext.getExecutable(); if (exec == null) { exec = new Executable(config); exec.setHostLanguage(Configuration.XQUERY); staticContext.setExecutable(exec); } Properties outputProps = new Properties(); outputProps.setProperty(OutputKeys.METHOD, "xml"); outputProps.setProperty(OutputKeys.INDENT, "yes"); exec.setDefaultOutputProperties(outputProps); exec.setLocationMap(new LocationMap()); exec.setFunctionLibrary(new ExecutableFunctionLibrary(config)); // this will be changed later setExecutable(exec); Expression exp = parseQuery(query, 0, Token.EOF, staticContext); int loc = env.getLocationMap().allocateLocationId(env.getSystemId(), 1); exp.setContainer(new TemporaryContainer(staticContext.getLocationMap(), loc)); //staticContext.bindUnboundFunctionCalls(); exec.fixupQueryModules(staticContext); // Check for cyclic dependencies among the modules if (!disableCycleChecks) { Iterator miter = exec.getQueryLibraryModules(); while (miter.hasNext()) { QueryModule module = (QueryModule)miter.next(); module.lookForModuleCycles(new Stack(), 1); } } // Make the XQueryexpression object XQueryExpression queryExp = new XQueryExpression(exp, exec, staticContext, config); //exp = queryExp.getExpression(); // Make the function library that's available at run-time (e.g. for saxon:evaluate()). This includes // all user-defined functions regardless of which module they are in FunctionLibrary userlib = exec.getFunctionLibrary(); FunctionLibraryList lib = new FunctionLibraryList(); lib.addFunctionLibrary( SystemFunctionLibrary.getSystemFunctionLibrary(SystemFunctionLibrary.XPATH_ONLY)); lib.addFunctionLibrary(config.getVendorFunctionLibrary()); lib.addFunctionLibrary(new ConstructorFunctionLibrary(config)); if (config.isAllowExternalFunctions()) { Configuration.getPlatform().addFunctionLibraries(lib, config, Configuration.XQUERY); } lib.addFunctionLibrary(userlib); exec.setFunctionLibrary(lib); return queryExp; } catch (XPathException e) { if (!e.hasBeenReported()) { reportError(e); } throw e; } } /** * Normalize line endings in the source query, according to the XML 1.1 rules. * @param in the input query * @return the query with line endings normalized */ private static String normalizeLineEndings11(String in) { if (in.indexOf((char)0xa) < 0 && in.indexOf((char)0x85) < 0 && in.indexOf((char)0x2028) < 0) { return in; } FastStringBuffer sb = new FastStringBuffer(in.length()); for (int i = 0; i < in.length(); i++) { char ch = in.charAt(i); switch (ch) { case 0x85: case 0x2028: sb.append((char)0xa); break; case 0xd: if (i < in.length() - 1 && (in.charAt(i + 1) == (char)0xa || in.charAt(i + 1) == (char)0x85)) { sb.append((char)0xa); i++; } else { sb.append((char)0xa); } break; default: sb.append(ch); } } return sb.toString(); } /** * Normalize line endings in the source query, according to the XML 1.0 rules. * @param in the input query * @return the query text with line endings normalized */ private static String normalizeLineEndings10(String in) { if (in.indexOf((char)0xa) < 0) { return in; } FastStringBuffer sb = new FastStringBuffer(in.length()); for (int i = 0; i < in.length(); i++) { char ch = in.charAt(i); switch (ch) { case 0xd: if (i < in.length() - 1 && in.charAt(i + 1) == (char)0xa) { sb.append((char)0xa); i++; } else { sb.append((char)0xa); } break; default: sb.append(ch); } } return sb.toString(); } /** * Get the executable containing this expression. * @return the executable */ public Executable getExecutable() { return executable; } /** * Set the executable used for this query expression * @param exec the executable */ public void setExecutable(Executable exec) { executable = exec; } /** * Disable checks for certain kinds of cycle. This is equivalent to *

    declare option saxon:allow-cycles "true"

    * @param disable true if checks for import cycles are to be suppressed, that is, * if cycles should be allowed */ public void setDisableCycleChecks(boolean disable) { disableCycleChecks = disable; } /** * Parse a top-level Query. * Prolog? Expression * * @param queryString The text of the query * @param start Offset of the start of the query * @param terminator Token expected to follow the query (usually Token.EOF) * @param env The static context * @return the Expression object that results from parsing * @throws net.sf.saxon.trans.XPathException * if the expression contains a syntax error */ private Expression parseQuery(String queryString, int start, int terminator, QueryModule env) throws XPathException { this.env = env; nameChecker = env.getConfiguration().getNameChecker(); language = XQUERY; t = new Tokenizer(); try { t.tokenize(queryString, start, -1, 1); } catch (XPathException err) { grumble(err.getMessage()); } parseVersionDeclaration(); parseProlog(); processPreamble(); Expression exp = parseExpression(); // Diagnostic code - show the expression before any optimizations // ExpressionPresenter ep = ExpressionPresenter.make(env.getConfiguration()); // exp.explain(ep); // ep.close(); // End of diagnostic code if (t.currentToken != terminator) { grumble("Unexpected token " + currentTokenDisplay() + " beyond end of query"); } setLocation(exp); if (errorCount == 0) { return exp; } else { XPathException err = new XPathException("One or more static errors were reported during query analysis"); err.setHasBeenReported(); err.setErrorCode(firstError.getErrorCodeLocalPart()); // largely for the XQTS test driver throw err; } } /** * Parse a library module. * Prolog? Expression * * @param queryString The text of the library module. * @param env The static context. The result of parsing * a library module is that the static context is populated with a set of function * declarations and variable declarations. Each library module must have its own * static context objext. * @throws XPathException if the expression contains a syntax error */ public final void parseLibraryModule(String queryString, QueryModule env) throws XPathException { this.env = env; nameChecker = env.getConfiguration().getNameChecker(); executable = env.getExecutable(); t = new Tokenizer(); try { t.tokenize(queryString, 0, -1, 1); } catch (XPathException err) { grumble(err.getMessage()); } parseVersionDeclaration(); parseModuleDeclaration(); parseProlog(); processPreamble(); if (t.currentToken != Token.EOF) { grumble("Unrecognized content found after the variable and function declarations in a library module"); } if (errorCount != 0) { XPathException err = new XPathException("Static errors were reported in the imported library module"); err.setErrorCode(firstError.getErrorCodeLocalPart()); throw err; } } /** * Report a static error * * @param message the error message * @throws XPathException always thrown: an exception containing the * supplied message */ protected void grumble(String message, String errorCode) throws XPathException { String s = t.recentText(); ExpressionLocation loc = makeLocator(); String prefix = getLanguage() + ("XPST0003".equals(errorCode) ? " syntax error " : " static error ") + (message.startsWith("...") ? "near" : "in") + " #" + s + "#:\n "; XPathException exception = new XPathException(prefix + message); exception.setErrorCode(errorCode); exception.setLocator(loc); reportError(exception); } private void reportError(XPathException exception) throws XPathException { errorCount++; if (firstError == null) { firstError = exception; } ((QueryModule)env).reportFatalError(exception); throw exception; } /** * Make a Locator object representing the current parsing location * * @return a Locator */ private ExpressionLocation makeLocator() { int line = t.getLineNumber(); int column = t.getColumnNumber(); ExpressionLocation loc = new ExpressionLocation(); loc.setSystemId(env.getSystemId()); loc.setLineNumber(line); loc.setColumnNumber(column); return loc; } private static Pattern encNamePattern = Pattern.compile("^[A-Za-z]([A-Za-z0-9._\\x2D])*$"); /** * Parse the version declaration if present. * * @throws XPathException in the event of a syntax error. */ private void parseVersionDeclaration() throws XPathException { if (t.currentToken == Token.XQUERY_VERSION) { nextToken(); expect(Token.STRING_LITERAL); if (!("1.0".equals(t.currentTokenValue))) { grumble("XQuery version must be 1.0", "XQST0031"); } nextToken(); if ("encoding".equals(t.currentTokenValue)) { nextToken(); expect(Token.STRING_LITERAL); if (!encNamePattern.matcher(t.currentTokenValue).matches()) { grumble("Encoding name contains invalid characters", "XQST0087"); } // we ignore the encoding now: it was handled earlier, while decoding the byte stream nextToken(); } expect(Token.SEMICOLON); nextToken(); } } /** * In a library module, parse the module declaration * Syntax: <"module" "namespace"> prefix "=" uri ";" * * @throws XPathException in the event of a syntax error. */ private void parseModuleDeclaration() throws XPathException { expect(Token.MODULE_NAMESPACE); nextToken(); expect(Token.NAME); String prefix = t.currentTokenValue; nextToken(); expect(Token.EQUALS); nextToken(); expect(Token.STRING_LITERAL); String uri = URILiteral(t.currentTokenValue); checkProhibitedPrefixes(prefix, uri); if (uri.length()==0) { grumble("Module namespace cannot be \"\"", "XQST0088"); uri = "http://saxon.fallback.namespace/"; // for error recovery } nextToken(); expect(Token.SEMICOLON); nextToken(); try { ((QueryModule)env).declarePrologNamespace(prefix, uri); } catch (XPathException err) { err.setLocator(makeLocator()); reportError(err); } ((QueryModule)env).setModuleNamespace(uri); } /** * Parse the query prolog. This method, and its subordinate methods which handle * individual declarations in the prolog, cause the static context to be updated * with relevant context information. On exit, t.currentToken is the first token * that is not recognized as being part of the prolog. * * @throws XPathException in the event of a syntax error. */ private void parseProlog() throws XPathException { //boolean allowSetters = true; boolean allowModuleDecl = true; boolean allowDeclarations = true; while (true) { try { if (t.currentToken == Token.MODULE_NAMESPACE) { String uri = ((QueryModule)env).getModuleNamespace(); if (uri == null) { grumble("Module declaration must not be used in a main module"); } else { grumble("Module declaration appears more than once"); } if (!allowModuleDecl) { grumble("Module declaration must precede other declarations in the query prolog"); } } allowModuleDecl = false; switch (t.currentToken) { case Token.DECLARE_NAMESPACE: if (!allowDeclarations) { grumble("Namespace declarations cannot follow variables, functions, or options"); } //allowSetters = false; parseNamespaceDeclaration(); break; case Token.DECLARE_DEFAULT: nextToken(); expect(Token.NAME); if (t.currentTokenValue.equals("element")) { if (!allowDeclarations) { grumble("Namespace declarations cannot follow variables, functions, or options"); } //allowSetters = false; parseDefaultElementNamespace(); } else if (t.currentTokenValue.equals("function")) { if (!allowDeclarations) { grumble("Namespace declarations cannot follow variables, functions, or options"); } //allowSetters = false; parseDefaultFunctionNamespace(); } else if (t.currentTokenValue.equals("collation")) { if (!allowDeclarations) { grumble("Collation declarations must appear earlier in the prolog"); } parseDefaultCollation(); } else if (t.currentTokenValue.equals("order")) { if (!allowDeclarations) { grumble("Order declarations must appear earlier in the prolog"); } parseDefaultOrder(); } else { grumble("After 'declare default', expected 'element', 'function', or 'collation'"); } break; case Token.DECLARE_BOUNDARY_SPACE: if (!allowDeclarations) { grumble("'declare boundary-space' must appear earlier in the query prolog"); } parseBoundarySpaceDeclaration(); break; case Token.DECLARE_ORDERING: if (!allowDeclarations) { grumble("'declare ordering' must appear earlier in the query prolog"); } parseOrderingDeclaration(); break; case Token.DECLARE_COPY_NAMESPACES: if (!allowDeclarations) { grumble("'declare copy-namespaces' must appear earlier in the query prolog"); } parseCopyNamespacesDeclaration(); break; case Token.DECLARE_BASEURI: if (!allowDeclarations) { grumble("'declare base-uri' must appear earlier in the query prolog"); } parseBaseURIDeclaration(); break; case Token.IMPORT_SCHEMA: //allowSetters = false; if (!allowDeclarations) { grumble("Import schema must appear earlier in the prolog"); } parseSchemaImport(); break; case Token.IMPORT_MODULE: //allowSetters = false; if (!allowDeclarations) { grumble("Import module must appear earlier in the prolog"); } parseModuleImport(); break; case Token.DECLARE_VARIABLE: //allowSetters = false; if (allowDeclarations) { sealNamespaces(namespacesToBeSealed, env.getConfiguration()); allowDeclarations = false; } processPreamble(); parseVariableDeclaration(); break; case Token.DECLARE_FUNCTION: if (allowDeclarations) { sealNamespaces(namespacesToBeSealed, env.getConfiguration()); allowDeclarations = false; } processPreamble(); parseFunctionDeclaration(false); break; case Token.DECLARE_UPDATING: nextToken(); if (!isKeyword("function")) { grumble("expected 'function' after 'declare updating"); } if (allowDeclarations) { sealNamespaces(namespacesToBeSealed, env.getConfiguration()); allowDeclarations = false; } processPreamble(); parseUpdatingFunctionDeclaration(); break; case Token.DECLARE_OPTION: if (allowDeclarations) { sealNamespaces(namespacesToBeSealed, env.getConfiguration()); allowDeclarations = false; } parseOptionDeclaration(); break; case Token.DECLARE_CONSTRUCTION: if (!allowDeclarations) { grumble("'declare construction' must appear earlier in the query prolog"); } parseConstructionDeclaration(); break; case Token.DECLARE_REVALIDATION: if (!allowDeclarations) { grumble("'declare revalidation' must appear earlier in the query prolog"); } parseRevalidationDeclaration(); break; default: return; } expect(Token.SEMICOLON); nextToken(); } catch (XPathException err) { if (err.getLocator() == null) { err.setLocator(makeLocator()); } if (!err.hasBeenReported()) { errorCount++; if (firstError == null) { firstError = err; } ((QueryModule)env).reportFatalError(err); } // we've reported an error, attempt to recover by skipping to the // next semicolon while (t.currentToken != Token.SEMICOLON) { nextToken(); if (t.currentToken == Token.EOF) { return; } else if (t.currentToken == Token.RCURLY) { t.lookAhead(); } else if (t.currentToken == Token.TAG) { parsePseudoXML(true); } } nextToken(); } } } private void sealNamespaces(List namespacesToBeSealed, Configuration config) { for (Iterator iter = namespacesToBeSealed.iterator(); iter.hasNext();) { String ns = (String)iter.next(); config.sealNamespace(ns); } } /** * Method called once the setters have been read to do tidying up that can't be done until we've got * to the end * * @throws XPathException */ private void processPreamble() throws XPathException { if (preambleProcessed) { return; } preambleProcessed = true; if (foundDefaultCollation) { String collationName = env.getDefaultCollationName(); URI collationURI; try { collationURI = new URI(collationName); if (!collationURI.isAbsolute()) { URI base = new URI(env.getBaseURI()); collationURI = base.resolve(collationURI); collationName = collationURI.toString(); } } catch (URISyntaxException err) { grumble("Default collation name '" + collationName + "' is not a valid URI"); collationName = NamespaceConstant.CODEPOINT_COLLATION_URI; } if (env.getCollation(collationName) == null) { grumble("Default collation name '" + collationName + "' is not a recognized collation", "XQST0038"); collationName = NamespaceConstant.CODEPOINT_COLLATION_URI; } ((QueryModule)env).setDefaultCollationName(collationName); } for (Iterator iter = schemaImports.iterator(); iter.hasNext();) { Import imp = (Import)iter.next(); applySchemaImport(imp); } for (Iterator iter = moduleImports.iterator(); iter.hasNext();) { Import imp = (Import)iter.next(); // Check that this import would not create a cycle involving a change of namespace if (!disableCycleChecks) { if (!imp.namespaceURI.equals(((QueryModule)env).getModuleNamespace())) { QueryModule parent = (QueryModule)env; if (!parent.mayImportModule(imp.namespaceURI)) { XPathException err = new XPathException( "A module cannot import itself directly or indirectly, unless all modules in the cycle are in the same namespace"); err.setErrorCode("XQST0073"); err.setIsStaticError(true); throw err; } } } applyModuleImport(imp); } } private void parseDefaultCollation() throws XPathException { // <"default" "collation"> StringLiteral if (foundDefaultCollation) { grumble("default collation appears more than once", "XQST0038"); } foundDefaultCollation = true; nextToken(); expect(Token.STRING_LITERAL); String uri = URILiteral(t.currentTokenValue); ((QueryModule)env).setDefaultCollationName(uri); nextToken(); } /** * parse "declare default order empty (least|greatest)" */ private void parseDefaultOrder() throws XPathException { if (foundEmptyOrderingDeclaration) { grumble("empty ordering declaration appears more than once", "XQST0069"); } foundEmptyOrderingDeclaration = true; nextToken(); if (!isKeyword("empty")) { grumble("After 'declare default order', expected keyword 'empty'"); } nextToken(); if (isKeyword("least")) { ((QueryModule)env).setEmptyLeast(true); } else if (isKeyword("greatest")) { ((QueryModule)env).setEmptyLeast(false); } else { grumble("After 'declare default order empty', expected keyword 'least' or 'greatest'"); } nextToken(); } /** * Parse the "declare xmlspace" declaration. * Syntax: <"declare" "boundary-space"> ("preserve" | "strip") * * @throws XPathException */ private void parseBoundarySpaceDeclaration() throws XPathException { if (foundBoundarySpaceDeclaration) { grumble("'declare boundary-space' appears more than once", "XQST0068"); } foundBoundarySpaceDeclaration = true; nextToken(); expect(Token.NAME); if ("preserve".equals(t.currentTokenValue)) { ((QueryModule)env).setPreserveBoundarySpace(true); } else if ("strip".equals(t.currentTokenValue)) { ((QueryModule)env).setPreserveBoundarySpace(false); } else { grumble("boundary-space must be 'preserve' or 'strip'"); } nextToken(); } /** * Parse the "declare ordering" declaration. * Syntax: <"declare" "ordering"> ("ordered" | "unordered") * * @throws XPathException */ private void parseOrderingDeclaration() throws XPathException { if (foundOrderingDeclaration) { grumble("ordering mode declaration appears more than once", "XQST0065"); } foundOrderingDeclaration = true; nextToken(); expect(Token.NAME); if ("ordered".equals(t.currentTokenValue)) { // no action } else if ("unordered".equals(t.currentTokenValue)) { // no action } else { grumble("ordering mode must be 'ordered' or 'unordered'"); } nextToken(); } /** * Parse the "declare copy-namespaces" declaration. * Syntax: <"declare" "copy-namespaces"> ("preserve" | "no-preserve") "," ("inherit" | "no-inherit") * * @throws XPathException */ private void parseCopyNamespacesDeclaration() throws XPathException { if (foundCopyNamespaces) { grumble("declare inherit-namespaces appears more than once", "XQST0055"); } foundCopyNamespaces = true; nextToken(); expect(Token.NAME); if ("preserve".equals(t.currentTokenValue)) { ((QueryModule)env).setPreserveNamespaces(true); } else if ("no-preserve".equals(t.currentTokenValue)) { ((QueryModule)env).setPreserveNamespaces(false); } else { grumble("copy-namespaces must be followed by 'preserve' or 'no-preserve'"); } nextToken(); expect(Token.COMMA); nextToken(); expect(Token.NAME); if ("inherit".equals(t.currentTokenValue)) { ((QueryModule)env).setInheritNamespaces(true); } else if ("no-inherit".equals(t.currentTokenValue)) { ((QueryModule)env).setInheritNamespaces(false); } else { grumble("After the comma in the copy-namespaces declaration, expected 'inherit' or 'no-inherit'"); } nextToken(); } /** * Parse the "declare construction" declaration. * Syntax: <"declare" "construction"> ("preserve" | "strip") * * @throws XPathException */ private void parseConstructionDeclaration() throws XPathException { if (foundConstructionDeclaration) { grumble("declare construction appears more than once", "XQST0067"); } foundConstructionDeclaration = true; nextToken(); expect(Token.NAME); int val; if ("preserve".equals(t.currentTokenValue)) { val = Validation.PRESERVE; } else if ("strip".equals(t.currentTokenValue)) { val = Validation.STRIP; } else { grumble("construction mode must be 'preserve' or 'strip'"); val = Validation.STRIP; } ((QueryModule)env).setConstructionMode(val); nextToken(); } /** * Parse the "declare revalidation" declaration. * Syntax: not allowed unless XQuery update is in use * * @throws XPathException */ protected void parseRevalidationDeclaration() throws XPathException { grumble("declare revalidation is allowed only in XQuery Update"); } /** * Parse (and process) the schema import declaration. * SchemaImport ::= "import" "schema" SchemaPrefix? URILiteral ("at" URILiteral ("," URILiteral)*)? * SchemaPrefix ::= ("namespace" NCName "=") | ("default" "element" "namespace") */ private void parseSchemaImport() throws XPathException { if (!env.getConfiguration().isSchemaAware(Configuration.XQUERY)) { grumble("To import a schema, you need the schema-aware version of Saxon", "XQST0009"); } Import sImport = new Import(); String prefix = null; sImport.namespaceURI = null; sImport.locationURIs = new ArrayList(5); nextToken(); if (isKeyword("namespace")) { t.setState(Tokenizer.DEFAULT_STATE); nextToken(); expect(Token.NAME); prefix = t.currentTokenValue; nextToken(); expect(Token.EQUALS); nextToken(); } else if (isKeyword("default")) { nextToken(); if (!isKeyword("element")) { grumble("In 'import schema', expected 'element namespace'"); } nextToken(); if (!isKeyword("namespace")) { grumble("In 'import schema', expected keyword 'namespace'"); } nextToken(); prefix = ""; } if (t.currentToken == Token.STRING_LITERAL) { String uri = URILiteral(t.currentTokenValue); checkProhibitedPrefixes(prefix, uri); sImport.namespaceURI = uri; nextToken(); if (isKeyword("at")) { nextToken(); expect(Token.STRING_LITERAL); sImport.locationURIs.add(URILiteral(t.currentTokenValue)); nextToken(); while (t.currentToken == Token.COMMA) { nextToken(); expect(Token.STRING_LITERAL); sImport.locationURIs.add(URILiteral(t.currentTokenValue)); nextToken(); } } else if (t.currentToken != Token.SEMICOLON) { grumble("After the target namespace URI, expected 'at' or ';'"); } } else { grumble("After 'import schema', expected 'namespace', 'default', or a string-literal"); } if (prefix != null) { try { if (prefix.length() == 0) { ((QueryModule)env).setDefaultElementNamespace(sImport.namespaceURI); } else { if (sImport.namespaceURI == null || "".equals(sImport.namespaceURI)) { grumble("A prefix cannot be bound to the null namespace", "XQST0057"); } ((QueryModule)env).declarePrologNamespace(prefix, sImport.namespaceURI); } } catch (XPathException err) { err.setLocator(makeLocator()); reportError(err); } } for (Iterator iter = schemaImports.iterator(); iter.hasNext();) { Import imp = (Import)iter.next(); if (imp.namespaceURI.equals(sImport.namespaceURI)) { grumble("Schema namespace '" + sImport.namespaceURI + "' is imported more than once", "XQST0058"); break; } } schemaImports.add(sImport); } private void applySchemaImport(Import sImport) throws XPathException { // Do the importing Configuration config = env.getConfiguration(); if (!config.isSchemaAvailable(sImport.namespaceURI)) { if (!sImport.locationURIs.isEmpty()) { try { PipelineConfiguration pipe = config.makePipelineConfiguration(); config.readMultipleSchemas(pipe, env.getBaseURI(), sImport.locationURIs, sImport.namespaceURI); namespacesToBeSealed.add(sImport.namespaceURI); } catch (TransformerConfigurationException err) { grumble("Error in schema. " + err.getMessage(), "XQST0059"); } } else { grumble("Unable to locate requested schema", "XQST0059"); } } ((QueryModule)env).addImportedSchema(sImport.namespaceURI, env.getBaseURI(), sImport.locationURIs); } /** * Parse (and expand) the module import declaration. * Syntax: <"import" "module" ("namespace" NCName "=")? uri ("at" uri ("," uri)*)? ";" */ private void parseModuleImport() throws XPathException { QueryModule thisModule = (QueryModule)env; Import mImport = new Import(); String prefix = null; mImport.namespaceURI = null; mImport.locationURIs = new ArrayList(5); nextToken(); if (t.currentToken == Token.NAME && t.currentTokenValue.equals("namespace")) { t.setState(Tokenizer.DEFAULT_STATE); nextToken(); expect(Token.NAME); prefix = t.currentTokenValue; nextToken(); expect(Token.EQUALS); nextToken(); } if (t.currentToken == Token.STRING_LITERAL) { String uri = URILiteral(t.currentTokenValue); checkProhibitedPrefixes(prefix, uri); mImport.namespaceURI = uri; if (mImport.namespaceURI.length() == 0) { grumble("Imported module namespace cannot be \"\"", "XQST0088"); mImport.namespaceURI = "http://saxon.fallback.namespace/line" + t.getLineNumber(); // for error recovery } if (importedModules.contains(mImport.namespaceURI)) { grumble("Two 'import module' declarations specify the same module namespace", "XQST0047"); } importedModules.add(mImport.namespaceURI); ((QueryModule)env).addImportedNamespace(mImport.namespaceURI); nextToken(); if (isKeyword("at")) { do { nextToken(); expect(Token.STRING_LITERAL); mImport.locationURIs.add(URILiteral(t.currentTokenValue)); nextToken(); } while (t.currentToken == Token.COMMA); } } else { grumble("After 'import module', expected 'namespace' or a string-literal"); } if (prefix != null) { try { thisModule.declarePrologNamespace(prefix, mImport.namespaceURI); } catch (XPathException err) { err.setLocator(makeLocator()); reportError(err); } } // // Check that this import would not create a cycle involving a change of namespace // if (!disableCycleChecks) { // if (!mImport.namespaceURI.equals(((QueryModule)env).getModuleNamespace())) { // QueryModule parent = (QueryModule)env; // if (!parent.mayImport(mImport.namespaceURI)) { // StaticError err = new StaticError("A module cannot import itself directly or indirectly, unless all modules in the cycle are in the same namespace"); // err.setErrorCode("XQST0073"); // throw err; // } // } // } moduleImports.add(mImport); } public void applyModuleImport(Import mImport) throws XPathException { boolean foundOne = false; // resolve the location URIs against the base URI Platform platform = Configuration.getPlatform(); for (int i=0; i= 0; h--) { if (mImport.locationURIs.get(h).equals(importedModule.getLocationURI())) { mImport.locationURIs.remove(h); } } } } // If we've found at least one module, and there are no location URIs left, call it a day. if (mImport.locationURIs.isEmpty() && foundOne) { return; } // Call the module URI resolver to find the remaining modules ModuleURIResolver resolver = ((QueryModule)env).getUserQueryContext().getModuleURIResolver(); String[] hints = new String[mImport.locationURIs.size()]; for (int h=0; h uri-literal * * @throws XPathException */ private void parseBaseURIDeclaration() throws XPathException { if (foundBaseURIDeclaration) { grumble("Base URI Declaration may only appear once", "XQST0032"); } foundBaseURIDeclaration = true; nextToken(); expect(Token.STRING_LITERAL); String uri = URILiteral(t.currentTokenValue); try { // if the supplied URI is relative, try to resolve it URI baseURI = new URI(uri); if (!baseURI.isAbsolute()) { String oldBase = env.getBaseURI(); URI oldBaseURI = new URI(oldBase); uri = oldBaseURI.resolve(uri).toString(); } ((QueryModule)env).setBaseURI(uri); } catch (URISyntaxException err) { // The spec says this "is not intrinsically an error", but can cause a failure later ((QueryModule)env).setBaseURI(uri); } nextToken(); } /** * Parse the "default function namespace" declaration. * Syntax: <"declare" "default" "function" "namespace"> StringLiteral * * @throws XPathException to indicate a syntax error */ private void parseDefaultFunctionNamespace() throws XPathException { if (foundDefaultFunctionNamespace) { grumble("default function namespace appears more than once", "XQST0066"); } foundDefaultFunctionNamespace = true; nextToken(); expect(Token.NAME); if (!"namespace".equals(t.currentTokenValue)) { grumble("After 'declare default function', expected 'namespace'"); } nextToken(); expect(Token.STRING_LITERAL); String uri = URILiteral(t.currentTokenValue); ((QueryModule)env).setDefaultFunctionNamespace(uri); nextToken(); } /** * Parse the "default element namespace" declaration. * Syntax: <"declare" "default" "element" "namespace"> StringLiteral * * @throws XPathException to indicate a syntax error */ private void parseDefaultElementNamespace() throws XPathException { if (foundDefaultElementNamespace) { grumble("default element namespace appears more than once", "XQST0066"); } foundDefaultElementNamespace = true; nextToken(); expect(Token.NAME); if (!"namespace".equals(t.currentTokenValue)) { grumble("After 'declare default element', expected 'namespace'"); } nextToken(); expect(Token.STRING_LITERAL); String uri = URILiteral(t.currentTokenValue); ((QueryModule)env).setDefaultElementNamespace(uri); nextToken(); } /** * Parse a namespace declaration in the Prolog. * Syntax: <"declare" "namespace"> NCName "=" StringLiteral * * @throws XPathException */ private void parseNamespaceDeclaration() throws XPathException { nextToken(); expect(Token.NAME); String prefix = t.currentTokenValue; if (!nameChecker.isValidNCName(prefix)) { grumble("Invalid namespace prefix " + Err.wrap(prefix)); } nextToken(); expect(Token.EQUALS); nextToken(); expect(Token.STRING_LITERAL); String uri = URILiteral(t.currentTokenValue); checkProhibitedPrefixes(prefix, uri); try { ((QueryModule)env).declarePrologNamespace(prefix, uri); } catch (XPathException err) { err.setLocator(makeLocator()); reportError(err); } nextToken(); } /** * Check that a namespace declaration does not use a prohibited prefix or URI (xml or xmlns) * @param prefix the prefix to be tested * @param uri the URI being declared * @throws XPathException if the prefix is prohibited */ private void checkProhibitedPrefixes(String prefix, String uri) throws XPathException { if (prefix == null) { prefix = ""; } if (uri == null) { uri = ""; } if ("xmlns".equals(prefix)) { grumble("The namespace prefix 'xmlns' cannot be redeclared", "XQST0070"); } if (uri.equals(NamespaceConstant.XMLNS)) { grumble("The xmlns namespace URI is reserved", "XQST0070"); } if (uri.equals(NamespaceConstant.XML) && !prefix.equals("xml")) { grumble("The XML namespace cannot be bound to any prefix other than 'xml'", "XQST0070"); } if (prefix.equals("xml") && !uri.equals(NamespaceConstant.XML)) { grumble("The prefix 'xml' cannot be bound to any namespace other than " + NamespaceConstant.XML, "XQST0070"); } // TODO: resolution of spec bug 4463 also appears to disallow explicit binding of the xml prefix to the xml namespace } /** * Parse a global variable definition. * <"declare" "variable" "$"> VarName TypeDeclaration? * ((":=" Expr ) | "external") * Currently accept both * * @throws XPathException */ private void parseVariableDeclaration() throws XPathException { int offset = t.currentTokenStartOffset; GlobalVariableDefinition var = new GlobalVariableDefinition(); var.setLineNumber(t.getLineNumber()); var.setSystemId(env.getSystemId()); nextToken(); expect(Token.DOLLAR); t.setState(Tokenizer.BARE_NAME_STATE); nextToken(); expect(Token.NAME); String varName = t.currentTokenValue; StructuredQName varQName = makeStructuredQName(t.currentTokenValue, false); var.setVariableQName(varQName); String uri = varQName.getNamespaceURI(); String moduleURI = ((QueryModule)env).getModuleNamespace(); if (moduleURI != null && !moduleURI.equals(uri)) { grumble("A variable declared in a library module must be in the module namespace", "XQST0048"); } nextToken(); SequenceType requiredType = SequenceType.ANY_SEQUENCE; if (t.currentToken == Token.AS) { t.setState(Tokenizer.SEQUENCE_TYPE_STATE); nextToken(); requiredType = parseSequenceType(); } var.setRequiredType(requiredType); if (t.currentToken == Token.ASSIGN) { t.setState(Tokenizer.DEFAULT_STATE); nextToken(); Expression exp = parseExprSingle(); var.setIsParameter(false); var.setValueExpression(makeTracer(offset, exp, StandardNames.XSL_VARIABLE, varQName)); } else if (t.currentToken == Token.NAME) { if ("external".equals(t.currentTokenValue)) { var.setIsParameter(true); if (defaultValue != null) { var.setValueExpression(defaultValue); } nextToken(); } else { grumble("Variable must either be initialized or be declared as external"); } } else { grumble("Expected ':=' or 'external' in variable declaration"); } QueryModule qenv = (QueryModule)env; if (qenv.getModuleNamespace() != null && !uri.equals(qenv.getModuleNamespace())) { grumble("Variable " + Err.wrap(varName, Err.VARIABLE) + " is not defined in the module namespace"); } try { qenv.declareVariable(var); } catch (XPathException e) { grumble(e.getMessage(), e.getErrorCodeLocalPart()); } } /** * Parse a function declaration. *

    Syntax:
    * <"declare" "function"> ParamList? (")" | (<")" "as"> SequenceType)) * (EnclosedExpr | "external") *

    *

    On entry, the "define function" has already been recognized

    * * @throws XPathException if a syntax error is found */ protected void parseFunctionDeclaration(boolean isUpdating) throws XPathException { // the next token should be the < QNAME "("> pair int offset = t.currentTokenStartOffset; nextToken(); expect(Token.FUNCTION); String uri; StructuredQName qName; if (t.currentTokenValue.indexOf(':') < 0) { uri = env.getDefaultFunctionNamespace(); qName = new StructuredQName("", uri, t.currentTokenValue); } else { qName = makeStructuredQName(t.currentTokenValue, false); uri = qName.getNamespaceURI(); } if (uri.length()==0) { grumble("The function must be in a namespace", "XQST0060"); } String moduleURI = ((QueryModule)env).getModuleNamespace(); if (moduleURI != null && !moduleURI.equals(uri)) { grumble("A function in a library module must be in the module namespace", "XQST0048"); } if (NamespaceConstant.isReservedInQuery(uri)) { grumble("The function name " + t.currentTokenValue + " is in a reserved namespace", "XQST0045"); } XQueryFunction func = new XQueryFunction(); func.setFunctionName(qName); func.setResultType(SequenceType.ANY_SEQUENCE); func.setBody(null); func.setLineNumber(t.getLineNumber(offset)); func.setColumnNumber(t.getColumnNumber(offset)); func.setSystemId(env.getSystemId()); func.setStaticContext((QueryModule)env); func.setMemoFunction(memoFunction); func.setExecutable(getExecutable()); func.setUpdating(isUpdating); nextToken(); HashSet paramNames = new HashSet(8); while (t.currentToken != Token.RPAR) { // ParamList ::= Param ("," Param)* // Param ::= "$" VarName TypeDeclaration? expect(Token.DOLLAR); nextToken(); expect(Token.NAME); String argName = t.currentTokenValue; StructuredQName argQName = makeStructuredQName(argName, false); if (paramNames.contains(argQName)) { grumble("Duplicate parameter name " + Err.wrap(t.currentTokenValue, Err.VARIABLE), "XQST0039"); } paramNames.add(argQName); SequenceType paramType = SequenceType.ANY_SEQUENCE; nextToken(); if (t.currentToken == Token.AS) { nextToken(); paramType = parseSequenceType(); } UserFunctionParameter arg = new UserFunctionParameter(); arg.setRequiredType(paramType); arg.setVariableQName(argQName); func.addArgument(arg); declareRangeVariable(arg); if (t.currentToken == Token.RPAR) { break; } else if (t.currentToken == Token.COMMA) { nextToken(); } else { grumble("Expected ',' or ')' after function argument, found '" + Token.tokens[t.currentToken] + '\''); } } t.setState(Tokenizer.BARE_NAME_STATE); nextToken(); if (t.currentToken == Token.AS) { t.setState(Tokenizer.SEQUENCE_TYPE_STATE); nextToken(); func.setResultType(parseSequenceType()); } if (isKeyword("external")) { grumble("Saxon does not allow external functions to be declared"); } else { expect(Token.LCURLY); t.setState(Tokenizer.DEFAULT_STATE); nextToken(); func.setBody(parseExpression()); expect(Token.RCURLY); lookAhead(); // must be done manually after an RCURLY } UserFunctionParameter[] params = func.getParameterDefinitions(); for (int i = 0; i < params.length; i++) { undeclareRangeVariable(); } t.setState(Tokenizer.DEFAULT_STATE); nextToken(); QueryModule qenv = (QueryModule)env; try { qenv.declareFunction(func); } catch (XPathException e) { grumble(e.getMessage(), e.getErrorCodeLocalPart()); } memoFunction = false; } /** * Parse an updating function declaration (allowed in XQuery Update only) */ protected void parseUpdatingFunctionDeclaration() throws XPathException { grumble("Updating functions are allowed only in XQuery Update"); } /** * Parse an option declaration. *

    Syntax:
    * <"declare" "option"> QName "string-literal" *

    *

    On entry, the "declare option" has already been recognized

    * * @throws XPathException if a syntax error is found */ private void parseOptionDeclaration() throws XPathException { nextToken(); expect(Token.NAME); int varNameCode = makeNameCode(t.currentTokenValue, false); String uri = env.getNamePool().getURI(varNameCode); if (uri.length() == 0) { grumble("The QName identifying an option declaration must be prefixed", "XPST0081"); return; } nextToken(); expect(Token.STRING_LITERAL); String value = URILiteral(t.currentTokenValue); if (uri.equals(NamespaceConstant.SAXON)) { String localName = env.getNamePool().getLocalName(varNameCode); if (localName.equals("output")) { setOutputProperty(value); } else if (localName.equals("default")) { defaultValue = setDefaultValue(value); } else if (localName.equals("memo-function")) { if (value.equals("true")) { memoFunction = true; } else if (value.equals("false")) { memoFunction = false; } else { warning("Value of saxon:memo-function must be 'true' or 'false'"); } } else if (localName.equals("allow-cycles")) { if (value.equals("true")) { disableCycleChecks = true; } else if (value.equals("false")) { disableCycleChecks = false; } else { warning("Value of saxon:allow-cycles must be 'true' or 'false'"); } } else { warning("Unknown Saxon option declaration: " + env.getNamePool().getDisplayName(varNameCode)); } } nextToken(); } /** * Handle a saxon:output option declaration. Format: * declare option saxon:output "indent = yes" * @param property a property name=value pair. The name is the name of a serialization * property, potentially as a prefixed QName; the value is the value of the property. A warning * is output for unrecognized properties or values */ private void setOutputProperty(String property) { int equals = property.indexOf("="); if (equals < 0) { badOutputProperty("no equals sign"); } else if (equals == 0) { badOutputProperty("starts with '="); } else if (equals == property.length() - 1) { badOutputProperty("ends with '="); } String keyword = Whitespace.trim(property.substring(0, equals)); String value = Whitespace.trim(property.substring(equals + 1)); Properties props = getExecutable().getDefaultOutputProperties(); try { int key = makeNameCode(keyword, false) & NamePool.FP_MASK; String lname = env.getNamePool().getLocalName(key); String uri = env.getNamePool().getURI(key); ResultDocument.setSerializationProperty(props, uri, lname, value, env.getNamespaceResolver(), false, nameChecker); } catch (XPathException e) { badOutputProperty(e.getMessage()); } } private void badOutputProperty(String s) { try { warning("Invalid serialization property (" + s + ") - ignored"); } catch (XPathException staticError) { // } } /** * Parse the expression (inside a string literal) used to define default values * for external variables. This requires instantiating a nested XPath parser. * @param exp holds the expression used to define a default value * @return the compiled expression that computes the default value */ public Expression setDefaultValue(String exp) { try { IndependentContext ic = new IndependentContext(env.getConfiguration()); ic.setNamespaceResolver(env.getNamespaceResolver()); Expression expr = ExpressionTool.make(exp, ic, 0, Token.EOF, 1, false); ItemType contextItemType = Type.ITEM_TYPE; ExpressionVisitor visitor = ExpressionVisitor.make(ic); expr = visitor.typeCheck(expr, contextItemType); expr = visitor.optimize(expr, contextItemType); SlotManager stackFrameMap = ic.getStackFrameMap(); ExpressionTool.allocateSlots(expr, stackFrameMap.getNumberOfVariables(), stackFrameMap); return expr; } catch (XPathException e) { try { warning("Invalid expression for default value: " + e.getMessage() + " (ignored)"); } catch (XPathException staticError) { // } return null; } } /** * Parse a FLWOR expression. This replaces the XPath "for" expression. * Full syntax: *

    * [41] FLWORExpr ::= (ForClause | LetClause)+ * WhereClause? OrderByClause? * "return" ExprSingle * [42] ForClause ::= <"for" "$"> VarName TypeDeclaration? PositionalVar? "in" ExprSingle * ("," "$" VarName TypeDeclaration? PositionalVar? "in" ExprSingle)* * [43] PositionalVar ::= "at" "$" VarName * [44] LetClause ::= <"let" "$"> VarName TypeDeclaration? ":=" ExprSingle * ("," "$" VarName TypeDeclaration? ":=" ExprSingle)* * [45] WhereClause ::= "where" Expr * [46] OrderByClause ::= (<"order" "by"> | <"stable" "order" "by">) OrderSpecList * [47] OrderSpecList ::= OrderSpec ("," OrderSpec)* * [48] OrderSpec ::= ExprSingle OrderModifier * [49] OrderModifier ::= ("ascending" | "descending")? * (<"empty" "greatest"> | <"empty" "least">)? * ("collation" StringLiteral)? *

    * * @return the resulting subexpression * @throws XPathException if any error is encountered */ protected Expression parseForExpression() throws XPathException { int offset = t.currentTokenStartOffset; Expression whereCondition = null; int whereOffset = -1; //boolean stableOrder = false; List clauseList = new ArrayList(4); while (true) { if (t.currentToken == Token.FOR) { parseForClause(clauseList); } else if (t.currentToken == Token.LET) { parseLetClause(clauseList); } else { break; } } if (t.currentToken == Token.WHERE || isKeyword("where")) { whereOffset = t.currentTokenStartOffset; nextToken(); whereCondition = parseExprSingle(); } int orderByOffset = t.currentTokenStartOffset; if (isKeyword("stable")) { // we read the "stable" keyword but ignore it; Saxon ordering is always stable nextToken(); if (!isKeyword("order")) { grumble("'stable' must be followed by 'order by'"); } } List sortSpecList = null; if (isKeyword("order")) { t.setState(Tokenizer.BARE_NAME_STATE); nextToken(); if (!isKeyword("by")) { grumble("'order' must be followed by 'by'"); } t.setState(Tokenizer.DEFAULT_STATE); nextToken(); sortSpecList = parseSortDefinition(); } int returnOffset = t.currentTokenStartOffset; expect(Token.RETURN); t.setState(Tokenizer.DEFAULT_STATE); nextToken(); Expression action = parseExprSingle(); action = makeTracer(returnOffset, action, Location.RETURN_EXPRESSION, null); // If there is an order by clause, we modify the "return" expression so that it // returns a tuple containing the actual return value, plus the value of // each of the sort keys. We then wrap the entire FLWR expression inside a // TupleSorter that sorts the stream of tuples according to the sort keys, // discarding the sort keys and returning only the true result. The tuple // is implemented as a Java object wrapped inside an ObjectValue, which is // a general-purpose wrapper for objects that don't fit in the XPath type system. if (sortSpecList != null) { TupleExpression exp = new TupleExpression(1 + sortSpecList.size()); setLocation(exp); exp.setExpression(0, action); for (int i = 0; i < sortSpecList.size(); i++) { try { RoleLocator role = new RoleLocator(RoleLocator.ORDER_BY, "FLWR", i); //role.setSourceLocator(makeLocator()); Expression sk = TypeChecker.staticTypeCheck(((SortSpec)sortSpecList.get(i)).sortKey, SequenceType.OPTIONAL_ATOMIC, false, role, ExpressionVisitor.make(env)); exp.setExpression(i + 1, sk); } catch (XPathException err) { grumble(err.getMessage()); } } action = exp; } // if there is a "where" condition, we implement this by wrapping an if/then/else // around the "return" expression. No clever optimization yet! if (whereCondition != null) { action = Choose.makeConditional(whereCondition, action); action = makeTracer(whereOffset, action, Location.WHERE_CLAUSE, null); setLocation(action); } for (int i = clauseList.size() - 1; i >= 0; i--) { Object clause = clauseList.get(i); if (clause instanceof ExpressionParser.ForClause) { ExpressionParser.ForClause fc = (ExpressionParser.ForClause)clause; ForExpression exp = (ForExpression)fc.rangeVariable; exp.setPositionVariable(fc.positionVariable); exp.setLocationId(env.getLocationMap().allocateLocationId(env.getSystemId(), t.getLineNumber(fc.offset))); exp.setSequence(fc.sequence); exp.setAction(action); action = makeTracer(fc.offset, exp, Location.FOR_EXPRESSION, fc.rangeVariable.getVariableQName()); } else { LetClause lc = (LetClause)clause; LetExpression exp = lc.variable; exp.setLocationId(env.getLocationMap().allocateLocationId(env.getSystemId(), t.getLineNumber(lc.offset))); //exp.setSequence(lc.value); exp.setAction(action); action = makeTracer(lc.offset, exp, Location.LET_EXPRESSION, lc.variable.getVariableQName()); } } // Now wrap the whole expression in a TupleSorter if there is a sort specification if (sortSpecList != null) { SortKeyDefinition[] keys = new SortKeyDefinition[sortSpecList.size()]; for (int i = 0; i < keys.length; i++) { SortSpec spec = (SortSpec)sortSpecList.get(i); SortKeyDefinition key = new SortKeyDefinition(); key.setSortKey(((SortSpec) sortSpecList.get(i)).sortKey); key.setOrder(new StringLiteral(spec.ascending ? "ascending" : "descending")); key.setEmptyLeast(spec.emptyLeast); if (spec.collation != null) { final StringCollator comparator = env.getCollation(spec.collation); if (comparator == null) { grumble("Unknown collation '" + spec.collation + '\'', "XQST0076"); } key.setCollation(comparator); } keys[i] = key; } TupleSorter sorter = new TupleSorter(action, keys); setLocation(sorter); action = makeTracer(orderByOffset, sorter, Location.ORDER_BY_CLAUSE, null); } // undeclare all the range variables for (int i = clauseList.size() - 1; i >= 0; i--) { Object clause = clauseList.get(i); if ((clause instanceof ExpressionParser.ForClause) && ((ExpressionParser.ForClause)clause).positionVariable != null) { // undeclare the "at" variable if it was declared undeclareRangeVariable(); } // undeclare the primary variable undeclareRangeVariable(); } setLocation(action, offset); return action; } /** * Make a LetExpression. This returns an ordinary LetExpression if tracing is off, and an EagerLetExpression * if tracing is on. This is so that trace events occur in an order that the user can follow. * @return the constructed "let" expression */ private LetExpression makeLetExpression() { if (env.getConfiguration().isCompileWithTracing()) { return new EagerLetExpression(); } else { return new LetExpression(); } } /** * Parse a ForClause. *

    * [42] ForClause ::= <"for" "$"> VarName TypeDeclaration? PositionalVar? "in" ExprSingle * ("," "$" VarName TypeDeclaration? PositionalVar? "in" ExprSingle)* *

    * * @param clauseList - the components of the parsed ForClause are appended to the * supplied list * @throws XPathException */ private void parseForClause(List clauseList) throws XPathException { boolean first = true; do { ExpressionParser.ForClause clause = new ExpressionParser.ForClause(); if (first) { clause.offset = t.currentTokenStartOffset; } clauseList.add(clause); nextToken(); if (first) { first = false; } else { clause.offset = t.currentTokenStartOffset; } expect(Token.DOLLAR); nextToken(); expect(Token.NAME); String var = t.currentTokenValue; ForExpression v = new ForExpression(); StructuredQName varQName = makeStructuredQName(var, false); v.setVariableQName(varQName); v.setRequiredType(SequenceType.SINGLE_ITEM); clause.rangeVariable = v; nextToken(); if (t.currentToken == Token.AS /*isKeyword("as")*/) { nextToken(); SequenceType type = parseSequenceType(); if (type.getCardinality() != StaticProperty.EXACTLY_ONE) { warning("Occurrence indicator on singleton range variable has no effect"); type = SequenceType.makeSequenceType(type.getPrimaryType(), StaticProperty.EXACTLY_ONE); } v.setRequiredType(type); } clause.positionVariable = null; if (isKeyword("at")) { nextToken(); expect(Token.DOLLAR); nextToken(); expect(Token.NAME); PositionVariable pos = new PositionVariable(); StructuredQName posQName = makeStructuredQName(t.currentTokenValue, false); if (!scanOnly && posQName.equals(varQName)) { grumble("The two variables declared in a single 'for' clause must have different names", "XQST0089"); } pos.setVariableQName(posQName); clause.positionVariable = pos; nextToken(); } expect(Token.IN); nextToken(); clause.sequence = parseExprSingle(); declareRangeVariable(clause.rangeVariable); if (clause.positionVariable != null) { declareRangeVariable(clause.positionVariable); } } while (t.currentToken == Token.COMMA); } /** * Parse a LetClause. *

    * [44] LetClause ::= <"let" "$"> VarName TypeDeclaration? ":=" ExprSingle * ("," "$" VarName TypeDeclaration? ":=" ExprSingle)* *

    * * @param clauseList - the components of the parsed LetClause are appended to the * supplied list * @throws XPathException */ private void parseLetClause(List clauseList) throws XPathException { boolean first = true; do { LetClause clause = new LetClause(); if (first) { clause.offset = t.currentTokenStartOffset; } clauseList.add(clause); nextToken(); if (first) { first = false; } else { clause.offset = t.currentTokenStartOffset; } expect(Token.DOLLAR); nextToken(); expect(Token.NAME); String var = t.currentTokenValue; LetExpression v = new LetExpression(); StructuredQName varQName = makeStructuredQName(var, false); v.setRequiredType(SequenceType.ANY_SEQUENCE); v.setVariableQName(varQName); clause.variable = v; nextToken(); if (t.currentToken == Token.AS) { nextToken(); v.setRequiredType(parseSequenceType()); } expect(Token.ASSIGN); nextToken(); v.setSequence(parseExprSingle()); declareRangeVariable(v); } while (t.currentToken == Token.COMMA); } /** * Make a string-join expression that concatenates the string-values of items in * a sequence with intervening spaces. This may be simplified later as a result * of type-checking. * @param exp the base expression, evaluating to a sequence * @param env the static context * @return a call on string-join to create a string containing the * representations of the items in the sequence separated by spaces. */ public static Expression makeStringJoin(Expression exp, StaticContext env) { exp = new Atomizer(exp, env.getConfiguration()); final TypeHierarchy th = env.getConfiguration().getTypeHierarchy(); ItemType t = exp.getItemType(th); if (!t.equals(BuiltInAtomicType.STRING) && !t.equals(BuiltInAtomicType.UNTYPED_ATOMIC)) { exp = new AtomicSequenceConverter(exp, BuiltInAtomicType.STRING); } StringJoin fn = (StringJoin)SystemFunction.makeSystemFunction( "string-join", new Expression[]{exp, new StringLiteral(StringValue.SINGLE_SPACE)}); ExpressionTool.copyLocationInfo(exp, fn); return fn; } private static class LetClause { public LetExpression variable; public int offset; } /** * Parse the "order by" clause. * [46] OrderByClause ::= (<"order" "by"> | <"stable" "order" "by">) OrderSpecList * [47] OrderSpecList ::= OrderSpec ("," OrderSpec)* * [48] OrderSpec ::= ExprSingle OrderModifier * [49] OrderModifier ::= ("ascending" | "descending")? * (<"empty" "greatest"> | <"empty" "least">)? * ("collation" StringLiteral)? * * @return a list of sort specifications (SortSpec), one per sort key * @throws XPathException */ private List parseSortDefinition() throws XPathException { List sortSpecList = new ArrayList(5); while (true) { SortSpec sortSpec = new SortSpec(); sortSpec.sortKey = parseExprSingle(); sortSpec.ascending = true; sortSpec.emptyLeast = ((QueryModule)env).isEmptyLeast(); sortSpec.collation = env.getDefaultCollationName(); //t.setState(t.BARE_NAME_STATE); if (isKeyword("ascending")) { nextToken(); } else if (isKeyword("descending")) { sortSpec.ascending = false; nextToken(); } if (isKeyword("empty")) { nextToken(); if (isKeyword("greatest")) { sortSpec.emptyLeast = false; nextToken(); } else if (isKeyword("least")) { sortSpec.emptyLeast = true; nextToken(); } else { grumble("'empty' must be followed by 'greatest' or 'least'"); } } if (isKeyword("collation")) { nextToken(); expect(Token.STRING_LITERAL); String collationName = URILiteral(t.currentTokenValue); URI collationURI; try { collationURI = new URI(collationName); if (!collationURI.isAbsolute()) { URI base = new URI(env.getBaseURI()); collationURI = base.resolve(collationURI); collationName = collationURI.toString(); } } catch (URISyntaxException err) { grumble("Collation name '" + collationName + "' is not a valid URI", "XQST0046"); collationName = NamespaceConstant.CODEPOINT_COLLATION_URI; } sortSpec.collation = collationName; nextToken(); } sortSpecList.add(sortSpec); if (t.currentToken == Token.COMMA) { nextToken(); } else { break; } } return sortSpecList; } private static class SortSpec { public Expression sortKey; public boolean ascending; public boolean emptyLeast; public String collation; } /** * Parse a Typeswitch Expression. * This construct is XQuery-only. * TypeswitchExpr ::= * "typeswitch" "(" Expr ")" * CaseClause+ * "default" ("$" VarName)? "return" ExprSingle * CaseClause ::= * "case" ("$" VarName "as")? SequenceType "return" ExprSingle */ protected Expression parseTypeswitchExpression() throws XPathException { // On entry, the "(" has already been read int offset = t.currentTokenStartOffset; nextToken(); Expression operand = parseExpression(); List types = new ArrayList(10); List actions = new ArrayList(10); expect(Token.RPAR); nextToken(); // The code generated takes the form: // let $zzz := operand return // if ($zzz instance of t1) then action1 // else if ($zzz instance of t2) then action2 // else default-action // // If a variable is declared in a case clause or default clause, // then "action-n" takes the form // let $v as type := $zzz return action-n // we were generating "let $v as type := $zzz return action-n" but this gives a compile time error if // there's a case clause that specifies an impossible type. LetExpression outerLet = makeLetExpression(); outerLet.setRequiredType(SequenceType.ANY_SEQUENCE); outerLet.setVariableQName(new StructuredQName("zz", NamespaceConstant.SAXON, "zz_typeswitchVar")); outerLet.setSequence(operand); while (t.currentToken == Token.CASE) { int caseOffset = t.currentTokenStartOffset; SequenceType type; Expression action; nextToken(); if (t.currentToken == Token.DOLLAR) { nextToken(); expect(Token.NAME); final String var = t.currentTokenValue; final StructuredQName varQName = makeStructuredQName(var, false); nextToken(); expect(Token.AS); // expect(Token.NAME); // if (!"as".equals(t.currentTokenValue)) { // grumble("After 'case $" + var + "', expected 'as'"); // } nextToken(); type = parseSequenceType(); action = makeTracer(caseOffset, parseTypeswitchReturnClause(varQName, outerLet), Location.CASE_EXPRESSION, varQName); if (action instanceof TraceExpression) { ((TraceExpression)action).setProperty("type", type.toString()); } } else { type = parseSequenceType(); t.treatCurrentAsOperator(); expect(Token.RETURN); nextToken(); action = makeTracer(caseOffset, parseExprSingle(), Location.CASE_EXPRESSION, null); if (action instanceof TraceExpression) { ((TraceExpression)action).setProperty("type", type.toString()); } } types.add(type); actions.add(action); } if (types.isEmpty()) { grumble("At least one case clause is required in a typeswitch"); } expect(Token.DEFAULT); final int defaultOffset = t.currentTokenStartOffset; nextToken(); Expression defaultAction; if (t.currentToken == Token.DOLLAR) { nextToken(); expect(Token.NAME); final String var = t.currentTokenValue; final StructuredQName varQName = makeStructuredQName(var, false); nextToken(); defaultAction = makeTracer(defaultOffset, parseTypeswitchReturnClause(varQName, outerLet), Location.DEFAULT_EXPRESSION, varQName); } else { t.treatCurrentAsOperator(); expect(Token.RETURN); nextToken(); defaultAction = makeTracer(defaultOffset, parseExprSingle(), Location.DEFAULT_EXPRESSION, null); } Expression lastAction = defaultAction; // Note, the ragged "choose" later gets flattened into a single-level choose, saving stack space for (int i = types.size() - 1; i >= 0; i--) { final LocalVariableReference var = new LocalVariableReference(outerLet); setLocation(var); final InstanceOfExpression ioe = new InstanceOfExpression(var, (SequenceType)types.get(i)); setLocation(ioe); final Expression ife = Choose.makeConditional(ioe, (Expression)actions.get(i), lastAction); setLocation(ife); lastAction = ife; } outerLet.setAction(lastAction); return makeTracer(offset, outerLet, Location.TYPESWITCH_EXPRESSION, null); } private Expression parseTypeswitchReturnClause(StructuredQName varQName, LetExpression outerLet) throws XPathException { Expression action; t.treatCurrentAsOperator(); expect(Token.RETURN); nextToken(); LetExpression innerLet = makeLetExpression(); innerLet.setRequiredType(SequenceType.ANY_SEQUENCE); innerLet.setVariableQName(varQName); innerLet.setSequence(new LocalVariableReference(outerLet)); declareRangeVariable(innerLet); action = parseExprSingle(); undeclareRangeVariable(); innerLet.setAction(action); return innerLet; // if (Literal.isEmptySequence(action)) { // // The purpose of simplifying this now is that () is allowed in a branch even in XQuery Update when // // other branches of the typeswitch are updating. // return action; // } else { // return innerLet; // } } /** * Parse a Validate Expression. * This construct is XQuery-only. The syntax allows: * validate mode? { Expr } * mode ::= "strict" | "lax" */ protected Expression parseValidateExpression() throws XPathException { if (!env.getConfiguration().isSchemaAware(Configuration.XQUERY)) { grumble("To use a validate expression, you need the schema-aware processor from http://www.saxonica.com/"); } int offset = t.currentTokenStartOffset; int mode = Validation.STRICT; boolean foundCurly = false; switch (t.currentToken) { case Token.VALIDATE_STRICT: mode = Validation.STRICT; nextToken(); break; case Token.VALIDATE_LAX: mode = Validation.LAX; nextToken(); break; case Token.KEYWORD_CURLY: if (t.currentTokenValue.equals("validate")) { mode = Validation.STRICT; } else { throw new AssertionError("shouldn't be parsing a validate expression"); } foundCurly = true; } if (!foundCurly) { expect(Token.LCURLY); } nextToken(); Expression exp = parseExpression(); if (exp instanceof ElementCreator) { ((ElementCreator)exp).setValidationMode(mode); } else if (exp instanceof DocumentInstr) { ((DocumentInstr)exp).setValidationMode(mode); } else { // the expression must return a single element or document node. The type- // checking machinery can't handle a union type, so we just check that it's // a node for now. Because we are reusing XSLT copy-of code, we need // an ad-hoc check that the node is of the right kind. try { RoleLocator role = new RoleLocator(RoleLocator.TYPE_OP, "validate", 0); role.setErrorCode("XQTY0030"); //role.setSourceLocator(makeLocator()); exp = TypeChecker.staticTypeCheck(exp, SequenceType.SINGLE_NODE, false, role, ExpressionVisitor.make(env)); } catch (XPathException err) { grumble(err.getMessage(), err.getErrorCodeLocalPart()); } exp = new CopyOf(exp, true, mode, null, true); setLocation(exp); ((CopyOf)exp).setRequireDocumentOrElement(true); } expect(Token.RCURLY); t.lookAhead(); // always done manually after an RCURLY nextToken(); return makeTracer(offset, exp, Location.VALIDATE_EXPRESSION, null); } /** * Parse an Extension Expression. * Syntax: "(#" QName arbitrary-text "#)")+ "{" expr? "}" */ protected Expression parseExtensionExpression() throws XPathException { SchemaType requiredType = null; CharSequence trimmed = Whitespace.removeLeadingWhitespace(t.currentTokenValue); int c = 0; int len = trimmed.length(); while (c < len && " \t\r\n".indexOf(trimmed.charAt(c)) < 0) { c++; } String qname = trimmed.subSequence(0, c).toString(); String pragmaContents = ""; while (c < len && " \t\r\n".indexOf(trimmed.charAt(c)) >= 0) { c++; } if (c < len) { pragmaContents = trimmed.subSequence(c, len).toString(); } boolean validateType = false; boolean streaming = false; if (!nameChecker.isQName(qname)) { grumble("First token in pragma must be a valid QName, terminated by whitespace"); } else { int nameCode = makeNameCode(qname, false); String uri = env.getNamePool().getURI(nameCode); if (uri.equals(NamespaceConstant.SAXON)) { String localName = env.getNamePool().getLocalName(nameCode); if (localName.equals("validate-type")) { if (!env.getConfiguration().isSchemaAware(Configuration.XQUERY)) { grumble("To use saxon:validate-type, " + "you need the Saxon-SA processor from http://www.saxonica.com/"); } String typeName = Whitespace.trim(pragmaContents); if (!nameChecker.isQName(typeName)) { grumble("Schema type expected in saxon:validate-type pragma"); } int typeCode = makeNameCode(typeName, true); requiredType = env.getConfiguration().getSchemaType(typeCode & NamePool.FP_MASK); if (requiredType == null) { grumble("Unknown schema type " + typeName); } validateType = true; } else if (localName.equals("stream")) { if (!env.getConfiguration().isSchemaAware(Configuration.XQUERY)) { grumble("To use saxon:stream, " + "you need the Saxon-SA processor from http://www.saxonica.com/"); } streaming = true; } else { grumble("Unrecognized Saxon pragma " + qname); } } else if (uri.length() == 0) { grumble("The QName identifying an option declaration must be prefixed", "XPST0081"); } } nextToken(); Expression expr; if (t.currentToken == Token.PRAGMA) { expr = parseExtensionExpression(); } else { expect(Token.LCURLY); nextToken(); if (t.currentToken == Token.RCURLY) { t.lookAhead(); // always done manually after an RCURLY nextToken(); grumble("Unrecognized pragma, with no fallback expression", "XQST0079"); } expr = parseExpression(); expect(Token.RCURLY); t.lookAhead(); // always done manually after an RCURLY nextToken(); } if (validateType) { if (expr instanceof ElementCreator) { ((ElementCreator)expr).setSchemaType(requiredType); ((ElementCreator)expr).setValidationMode(Validation.BY_TYPE); return expr; } else if (expr instanceof DocumentInstr) { ((DocumentInstr)expr).setSchemaType(requiredType); ((DocumentInstr)expr).setValidationMode(Validation.BY_TYPE); return expr; } else if (expr instanceof AttributeCreator) { if (!(requiredType instanceof SimpleType)) { grumble("The type used for validating an attribute must be a simple type"); } ((AttributeCreator)expr).setSchemaType((SimpleType)requiredType); ((AttributeCreator)expr).setValidationAction(Validation.BY_TYPE); return expr; } else { CopyOf copy = new CopyOf(expr, true, Validation.BY_TYPE, requiredType, true); copy.setLocationId(env.getLocationMap().allocateLocationId(env.getSystemId(), t.getLineNumber())); return copy; } } else if (streaming) { CopyOf copy = new CopyOf(expr, true, Validation.PRESERVE, null, true); copy.setLocationId(env.getLocationMap().allocateLocationId(env.getSystemId(), t.getLineNumber())); copy.setReadOnce(true); return copy; } else { return expr; } } /** * Parse a node constructor. This is allowed only in XQuery. This method handles * both the XML-like "direct" constructors, and the XQuery-based "computed" * constructors. * * @return an Expression for evaluating the parsed constructor * @throws XPathException in the event of a syntax error. */ protected Expression parseConstructor() throws XPathException { int offset = t.currentTokenStartOffset; switch (t.currentToken) { case Token.TAG: Expression tag = parsePseudoXML(false); lookAhead(); t.setState(Tokenizer.OPERATOR_STATE); nextToken(); return tag; case Token.KEYWORD_CURLY: String nodeKind = t.currentTokenValue; if (nodeKind.equals("validate")) { return parseValidateExpression(); } else if (nodeKind.equals("ordered") || nodeKind.equals("unordered")) { // these are currently no-ops in Saxon nextToken(); Expression content = parseExpression(); expect(Token.RCURLY); lookAhead(); // must be done manually after an RCURLY nextToken(); return content; } else if (nodeKind.equals("document")) { nextToken(); Expression content = parseExpression(); expect(Token.RCURLY); lookAhead(); // must be done manually after an RCURLY nextToken(); DocumentInstr doc = new DocumentInstr(false, null, env.getBaseURI()); if (!((QueryModule)env).isPreserveNamespaces()) { content = new CopyOf(content, false, Validation.PRESERVE, null, true); } doc.setValidationMode(((QueryModule)env).getConstructionMode()); doc.setContentExpression(content); setLocation(doc, offset); return doc; } else if ("element".equals(nodeKind)) { nextToken(); // get the expression that yields the element name Expression name = parseExpression(); expect(Token.RCURLY); lookAhead(); // must be done manually after an RCURLY nextToken(); expect(Token.LCURLY); t.setState(Tokenizer.DEFAULT_STATE); nextToken(); Expression content = null; if (t.currentToken != Token.RCURLY) { // get the expression that yields the element content content = parseExpression(); // if the child expression creates another element, // suppress validation, as the parent already takes care of it if (content instanceof ElementCreator) { ((ElementCreator)content).setValidationMode(Validation.PRESERVE); } expect(Token.RCURLY); } lookAhead(); // done manually after an RCURLY nextToken(); Instruction inst; if (name instanceof Literal) { Value vName = ((Literal)name).getValue(); // if element name is supplied as a literal, treat it like a direct element constructor int nameCode; if (vName instanceof StringValue && !(vName instanceof AnyURIValue)) { String lex = vName.getStringValue(); try { nameCode = makeNameCodeSilently(lex, true); } catch (XPathException staticError) { String code = staticError.getErrorCodeLocalPart(); if ("XPST0008".equals(code) || "XPST0081".equals(code)) { staticError.setErrorCode("XQDY0074"); } staticError.setLocator(makeLocator()); throw staticError; } catch (QNameException qerr) { XPathException e = new XPathException("Invalid QName in element constructor: " + lex); e.setErrorCode("XQDY0074"); e.setLocator(makeLocator()); throw e; } } else if (vName instanceof QualifiedNameValue) { String uri = ((QualifiedNameValue)vName).getNamespaceURI(); nameCode = env.getNamePool().allocate("", (uri == null ? "" : uri), ((QualifiedNameValue)vName).getLocalName()); } else { grumble("Element name must be either a string or a QName", "XPTY0004"); return null; } inst = new FixedElement(nameCode, ((QueryModule)env).getActiveNamespaceCodes(), ((QueryModule)env).isInheritNamespaces(), null, ((QueryModule)env).getConstructionMode()); ((FixedElement)inst).setBaseURI(env.getBaseURI()); if (content == null) { content = new Literal(EmptySequence.getInstance()); } ((FixedElement)inst).setContentExpression(content); setLocation(inst, offset); //makeContentConstructor(content, (InstructionWithChildren) inst, offset); return makeTracer(offset, inst, Location.LITERAL_RESULT_ELEMENT, new StructuredQName(env.getNamePool(), nameCode)); } else { // it really is a computed element constructor: save the namespace context NamespaceResolver ns = new NamespaceResolverForElements( env.getNamespaceResolver(), env.getDefaultElementNamespace()); inst = new ComputedElement(name, null, ns, null, ((QueryModule)env).getConstructionMode(), ((QueryModule)env).isInheritNamespaces(), true); setLocation(inst); if (content == null) { content = new Literal(EmptySequence.getInstance()); } ((ComputedElement)inst).setContentExpression(content); setLocation(inst, offset); //makeContentConstructor(content, (InstructionWithChildren) inst, offset); return makeTracer(offset, inst, StandardNames.XSL_ELEMENT, null); } } else if ("attribute".equals(nodeKind)) { nextToken(); Expression name = parseExpression(); expect(Token.RCURLY); lookAhead(); // must be done manually after an RCURLY nextToken(); expect(Token.LCURLY); t.setState(Tokenizer.DEFAULT_STATE); nextToken(); Expression content = null; if (t.currentToken != Token.RCURLY) { content = parseExpression(); expect(Token.RCURLY); } lookAhead(); // after an RCURLY nextToken(); if (name instanceof Literal) { Value vName = ((Literal)name).getValue(); if (vName instanceof StringValue && !(vName instanceof AnyURIValue)) { String lex = vName.getStringValue(); if (lex.equals("xmlns") || lex.startsWith("xmlns:")) { grumble("Cannot create a namespace using an attribute constructor", "XQDY0044"); } int nameCode; // prevalidate the name before calling makeNameCode, because we want different // error behaviour // try { // nameChecker.getQNameParts(lex); // } catch (QNameException err) { // XPathException e = new XPathException("Invalid QName in attribute constructor: " + lex); // e.setErrorCode("XQDY0074"); // return new ErrorExpression(e); // } try { nameCode = makeNameCodeSilently(lex, false); } catch (XPathException staticError) { String code = staticError.getErrorCodeLocalPart(); staticError.setLocator(makeLocator()); if ("XPST0008".equals(code) || "XPST0081".equals(code)) { staticError.setErrorCode("XQDY0074"); } throw staticError; } catch (QNameException err) { XPathException e = new XPathException("Invalid QName in attribute constructor: " + lex); e.setErrorCode("XQDY0074"); e.setLocator(makeLocator()); throw e; } FixedAttribute fatt = new FixedAttribute(nameCode, Validation.STRIP, null, StandardNames.XS_UNTYPED_ATOMIC); fatt.setRejectDuplicates(); makeSimpleContent(content, fatt, offset); return makeTracer(offset, fatt, StandardNames.XSL_ATTRIBUTE, null); } else if (vName instanceof QNameValue) { QNameValue qnv = (QNameValue)vName; int nameCode = env.getNamePool().allocate( qnv.getPrefix(), qnv.getNamespaceURI(), qnv.getLocalName()); FixedAttribute fatt = new FixedAttribute(nameCode, Validation.STRIP, null, StandardNames.XS_UNTYPED_ATOMIC); fatt.setRejectDuplicates(); makeSimpleContent(content, fatt, offset); return makeTracer(offset, fatt, StandardNames.XSL_ATTRIBUTE, null); } } ComputedAttribute att = new ComputedAttribute(name, null, env.getNamespaceResolver(), Validation.STRIP, null, -1, true); att.setRejectDuplicates(); makeSimpleContent(content, att, offset); return makeTracer(offset, att, StandardNames.XSL_ATTRIBUTE, null); } else if ("text".equals(nodeKind)) { nextToken(); Expression value = parseExpression(); expect(Token.RCURLY); lookAhead(); // after an RCURLY nextToken(); Expression select = stringify(value, true); ValueOf vof = new ValueOf(select, false, true); setLocation(vof, offset); return makeTracer(offset, vof, StandardNames.XSL_TEXT, null); } else if ("comment".equals(nodeKind)) { nextToken(); Expression value = parseExpression(); expect(Token.RCURLY); lookAhead(); // after an RCURLY nextToken(); Comment com = new Comment(); makeSimpleContent(value, com, offset); return makeTracer(offset, com, StandardNames.XSL_COMMENT, null); } else if ("processing-instruction".equals(nodeKind)) { nextToken(); Expression name = parseExpression(); expect(Token.RCURLY); lookAhead(); // must be done manually after an RCURLY nextToken(); expect(Token.LCURLY); t.setState(Tokenizer.DEFAULT_STATE); nextToken(); Expression content = null; if (t.currentToken != Token.RCURLY) { content = parseExpression(); expect(Token.RCURLY); } lookAhead(); // after an RCURLY nextToken(); ProcessingInstruction pi = new ProcessingInstruction(name); makeSimpleContent(content, pi, offset); return makeTracer(offset, pi, StandardNames.XSL_PROCESSING_INSTRUCTION, null); } else { grumble("Unrecognized node constructor " + t.currentTokenValue + "{}"); } case Token.ELEMENT_QNAME: int nameCode = makeNameCode(t.currentTokenValue, true); Expression content = null; nextToken(); if (t.currentToken != Token.RCURLY) { content = parseExpression(); expect(Token.RCURLY); } lookAhead(); // after an RCURLY nextToken(); FixedElement el2 = new FixedElement(nameCode, ((QueryModule)env).getActiveNamespaceCodes(), ((QueryModule)env).isInheritNamespaces(), null, ((QueryModule)env).getConstructionMode()); el2.setBaseURI(env.getBaseURI()); setLocation(el2, offset); if (content == null) { content = new Literal(EmptySequence.getInstance()); } el2.setContentExpression(content); //makeContentConstructor(content, el2, offset); return makeTracer(offset, el2, Location.LITERAL_RESULT_ELEMENT, new StructuredQName(env.getNamePool(), nameCode)); case Token.ATTRIBUTE_QNAME: if (t.currentTokenValue.equals("xmlns") || t.currentTokenValue.startsWith("xmlns:")) { grumble("Cannot create a namespace using an attribute constructor", "XQDY0044"); } int attNameCode = makeNameCode(t.currentTokenValue, false); Expression attContent = null; nextToken(); if (t.currentToken != Token.RCURLY) { attContent = parseExpression(); expect(Token.RCURLY); } lookAhead(); // after an RCURLY nextToken(); FixedAttribute att2 = new FixedAttribute(attNameCode, Validation.STRIP, null, StandardNames.XS_UNTYPED_ATOMIC); att2.setRejectDuplicates(); makeSimpleContent(attContent, att2, offset); return makeTracer(offset, att2, Location.LITERAL_RESULT_ATTRIBUTE, new StructuredQName(env.getNamePool(), attNameCode)); case Token.PI_QNAME: String target = t.currentTokenValue; if (target.equalsIgnoreCase("xml")) { grumble("A processing instruction must not be named 'xml' in any combination of upper and lower case", "XQDY0064"); } if (!nameChecker.isValidNCName(target)) { grumble("Invalid processing instruction name " + Err.wrap(target)); } Expression piName = new StringLiteral(target); Expression piContent = null; nextToken(); if (t.currentToken != Token.RCURLY) { piContent = parseExpression(); expect(Token.RCURLY); } lookAhead(); // after an RCURLY nextToken(); ProcessingInstruction pi2 = new ProcessingInstruction(piName); makeSimpleContent(piContent, pi2, offset); return makeTracer(offset, pi2, StandardNames.XSL_PROCESSING_INSTRUCTION, null); } return null; } /** * Make the instructions for the children of a node with simple content (attribute, text, PI, etc) * * @param content the expression making up the simple content * @param inst the skeletal instruction for creating the node * @param offset the character position of this construct within the source query */ private void makeSimpleContent(Expression content, SimpleNodeConstructor inst, int offset) throws XPathException { try { if (content == null) { inst.setSelect(new StringLiteral(StringValue.EMPTY_STRING), env.getConfiguration()); } else { inst.setSelect(stringify(content, false), env.getConfiguration()); } setLocation(inst, offset); } catch (XPathException e) { grumble(e.getMessage()); } } /** * Make a sequence of instructions as the children of an element-construction instruction. * The idea here is to convert an XPath expression that "pulls" the content into a sequence * of XSLT-style instructions that push nodes directly onto the subtree, thus reducing the * need for copying of intermediate nodes. * @param content The content of the element as an expression * @param inst The element-construction instruction (Element or FixedElement) * @param offset the character position in the query */ // private void makeContentConstructor(Expression content, InstructionWithChildren inst, int offset) { // if (content == null) { // inst.setChildren(null); // } else if (content instanceof AppendExpression) { // List instructions = new ArrayList(10); // convertAppendExpression((AppendExpression) content, instructions); // inst.setChildren((Expression[]) instructions.toArray(new Expression[instructions.size()])); // } else { // Expression children[] = {content}; // inst.setChildren(children); // } // setLocation(inst, offset); // } /** * Parse pseudo-XML syntax in direct element constructors, comments, CDATA, etc. * This is handled by reading single characters from the Tokenizer until the * end of the tag (or an enclosed expression) is enountered. * This method is also used to read an end tag. Because an end tag is not an * expression, the method in this case returns a StringValue containing the * contents of the end tag. * * @param allowEndTag true if the context allows an End Tag to appear here * @return an Expression representing the result of parsing the constructor. * If an end tag was read, its contents will be returned as a StringValue. */ private Expression parsePseudoXML(boolean allowEndTag) throws XPathException { try { Expression exp = null; int offset = t.inputOffset; // we're reading raw characters, so we don't want the currentTokenStartOffset char c = t.nextChar(); switch (c) { case '!': c = t.nextChar(); if (c == '-') { exp = parseCommentConstructor(); } else if (c == '[') { grumble("A CDATA section is allowed only in element content"); // if CDATA were allowed here, we would have already read it } else { grumble("Expected '--' or '[CDATA[' after '') { break; } sb.append(c); } return new StringLiteral(new StringValue(sb)); } grumble("Unmatched XML end tag"); break; default: t.unreadChar(); exp = parseDirectElementConstructor(); } setLocation(exp, offset); return exp; } catch (StringIndexOutOfBoundsException e) { grumble("End of input encountered while parsing direct constructor"); return null; } } /** * Parse a direct element constructor * * @return the expression representing the constructor * @throws XPathException * @throws StringIndexOutOfBoundsException if the end of input is encountered prematurely */ private Expression parseDirectElementConstructor() throws XPathException, StringIndexOutOfBoundsException { int offset = t.inputOffset - 1; // we're reading raw characters, so we don't want the currentTokenStartOffset char c; FastStringBuffer buff = new FastStringBuffer(40); int namespaceCount = 0; while (true) { c = t.nextChar(); if (c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == '/' || c == '>') { break; } buff.append(c); } String elname = buff.toString(); HashMap attributes = new HashMap(10); while (true) { // loop through the attributes // We must process namespace declaration attributes first; // their scope applies to all preceding attribute names and values. // But finding the delimiting quote of an attribute value requires the // XPath expressions to be parsed, because they may contain nested quotes. // So we parse in "scanOnly" mode, which ignores any undeclared namespace // prefixes, use the result of this parse to determine the length of the // attribute value, save the value, and reparse it when all the namespace // declarations have been dealt with. c = skipSpaces(c); if (c == '/' || c == '>') { break; } int attOffset = t.inputOffset - 1; buff.setLength(0); // read the attribute name while (true) { buff.append(c); c = t.nextChar(); if (c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == '=') { break; } } String attName = buff.toString(); if (!nameChecker.isQName(attName)) { grumble("Invalid attribute name " + Err.wrap(attName, Err.ATTRIBUTE)); } c = skipSpaces(c); expectChar(c, '='); c = t.nextChar(); c = skipSpaces(c); char delim = c; boolean isNamespace = ("xmlns".equals(attName) || attName.startsWith("xmlns:")); int end; if (isNamespace) { end = makeNamespaceContent(t.input, t.inputOffset, delim); } else { Expression avt; try { avt = makeAttributeContent(t.input, t.inputOffset, delim, true); } catch (XPathException err) { grumble(err.getMessage()); return null; } // by convention, this returns the end position when called with scanOnly set end = (int)((Int64Value)((Literal)avt).getValue()).longValue(); } // save the value with its surrounding quotes String val = t.input.substring(t.inputOffset - 1, end + 1); // and without String rval = t.input.substring(t.inputOffset, end); t.inputOffset = end + 1; // on return, the current character is the closing quote c = t.nextChar(); if (!(c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == '/' || c == '>')) { grumble("There must be whitespace after every attribute except the last"); } if (isNamespace) { // Processing follows the resolution of bug 5083: doubled curly braces represent single // curly braces, single curly braces are not allowed. FastStringBuffer sb = new FastStringBuffer(rval.length()); boolean prevDelim = false; boolean prevOpenCurly = false; boolean prevCloseCurly = false; for (int i=0; i'); } else { readElementContent(elname, contents); } Expression[] elk = new Expression[contents.size()]; for (int i = 0; i < contents.size(); i++) { // if the child expression creates another element, // suppress validation, as the parent already takes care of it if (validationMode != Validation.STRIP) { ((Expression)contents.get(i)).suppressValidation(validationMode); } elk[i] = (Expression)contents.get(i); } Block block = new Block(); block.setChildren(elk); elInst.setContentExpression(block); // reset the in-scope namespaces to what they were before for (int n = 0; n < namespaceCount; n++) { ((QueryModule)env).undeclareNamespace(); } return makeTracer(offset, elInst, Location.LITERAL_RESULT_ELEMENT, new StructuredQName(env.getNamePool(), elNameCode)); } /** * Parse the content of an attribute in a direct element constructor. This may contain nested expressions * within curly braces. A particular problem is that the namespaces used in the expression may not yet be * known. This means we need the ability to parse in "scanOnly" mode, where undeclared namespace prefixes * are ignored. *

    * The code is based on the XSLT code in {@link AttributeValueTemplate#make}: the main difference is that * character entities and built-in entity references need to be recognized and expanded. Also, whitespace * needs to be normalized, mimicking the action of an XML parser * * @param avt the content of the attribute as written, including variable portions enclosed in curly braces * @param start the character position in the attribute value where parsing should start * @param terminator a character that is to be taken as marking the end of the expression * @param scanOnly if the purpose of this parse is simply to locate the end of the attribute value, and not * to report any semantic errors. * @return the expression that will evaluate the content of the attribute */ private Expression makeAttributeContent(String avt, int start, char terminator, boolean scanOnly) throws XPathException { int lineNumber = t.getLineNumber(); List components = new ArrayList(10); int i0, i1, i2, i8, i9, len, last; last = start; len = avt.length(); while (last < len) { i2 = avt.indexOf(terminator, last); if (i2 < 0) { XPathException e = new XPathException("Attribute constructor is not properly terminated"); e.setIsStaticError(true); throw e; } i0 = avt.indexOf("{", last); i1 = avt.indexOf("{{", last); i8 = avt.indexOf("}", last); i9 = avt.indexOf("}}", last); if ((i0 < 0 || i2 < i0) && (i8 < 0 || i2 < i8)) { // found end of string addStringComponent(components, avt, last, i2); // look for doubled quotes, and skip them (for now) if (i2 + 1 < avt.length() && avt.charAt(i2 + 1) == terminator) { components.add(new StringLiteral(terminator + "")); last = i2 + 2; //continue; } else { last = i2; break; } } else if (i8 >= 0 && (i0 < 0 || i8 < i0)) { // found a "}" if (i8 != i9) { // a "}" that isn't a "}}" XPathException e = new XPathException( "Closing curly brace in attribute value template \"" + avt + "\" must be doubled"); e.setIsStaticError(true); throw e; } addStringComponent(components, avt, last, i8 + 1); last = i8 + 2; } else if (i1 >= 0 && i1 == i0) { // found a doubled "{{" addStringComponent(components, avt, last, i1 + 1); last = i1 + 2; } else if (i0 >= 0) { // found a single "{" if (i0 > last) { addStringComponent(components, avt, last, i0); } Expression exp; ExpressionParser parser; parser = new QueryParser(); parser.setScanOnly(scanOnly); if (rangeVariables != null) { parser.setRangeVariableStack(rangeVariables); } exp = parser.parse(avt, i0 + 1, Token.RCURLY, lineNumber, env); if (!scanOnly) { exp = ExpressionVisitor.make(env).simplify(exp); } last = parser.getTokenizer().currentTokenStartOffset + 1; components.add(makeStringJoin(exp, env)); } else { throw new IllegalStateException("Internal error parsing direct attribute constructor"); } } // if this is simply a prescan, return the position of the end of the // AVT, so we can parse it properly later if (scanOnly) { return new Literal(Int64Value.makeIntegerValue(last)); } // is it empty? if (components.isEmpty()) { return new StringLiteral(StringValue.EMPTY_STRING); } // is it a single component? if (components.size() == 1) { return ExpressionVisitor.make(env).simplify((Expression)components.get(0)); } // otherwise, return an expression that concatenates the components Expression[] args = new Expression[components.size()]; components.toArray(args); Concat fn = (Concat)SystemFunction.makeSystemFunction("concat", args); fn.setLocationId(env.getLocationMap().allocateLocationId(env.getSystemId(), lineNumber)); return ExpressionVisitor.make(env).simplify(fn); } private void addStringComponent(List components, String avt, int start, int end) throws XPathException { // analyze fixed text within the value of a direct attribute constructor. if (start < end) { FastStringBuffer sb = new FastStringBuffer(end - start); for (int i = start; i < end; i++) { char c = avt.charAt(i); switch (c) { case '&': { int semic = avt.indexOf(';', i); if (semic < 0) { grumble("No closing ';' found for entity or character reference"); } else { String entity = avt.substring(i + 1, semic); sb.append(analyzeEntityReference(entity)); i = semic; } break; } case '<': grumble("The < character must not appear in attribute content"); break; case '\n': case '\t': sb.append(' '); break; case '\r': sb.append(' '); if (i + 1 < end && avt.charAt(i + 1) == '\n') { i++; } break; default: sb.append(c); } } components.add(new StringLiteral(sb.toString())); } } /** * Parse the content of an namespace declaration attribute in a direct element constructor. This is simpler * than an ordinary attribute because it does not contain nested expressions in curly braces. (But see bug 5083). * * @param avt the content of the attribute as written, including variable portions enclosed in curly braces * @param start the character position in the attribute value where parsing should start * @param terminator a character that is to be taken as marking the end of the expression * @return the position of the end of the URI value */ private int makeNamespaceContent(String avt, int start, char terminator) throws XPathException { int i2, len, last; last = start; len = avt.length(); while (last < len) { i2 = avt.indexOf(terminator, last); if (i2 < 0) { XPathException e = new XPathException("Namespace declaration is not properly terminated"); e.setIsStaticError(true); throw e; } // look for doubled quotes, and skip them (for now) if (i2 + 1 < avt.length() && avt.charAt(i2 + 1) == terminator) { last = i2 + 2; //continue; } else { last = i2; break; } } // return the position of the end of the literal return last; } /** * Read the content of a direct element constructor * * @param startTag the element start tag * @param components an empty list, to which the expressions comprising the element contents are added * @throws XPathException if any static errors are detected */ private void readElementContent(String startTag, List components) throws XPathException { final TypeHierarchy th = env.getConfiguration().getTypeHierarchy(); try { boolean afterEnclosedExpr = false; while (true) { // read all the components of the element value FastStringBuffer text = new FastStringBuffer(256); char c; boolean containsEntities = false; while (true) { c = t.nextChar(); if (c == '<') { // See if we've got a CDATA section if (t.nextChar() == '!') { if (t.nextChar() == '[') { readCDATASection(text); containsEntities = true; continue; } else { t.unreadChar(); t.unreadChar(); } } else { t.unreadChar(); } break; } else if (c == '&') { text.append(readEntityReference()); containsEntities = true; } else if (c == '}') { c = t.nextChar(); if (c != '}') { grumble("'}' must be written as '}}' within element content"); } text.append(c); } else if (c == '{') { c = t.nextChar(); if (c != '{') { c = '{'; break; } text.append(c); } else { text.append(c); } } if (text.length() > 0 && (containsEntities | ((QueryModule)env).isPreserveBoundarySpace() | !Whitespace.isWhite(text))) { ValueOf inst = new ValueOf(new StringLiteral(new StringValue(text.condense())), false, false); setLocation(inst); components.add(inst); afterEnclosedExpr = false; } if (c == '<') { Expression exp = parsePseudoXML(true); // An end tag can appear here, and is returned as a string value if (exp instanceof StringLiteral) { String endTag = ((StringLiteral)exp).getStringValue(); if (Whitespace.isWhitespace(endTag.charAt(0))) { grumble("End tag contains whitespace before the name"); } endTag = Whitespace.trim(endTag); if (endTag.equals(startTag)) { return; } else { grumble("End tag does not match start tag <" + startTag + '>'); } } else { components.add(exp); } } else { // we read an '{' indicating an enclosed expression if (afterEnclosedExpr) { Expression previousComponent = (Expression)components.get(components.size() - 1); ItemType previousItemType = previousComponent.getItemType(th); if (!(previousItemType instanceof NodeTest)) { // Add a zero-length text node, to prevent {"a"}{"b"} generating an intervening space // See tests (qxmp132, qxmp261) ValueOf inst = new ValueOf(new StringLiteral(StringValue.EMPTY_STRING), false, false); setLocation(inst); components.add(inst); } } t.unreadChar(); t.setState(Tokenizer.DEFAULT_STATE); lookAhead(); nextToken(); Expression exp = parseExpression(); if (!((QueryModule)env).isPreserveNamespaces()) { exp = new CopyOf(exp, false, Validation.PRESERVE, null, true); } components.add(exp); expect(Token.RCURLY); afterEnclosedExpr = true; } } } catch (StringIndexOutOfBoundsException err) { grumble("No closing end tag found for direct element constructor"); } } private Expression parsePIConstructor() throws XPathException { try { FastStringBuffer pi = new FastStringBuffer(120); int firstSpace = -1; while (!pi.toString().endsWith("?>")) { char c = t.nextChar(); if (firstSpace < 0 && " \t\r\n".indexOf(c) >= 0) { firstSpace = pi.length(); } pi.append(c); } pi.setLength(pi.length() - 2); String target; String data = ""; if (firstSpace < 0) { // there is no data part target = pi.toString(); } else { // trim leading space from the data part, but not trailing space target = pi.toString().substring(0, firstSpace); firstSpace++; while (firstSpace < pi.length() && " \t\r\n".indexOf(pi.charAt(firstSpace)) >= 0) { firstSpace++; } data = pi.toString().substring(firstSpace); } if (!nameChecker.isValidNCName(target)) { grumble("Invalid processing instruction name " + Err.wrap(target)); } if (target.equalsIgnoreCase("xml")) { grumble("A processing instruction must not be named 'xml' in any combination of upper and lower case"); } ProcessingInstruction instruction = new ProcessingInstruction(new StringLiteral(target)); instruction.setSelect(new StringLiteral(data), env.getConfiguration()); setLocation(instruction); return instruction; } catch (StringIndexOutOfBoundsException err) { grumble("No closing '?>' found for processing instruction"); return null; } } private void readCDATASection(FastStringBuffer cdata) throws XPathException { try { char c; // CDATA section c = t.nextChar(); expectChar(c, 'C'); c = t.nextChar(); expectChar(c, 'D'); c = t.nextChar(); expectChar(c, 'A'); c = t.nextChar(); expectChar(c, 'T'); c = t.nextChar(); expectChar(c, 'A'); c = t.nextChar(); expectChar(c, '['); while (!cdata.toString().endsWith("]]>")) { cdata.append(t.nextChar()); } cdata.setLength(cdata.length() - 3); } catch (StringIndexOutOfBoundsException err) { grumble("No closing ']]>' found for CDATA section"); } } private Expression parseCommentConstructor() throws XPathException { try { char c = t.nextChar(); // XML-like comment expectChar(c, '-'); FastStringBuffer comment = new FastStringBuffer(240); while (!comment.toString().endsWith("--")) { comment.append(t.nextChar()); } if (t.nextChar() != '>') { grumble("'--' is not permitted in an XML comment"); } CharSequence commentText = comment.subSequence(0, comment.length() - 2); Comment instruction = new Comment(); instruction.setSelect(new StringLiteral(new StringValue(commentText)), env.getConfiguration()); setLocation(instruction); return instruction; } catch (StringIndexOutOfBoundsException err) { grumble("No closing '-->' found for comment constructor"); return null; } } /** * Convert an expression so it generates a space-separated sequence of strings * * @param exp the expression that calculates the content * @param noNodeIfEmpty if true, no node is produced when the value of the content * expression is an empty sequence. If false, the effect of supplying an empty sequence * is that a node is created whose string-value is a zero-length string. Set to true for * text node constructors, false for other kinds of node. * @return an expression that computes the content and converts the result to a character string */ private Expression stringify(Expression exp, boolean noNodeIfEmpty) throws XPathException { return ExpressionVisitor.make(env).simplify(new QuerySimpleContentConstructor( exp, new StringLiteral(StringValue.SINGLE_SPACE), noNodeIfEmpty)); } /** * Method to make a string literal from a token identified as a string * literal. This is trivial in XPath, but in XQuery the method is overridden * to identify pseudo-XML character and entity references * * @param token the string as written (or as returned by the tokenizer) * @return The string value of the string literal, after dereferencing entity and * character references */ protected Literal makeStringLiteral(String token) throws XPathException { StringLiteral lit; if (token.indexOf('&') == -1) { lit = new StringLiteral(token); } else { FastStringBuffer sb = unescape(token); lit = new StringLiteral(StringValue.makeStringValue(sb)); } setLocation(lit); return lit; } /** * Unescape character references and built-in entity references in a string * * @param token the input string, which may include XML-style character references or built-in * entity references * @return the string with character references and built-in entity references replaced by their expansion * @throws XPathException if a malformed character or entity reference is found */ private FastStringBuffer unescape(String token) throws XPathException { FastStringBuffer sb = new FastStringBuffer(80); for (int i = 0; i < token.length(); i++) { char c = token.charAt(i); if (c == '&') { int semic = token.indexOf(';', i); if (semic < 0) { grumble("No closing ';' found for entity or character reference"); } else { String entity = token.substring(i + 1, semic); sb.append(analyzeEntityReference(entity)); i = semic; } } else { sb.append(c); } } return sb; } /** * Read a pseudo-XML character reference or entity reference. * * @return The character represented by the character or entity reference. Note * that this is a string rather than a char because a char only accommodates characters * up to 65535. * @throws XPathException if the character or entity reference is not well-formed */ private String readEntityReference() throws XPathException { try { FastStringBuffer sb = new FastStringBuffer(40); while (true) { char c = t.nextChar(); if (c == ';') { break; } sb.append(c); } String entity = sb.toString(); return analyzeEntityReference(entity); } catch (StringIndexOutOfBoundsException err) { grumble("No closing ';' found for entity or character reference"); } return null; // to keep the Java compiler happy } private String analyzeEntityReference(String entity) throws XPathException { if ("lt".equals(entity)) { return "<"; } else if ("gt".equals(entity)) { return ">"; } else if ("amp".equals(entity)) { return "&"; } else if ("quot".equals(entity)) { return "\""; } else if ("apos".equals(entity)) { return "'"; } else if (entity.length() < 2 || entity.charAt(0) != '#') { grumble("invalid character reference &" + entity + ';'); return null; } else { //entity = entity.toLowerCase(); return parseCharacterReference(entity); } } private String parseCharacterReference(String entity) throws XPathException { int value = 0; if (entity.charAt(1) == 'x') { if (entity.length() < 3) { grumble("No hex digits in hexadecimal character reference"); } entity = entity.toLowerCase(); for (int i = 2; i < entity.length(); i++) { int digit = "0123456789abcdef".indexOf(entity.charAt(i)); if (digit < 0) { grumble("Invalid hex digit '" + entity.charAt(i) + "' in character reference"); } value = (value * 16) + digit; if (value > UTF16.NONBMP_MAX) { grumble("Character reference exceeds Unicode codepoint limit", "XQST0090"); } } } else { for (int i = 1; i < entity.length(); i++) { int digit = "0123456789".indexOf(entity.charAt(i)); if (digit < 0) { grumble("Invalid digit '" + entity.charAt(i) + "' in decimal character reference"); } value = (value * 10) + digit; if (value > UTF16.NONBMP_MAX) { grumble("Character reference exceeds Unicode codepoint limit", "XQST0090"); } } } NameChecker nc = env.getConfiguration().getNameChecker(); if (!nc.isValidChar(value)) { grumble("Invalid XML character reference x" + Integer.toHexString(value), "XQST0090"); } // following code borrowed from AElfred // Check for surrogates: 00000000 0000xxxx yyyyyyyy zzzzzzzz // (1101|10xx|xxyy|yyyy + 1101|11yy|zzzz|zzzz: if (value <= 0x0000ffff) { // no surrogates needed return "" + (char)value; } else if (value <= 0x0010ffff) { value -= 0x10000; // > 16 bits, surrogate needed return "" + ((char)(0xd800 | (value >> 10))) + ((char)(0xdc00 | (value & 0x0003ff))); } else { // too big for surrogate grumble("Character reference x" + Integer.toHexString(value) + " is too large", "XQST0090"); } return null; } /** * Handle a URI literal. This is whitespace-normalized as well as being unescaped * @param in the string as written * @return the URI after unescaping of entity and character references * followed by whitespace normalization */ private String URILiteral(String in) throws XPathException { return Whitespace.applyWhitespaceNormalization(Whitespace.COLLAPSE, unescape(in)).toString(); } /** * Lookahead one token, catching any exception thrown by the tokenizer. This * method is only called from the query parser when switching from character-at-a-time * mode to tokenizing mode */ private void lookAhead() throws XPathException { try { t.lookAhead(); } catch (XPathException err) { grumble(err.getMessage()); } } /** * Skip whitespace. * * @param c the current character * @return the first character after any whitespace * @throws StringIndexOutOfBoundsException if the end of input is encountered */ private char skipSpaces(char c) throws StringIndexOutOfBoundsException { while (c == ' ' || c == '\n' || c == '\r' || c == '\t') { c = t.nextChar(); } return c; } /** * Test whether the current character is the expected character. * * @param actual The character that was read * @param expected The character that was expected * @throws XPathException if they are different */ private void expectChar(char actual, char expected) throws XPathException { if (actual != expected) { grumble("Expected '" + expected + "', found '" + actual + '\''); } } /** * Get the current language (XPath or XQuery) */ protected String getLanguage() { return "XQuery"; } private static class AttributeDetails { String value; int startOffset; } private static class Import { String namespaceURI; List locationURIs; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/query/StandardModuleURIResolver.java0000644000175000017500000001664011033112257024426 0ustar eugeneeugenepackage net.sf.saxon.query; import net.sf.saxon.Configuration; import net.sf.saxon.Platform; import net.sf.saxon.trans.XPathException; import javax.xml.transform.stream.StreamSource; import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.net.URLConnection; /** * This class is the standard ModuleURIResolver used to implement the "import module" declaration * in a Query Prolog. It is used when no user-defined ModuleURIResolver has been specified, or when * the user-defined ModuleURIResolver decides to delegate to the standard ModuleURIResolver. * * @author Michael H. Kay */ public class StandardModuleURIResolver implements ModuleURIResolver { private static StandardModuleURIResolver THE_INSTANCE = new StandardModuleURIResolver(); /** * Get the singular instance of this class * @return the singular instance of this class */ public static StandardModuleURIResolver getInstance() { return THE_INSTANCE; } /** * Create a StandardModuleURIResolver */ protected StandardModuleURIResolver() { } /** * Resolve a module URI and associated location hints. * @param moduleURI The module namespace URI of the module to be imported; or null when * loading a non-library module. * @param baseURI The base URI of the module containing the "import module" declaration; * null if no base URI is known * @param locations The set of URIs specified in the "at" clause of "import module", * which serve as location hints for the module * @return an array of StreamSource objects each identifying the contents of a module to be * imported. Each StreamSource must contain a * non-null absolute System ID which will be used as the base URI of the imported module, * and either an InputSource or a Reader representing the text of the module. * @throws XPathException (error XQST0059) if the module cannot be located */ public StreamSource[] resolve(String moduleURI, String baseURI, String[] locations) throws XPathException { if (locations.length == 0) { XPathException err = new XPathException("Cannot locate module for namespace " + moduleURI); err.setErrorCode("XQST0059"); err.setIsStaticError(true); throw err; } else { // One or more locations given: import modules from all these locations Platform platform = Configuration.getPlatform(); StreamSource[] sources = new StreamSource[locations.length]; for (int m=0; m=0) { pos = contentType.indexOf('=', pos + 7); if (pos>=0) { contentType = contentType.substring(pos + 1); } if ((pos = contentType.indexOf(';')) > 0) { contentType = contentType.substring(0, pos); } // attributes can have comment fields (RFC 822) if ((pos = contentType.indexOf('(')) > 0) { contentType = contentType.substring(0, pos); } // ... and values may be quoted if ((pos = contentType.indexOf('"')) > 0) { contentType = contentType.substring(pos + 1, contentType.indexOf('"', pos + 2)); } encoding = contentType.trim(); } } } StreamSource ss = new StreamSource(); if (encoding == null) { ss.setInputStream(is); } else { ss.setReader(new InputStreamReader(is, encoding)); } ss.setSystemId(absoluteURL.toString()); return ss; } catch (IOException err) { XPathException se = new XPathException(err); se.setErrorCode("XQST0059"); se.setIsStaticError(true); throw se; } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/query/QueryModule.java0000644000175000017500000020574711055524115021705 0ustar eugeneeugenepackage net.sf.saxon.query; import net.sf.saxon.Configuration; import net.sf.saxon.Platform; import net.sf.saxon.expr.*; import net.sf.saxon.functions.ConstructorFunctionLibrary; import net.sf.saxon.functions.FunctionLibrary; import net.sf.saxon.functions.FunctionLibraryList; import net.sf.saxon.functions.SystemFunctionLibrary; import net.sf.saxon.instruct.*; import net.sf.saxon.om.*; import net.sf.saxon.pattern.CombinedNodeTest; import net.sf.saxon.pattern.ContentTypeTest; import net.sf.saxon.pattern.NodeTest; import net.sf.saxon.sort.IntArraySet; import net.sf.saxon.sort.StringCollator; import net.sf.saxon.trace.ExpressionPresenter; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.*; import net.sf.saxon.value.SequenceType; import javax.xml.transform.SourceLocator; import javax.xml.transform.TransformerException; import java.net.URI; import java.net.URISyntaxException; import java.util.*; /** * This class represents a query module, and includes information about the static context of the query module. * The class is intended for internal Saxon use. User settings that affect the static context are made in the * StaticQueryContext object, and those settings are copied to each QueryModule when the query module is compiled. */ public class QueryModule implements StaticContext { private boolean isMainModule; private Configuration config; private StaticQueryContext userQueryContext; private QueryModule topModule; private URI locationURI; private String baseURI; private String moduleNamespace; private short moduleNamespaceURICode; private HashMap explicitPrologNamespaces; private Stack activeNamespaces; private HashMap variables; // global variables declared in this module private HashMap libraryVariables; // all global variables defined in library modules // defined only on the top-level module private HashMap undeclaredVariables; private HashSet importedSchemata; // The schema target namespaces imported into this module private HashMap loadedSchemata; // For the top-level module only, all imported schemas for all modules, // Key is the targetNamespace, value is the set of absolutized location URIs private Executable executable; private List importers; // A list of QueryModule objects representing the modules that import this one, // Null for the main module // This is needed *only* to implement the rules banning cyclic imports private FunctionLibraryList functionLibraryList; private XQueryFunctionLibrary globalFunctionLibrary; // used only on a top-level module private int localFunctionLibraryNr; private int importedFunctionLibraryNr; private int unboundFunctionLibraryNr; private Set importedModuleNamespaces; private boolean inheritNamespaces = true; private boolean preserveNamespaces = true; private int constructionMode = Validation.PRESERVE; private String defaultFunctionNamespace; private String defaultElementNamespace; private boolean preserveSpace = false; private boolean defaultEmptyLeast = true; private String defaultCollationName; private int revalidationMode = Validation.SKIP; private boolean isUpdating = false; /** * Create a QueryModule for a main module, copying the data that has been set up in a * StaticQueryContext object * @param sqc the StaticQueryContext object from which this module is initialized */ public QueryModule(StaticQueryContext sqc) throws XPathException { config = sqc.getConfiguration(); isMainModule = true; topModule = this; activeNamespaces = new Stack(); baseURI = sqc.getBaseURI(); try { locationURI = (baseURI == null ? null : new URI(baseURI)); } catch (URISyntaxException err) { throw new XPathException("Invalid location URI: " + baseURI); } executable = null; importers = null; init(sqc); resetFunctionLibraries(); for (Iterator vars = sqc.iterateDeclaredGlobalVariables(); vars.hasNext(); ) { GlobalVariableDefinition var = (GlobalVariableDefinition)vars.next(); declareVariable(var); } } /** * Create a QueryModule for a library module. * @param config the Saxon configuration * @param importer the module that imported this module. This may be null, in the case where * the library module is being imported into an XSLT stylesheet */ public QueryModule(Configuration config, QueryModule importer) { this.config = config; importers = null; if (importer == null) { topModule = this; } else { topModule = importer.topModule; userQueryContext = importer.userQueryContext; importers = new ArrayList(2); importers.add(importer); } init(userQueryContext); activeNamespaces = new Stack(); executable = null; } /** * Initialize data from a user-supplied StaticQueryContext object * @param sqc the user-supplied StaticQueryContext. Null if this is a library module imported * into XSLT. */ private void init(StaticQueryContext sqc) { //reset(); userQueryContext = sqc; variables = new HashMap(10); undeclaredVariables = new HashMap(5); if (isTopLevelModule()) { libraryVariables = new HashMap(10); } importedSchemata = null; importedModuleNamespaces = new HashSet(5); moduleNamespace = null; moduleNamespaceURICode = 0; activeNamespaces = new Stack(); resetFunctionLibraries(); explicitPrologNamespaces = new HashMap(10); if (sqc != null) { executable = sqc.getExecutable(); inheritNamespaces = sqc.isInheritNamespaces(); preserveNamespaces = sqc.isPreserveNamespaces(); preserveSpace = sqc.isPreserveBoundarySpace(); defaultEmptyLeast = sqc.isEmptyLeast(); defaultFunctionNamespace = sqc.getDefaultFunctionNamespace(); defaultElementNamespace = sqc.getDefaultElementNamespace(); defaultCollationName = sqc.getDefaultCollationName(); constructionMode = sqc.getConstructionMode(); isUpdating = sqc.isUpdatingEnabled(); } } /** * Supporting method to load an imported library module. * Used also by saxon:import-query in XSLT. *

    * This method is intended for internal use only. * * @param baseURI The base URI and location URI of the module * @param executable The Executable * @param importer The importing query module (used to check for cycles). This is null * when loading a query module from XSLT. * @param query The text of the query, after decoding and normalizing line endings * @param namespaceURI namespace of the query module to be loaded * @param allowCycles True if cycles of module imports (disallowed by the spec) are to be permitted * @return The StaticQueryContext representing the loaded query module * @throws XPathException */ public static QueryModule makeQueryModule ( String baseURI, Executable executable, QueryModule importer, String query, String namespaceURI, boolean allowCycles) throws XPathException { Configuration config = executable.getConfiguration(); QueryModule module = new QueryModule(config, importer); try { module.setLocationURI(new URI(baseURI)); } catch (URISyntaxException e) { throw new XPathException("Invalid location URI " + baseURI, e); } module.setBaseURI(baseURI); module.setExecutable(executable); module.setModuleNamespace(namespaceURI); executable.addQueryLibraryModule(module); QueryParser qp = config.newQueryParser(importer.isUpdating()); qp.setCompileWithTracing(config.isCompileWithTracing()); qp.setDisableCycleChecks(allowCycles); qp.parseLibraryModule(query, module); if (module.getModuleNamespace() == null) { XPathException err = new XPathException("Imported module must be a library module"); err.setErrorCode("XQST0059"); err.setIsStaticError(true); throw err; } if (!module.getModuleNamespace().equals(namespaceURI)) { XPathException err = new XPathException("Imported module's namespace does not match requested namespace"); err.setErrorCode("XQST0059"); err.setIsStaticError(true); throw err; } return module; } /** * Reset function libraries */ private void resetFunctionLibraries() { Configuration config = getConfiguration(); if (isTopLevelModule()) { globalFunctionLibrary = new XQueryFunctionLibrary(config); } functionLibraryList = new FunctionLibraryList(); functionLibraryList.addFunctionLibrary( SystemFunctionLibrary.getSystemFunctionLibrary(SystemFunctionLibrary.XPATH_ONLY)); functionLibraryList.addFunctionLibrary(config.getVendorFunctionLibrary()); functionLibraryList.addFunctionLibrary(new ConstructorFunctionLibrary(config)); localFunctionLibraryNr = functionLibraryList.addFunctionLibrary( new XQueryFunctionLibrary(config)); importedFunctionLibraryNr = functionLibraryList.addFunctionLibrary( new ImportedFunctionLibrary(this, getTopLevelModule().getGlobalFunctionLibrary())); if (config.isAllowExternalFunctions()) { Configuration.getPlatform().addFunctionLibraries(functionLibraryList, config, Configuration.XQUERY); } unboundFunctionLibraryNr = functionLibraryList.addFunctionLibrary( new UnboundFunctionLibrary()); } /** * Get the Saxon Configuration * @return the Saxon Configuration */ public Configuration getConfiguration() { return config; } /** * Get the NamePool used for compiling expressions * @return the name pool */ public NamePool getNamePool() { return config.getNamePool(); } /** * Test whether this is a "top-level" module. This is true for a main module and also for a * module directly imported into an XSLT stylesheet. It may also be true in future for independently-compiled * modules * @return true if this is top-level module */ public boolean isTopLevelModule() { return this == topModule; } /** * Ask whether this is a "main" module, in the sense of the XQuery language specification * @return true if this is a main module, false if it is a library model */ public boolean isMainModule() { return isMainModule; } /** * Check whether this module is allowed to import a module with namespace N. Note that before * calling this we have already handled the exception case where a module imports another in the same * namespace (this is the only case where cycles are allowed, though as a late change to the spec they * are no longer useful, since they cannot depend on each other cyclically) * @param namespace the namespace to be tested * @return true if the import is permitted */ public boolean mayImportModule(String namespace) { if (namespace.equals(moduleNamespace)) { return false; } if (importers == null) { return true; } for (int i=0; iThis method is intended for internal use.

    * * @param uri the URI of the imported namespace. */ public void addImportedNamespace(String uri) { if (importedModuleNamespaces == null) { importedModuleNamespaces = new HashSet(5); } importedModuleNamespaces.add(uri); getImportedFunctionLibrary().addImportedNamespace(uri); } /** * Ask whether this module directly imports a particular namespace *

    This method is intended for internal use.

    * @param uri the URI of the possibly-imported namespace. * @return true if the schema for the namespace has been imported */ public boolean importsNamespace(String uri) { return importedModuleNamespaces != null && importedModuleNamespaces.contains(uri); } /** * Test whether this module imports a particular namespace directly or indirectly *

    This method is intended for internal use.

    * @param uri the URI of the possibly-imported namespace. * @return true if the schema for the namespace has been imported */ public boolean importsNamespaceIndirectly(String uri) { if (importsNamespace(uri)) { return true; } for (Iterator it = iterateImportedNamespaces(); it.hasNext();) { String moduleURI = (String)it.next(); List list = executable.getQueryLibraryModules(moduleURI); for (Iterator i2 = list.iterator(); i2.hasNext();) { QueryModule sqc = (QueryModule)i2.next(); if (sqc.importsNamespaceIndirectly(uri)) { return true; } } } return false; } /** * Get an iterator over all the module namespaces that this module imports * @return an iterator over the imported namespaces (delivered as strings) */ public Iterator iterateImportedNamespaces() { if (importedModuleNamespaces == null) { return Collections.EMPTY_LIST.iterator(); } return importedModuleNamespaces.iterator(); } /** * Get the QueryModule for the top-level module. This will normally be a main module, * but in the case of saxon:import-query it will be the library module that is imported into * the stylesheet * @return the StaticQueryContext object associated with the top level module */ public QueryModule getTopLevelModule() { return topModule; } /** * Get the Executable, an object representing the compiled query and its environment. *

    * This method is intended for internal use only. * * @return the Executable */ public Executable getExecutable() { return executable; } /** * Set the executable. *

    * This method is intended for internal use only. * * @param executable the Executable */ public void setExecutable(Executable executable) { this.executable = executable; } /** * Get the StaticQueryContext object containing options set up by the user * @return the user-created StaticQueryContext object */ public StaticQueryContext getUserQueryContext() { return userQueryContext; } /** * Get the LocationMap, an data structure used to identify the location of compiled expressions within * the query source text. *

    * This method is intended for internal use only. * * @return the LocationMap */ public LocationMap getLocationMap() { return executable.getLocationMap(); } /** * Set the namespace for a library module. *

    * This method is for internal use only. * @param uri the module namespace URI of the library module */ public void setModuleNamespace(String uri) { moduleNamespace = uri; moduleNamespaceURICode = getNamePool().getCodeForURI(uri); } /** * Get the namespace of the current library module. *

    * This method is intended primarily for internal use. * * @return the module namespace, or null if this is a main module */ public String getModuleNamespace() { return moduleNamespace; } /** * Get the namesapce code of the current library module. *

    * This method is intended primarily for internal use. * * @return the module namespace, or null if this is a main module */ public short getModuleNamespaceCode() { return moduleNamespaceURICode; } /** * Set the location URI for a module * @param uri the location URI */ public void setLocationURI(URI uri) { locationURI = uri; } /** * Get the location URI for a module * @return the location URI */ public URI getLocationURI() { return locationURI; } /** * Get the System ID for a module * @return the location URI */ public String getSystemId() { return (locationURI == null ? null : locationURI.toString()); } /** * Set the base URI for a module * @param uri the base URI */ public void setBaseURI(String uri) { baseURI = uri; } /** * Get the base URI for a module * @return the base URI */ public String getBaseURI() { return baseURI; } /** * Get the stack frame map for global variables. *

    * This method is intended for internal use. * @return the stack frame map (a SlotManager) for global variables. */ public SlotManager getGlobalStackFrameMap() { return executable.getGlobalVariableMap(); } /** * Declare a global variable. A variable must normally be declared before an expression referring * to it is compiled, but there are exceptions where a set of modules in the same namespace * import each other cyclically. Global variables are normally declared in the Query Prolog, but * they can also be predeclared using the Java API. All global variables are held in the QueryModule * for the main module. The fact that a global variable is present therefore does not mean that it * is visible: there are two additional conditions (a) the module namespace must be imported into the * module where the reference appears, and (b) the declaration must not be in the same module and textually * after the reference. * *

    Note that the same VariableDeclaration object cannot be used with more than one query. This is because * the VariableDeclaration is modified internally to hold a list of references to all the places where * the variable is used.

    * * @param var the Variable declaration being declared */ public void declareVariable(VariableDeclaration var) throws XPathException { StructuredQName key = var.getVariableQName(); if (variables.get(key) != null) { VariableDeclaration old = (VariableDeclaration)variables.get(key); if (old == var) { // do nothing } else { String oldloc = ""; if (old instanceof GlobalVariableDefinition && var instanceof GlobalVariableDefinition) { oldloc = " (see line " + ((GlobalVariableDefinition)old).getLineNumber(); String oldSysId = ((GlobalVariableDefinition)old).getSystemId(); if (oldSysId != null && !oldSysId.equals(((GlobalVariableDefinition)var).getSystemId())) { oldloc += " in module ((GlobalVariableDefinition)old).getSystemId()"; } oldloc += ')'; } XPathException err = new XPathException("Duplicate definition of global variable " + var.getVariableQName().getDisplayName() + oldloc); err.setErrorCode("XQST0049"); err.setIsStaticError(true); if (var instanceof GlobalVariableDefinition) { ExpressionLocation loc = new ExpressionLocation(); loc.setLineNumber(((GlobalVariableDefinition)var).getLineNumber()); loc.setSystemId(((GlobalVariableDefinition)var).getSystemId()); err.setLocator(loc); } throw err; } } variables.put(key, var); final HashMap libVars = getTopLevelModule().libraryVariables; GlobalVariableDefinition old = (GlobalVariableDefinition)libVars.get(key); if (old == null || old == var) { // do nothing } else { XPathException err = new XPathException("Duplicate definition of global variable " + var.getVariableQName().getDisplayName() + " (see line " + old.getLineNumber() + " in module " + old.getSystemId() + ')'); err.setErrorCode("XQST0049"); err.setIsStaticError(true); if (var instanceof GlobalVariableDefinition) { ExpressionLocation loc = new ExpressionLocation(); loc.setLineNumber(((GlobalVariableDefinition)var).getLineNumber()); loc.setSystemId(((GlobalVariableDefinition)var).getSystemId()); err.setLocator(loc); } throw err; } if (!isMainModule()) { libVars.put(key, var); } } /** * Fixup all references to global variables. *

    * This method is for internal use by the Query Parser only. * @param globalVariableMap a SlotManager that holds details of the assignment of slots to global variables. * @return a list containing the global variable definitions. */ public List fixupGlobalVariables(SlotManager globalVariableMap) throws XPathException { List varDefinitions = new ArrayList(20); Iterator[] iters = {variables.values().iterator(), libraryVariables.values().iterator()}; for (int i=0; i<2; i++) { while (iters[i].hasNext()) { GlobalVariableDefinition var = (GlobalVariableDefinition)iters[i].next(); int slot = globalVariableMap.allocateSlotNumber(var.getVariableQName()); GlobalVariable gv = var.getCompiledVariable(); if (gv == null) { var.compile(getExecutable(), slot); } if (!varDefinitions.contains(var)) { varDefinitions.add(var); } } } return varDefinitions; } /** * Look for module cycles. This is a restriction introduced in the PR specification because of * difficulties in defining the formal semantics. * *

    [Definition: A module M1 directly depends on another module M2 (different from M1) if a * variable or function declared in M1 depends on a variable or function declared in M2.] * It is a static error [err:XQST0093] to import a module M1 if there exists a sequence * of modules M1 ... Mi ... M1 such that each module directly depends on the next module * in the sequence (informally, if M1 depends on itself through some chain of module dependencies.)

    * * @param referees a Stack containing the chain of module import references leading to this * module * @param lineNumber used for diagnostics */ public void lookForModuleCycles(Stack referees, int lineNumber) throws XPathException { if (referees.contains(this)) { int s = referees.indexOf(this); referees.push(this); String message = "Circular dependency between modules. "; for (int i = s; i < referees.size() - 1; i++) { QueryModule next = (QueryModule)referees.get(i + 1); if (i == s) { message += "Module " + getSystemId() + " references module " + next.getSystemId(); } else { message += ", which references module " + next.getSystemId(); } } message += '.'; XPathException err = new XPathException(message); err.setErrorCode("XQST0093"); err.setIsStaticError(true); ExpressionLocation loc = new ExpressionLocation(); loc.setSystemId(getSystemId()); loc.setLineNumber(lineNumber); err.setLocator(loc); throw err; } else { referees.push(this); Iterator viter = getModuleVariables(); while (viter.hasNext()) { GlobalVariableDefinition gv = (GlobalVariableDefinition)viter.next(); List list = new ArrayList(10); Expression select = gv.getCompiledVariable().getSelectExpression(); if (select != null) { ExpressionTool.gatherReferencedVariables(select, list); for (int i=0; iThis method is intended for internal use

    * @param compiledVars a list of {@link GlobalVariableDefinition} objects to be checked */ public void checkForCircularities(List compiledVars, XQueryFunctionLibrary globalFunctionLibrary) throws XPathException { Iterator iter = compiledVars.iterator(); Stack stack = null; while (iter.hasNext()) {if (stack == null) {stack = new Stack();} GlobalVariableDefinition gvd = (GlobalVariableDefinition)iter.next(); GlobalVariable gv = gvd.getCompiledVariable(); gv.lookForCycles(stack, globalFunctionLibrary); } } /** * Perform type checking on global variables. *

    This method is intended for internal use

    * @param compiledVars a list of {@link GlobalVariableDefinition} objects to be checked */ public void typeCheckGlobalVariables(List compiledVars) throws XPathException { ExpressionVisitor visitor = ExpressionVisitor.make(this); visitor.setExecutable(getExecutable()); Iterator iter = compiledVars.iterator(); //Stack stack = new Stack(); while (iter.hasNext()) { GlobalVariableDefinition gvd = (GlobalVariableDefinition)iter.next(); //GlobalVariable gv = gvd.getCompiledVariable(); //gv.lookForCycles(stack); gvd.typeCheck(visitor); } } /** * Bind a variable used in a query to the expression in which it is declared. *

    * This method is provided for use by the XQuery parser, and it should not be called by the user of * the API, or overridden, unless variables are to be declared using a mechanism other than the * declareVariable method of this class. * @param qName the name of the variable to be bound * @return a VariableReference object representing a reference to a variable on the abstract syntac rtee of * the query. */ public VariableReference bindVariable(StructuredQName qName) throws XPathException { VariableDeclaration var = (VariableDeclaration)variables.get(qName); if (var == null) { String uri = qName.getNamespaceURI(); if (importsNamespace(uri)) { QueryModule main = getTopLevelModule(); var = (VariableDeclaration)main.libraryVariables.get(qName); if (var == null) { // If the namespace has been imported there's the possibility that // the variable declaration hasn't yet been read, because of the limited provision // for cyclic imports UndeclaredVariable uvar = new UndeclaredVariable(); uvar.setVariableQName(qName); VariableReference ref = new VariableReference(); uvar.registerReference(ref); undeclaredVariables.put(qName, uvar); return ref; } else { GlobalVariableDefinition gvar = ((GlobalVariableDefinition)var); checkImportedType(gvar.getRequiredType(), gvar); } } else { // If the namespace hasn't been imported then we might as well throw the error right away XPathException err = new XPathException("Unresolved reference to variable"); err.setErrorCode("XPST0008"); err.setIsStaticError(true); // the message isn't used... throw err; } } VariableReference vref = new VariableReference(); var.registerReference(vref); return vref; } /** * Set the function library used for binding any function call appearing within the query module. *

    * This method is available for use by advanced applications. The details of the FunctionLibrary * interface are subject to change. Applications using this interface take responsibility for * ensuring that the results conform to the constraints imposed by the XQuery language specification, * for example that one function within a query module can call other functions defined in the same * query module. * * @param functionLibrary the FunctionLibrary to be used. This will typically be a * FunctionLibraryList; in most cases it will be a slightly modified copy of a FunctionLibraryList * constructed by the system and obtained using the {@link #getFunctionLibrary} method. * @see net.sf.saxon.functions.FunctionLibraryList */ public void setFunctionLibraryList(FunctionLibraryList functionLibrary) { functionLibraryList = functionLibrary; } /** * Get the function library containing all the in-scope functions available in this static * context (that is, the functions available in this query module). *

    * This method is provided for use by advanced applications. * The details of the interface are subject to change. * * @return the FunctionLibrary used. For XQuery, this will always be a FunctionLibraryList. * @see net.sf.saxon.functions.FunctionLibraryList */ public FunctionLibrary getFunctionLibrary() { return functionLibraryList; } /** * Get the functions declared locally within this module * @return a FunctionLibrary object containing the function declarations */ public XQueryFunctionLibrary getLocalFunctionLibrary() { return (XQueryFunctionLibrary)functionLibraryList.get(localFunctionLibraryNr); } /** * Register a user-defined XQuery function. *

    * This method is intended for internal use only. * @param function the function being declared */ public void declareFunction(XQueryFunction function) throws XPathException { Configuration config = getConfiguration(); if (function.getNumberOfArguments() == 1) { StructuredQName name = function.getFunctionName(); int fingerprint = config.getNamePool().getFingerprint(name.getNamespaceURI(), name.getLocalName()); if (fingerprint != -1) { SchemaType t = config.getSchemaType(fingerprint); if (t != null && t.isAtomicType()) { XPathException err = new XPathException("Function name " + function.getDisplayName() + " clashes with the name of the constructor function for an atomic type"); err.setErrorCode("XQST0034"); err.setIsStaticError(true); throw err; } } } XQueryFunctionLibrary local = getLocalFunctionLibrary(); local.declareFunction(function); QueryModule main = getTopLevelModule(); main.globalFunctionLibrary.declareFunction(function); } /** * Bind function calls that could not be bound when first encountered. These * will either be forwards references to functions declared later in the same query module, * or in modules that are being imported recursively, or errors. *

    * This method is for internal use only. * * @throws net.sf.saxon.trans.XPathException if a function call refers to a function that has * not been declared */ public void bindUnboundFunctionCalls() throws XPathException { UnboundFunctionLibrary lib = (UnboundFunctionLibrary)functionLibraryList.get(unboundFunctionLibraryNr); lib.bindUnboundFunctionCalls(functionLibraryList, getConfiguration()); } /** * Fixup all references to global functions. This method is called * on completion of query parsing. Each XQueryFunction is required to * bind all references to that function to the object representing the run-time * executable code of the function. *

    * This method is for internal use only. It is called only on the StaticQueryContext for the main * query body (not for library modules). */ public void fixupGlobalFunctions() throws XPathException { globalFunctionLibrary.fixupGlobalFunctions(this); } /** * Optimize the body of all global functions. *

    * This method is for internal use only. It is called only on the StaticQueryContext for the main * query body (not for library modules). */ public void optimizeGlobalFunctions() throws XPathException { globalFunctionLibrary.optimizeGlobalFunctions(); } /** * Output "explain" information about each declared function. *

    * This method is intended primarily for internal use. * @param out the expression presenter used to display the output */ public void explainGlobalFunctions(ExpressionPresenter out) { globalFunctionLibrary.explainGlobalFunctions(out); } /** * Get the function with a given name and arity. This method is provided so that XQuery functions * can be called directly from a Java application. Note that there is no type checking or conversion * of arguments when this is done: the arguments must be provided in exactly the form that the function * signature declares them. * * @param uri the uri of the function name * @param localName the local part of the function name * @param arity the number of arguments. * @return the user-defined function * @since 8.4 */ public UserFunction getUserDefinedFunction(String uri, String localName, int arity) { return globalFunctionLibrary.getUserDefinedFunction(uri, localName, arity); } /** * Bind unbound variables (these are typically variables that reference another module * participating in a same-namespace cycle, since local forwards references are not allowed */ public void bindUnboundVariables() throws XPathException { for (Iterator iter = undeclaredVariables.values().iterator(); iter.hasNext();) { UndeclaredVariable uv = (UndeclaredVariable)iter.next(); StructuredQName qName = uv.getVariableQName(); VariableDeclaration var = (VariableDeclaration)variables.get(qName); if (var == null) { String uri = qName.getNamespaceURI(); if (importsNamespace(uri)) { QueryModule main = getTopLevelModule(); var = (VariableDeclaration)main.libraryVariables.get(qName); } } if (var == null) { XPathException err = new XPathException("Unresolved reference to variable $" + uv.getVariableQName().getDisplayName()); err.setErrorCode("XPST0008"); err.setIsStaticError(true); throw err; } else { GlobalVariableDefinition gvar = ((GlobalVariableDefinition)var); checkImportedType(gvar.getRequiredType(), gvar); uv.transferReferences(var); } } } /** * Add an imported schema to this static context. A query module can reference * types in a schema provided two conditions are satisfied: the schema containing those * types has been loaded into the Configuration, and the target namespace has been imported * by this query module. This method achieves the second of these conditions. It does not * cause the schema to be loaded. *

    * * @param targetNamespace The target namespace of the schema to be added * @param baseURI The base URI against which the locationURIs are to be absolutized * @param locationURIs a list of strings containing the absolutized URIs of the "location hints" supplied * for this schema * @since 8.4 */ public void addImportedSchema(String targetNamespace, String baseURI, List locationURIs) { if (importedSchemata == null) { importedSchemata = new HashSet(5); } importedSchemata.add(targetNamespace); HashMap loadedSchemata = getTopLevelModule().loadedSchemata; if (loadedSchemata == null) { loadedSchemata = new HashMap(5); getTopLevelModule().loadedSchemata = loadedSchemata; } HashSet entries = (HashSet)loadedSchemata.get(targetNamespace); if (entries == null) { entries = new HashSet(locationURIs.size()); loadedSchemata.put(targetNamespace, entries); } Platform platform = Configuration.getPlatform(); for (Iterator iter = locationURIs.iterator(); iter.hasNext();) { String relative = (String)iter.next(); try { URI abs = platform.makeAbsolute(relative, baseURI); entries.add(abs.toString()); } catch (URISyntaxException e) { // ignore the URI if it's not valid } } } /** * For the top-level module only, get all the schema modules imported anywhere in the query. * @return a Map whose key is the target namespace of a set of schema documents, and whose * value is a Set containing the absolutized location URIs ("hints") of the locations from * which those schema documents were loaded, as strings. */ public Map getAllImportedSchemata() { return loadedSchemata; } /** * Get the schema for a given namespace, if it has been imported * * @param namespace The namespace of the required schema. Supply "" for * a no-namespace schema. * @return The schema if found, or null if not found. * @since 8.4 */ public boolean isImportedSchema(String namespace) { return importedSchemata != null && importedSchemata.contains(namespace); } /** * Get the set of imported schemas * * @return a Set, the set of URIs representing the names of imported schemas */ public Set getImportedSchemaNamespaces() { if (importedSchemata == null) { return Collections.EMPTY_SET; } else { return importedSchemata; } } /** * Report a fatal error in the query (via the registered ErrorListener) * @param err the error to be signalled */ public void reportFatalError(XPathException err) { if (!err.hasBeenReported()) { try { if (userQueryContext == null) { config.getErrorListener().fatalError(err); } else { userQueryContext.getErrorListener().fatalError(err); } } catch (TransformerException e) { // ignore secondary errors } err.setHasBeenReported(); } } /** * Check that all the types used in the signature of an imported function * are available in the module of the caller of the function * @param fd the declaration of the imported function * @throws XPathException if an error is found */ public void checkImportedFunctionSignature(XQueryFunction fd) throws XPathException { checkImportedType(fd.getResultType(), fd); for (int a=0; a * This method is intended for internal use only. * @param prefix the namespace prefix * @param uri the namespace URI */ public void declareActiveNamespace(String prefix, String uri) { if (prefix == null) { throw new NullPointerException("Null prefix supplied to declareActiveNamespace()"); } if (uri == null) { throw new NullPointerException("Null namespace URI supplied to declareActiveNamespace()"); } int nscode = getNamePool().allocateNamespaceCode(prefix, uri); ActiveNamespace entry = new ActiveNamespace(); entry.prefix = prefix; entry.uri = uri; entry.code = nscode; activeNamespaces.push(entry); // if (prefix.length() == 0) { // defaultElementNamespace = uri; // } } /** * Undeclare the most recently-declared active namespace. This method is called * when a namespace declaration goes out of scope (while processing an element end tag). * It is NOT called when an XML 1.1-style namespace undeclaration is encountered. *

    * This method is intended for internal use only. * * @see #declareActiveNamespace(String, String) */ public void undeclareNamespace() { activeNamespaces.pop(); } /** * Get the URI for a prefix. * This method is used by the XQuery parser to resolve namespace prefixes. *

    * This method is intended primarily for internal use. * * @param prefix The prefix * @return the corresponding namespace URI * @throws net.sf.saxon.trans.XPathException (with error code XPST0081) * if the prefix has not been declared */ public String getURIForPrefix(String prefix) throws XPathException { String uri = checkURIForPrefix(prefix); if (uri == null) { XPathException err = new XPathException("Prefix " + prefix + " has not been declared"); err.setErrorCode("XPST0081"); err.setIsStaticError(true); throw err; } return uri; } /** * Get the URI for a prefix if there is one, return null if not. * This method is used by the XQuery parser to resolve namespace prefixes. *

    * This method is intended primarily for internal use. * * @param prefix The prefix. Supply "" to obtain the default namespace for elements and types. * @return the corresponding namespace URI, or null if the prefix has not * been declared. If the prefix is "" and the default namespace is the non-namespace, * return "". */ public String checkURIForPrefix(String prefix) { // Search the active namespaces first, then the passive ones. if (activeNamespaces != null) { for (int i = activeNamespaces.size() - 1; i >= 0; i--) { if (((ActiveNamespace)activeNamespaces.get(i)).prefix.equals(prefix)) { return ((ActiveNamespace)activeNamespaces.get(i)).uri; } } } if (prefix.length() == 0) { return defaultElementNamespace; } String uri = (String)explicitPrologNamespaces.get(prefix); if (uri != null) { // A zero-length URI means the prefix was undeclared in the prolog, and we mustn't look elsewhere return (uri.length() == 0 ? null : uri); } if (userQueryContext != null) { uri = userQueryContext.getNamespaceForPrefix(prefix); if (uri != null) { return uri; } NamespaceResolver externalResolver = userQueryContext.getExternalNamespaceResolver(); if (externalResolver != null) { return externalResolver.getURIForPrefix(prefix, true); } } return null; } /** * Get the default XPath namespace for elements and types. Note that this is not necessarily * the default namespace declared in the query prolog; within an expression, it may change in response * to namespace declarations on element constructors. * * @return the default namespace, or NamespaceConstant.NULL for the non-namespace */ public String getDefaultElementNamespace() { return checkURIForPrefix(""); } /** * Set the default element namespace as declared in the query prolog * @param uri the default namespace for elements and types */ public void setDefaultElementNamespace(String uri) { defaultElementNamespace = uri; } /** * Get the default function namespace * * @return the default namespace for function names */ public String getDefaultFunctionNamespace() { return defaultFunctionNamespace; } /** * Set the default function namespace * @param uri the default namespace for functions */ public void setDefaultFunctionNamespace(String uri) { defaultFunctionNamespace = uri; } /** * Set the revalidation mode. This is used only if XQuery Updates are in use, in other cases * the value is ignored. * @param mode the revalidation mode. This must be one of {@link Validation#STRICT}, * {@link Validation#LAX}, or {@link Validation#SKIP} */ public void setRevalidationMode(int mode) { if (mode==Validation.STRICT || mode==Validation.LAX || mode==Validation.SKIP) { revalidationMode = mode; } else { throw new IllegalArgumentException("Invalid mode " + mode); } } /** * Get the revalidation mode. This is used only if XQuery Updates are in use, in other cases * the value is ignored. * @return the revalidation mode. This will be one of {@link Validation#STRICT}, * {@link Validation#LAX}, or {@link Validation#SKIP} */ public int getRevalidationMode() { return revalidationMode; } /** * Get an array containing the namespace codes of all active namespaces. *

    * This method is for internal use only. * @return an array of namespace codes. A namespace code is an int that holds a prefix code in the * top half and a uri code in the bottom half. */ public int[] getActiveNamespaceCodes() { if (activeNamespaces == null) { return IntArraySet.EMPTY_INT_ARRAY; } int[] nscodes = new int[activeNamespaces.size()]; int used = 0; HashSet prefixes = new HashSet(10); for (int n = activeNamespaces.size() - 1; n >= 0; n--) { ActiveNamespace an = (ActiveNamespace)activeNamespaces.get(n); if (!prefixes.contains(an.prefix)) { prefixes.add(an.prefix); nscodes[used++] = an.code; } } if (used < nscodes.length) { int[] nscodes2 = new int[used]; System.arraycopy(nscodes, 0, nscodes2, 0, used); nscodes = nscodes2; } return nscodes; } /** * Get a copy of the Namespace Context. This method is used internally * by the query parser when a construct is encountered that needs * to save the namespace context for use at run-time. Note that unlike other implementations of * StaticContext, the state of the QueryModule changes as the query is parsed, with different namespaces * in scope at different times. It's therefore necessary to compute the whole namespace context each time. *

    * This method is for internal use only. */ public NamespaceResolver getNamespaceResolver() { List externalNamespaceCodes = null; NamespaceResolver externalResolver = userQueryContext.getExternalNamespaceResolver(); if (externalResolver != null) { externalNamespaceCodes = new ArrayList(); Iterator iter = externalResolver.iteratePrefixes(); while (iter.hasNext()) { String prefix = (String)iter.next(); String uri = externalResolver.getURIForPrefix(prefix, true); int nscode = getNamePool().allocateNamespaceCode(prefix, uri); externalNamespaceCodes.add(new Integer(nscode)); } } HashMap userDeclaredNamespaces = userQueryContext.getUserDeclaredNamespaces(); int[] active = getActiveNamespaceCodes(); int[] nscodes = new int[explicitPrologNamespaces.size() + userDeclaredNamespaces.size() + active.length + (externalNamespaceCodes == null ? 0 : externalNamespaceCodes.size())]; int used = 0; NamePool namePool = getNamePool(); for (Iterator iter = userDeclaredNamespaces.keySet().iterator(); iter.hasNext();) { String prefix = (String)iter.next(); String uri = (String)userDeclaredNamespaces.get(prefix); nscodes[used++] = namePool.getNamespaceCode(prefix, uri); } for (Iterator iter = explicitPrologNamespaces.keySet().iterator(); iter.hasNext();) { String prefix = (String)iter.next(); String uri = (String)explicitPrologNamespaces.get(prefix); nscodes[used++] = namePool.getNamespaceCode(prefix, uri); } for (int a = 0; a < active.length; a++) { nscodes[used++] = active[a]; } if (externalNamespaceCodes != null) { for (int a = 0; a < externalNamespaceCodes.size(); a++) { nscodes[used++] = ((Integer)externalNamespaceCodes.get(a)).intValue(); } } return new SavedNamespaceContext(nscodes, namePool); } /** * Issue a compile-time warning. This method is used during XQuery expression compilation to * output warning conditions. *

    * This method is intended for internal use only. */ public void issueWarning(String s, SourceLocator locator) { XPathException err = new XPathException(s); err.setLocator(locator); try { getConfiguration().getErrorListener().warning(err); } catch (TransformerException e) { // ignore any error thrown } } /** * Get the line number of the expression within that container. * Used to construct error messages. This method is provided to satisfy the StaticContext interface, * but the value is meaningful only for XPath expressions within a document such as a stylesheet. * * @return -1 always */ public int getLineNumber() { return -1; } /** * Determine whether Backwards Compatible Mode is used * * @return false; XPath 1.0 compatibility mode is not supported in XQuery * @since 8.4 */ public boolean isInBackwardsCompatibleMode() { return false; } /** * Determine whether a built-in type is available in this context. This method caters for differences * between host languages as to which set of types are built in. * * @param type the supposedly built-in type. This will always be a type in the * XS or XDT namespace. * @return true if this type can be used in this static context */ public boolean isAllowedBuiltInType(BuiltInAtomicType type) { return true; } /** * Set whether the query is allowed to be updating * @param updating true if the query may use the XQuery Update facility (requires Saxon-SA) * @since 9.1 */ public void setUpdating(boolean updating) { isUpdating = updating; } /** * Ask whether the query is allowed to be updating * @return true if the query is allowed to use the XQuery Update facility * @since 9.1 */ public boolean isUpdating() { return isUpdating; } /** * Check that the namespace of a given name is the namespace of an imported schema * @param fingerprint the fingerprint of the "given name" * @param declaration the declaration of the variable or function that has this given name * @throws net.sf.saxon.trans.XPathException (error XQST0036) if the namespace is not present in a schema * imported by the importing query module */ private void checkSchemaNamespaceImported(int fingerprint, Declaration declaration) throws XPathException { String uri = getNamePool().getURI(fingerprint); if (!uri.equals(NamespaceConstant.SCHEMA) && !uri.equals(NamespaceConstant.ANONYMOUS) && !uri.equals(NamespaceConstant.JAVA_TYPE) && !isImportedSchema(uri)) { String msg = "Schema component " + getNamePool().getDisplayName(fingerprint) + " used in "; if (declaration instanceof GlobalVariableDefinition) { msg += "declaration of imported variable " + ((GlobalVariableDefinition)declaration).getVariableQName().getDisplayName(); } else { msg += "signature of imported function " + ((XQueryFunction)declaration).getDisplayName(); } msg += " is not declared in any schema imported by "; String module = getModuleNamespace(); if (module == null) { msg += "the main query module"; } else { msg += "query module " + module; } XPathException err = new XPathException(msg); err.setErrorCode("XQST0036"); err.setIsStaticError(true); err.setLocator(declaration); throw err; } } /** * Inner class containing information about an active namespace entry */ private static class ActiveNamespace { public String prefix; public String uri; public int code; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/query/UnboundFunctionLibrary.java0000644000175000017500000001603211033112257024056 0ustar eugeneeugenepackage net.sf.saxon.query; import net.sf.saxon.Configuration; import net.sf.saxon.expr.Expression; import net.sf.saxon.expr.StaticContext; import net.sf.saxon.expr.UserFunctionCall; import net.sf.saxon.functions.FunctionLibrary; import net.sf.saxon.om.StructuredQName; import net.sf.saxon.trans.XPathException; import java.util.ArrayList; import java.util.List; /** * An UnboundFunctionLibrary is not a real function library; rather, it is used to keep track of function calls * that cannot yet be bound to a known declared function, but will have to be bound when all user-declared functions * are available. */ public class UnboundFunctionLibrary implements FunctionLibrary { private List unboundFunctionCalls = new ArrayList(20); private List correspondingStaticContext = new ArrayList(20); private boolean resolving = false; /** * Create an XQueryFunctionLibrary */ public UnboundFunctionLibrary() { } /** * Test whether a function with a given name and arity is available. This supports * the function-available() function in XSLT. Since this library is used only in XQuery, * and contains no real functions, we always return false * @param functionName the name of the function required * @param arity The number of arguments. This is set to -1 in the case of the single-argument * function-available() function; in this case the method should return true if there is some */ public boolean isAvailable(StructuredQName functionName, int arity) { return false; } /** * Identify a (namespace-prefixed) function appearing in the expression. This * method is called by the XQuery parser to resolve function calls found within * the query. *

    Note that a function call may appear earlier in the query than the definition * of the function to which it is bound. Unlike XSLT, we cannot search forwards to * find the function definition. Binding of function calls is therefore a two-stage * process; at the time the function call is parsed, we simply register it as * pending; subsequently at the end of query parsing all the pending function * calls are resolved. Another consequence of this is that we cannot tell at the time * a function call is parsed whether it is a call to an internal (XSLT or XQuery) * function or to an extension function written in Java. * @return an Expression representing the function call. This will normally be * a FunctionCall, but it may be rewritten as some other expression. * @throws net.sf.saxon.trans.XPathException if the function call is invalid, either because it is * an unprefixed call to a non-system function, or because it is calling a system * function that is available in XSLT only. A prefixed function call that cannot * be recognized at this stage is assumed to be a forwards reference, and is bound * later when bindUnboundFunctionCalls() is called. */ public Expression bind(StructuredQName functionName, Expression[] arguments, StaticContext env) throws XPathException { if (resolving) { return null; } UserFunctionCall ufc = new UserFunctionCall(); ufc.setFunctionName(functionName); ufc.setArguments(arguments); unboundFunctionCalls.add(ufc); correspondingStaticContext.add(env); return ufc; } /** * Bind function calls that could not be bound when first encountered. These * will either be forwards references to functions declared later in the query, * or errors. This method is for internal use. * @param lib A library containing all the XQuery functions that have been declared; * the method searches this library for this missing function call * @param config The Saxon configuration * @throws XPathException if a function call refers to a function that has * not been declared */ public void bindUnboundFunctionCalls(XQueryFunctionBinder lib, Configuration config) throws XPathException { resolving = true; for (int i=0; iThe method reads from the InputStream or Reader contained in the StreamSource up to the end * of file unless a fatal error occurs. It does not close the InputStream or Reader; this is the caller's * responsibility.

    * @param nameChecker this checks XML names against either the XML 1.0 or XML 1.1 rules * @return the text of the query */ public static String readSourceQuery(StreamSource ss, NameChecker nameChecker) throws XPathException { CharSequence queryText; if (ss.getInputStream() != null) { InputStream is = ss.getInputStream(); if (!is.markSupported()) { is = new BufferedInputStream(is); } String encoding = readEncoding(is); queryText = readInputStream(is, encoding, nameChecker); } else if (ss.getReader() != null) { queryText = readQueryFromReader(ss.getReader(), nameChecker); } else { throw new XPathException("Module URI Resolver must supply either an InputSource or a Reader"); } return queryText.toString(); } /** * Read an input stream non-destructively to determine the encoding from the Query Prolog * @param is the input stream: this must satisfy the precondition is.markSupported() = true. * @return the encoding to be used: defaults to UTF-8 if no encoding was specified explicitly * in the query prolog * @throws XPathException if the input stream cannot be read */ public static String readEncoding(InputStream is) throws XPathException { try { if (!is.markSupported()) { throw new IllegalArgumentException("InputStream must have markSupported() = true"); } is.mark(100); byte[] start = new byte[100]; int read = is.read(start, 0, 100); if (read == -1) { throw new XPathException("Query source file is empty"); } is.reset(); return inferEncoding(start, read); } catch (IOException e) { throw new XPathException("Failed to read query source file", e); } } /** * Read a query from an InputStream. The method checks that all characters are valid XML * characters, and also performs normalization of line endings. * @param is the input stream * @param encoding the encoding, or null if the encoding is unknown * @param nameChecker the nameChecker to be used for checking characters * @return the content of the InputStream as a string */ public static String readInputStream(InputStream is, String encoding, NameChecker nameChecker) throws XPathException { if (encoding == null) { if (!is.markSupported()) { is = new BufferedInputStream(is); } encoding = readEncoding(is); } try { Reader reader = new BufferedReader(new InputStreamReader(is, encoding)); return readQueryFromReader(reader, nameChecker); } catch (UnsupportedEncodingException encErr) { throw new XPathException("Unknown encoding " + Err.wrap(encoding), encErr); } } /** * Read a query from a Reader. The method checks that all characters are valid XML * characters. * @param reader The Reader supplying the input * @param nameChecker the NameChecker to be used * @return the text of the query module, as a string * @throws XPathException if the file cannot be read or contains illegal characters */ private static String readQueryFromReader(Reader reader, NameChecker nameChecker) throws XPathException { try { FastStringBuffer sb = new FastStringBuffer(2048); char[] buffer = new char[2048]; boolean first = true; int actual; int line = 1; // track line/column position for reporting bad characters int column = 1; while (true) { actual = reader.read(buffer, 0, 2048); if (actual < 0) { break; } for (int c=0; c= 2) { if (ch(start[0]) == 0xFE && ch(start[1]) == 0xFF) { return "UTF-16"; } else if (ch(start[0]) == 0xFF && ch(start[1]) == 0xFE) { return "UTF-16LE"; } } if (read >= 3) { if (ch(start[0]) == 0xEF && ch(start[1]) == 0xBB && ch(start[2]) == 0xBF) { return "UTF-8"; } } // Try to handle a UTF-16 file with no BOM if (read >= 8 && start[0] == 0 && start[2] == 0 && start[4] == 0 && start[6] == 0) { return "UTF-16"; } if (read >= 8 && start[1] == 0 && start[3] == 0 && start[5] == 0 && start[7] == 0) { return "UTF-16LE"; } // In all other cases, we assume an encoding that has ISO646 as a subset // Note, we don't care about syntax errors here: they'll be reported later. We just need to // establish the encoding. int i=0; String tok = readToken(start, i, read); if (Whitespace.trim(tok).equals("xquery")) { i += tok.length(); } else { return "UTF-8"; } tok = readToken(start, i, read); if (Whitespace.trim(tok).equals("version")) { i += tok.length(); } else { return "UTF-8"; } tok = readToken(start, i, read); if (tok == null) { return "UTF-8"; } i += tok.length(); tok = readToken(start, i, read); if (Whitespace.trim(tok).equals("encoding")) { i += tok.length(); } else { return "UTF-8"; } tok = Whitespace.trim(readToken(start, i, read)); if (tok.startsWith("\"") && tok.endsWith("\"") && tok.length()>2) { return tok.substring(1, tok.length()-1); } else if (tok.startsWith("'") && tok.endsWith("'") && tok.length()>2) { return tok.substring(1, tok.length()-1); } else { throw new XPathException("Unrecognized encoding " + Err.wrap(tok) + " in query prolog"); } } /** * Simple tokenizer for use when reading the encoding declaration in the query prolog. A token * is a sequence of characters delimited either by whitespace, or by single or double quotes; the * quotes if present are returned as part of the token. * @param in the character buffer * @param i offset where to start reading * @param len the length of buffer * @return the next token */ private static String readToken(byte[] in, int i, int len) { int p = i; while (p= 0) { p++; } if (ch(in[p])=='"') { p++; while (p=len) { return new String(in, i, len-i); } FastStringBuffer sb = new FastStringBuffer(p-i+1); for (int c=i; c<=p; c++) { sb.append((char)ch(in[c])); } return sb.toString(); } /** * Convert a byte containing an ASCII character to that character * @param b the input byte * @return the ASCII character */ private static int ch(byte b) { return ((int)b) & 0xff; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/query/XQueryFunction.java0000644000175000017500000005563411210065406022367 0ustar eugeneeugenepackage net.sf.saxon.query; import net.sf.saxon.Configuration; import net.sf.saxon.event.LocationProvider; import net.sf.saxon.expr.*; import net.sf.saxon.functions.ExecutableFunctionLibrary; import net.sf.saxon.instruct.*; import net.sf.saxon.om.*; import net.sf.saxon.trace.ExpressionPresenter; import net.sf.saxon.trace.InstructionInfo; import net.sf.saxon.trace.Location; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.SequenceType; import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class XQueryFunction implements InstructionInfo, Container, Declaration { private StructuredQName functionName; private List arguments; // A list of UserFunctionParameter objects private SequenceType resultType; private Expression body = null; private List references = new ArrayList(10); private int lineNumber; private int columnNumber; private String systemId; private Executable executable; private UserFunction compiledFunction = null; private boolean memoFunction; private NamespaceResolver namespaceResolver; private QueryModule staticContext; private boolean isUpdating = false; /** * Create an XQuery function */ public XQueryFunction() { arguments = new ArrayList(8); } /** * Set the name of the function * @param name the name of the function as a StructuredQName object */ protected void setFunctionName(StructuredQName name) { functionName = name; } /** * Set the arguments of the function * @param arguments a list of the arguments of the function, as a list whose * members are instances of {@link UserFunctionParameter} */ // protected void setArgumentList(List arguments) { // this.arguments = arguments; // } /** * Add an argument to the list of arguments * @param argument the formal declaration of the argument to be added */ protected void addArgument(UserFunctionParameter argument) { arguments.add(argument); } /** * Set the required result type of the function * @param resultType the declared result type of the function */ protected void setResultType(SequenceType resultType) { this.resultType = resultType; } /** * Set the body of the function * @param body the expression forming the body of the function */ protected void setBody(Expression body) { this.body = body; if (body != null) { body.setContainer(this); } } /** * Get the body of the function * @return the expression making up the body of the function */ public Expression getBody() { return body; } /** * Set the system ID of the module containing the function * @param systemId the system ID (= base URI) of the module containing the function */ protected void setSystemId(String systemId) { this.systemId = systemId; } /** * Set the line number of the function declaration within its module * @param line the line number of the function declaration */ protected void setLineNumber(int line) { lineNumber = line; } /** * Set the column number of the function declaration * @param column the column number of the function declaration */ protected void setColumnNumber(int column) { columnNumber = column; } /** * Get the name of the function as a structured QName * @return the name of the function as a structured QName */ public StructuredQName getFunctionName() { return functionName; } /** * Get the name of the function for display in error messages * @return the name of the function as a lexical QName */ public String getDisplayName() { return functionName.getDisplayName(); } /** * Get an identifying key for this function, which incorporates the URI and local part of the * function name plus the arity * @return an identifying key */ public String getIdentificationKey() { return functionName.getClarkName() + '/' + arguments.size(); } /** * Construct what the identification key would be for a function with given URI, local name, and arity * @param uri the URI part of the function name * @param localName the local part of the function name * @param arity the number of arguments in the function * @return an identifying key */ public static String getIdentificationKey(String uri, String localName, int arity) { FastStringBuffer sb = new FastStringBuffer(uri.length() + localName.length() + 8); sb.append('{'); sb.append(uri); sb.append('}'); sb.append(localName); sb.append('/'); sb.append(arity+""); return sb.toString(); } /** * Construct what the identification key would be for a function with given URI, local name, and arity * @param qName the name of the function * @param arity the number of arguments * @return an identifying key */ public static String getIdentificationKey(StructuredQName qName, int arity) { String uri = qName.getNamespaceURI(); String localName = qName.getLocalName(); FastStringBuffer sb = new FastStringBuffer(uri.length() + localName.length() + 8); sb.append('{'); sb.append(uri); sb.append('}'); sb.append(localName); sb.append('/'); sb.append(arity+""); return sb.toString(); } /** * Get the result type of the function * @return the declared result type */ public SequenceType getResultType() { return resultType; } /** * Set the executable in which this function is contained * @param exec the executable */ public void setExecutable(Executable exec) { executable = exec; } /** * Get the executable in which this function is contained * @return the executable */ public Executable getExecutable() { return executable; } /** * Get the LocationProvider allowing location identifiers to be resolved. * @return the location provider */ public LocationProvider getLocationProvider() { return executable.getLocationMap(); } /** * Set the static context for this function * @param env the static context for the module in which the function is declared */ public void setStaticContext(QueryModule env) { staticContext = env; } /** * Get the static context for this function * @return the static context for the module in which the function is declared */ public StaticContext getStaticContext() { return staticContext; } /** * Get the declared types of the arguments of this function * @return an array, holding the types of the arguments in order */ public SequenceType[] getArgumentTypes() { SequenceType[] types = new SequenceType[arguments.size()]; for (int i=0; i 0, tailCalls > 1); body = new TailCallLoop(compiledFunction); } } body.setContainer(this); compiledFunction.setBody(body); compiledFunction.computeEvaluationMode(); ExpressionTool.allocateSlots(body, arity, compiledFunction.getStackFrameMap()); } /** * Fix up references to this function * @param env the static context */ public void fixupReferences(StaticContext env) throws XPathException { Iterator iter = references.iterator(); while (iter.hasNext()) { UserFunctionCall ufc = (UserFunctionCall)iter.next(); ufc.setFunction(compiledFunction); ufc.computeArgumentEvaluationModes(); } } /** * Type-check references to this function * @param visitor the expression visitor */ public void checkReferences(ExpressionVisitor visitor) throws XPathException { Iterator iter = references.iterator(); while (iter.hasNext()) { UserFunctionCall ufc = (UserFunctionCall)iter.next(); ufc.checkFunctionCall(compiledFunction, visitor); ufc.computeArgumentEvaluationModes(); } // clear the list of references, so that more can be added in another module references = new ArrayList(0); } /** * Produce diagnostic output showing the compiled and optimized expression tree for a function * @param out the destination to be used */ public void explain(ExpressionPresenter out) { out.startElement("declareFunction"); out.emitAttribute("name", functionName.getDisplayName()); out.emitAttribute("arity", ""+getNumberOfArguments()); if (compiledFunction == null) { out.emitAttribute("unreferenced", "true"); } else { if (compiledFunction.isMemoFunction()) { out.emitAttribute("memo", "true"); } out.emitAttribute("tailRecursive", (compiledFunction.isTailRecursive() ? "true" : "false")); body.explain(out); } out.endElement(); } /** * Get the callable compiled function contained within this XQueryFunction definition. * @return the compiled function object */ public UserFunction getUserFunction() { return compiledFunction; } /** * Get the type of construct. This will be a constant in * class {@link Location}. */ public int getConstructType() { return StandardNames.XSL_FUNCTION; } /** * Get a name identifying the object of the expression, for example a function name, template name, * variable name, key name, element name, etc. This is used only where the name is known statically. */ public StructuredQName getObjectName() { return functionName; } /** * Get the system identifier (URI) of the source module containing * the instruction. This will generally be an absolute URI. If the system * identifier is not known, the method may return null. In some cases, for example * where XML external entities are used, the correct system identifier is not * always retained. */ public String getSystemId() { return systemId; } /** * Get the line number of the instruction in the source stylesheet module. * If this is not known, or if the instruction is an artificial one that does * not relate to anything in the source code, the value returned may be -1. */ public int getLineNumber() { return lineNumber; } /** * Return the public identifier for the current document event. * @return A string containing the public identifier, or * null if none is available. * @see #getSystemId */ public String getPublicId() { return null; } /** * Return the column number * @return The column number, or -1 if none is available. * @see #getLineNumber */ public int getColumnNumber() { return -1; } public String getSystemId(long locationId) { return getSystemId(); } public int getLineNumber(long locationId) { return getLineNumber(); } public int getColumnNumber(long locationId) { return getColumnNumber(); } /** * Get the namespace context of the instruction. This will not always be available, in which * case the method returns null. */ public NamespaceResolver getNamespaceResolver() { return namespaceResolver; } /** * Get the value of a particular property of the instruction. Properties * of XSLT instructions are generally known by the name of the stylesheet attribute * that defines them. * @param name The name of the required property * @return The value of the requested property, or null if the property is not available */ public Object getProperty(String name) { if ("name".equals(name)) { return functionName.getDisplayName(); } else if ("as".equals(name)) { return resultType.toString(); } else { return null; } } /** * Get an iterator over all the properties available. The values returned by the iterator * will be of type String, and each string can be supplied as input to the getProperty() * method to retrieve the value of the property. */ public Iterator getProperties() { return new PairIterator("name", "as"); } /** * Get the host language (XSLT, XQuery, XPath) used to implement the code in this container * @return typically {@link net.sf.saxon.Configuration#XSLT} or {@link net.sf.saxon.Configuration#XQUERY} */ public int getHostLanguage() { return Configuration.XQUERY; } /** * Replace one subexpression by a replacement subexpression * @param original the original subexpression * @param replacement the replacement subexpression * @return true if the original subexpression is found */ public boolean replaceSubExpression(Expression original, Expression replacement) { boolean found = false; if (body == original) { body = replacement; found = true; } return found; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none //saxonb-9.1.0.8/bj/net/sf/saxon/query/QueryResult.java0000644000175000017500000002743611033112257021727 0ustar eugeneeugenepackage net.sf.saxon.query; import net.sf.saxon.Configuration; import net.sf.saxon.event.*; import net.sf.saxon.om.*; import net.sf.saxon.tinytree.TinyBuilder; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.Type; import javax.xml.transform.Result; import javax.xml.transform.stream.StreamResult; import java.io.*; import java.net.URI; import java.net.URISyntaxException; import java.util.Properties; /** * This utility class takes the result sequence produced by a query, and wraps it as * an XML document. The class is never instantiated. */ public class QueryResult { public static String RESULT_NS = "http://saxon.sf.net/xquery-results"; private QueryResult() { } /** * Convenience method to serialize a node using default serialization options, placing * the result in a string. * @param nodeInfo the node to be serialized. This must not be an attribute or namespace node. * @return the serialization of the node * @since 9.0 */ public static String serialize(NodeInfo nodeInfo) throws XPathException { StringWriter sw = new StringWriter(); Properties props = new Properties(); props.setProperty("method", "xml"); props.setProperty("indent", "yes"); props.setProperty("omit-xml-declaration", "yes"); serialize(nodeInfo, new StreamResult(sw), props); return sw.toString(); } /** * Take the results of a query (or any other SequenceIterator) and create * an XML document containing copies of all items in the sequence, each item wrapped in a containing * element that identifies its type * @param iterator The values to be wrapped * @param config The Saxon configuration used to evaluate the query * @return the document containing the wrapped results * @throws XPathException * @since 8.8 */ public static DocumentInfo wrap(SequenceIterator iterator, Configuration config) throws XPathException { PipelineConfiguration pipe = config.makePipelineConfiguration(); TinyBuilder builder = new TinyBuilder(); builder.setPipelineConfiguration(pipe); NamespaceReducer reducer = new NamespaceReducer(); reducer.setUnderlyingReceiver(builder); reducer.setPipelineConfiguration(pipe); ComplexContentOutputter outputter = new ComplexContentOutputter(); outputter.setPipelineConfiguration(pipe); outputter.setReceiver(reducer); sendWrappedSequence(iterator, outputter); return (DocumentInfo)builder.getCurrentRoot(); } /** * Take a sequence supplied in the form of an iterator and generate a wrapped represention of the * items in the sequence, the wrapped representation being a sequence of events sent to a supplied * Receiver, in which each item is wrapped in a containing element that identifies its type * @param iterator the input sequence * @param destination the Receiver to accept the wrapped output * @since 8.8 */ public static void sendWrappedSequence(SequenceIterator iterator, Receiver destination) throws XPathException { SequenceCopier.copySequence(iterator, new SequenceWrapper(destination)); } /** * Serialize a document containing wrapped query results (or any other document, in fact) * as XML. * @param node The document or element to be serialized * @param destination The Result object to contain the serialized form * @param outputProperties Serialization options, as defined in JAXP. The requested properties are * not validated. * @param config The Configuration. This argument is ignored * @throws XPathException If serialization fails * @deprecated since 8.9; use {@link #serialize(NodeInfo, Result, Properties)} instead. */ //@SuppressWarnings({"UnusedDeclaration"}) public static void serialize(NodeInfo node, Result destination, Properties outputProperties, Configuration config) throws XPathException { serialize(node, destination, outputProperties); } /** * Serialize a document containing wrapped query results (or any other document, in fact) * as XML. * @param node The document or element to be serialized * @param destination The Result object to contain the serialized form * @param outputProperties Serialization options as defined in JAXP. The requested properties are * not validated. * @throws XPathException If serialization fails * @since 8.9 */ public static void serialize(NodeInfo node, Result destination, Properties outputProperties) throws XPathException { Configuration config = node.getConfiguration(); serializeSequence(SingletonIterator.makeIterator(node), config, destination, outputProperties); } /** * Serialize an arbitrary sequence, without any special wrapping. * @param iterator the sequence to be serialized * @param config the configuration (gives access to information such as the NamePool) * @param destination the output stream to which the output is to be written * @param outputProps a set of serialization properties as defined in JAXP. The requested properties are * not validated. * @throws XPathException if any failure occurs * @since 8.9 */ public static void serializeSequence( SequenceIterator iterator, Configuration config, OutputStream destination, Properties outputProps) throws XPathException { serializeSequence(iterator, config, new StreamResult(destination), outputProps); try { destination.flush(); } catch (IOException err) { throw new XPathException(err); } } /** * Serialize an arbitrary sequence, without any special wrapping. * @param iterator the sequence to be serialized * @param config the configuration (gives access to information such as the NamePool) * @param writer the writer to which the output is to be written * @param outputProps a set of serialization properties as defined in JAXP. The requested properties are * not validated. * @throws XPathException if any failure occurs * @since 8.9 */ public static void serializeSequence( SequenceIterator iterator, Configuration config, Writer writer, Properties outputProps) throws XPathException { serializeSequence(iterator, config, new StreamResult(writer), outputProps); try { writer.flush(); } catch (IOException err) { throw new XPathException(err); } } /** * Serialize a sequence to a given result * @param iterator the sequence to be serialized * @param config the Saxon Configuration * @param result the destination to receive the output * @param outputProperties the serialization properties to be used. The requested properties are * not validated. * @throws XPathException * @since 9.0 */ public static void serializeSequence( SequenceIterator iterator, Configuration config, Result result, Properties outputProperties) throws XPathException { SerializerFactory sf = config.getSerializerFactory(); PipelineConfiguration pipe = config.makePipelineConfiguration(); Receiver receiver = sf.getReceiver(result, pipe, outputProperties); TreeReceiver tr = new TreeReceiver(receiver); tr.open(); while (true) { Item item = iterator.next(); if (item == null) { break; } tr.append(item, 0, NodeInfo.ALL_NAMESPACES); } tr.close(); } /** * Write an updated document back to disk, using the original URI from which it was read * @param doc an updated document. Must be a document node, or a parentless element, or an * element that has a document node as its parent. The document will be written to the URI * found in the systemId property of this node. * @param outputProperties serialization properties * @param backup true if the old document at that location is to be copied to a backup file * @param log destination for progress messages; if null, no progress messages are written * @throws XPathException if the document has no known URI, if the URI is not a writable location, * or if a serialization error occurs. */ public static void rewriteToDisk(NodeInfo doc, Properties outputProperties, boolean backup, PrintStream log) throws XPathException { switch (doc.getNodeKind()) { case Type.DOCUMENT: // OK break; case Type.ELEMENT: NodeInfo parent = doc.getParent(); if (parent != null && parent.getNodeKind() != Type.DOCUMENT) { throw new XPathException("Cannot rewrite an element node unless it is top-level"); } break; default: throw new XPathException("Node to be rewritten must be a document or element node"); } String uri = doc.getSystemId(); if (uri == null || uri.length() == 0) { throw new XPathException("Cannot rewrite a document with no known URI"); } URI u; try { u = new URI(uri); } catch (URISyntaxException e) { throw new XPathException("SystemId of updated document is not a valid URI: " + uri); } File existingFile = new File(u); File dir = existingFile.getParentFile(); if (backup && existingFile.exists()) { File backupFile = new File(dir, existingFile.getName() + ".bak"); if (log != null) { log.println("Creating backup file " + backupFile); } existingFile.renameTo(backupFile); } if (!existingFile.exists()) { if (log != null) { log.println("Creating file " + existingFile); } try { existingFile.createNewFile(); } catch (IOException e) { throw new XPathException("Failed to create new file " + existingFile); } } else { if (log != null) { log.println("Overwriting file " + existingFile); } } Configuration config = doc.getConfiguration(); PipelineConfiguration pipe = config.makePipelineConfiguration(); SerializerFactory factory = config.getSerializerFactory(); Receiver r = factory.getReceiver(new StreamResult(existingFile), pipe, outputProperties); doc.copy(r, NodeInfo.ALL_NAMESPACES, false, 0); r.close(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/query/SequenceWrapper.java0000644000175000017500000002602511033112257022525 0ustar eugeneeugenepackage net.sf.saxon.query; import net.sf.saxon.event.Receiver; import net.sf.saxon.event.SequenceReceiver; import net.sf.saxon.om.*; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.AtomicType; import net.sf.saxon.value.AtomicValue; /** * This class can be used in a push pipeline: it accepts any sequence as input, and generates * a document in which the items of the sequence are wrapped by elements containing information about * the types of the items in the input sequence. */ public class SequenceWrapper extends SequenceReceiver { public static final String RESULT_NS = QueryResult.RESULT_NS; private Receiver out; private int depth = 0; //@SuppressWarnings({"FieldCanBeLocal"}) private int resultSequence; private int resultDocument; private int resultElement; private int resultAttribute; private int resultText; private int resultComment; private int resultPI; private int resultNamespace; private int resultAtomicValue; private int xsiType; /** * Create a sequence wrapper. This creates an XML representation of the items sent to destination * in which the types of all items are made explicit * @param destination the sequence being wrapped */ public SequenceWrapper(Receiver destination) { out = destination; // out = new TracingFilter(out); setPipelineConfiguration(destination.getPipelineConfiguration()); } public void open() throws XPathException { NamePool pool = getNamePool(); resultSequence = pool.allocate("result", RESULT_NS, "sequence"); resultDocument = pool.allocate("result", RESULT_NS, "document"); resultElement = pool.allocate("result", RESULT_NS, "element"); resultAttribute = pool.allocate("result", RESULT_NS, "attribute"); resultText = pool.allocate("result", RESULT_NS, "text"); resultComment = pool.allocate("result", RESULT_NS, "comment"); resultPI = pool.allocate("result", RESULT_NS, "processing-instruction"); resultNamespace = pool.allocate("result", RESULT_NS, "namespace"); resultAtomicValue = pool.allocate("result", RESULT_NS, "atomic-value"); xsiType = pool.allocate("xsi", NamespaceConstant.SCHEMA_INSTANCE, "type"); out.open(); out.startDocument(0); out.startElement(resultSequence, StandardNames.XS_UNTYPED, 0, 0); out.namespace(pool.allocateNamespaceCode("result", RESULT_NS), 0); out.namespace(pool.allocateNamespaceCode("xs", NamespaceConstant.SCHEMA), 0); out.namespace(pool.allocateNamespaceCode("xsi", NamespaceConstant.SCHEMA_INSTANCE), 0); out.startContent(); } /** * Start of a document node. */ public void startDocument(int properties) throws XPathException { out.startElement(resultDocument, StandardNames.XS_UNTYPED, 0, 0); out.startContent(); depth++; } /** * Notify the end of a document node */ public void endDocument() throws XPathException { out.endElement(); depth--; } /** * Notify the start of an element * * @param nameCode integer code identifying the name of the element within the name pool. * @param typeCode integer code identifying the element's type within the name pool. * @param properties properties of the element node */ public void startElement(int nameCode, int typeCode, int locationId, int properties) throws XPathException { if (depth++ == 0) { out.startElement(resultElement, StandardNames.XS_UNTYPED, 0, 0); out.startContent(); } out.startElement(nameCode, typeCode, locationId, properties); } /** * End of element */ public void endElement() throws XPathException { out.endElement(); if (--depth == 0) { out.endElement(); // close the wrapping element } } /** * Notify an attribute. Attributes are notified after the startElement event, and before any * children. Namespaces and attributes may be intermingled. * * @param nameCode The name of the attribute, as held in the name pool * @param typeCode The type of the attribute, as held in the name pool * @param properties Bit significant value. The following bits are defined: *
    DISABLE_ESCAPING
    Disable escaping for this attribute
    *
    NO_SPECIAL_CHARACTERS
    Attribute value contains no special characters
    * @throws IllegalStateException: attempt to output an attribute when there is no open element * start tag */ public void attribute(int nameCode, int typeCode, CharSequence value, int locationId, int properties) throws XPathException { if (depth==0) { out.startElement(resultAttribute, StandardNames.XS_UNTYPED, 0, 0); if ((nameCode &~ NamePool.FP_MASK) != 0) { out.namespace(getNamePool().allocateNamespaceCode(nameCode), 0); } out.attribute(nameCode, typeCode, value, locationId, properties); out.startContent(); out.endElement(); } else { out.attribute(nameCode, typeCode, value, locationId, properties); } } /** * Notify a namespace. Namespaces are notified after the startElement event, and before * any children for the element. The namespaces that are reported are only required * to include those that are different from the parent element; however, duplicates may be reported. * A namespace must not conflict with any namespaces already used for element or attribute names. * * @param namespaceCode an integer: the top half is a prefix code, the bottom half a URI code. * These may be translated into an actual prefix and URI using the name pool. A prefix code of * zero represents the empty prefix (that is, the default namespace). A URI code of zero represents * a URI of "", that is, a namespace undeclaration. * @throws IllegalStateException: attempt to output a namespace when there is no open element * start tag */ public void namespace(int namespaceCode, int properties) throws XPathException { if (depth == 0) { out.startElement(resultNamespace, StandardNames.XS_UNTYPED, 0, 0); out.namespace(namespaceCode, properties); out.startContent(); out.endElement(); } else { out.namespace(namespaceCode, properties); } } /** * Character data */ public void characters(CharSequence chars, int locationId, int properties) throws XPathException { if (depth==0) { out.startElement(resultText, StandardNames.XS_UNTYPED, 0, 0); out.startContent(); out.characters(chars, locationId, properties); out.endElement(); } else { out.characters(chars, locationId, properties); } } /** * Output a comment */ public void comment(CharSequence chars, int locationId, int properties) throws XPathException { if (depth==0) { out.startElement(resultComment, StandardNames.XS_UNTYPED, 0, 0); out.startContent(); out.comment(chars, locationId, properties); out.endElement(); } else { out.comment(chars, locationId, properties); } } /** * Processing Instruction */ public void processingInstruction(String target, CharSequence data, int locationId, int properties) throws XPathException { if (depth==0) { out.startElement(resultPI, StandardNames.XS_UNTYPED, 0, 0); out.startContent(); out.processingInstruction(target, data, locationId, properties); out.endElement(); } else { out.processingInstruction(target, data, locationId, properties); } } /** * Output an item (atomic value or node) to the sequence */ public void append(Item item, int locationId, int copyNamespaces) throws XPathException { if (item instanceof AtomicValue) { final NamePool pool = getNamePool(); out.startElement(resultAtomicValue, StandardNames.XS_UNTYPED, 0, 0); AtomicType type = (AtomicType)((AtomicValue)item).getItemType(getConfiguration().getTypeHierarchy()); int nameCode = type.getNameCode(); String prefix = pool.getPrefix(nameCode); String localName = pool.getLocalName(nameCode); String uri = pool.getURI(nameCode); if (prefix.length() == 0) { prefix = pool.suggestPrefixForURI(uri); if (prefix == null) { prefix = "p" + uri.hashCode(); } } int nscode = pool.allocateNamespaceCode(prefix, uri); String displayName = prefix + ':' + localName; out.namespace(nscode, 0); out.attribute(xsiType, StandardNames.XS_UNTYPED_ATOMIC, displayName, 0, 0); out.startContent(); out.characters(item.getStringValue(), 0, 0); out.endElement(); } else { ((NodeInfo)item).copy(this, NodeInfo.ALL_NAMESPACES, true, locationId); } } /** * Notify the start of the content, that is, the completion of all attributes and namespaces. * Note that the initial receiver of output from XSLT instructions will not receive this event, * it has to detect it itself. Note that this event is reported for every element even if it has * no attributes, no namespaces, and no content. */ public void startContent() throws XPathException { out.startContent(); } /** * Notify the end of the event stream */ public void close() throws XPathException { out.endElement(); // close the result:sequence element out.endDocument(); out.close(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/query/XQueryExpression.java0000644000175000017500000011557311057553175022756 0ustar eugeneeugenepackage net.sf.saxon.query; import net.sf.saxon.Configuration; import net.sf.saxon.Controller; import net.sf.saxon.event.*; import net.sf.saxon.evpull.ComplexContentProcessor; import net.sf.saxon.evpull.EventIterator; import net.sf.saxon.evpull.EventIteratorToReceiver; import net.sf.saxon.expr.*; import net.sf.saxon.instruct.Executable; import net.sf.saxon.instruct.GlobalVariable; import net.sf.saxon.instruct.SlotManager; import net.sf.saxon.om.*; import net.sf.saxon.pull.PullFromIterator; import net.sf.saxon.pull.PullNamespaceReducer; import net.sf.saxon.pull.PullProvider; import net.sf.saxon.pull.PullPushCopier; import net.sf.saxon.trace.ExpressionPresenter; import net.sf.saxon.trace.TraceListener; import net.sf.saxon.trans.UncheckedXPathException; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.Type; import net.sf.saxon.value.DateTimeValue; import net.sf.saxon.value.Value; import javax.xml.transform.ErrorListener; import javax.xml.transform.Result; import javax.xml.transform.TransformerException; import javax.xml.transform.stream.StreamResult; import java.io.OutputStream; import java.util.*; /** * XQueryExpression represents a compiled query. This object is immutable and thread-safe, * the same compiled query may be executed many times in series or in parallel. The object * can be created only by using the compileQuery method of the QueryProcessor class. *

    *

    Various methods are provided for evaluating the query, with different options for * delivery of the results.

    */ public class XQueryExpression implements Container { private Expression expression; private SlotManager stackFrameMap; private Executable executable; private QueryModule staticContext; private PathMap pathMap; private boolean allowDocumentProjection; private boolean isUpdating; /** * The constructor is protected, to ensure that instances can only be * created using the compileQuery() methods of StaticQueryContext * * @param exp an expression to be wrapped as an XQueryExpression * @param exec the executable * @param mainModule the static context of the main module * @param config the configuration * @throws XPathException if an error occurs */ protected XQueryExpression(Expression exp, Executable exec, QueryModule mainModule, Configuration config) throws XPathException { stackFrameMap = config.makeSlotManager(); executable = exec; exp.setContainer(this); try { ExpressionVisitor visitor = ExpressionVisitor.make(mainModule); visitor.setExecutable(exec); exp = visitor.simplify(exp); exp.checkForUpdatingSubexpressions(); exp = visitor.typeCheck(exp, mainModule.getUserQueryContext().getRequiredContextItemType()); // ExpressionPresenter presenter = new ExpressionPresenter(config, // ExpressionPresenter.defaultDestination(config, new FileOutputStream("c:/projects/montreal/before50.xml"))); // exp.explain(presenter); // presenter.close(); exp = exp.optimize(visitor, Type.ITEM_TYPE); } catch (XPathException err) { //err.printStackTrace(); mainModule.reportFatalError(err); throw err; } ExpressionTool.allocateSlots(exp, 0, stackFrameMap); expression = exp; executable.setConfiguration(config); executable.setDefaultCollationName(mainModule.getDefaultCollationName()); executable.setCollationTable(mainModule.getUserQueryContext().getAllCollations()); staticContext = mainModule; isUpdating = exp.isUpdatingExpression(); } /** * Get the expression wrapped in this XQueryExpression object * * @return the underlying expression */ public Expression getExpression() { return expression; } /** * Ask whether this query uses the context item * * @return true if the context item is referenced either in the query body or in the initializer * of any global variable */ public boolean usesContextItem() { if ((expression.getDependencies() & StaticProperty.DEPENDS_ON_FOCUS) != 0) { return true; } HashMap map = executable.getCompiledGlobalVariables(); if (map != null) { Iterator iter = map.values().iterator(); while (iter.hasNext()) { GlobalVariable var = (GlobalVariable)iter.next(); Expression select = var.getSelectExpression(); if (select != null && (select.getDependencies() & StaticProperty.DEPENDS_ON_FOCUS) != 0) { return true; } } } return false; } /** * Ask whether this is an update query * * @return true if the body of the query is an updating expression * (as defined by the XQuery Update specification). Note that a query can use Update syntax * (notably the copy-modify syntax) without being an updating expression. */ public boolean isUpdateQuery() { return isUpdating; } /** * Get the stack frame map used for the outermost level of this query * * @return the stack frame map */ public SlotManager getStackFrameMap() { return stackFrameMap; } /** * Replace one subexpression by a replacement subexpression. For internal use only * * @param original the original subexpression * @param replacement the replacement subexpression * @return true if the original subexpression is found */ public boolean replaceSubExpression(Expression original, Expression replacement) { boolean found = false; if (expression == original) { expression = replacement; found = true; } return found; } /** * Get the static context in which this expression was compiled. This is essentially an internal * copy of the original user-created StaticQueryContext object, augmented with information obtained * from the query prolog of the main query module, and with information about functions and variables * imported from other library modules. The user-created StaticQueryContext object is not modified * by Saxon, whereas the QueryModule object includes additional information found in the query prolog. * * @return the QueryModule object representing the static context of the main module of the query. * This is available for inspection, but must not be modified or reused by the application. */ public QueryModule getStaticContext() { return staticContext; } /** * Get a list containing the names of the external variables in the query. *

    *

    Changed in Saxon 9.0 to return an array of StructuredQName objects rather than * integer fingerprints.

    * * @return an array of StructuredQName objects, representing the names of external variables defined * in the query */ public StructuredQName[] getExternalVariableNames() { List list = stackFrameMap.getVariableMap(); StructuredQName[] names = new StructuredQName[stackFrameMap.getNumberOfVariables()]; for (int i = 0; i < names.length; i++) { names[i] = (StructuredQName)list.get(i); } return names; } /** * Execute a the compiled Query, returning the results as a List. * * @param env Provides the dynamic query evaluation context * @return The results of the expression, as a List. The List represents the sequence * of items returned by the expression. Each item in the list will either be an * object representing a node, or an object representing an atomic value. * For the types of Java object that may be returned, see the description of the * {@link net.sf.saxon.xpath.XPathEvaluator#evaluate evaluate} method * of class XPathProcessor */ public List evaluate(DynamicQueryContext env) throws XPathException { if (isUpdating) { throw new XPathException("Cannot call evaluate() on an updating query"); } SequenceIterator iterator = iterator(env); ArrayList list = new ArrayList(100); while (true) { Item item = iterator.next(); if (item == null) { return list; } list.add(Value.convertToJava(item)); } } /** * Execute the compiled Query, returning the first item in the result. * This is useful where it is known that the expression will only return * a singleton value (for example, a single node, or a boolean). * * @param env Provides the dynamic query evaluation context * @return The first item in the sequence returned by the expression. If the expression * returns an empty sequence, this method returns null. Otherwise, it returns the first * item in the result sequence, represented as a Java object using the same mapping as for * the {@link XQueryExpression#evaluate evaluate} method */ public Object evaluateSingle(DynamicQueryContext env) throws XPathException { if (isUpdating) { throw new XPathException("Cannot call evaluateSingle() on an updating query"); } SequenceIterator iterator = iterator(env); Item item = iterator.next(); if (item == null) { return null; } return Value.convertToJava(item); } /** * Get an iterator over the results of the expression. This returns results without * any conversion of the returned items to "native" Java classes. The iterator will * deliver a sequence of Item objects, each item being either a NodeInfo (representing * a node) or an AtomicValue (representing an atomic value). *

    *

    To get the results of the query in the form of an XML document in which each * item is wrapped by an element indicating its type, use:

    *

    *

    QueryResult.wrap(iterator(env))

    *

    *

    To serialize the results to a file, use the QueryResult.serialize() method.

    * * @param env Provides the dynamic query evaluation context * @return an iterator over the results of the query. The class SequenceIterator * is modeled on the standard Java Iterator class, but has extra functionality * and can throw exceptions when errors occur. * @throws XPathException if a dynamic error occurs in evaluating the query. Some * dynamic errors will not be reported by this method, but will only be reported * when the individual items of the result are accessed using the returned iterator. */ public SequenceIterator iterator(DynamicQueryContext env) throws XPathException { if (isUpdating) { throw new XPathException("Cannot call iterator() on an updating query"); } Controller controller = newController(); initializeController(env, controller); try { Item contextItem = env.getContextItem(); //Bindery bindery = controller.getBindery(); //bindery.openStackFrame(); controller.defineGlobalParameters(); XPathContextMajor context = controller.newXPathContext(); if (contextItem != null) { if (!staticContext.getUserQueryContext().getRequiredContextItemType().matchesItem( contextItem, false, env.getConfiguration())) { throw new XPathException("The supplied context item does not match the required context item type"); } UnfailingIterator single = SingletonIterator.makeIterator(contextItem); single.next(); context.setCurrentIterator(single); controller.setInitialContextItem(contextItem); } // In tracing/debugging mode, evaluate all the global variables first if (controller.getTraceListener() != null) { controller.preEvaluateGlobals(context); } context.openStackFrame(stackFrameMap); SequenceIterator iterator = expression.iterate(context); return new ErrorReportingIterator(iterator, controller.getErrorListener()); } catch (XPathException err) { TransformerException terr = err; while (terr.getException() instanceof TransformerException) { terr = (TransformerException)terr.getException(); } XPathException de = XPathException.makeXPathException(terr); controller.reportFatalError(de); throw de; } } private void initializeController(DynamicQueryContext env, Controller controller) { HashMap parameters = env.getParameters(); if (parameters != null) { Iterator iter = parameters.keySet().iterator(); while (iter.hasNext()) { String paramName = (String)iter.next(); Object paramValue = parameters.get(paramName); controller.setParameter(paramName, paramValue); } } controller.setURIResolver(env.getURIResolver()); controller.setErrorListener(env.getErrorListener()); controller.addTraceListener(env.getTraceListener()); controller.setTraceFunctionDestination(env.getTraceFunctionDestination()); DateTimeValue currentDateTime = env.getCurrentDateTime(); if (currentDateTime != null) { try { controller.setCurrentDateTime(currentDateTime); } catch (XPathException e) { throw new AssertionError(e); // the value should already have been checked } } } /** * Run the query, sending the results directly to a JAXP Result object. This way of executing * the query is most efficient in the case of queries that produce a single document (or parentless * element) as their output, because it avoids constructing the result tree in memory: instead, * it is piped straight to the serializer. * * @param env the dynamic query context * @param result the destination for the results of the query. The query is effectively wrapped * in a document{} constructor, so that the items in the result are concatenated to form a single * document; this is then written to the requested Result destination, which may be (for example) * a DOMResult, a SAXResult, or a StreamResult * @param outputProperties Supplies serialization properties, in JAXP format, if the result is to * be serialized. This parameter can be defaulted to null. * @throws XPathException if the query fails. */ public void run(DynamicQueryContext env, Result result, Properties outputProperties) throws XPathException { if (isUpdating) { throw new XPathException("Cannot call run() on an updating query"); } Controller controller = newController(); initializeController(env, controller); if (allowDocumentProjection) { controller.setUseDocumentProjection(getPathMap()); } Properties actualProperties = validateOutputProperties(controller, outputProperties); controller.defineGlobalParameters(); XPathContextMajor context = initialContext(env, controller); // In tracing/debugging mode, evaluate all the global variables first TraceListener tracer = controller.getTraceListener(); if (tracer != null) { controller.preEvaluateGlobals(context); tracer.open(); } context.openStackFrame(stackFrameMap); boolean mustClose = (result instanceof StreamResult && ((StreamResult)result).getOutputStream() == null); context.changeOutputDestination(actualProperties, result, true, Configuration.XQUERY, Validation.PRESERVE, null); context.getReceiver().open(); // Run the query try { expression.process(context); } catch (XPathException err) { controller.reportFatalError(err); throw err; } if (tracer != null) { tracer.close(); } context.getReceiver().close(); if (mustClose) { OutputStream os = ((StreamResult)result).getOutputStream(); if (os != null) { try { os.close(); } catch (java.io.IOException err) { throw new XPathException(err); } } } } private Properties validateOutputProperties(Controller controller, Properties outputProperties) throws XPathException { // Validate the serialization properties requested Properties baseProperties = controller.getOutputProperties(); if (outputProperties != null) { Enumeration iter = outputProperties.propertyNames(); while (iter.hasMoreElements()) { String key = (String)iter.nextElement(); String value = outputProperties.getProperty(key); try { SaxonOutputKeys.checkOutputProperty(key, value, controller.getConfiguration().getNameChecker()); baseProperties.setProperty(key, value); } catch (XPathException dynamicError) { try { outputProperties.remove(key); controller.getErrorListener().warning(dynamicError); } catch (TransformerException err2) { throw XPathException.makeXPathException(err2); } } } } if (baseProperties.getProperty("method") == null) { // XQuery forces the default method to XML, unlike XSLT where it depends on the contents of the result tree baseProperties.setProperty("method", "xml"); } return baseProperties; } /** * Run the query in pull mode. *

    *

    For maximum effect this method should be used when lazyConstructionMode has been set in the Configuration.

    *

    *

    Note: this method usually has very similar performance to the * {@link #run(DynamicQueryContext,javax.xml.transform.Result,java.util.Properties)} method (which does * the same thing), but sometimes it is significantly slower. Therefore, the run() method is preferred.

    * * @param dynamicEnv the dynamic context for query evaluation * @param destination the destination of the query results * @param outputProperties the serialization parameters * @see Configuration#setLazyConstructionMode(boolean) */ public void pullOLD(DynamicQueryContext dynamicEnv, Result destination, Properties outputProperties) throws XPathException { try { SequenceIterator iter = iterator(dynamicEnv); PullProvider pull = new PullFromIterator(iter); pull = new PullNamespaceReducer(pull); final Configuration config = executable.getConfiguration(); pull.setPipelineConfiguration(config.makePipelineConfiguration()); SerializerFactory sf = config.getSerializerFactory(); Receiver receiver = sf.getReceiver(destination, pull.getPipelineConfiguration(), outputProperties); // NamespaceReducer reducer = new NamespaceReducer(); // PipelineConfiguration pipe = pull.getPipelineConfiguration(); // reducer.setPipelineConfiguration(pipe); // reducer.setUnderlyingReceiver(receiver); // ComplexContentOutputter outputter = new ComplexContentOutputter(); // outputter.setReceiver(reducer); // outputter.setPipelineConfiguration(pipe); Receiver outputter = receiver; if ("yes".equals(outputProperties.getProperty(SaxonOutputKeys.WRAP))) { receiver = new SequenceWrapper(outputter); } else { //receiver = new TreeReceiver(outputter); } new PullPushCopier(pull, receiver).copy(); } catch (UncheckedXPathException e) { throw e.getXPathException(); } } /** * Run the query in pull mode. *

    *

    For maximum effect this method should be used when lazyConstructionMode has been set in the Configuration.

    *

    *

    Note: this method usually has very similar performance to the * {@link #run(DynamicQueryContext,javax.xml.transform.Result,java.util.Properties)} method (which does * the same thing), but sometimes it is significantly slower. Therefore, the run() method is preferred.

    * * @param dynamicEnv the dynamic context for query evaluation * @param destination the destination of the query results * @param outputProperties the serialization parameters * @see Configuration#setLazyConstructionMode(boolean) */ public void pull(DynamicQueryContext dynamicEnv, Result destination, Properties outputProperties) throws XPathException { if (isUpdating) { throw new XPathException("Cannot call pull() on an updating query"); } Configuration config = dynamicEnv.getConfiguration(); try { Controller controller = newController(); //initializeController(dynamicEnv, controller); EventIterator iter = iterateEvents(controller, dynamicEnv); //iter = new Decomposer(iter, config); Properties actualProperties = validateOutputProperties(controller, outputProperties); SerializerFactory sf = config.getSerializerFactory(); PipelineConfiguration pipe = config.makePipelineConfiguration(); pipe.setSerializing(true); Receiver receiver = sf.getReceiver(destination, pipe, actualProperties); receiver = new NamespaceReducer(receiver); if ("yes".equals(actualProperties.getProperty(SaxonOutputKeys.WRAP))) { receiver = new SequenceWrapper(receiver); //receiver = new TracingFilter(receiver); } else { receiver = new TreeReceiver(receiver); } EventIteratorToReceiver.copy(iter, (SequenceReceiver)receiver); } catch (XPathException err) { config.reportFatalError(err); throw err; } } /** * Run the query returning the results as an EventIterator * * @param controller The Controller used to run the query * @param dynamicEnv the XQuery dynamic context for evaluating the query * @return an EventIterator representing the results of the query as a sequence of events */ public EventIterator iterateEvents(Controller controller, DynamicQueryContext dynamicEnv) throws XPathException { if (isUpdating) { throw new XPathException("Cannot call iterateEvents() on an updating query"); } initializeController(dynamicEnv, controller); XPathContextMajor context = initialContext(dynamicEnv, controller); // In tracing/debugging mode, evaluate all the global variables first if (controller.getTraceListener() != null) { controller.preEvaluateGlobals(context); } context.openStackFrame(stackFrameMap); final Configuration config = executable.getConfiguration(); EventIterator ei = expression.iterateEvents(context); //ei = new TracingEventIterator(EventStackIterator.flatten(ei)); return new ComplexContentProcessor(config, ei); } /** * Run an updating query * * @param dynamicEnv the dynamic context for query execution * @return a set of nodes representing the roots of trees that have been modified as a result * of executing the update. Note that this method will never modify persistent data on disk; it returns * the root nodes of the affected documents (which will often be document nodes whose document-uri can * be ascertained), and it is the caller's responsibility to decide what to do with them. *

    On completion of this method it is generally unsafe to rely on the contents or relationships * of NodeInfo objects that were obtained before the updating query was run. Such objects may or may not * reflect the results of the update operations. This is especially true in the case of nodes that * are part of a subtree that has been deleted (detached from its parent). Instead, the new updated * tree should be accessed by navigation from the root nodes returned by this method.

    * @throws XPathException if evaluation of the update query fails, or it this is not an updating query */ public Set runUpdate(DynamicQueryContext dynamicEnv) throws XPathException { if (!isUpdating) { throw new XPathException("Calling runUpdate() on a non-updating query"); } Configuration config = executable.getConfiguration(); Controller controller = newController(); initializeController(dynamicEnv, controller); XPathContextMajor context = initialContext(dynamicEnv, controller); try { PendingUpdateList pul = config.newPendingUpdateList(); context.openStackFrame(stackFrameMap); expression.evaluatePendingUpdates(context, pul); pul.apply(context, staticContext.getRevalidationMode()); return pul.getAffectedTrees(); } catch (XPathException e) { if (!e.hasBeenReported()) { try { controller.getErrorListener().fatalError(e); } catch (TransformerException e2) { // ignore secondary error } } throw e; } } /** * Run an updating query, writing back eligible updated node to persistent storage. * *

    A node is eligible to be written back to disk if it is present in the document pool, * which generally means that it was originally read using the doc() or collection() function.

    * *

    On completion of this method it is generally unsafe to rely on the contents or relationships * of NodeInfo objects that were obtained before the updating query was run. Such objects may or may not * reflect the results of the update operations. This is especially true in the case of nodes that * are part of a subtree that has been deleted (detached from its parent). Instead, the new updated * tree should be accessed by navigation from the root nodes returned by this method.

    * *

    If one or more eligible updated nodes cannot be written back to disk, perhaps because the URI * identifies a non-updatable location, then an exception is thrown. In this case it is undefined * * @param dynamicEnv the dynamic context for query execution * * @throws XPathException if evaluation of the update query fails, or it this is not an updating query */ public void runUpdate(DynamicQueryContext dynamicEnv, UpdateAgent agent) throws XPathException { if (!isUpdating) { throw new XPathException("Calling runUpdate() on a non-updating query"); } Configuration config = executable.getConfiguration(); Controller controller = newController(); initializeController(dynamicEnv, controller); XPathContextMajor context = initialContext(dynamicEnv, controller); try { PendingUpdateList pul = config.newPendingUpdateList(); context.openStackFrame(stackFrameMap); expression.evaluatePendingUpdates(context, pul); pul.apply(context, staticContext.getRevalidationMode()); for (Iterator iter = pul.getAffectedTrees().iterator(); iter.hasNext();) { NodeInfo node = (NodeInfo)iter.next(); agent.update(node, controller); } } catch (XPathException e) { if (!e.hasBeenReported()) { try { controller.getErrorListener().fatalError(e); } catch (TransformerException e2) { // ignore secondary error } } throw e; } } private XPathContextMajor initialContext(DynamicQueryContext dynamicEnv, Controller controller) throws XPathException { Item contextItem = dynamicEnv.getContextItem(); controller.defineGlobalParameters(); XPathContextMajor context = controller.newXPathContext(); if (contextItem != null) { if (!staticContext.getUserQueryContext().getRequiredContextItemType().matchesItem( contextItem, false, dynamicEnv.getConfiguration())) { throw new XPathException("The supplied context item does not match the required context item type"); } UnfailingIterator single = SingletonIterator.makeIterator(contextItem); single.next(); context.setCurrentIterator(single); controller.setInitialContextItem(contextItem); } return context; } /** * Get a controller that can be used to execute functions in this compiled query. * Functions in the query module can be found using {@link QueryModule#getUserDefinedFunction}. * They can then be called directly from the Java application using {@link net.sf.saxon.instruct.UserFunction#call} * The same Controller can be used for a series of function calls. Note that the Controller should only be used * in a single thread. * * @return a newly constructed Controller */ public Controller newController() { Controller controller = new Controller(executable.getConfiguration(), executable); executable.initializeBindery(controller.getBindery()); if (isUpdating && controller.getTreeModel() == Builder.TINY_TREE) { controller.setTreeModel(Builder.LINKED_TREE); } return controller; } /** * Deprecated synonym for {@link #newController} * * @return a newly constructed Controller * @deprecated since 8.5.1 - use newController() */ public Controller getController() { return newController(); } /** * Diagnostic method: display a representation of the compiled query on the * selected output stream. * * @param out an ExpressionPresenter to which the XML representation of the compiled query * will be sent */ public void explain(ExpressionPresenter out) { out.startElement("query"); staticContext.getExecutable().getKeyManager().explainKeys(out); staticContext.getExecutable().explainGlobalVariables(out); staticContext.explainGlobalFunctions(out); out.startElement("body"); expression.explain(out); out.endElement(); out.endElement(); out.close(); } /** * Get the Executable (representing a complete stylesheet or query) of which this Container forms part */ public Executable getExecutable() { return executable; } /** * Get the path map for the query expression * * @return the path map (which is constructed if this has not already been done) */ public PathMap getPathMap() { if (pathMap == null) { pathMap = new PathMap(expression); } HashMap map = executable.getCompiledGlobalVariables(); if (map != null) { Iterator iter = map.values().iterator(); while (iter.hasNext()) { GlobalVariable var = (GlobalVariable)iter.next(); Expression select = var.getSelectExpression(); select.addToPathMap(pathMap, null); } } return pathMap; } /** * Get the LocationProvider allowing location identifiers to be resolved. */ public LocationProvider getLocationProvider() { return executable.getLocationMap(); } /** * Indicate that document projection is or is not allowed * * @param allowed true if projection is allowed */ public void setAllowDocumentProjection(boolean allowed) { allowDocumentProjection = allowed; } /** * Ask whether document projection is allowed * * @return true if document projection is allowed */ public boolean isDocumentProjectionAllowed() { return allowDocumentProjection; } /** * Return the public identifier for the current document event. *

    *

    The return value is the public identifier of the document * entity or of the external parsed entity in which the markup that * triggered the event appears.

    * * @return A string containing the public identifier, or * null if none is available. * @see #getSystemId */ public String getPublicId() { return null; } /** * Return the system identifier for the current document event. *

    *

    The return value is the system identifier of the document * entity or of the external parsed entity in which the markup that * triggered the event appears.

    *

    *

    If the system identifier is a URL, the parser must resolve it * fully before passing it to the application.

    * * @return A string containing the system identifier, or null * if none is available. * @see #getPublicId */ public String getSystemId() { return null; } /** * Return the line number where the current document event ends. *

    *

    Warning: The return value from the method * is intended only as an approximation for the sake of error * reporting; it is not intended to provide sufficient information * to edit the character content of the original XML document.

    *

    *

    The return value is an approximation of the line number * in the document entity or external parsed entity where the * markup that triggered the event appears.

    * * @return The line number, or -1 if none is available. * @see #getColumnNumber */ public int getLineNumber() { return -1; } /** * Return the character position where the current document event ends. *

    *

    Warning: The return value from the method * is intended only as an approximation for the sake of error * reporting; it is not intended to provide sufficient information * to edit the character content of the original XML document.

    *

    *

    The return value is an approximation of the column number * in the document entity or external parsed entity where the * markup that triggered the event appears.

    * * @return The column number, or -1 if none is available. * @see #getLineNumber */ public int getColumnNumber() { return -1; } /** * Get the host language (XSLT, XQuery, XPath) used to implement the code in this container * * @return typically {@link net.sf.saxon.Configuration#XSLT} or {@link net.sf.saxon.Configuration#XQUERY} */ public int getHostLanguage() { return Configuration.XQUERY; } /** * ErrorReportingIterator is an iterator that wraps a base iterator and reports * any exceptions that are raised to the ErrorListener */ private class ErrorReportingIterator implements SequenceIterator { private SequenceIterator base; private ErrorListener listener; public ErrorReportingIterator(SequenceIterator base, ErrorListener listener) { this.base = base; this.listener = listener; } public Item next() throws XPathException { try { return base.next(); } catch (XPathException e1) { e1.maybeSetLocation(expression); try { listener.fatalError(e1); } catch (TransformerException e2) { // } e1.setHasBeenReported(); throw e1; } } public Item current() { return base.current(); } public int position() { return base.position(); } public void close() { base.close(); } public SequenceIterator getAnother() throws XPathException { return new ErrorReportingIterator(base.getAnother(), listener); } /** * Get properties of this iterator, as a bit-significant integer. * * @return the properties of this iterator. This will be some combination of * properties such as {@link #GROUNDED}, {@link #LAST_POSITION_FINDER}, * and {@link #LOOKAHEAD}. It is always * acceptable to return the value zero, indicating that there are no known special properties. * It is acceptable for the properties of the iterator to change depending on its state. */ public int getProperties() { return 0; } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/query/package.html0000644000175000017500000002050611033112257021030 0ustar eugeneeugene Package overview for net.sf.saxon.query

    This package provides an API for executing XQuery queries directly from a Java application. It also includes the internal supporting code that implements XQuery within Saxon.

    For details of the API, see the JavaDoc documentation of individual classes, starting with the StaticQueryContext.

    The first thing you need to do is to create a net.sf.saxon.Configuration object. This holds values of all the system settings, corresponding to flags available on the command line. You don't need to set any properties in the Configuration object if you are happy with the default settings. For schema-aware processing, you will need to create a com.saxonica.SchemaAwareConfiguration instead.

    Then you need to create a StaticQueryContext object. As the name implies, this holds information about the static (compile-time) context for a query. Most aspects of the static context can be defined in the Query Prolog, but this object allows you to initialize the static context from the application instead if you need to. Some of the facilities provided are very much for advanced users only, for example the ability to declare variables and functions, and the ability to specify a NamePool to be used. One aspect of the static context that you may need to use is the ability to declare collations. Using the method declareCollation you can create a mapping between a collation URI (which can then be used anywhere in the Query) and a Java StringCollator object used to implement that collation.

    Having created, and possibly configured, the Configuration and StaticQueryContext objects, you can now compile a Query using the compileQuery method on the StaticQueryContext. The text of the Query can be supplied either as a String or as a Java Reader. There are thus two different compileQuery methods. Each of them returns the compiled query in the form of a XQueryExpression. The XQueryExpression, as you would expect, can be executed repeatedly, as often as you want, in the same or in different threads.

    Before you run your query, you may want to build one or more trees representing XML documents that can be used as input to your query. You don't need to do this: if the query loads its source documents using the doc() function then this will be done automatically, but doing it yourself gives you more control. A document node at the root of a tree is represented in Saxon by the net.sf.saxon.DocumentInfo interface. The StaticQueryContext provides a convenience method, buildDocument(), that allows an instance of DocumentInfo to be constructed. The input parameter to this is defined by the class javax.xml.transform.Source, which is part of the standard Java JAXP API: the Source interface is an umbrella for different kinds of XML document source, including a StreamSource which parses raw XML from a byte or character stream, SAXSource which takes the input from a SAX parser (or an object that is simulating a SAX parser), and DOMSource which provides the input from a DOM. Saxon also provides a net.sf.saxon.jdom.DocumentWrapper which allows the input to be taken from a JDOM document.

    To execute your compiled query, you need to create a DynamicQueryContext object that holds the run-time context information. The main things you can set in the run-time context are:

    • Values of parameters (external global variables). You can set these using the setParameter() method. The mappings from Java classes to XQuery/XPath data types is the same as the mapping used for the returned values from an external Java method call, and is described under Result of an Extension Function.
    • The context node can be set using the method setContextNode(). For some reason it isn't possible to set a context item other than a node.
    • You can also set a URIResolver and/or ErrorListener. These default to the ones that were used during Query compilation.

    You are now ready to evaluate the query. There are several methods on the QueryExpression object that you can use to achieve this. The evaluate() method returns the result sequence as a Java java.util.List. The evaluateSingle() method is suitable when you know that the result sequence will contain a single item: this returns this item as an Object, or returns null if the result is an empty sequence. There is also an iterator method that returns an iterator over the results. This is a Saxon object of class net.sf.saxon.SequenceIterator: it is similar to the standard Java iterator, but not quite identical; for example, it can throw exceptions.

    The evaluate() and evaluateSingle() methods return the result as a Java object of the most appropriate type: for example a String is returned as a java.lang.String, a boolean as a java.lang.Boolean. A node is returned using the Saxon representation of a node, net.sf.saxon.om.NodeInfo. With the standard and tinytree models, this object also implements the DOM Node interface (but any attempt to update the node throws an error).

    The iterator() method, by contrast, does not do any conversion of the result. It is returned using its native Saxon representation, for example a String is returned as an instance of sf.net.saxon.value.StringValue. You can then use all the methods available on this class to process the returned value.

    If you want to process the results of the query in your application, that's all there is to it. But you may want to output the results as serialized XML. Saxon provides two ways of doing this: you can produce wrapped output, or raw output. Raw output works only if the result consists of a single document or element node, and it outputs the subtree rooted at that element node in the form of a serialized XML document. Wrapped output works for any result sequence, for example a sequence of integers or a sequence of attribute and comment nodes; this works by wrapping each item in the result sequence as an XML element, with details of its type and value.

    To produce wrapped output, you first wrap the result sequence as an XML tree, and then serialize the tree. To produce unwrapped output, you skip the wrapping stage and just call the serializer directly.

    Both steps can be done using the QueryResult class. This class doesn't need to be instantiated, its methods are static. The method QueryResult.wrap takes as input the iterator produced by evaluating the query using the iterator() method, and produces as output a DocumentInfo object representing the results wrapped as an XML tree. The method QueryResult.serialize takes any document or element node as input, and writes it to a specified destination, using specified output properties. The destination is supplied as an object of class javax.xml.transform.Result. Like the Source, this is part of the JAXP API, and allows the destination to be specified as a StreamResult (representing a byte stream or character stream), a SAXResult (which wraps a SAX ContentHandler), or a DOMResult (which delivers the result as a DOM). The output properties are used only when writing to a StreamResult: they correspond to the properties available in the xsl:output element for XSLT. The property names are defined by constants in the JAXP javax.xml.transform.OutputKeys class (or net.sf.saxon.event.SaxonOutputKeys for Saxon extensions): for details of the values that are accepted, see the JavaDoc documentation or the JAXP specification.

    Michael H. Kay
    Saxonica Limited
    9 February 2005

    saxonb-9.1.0.8/bj/net/sf/saxon/TemplatesHandlerImpl.java0000644000175000017500000001431011033112257022317 0ustar eugeneeugenepackage net.sf.saxon; import net.sf.saxon.event.CommentStripper; import net.sf.saxon.event.ReceivingContentHandler; import net.sf.saxon.event.StartTagBuffer; import net.sf.saxon.style.StyleNodeFactory; import net.sf.saxon.style.StylesheetStripper; import net.sf.saxon.style.UseWhenFilter; import net.sf.saxon.trans.CompilerInfo; import net.sf.saxon.trans.XPathException; import net.sf.saxon.tree.DocumentImpl; import net.sf.saxon.tree.TreeBuilder; import org.xml.sax.Locator; import javax.xml.transform.Templates; import javax.xml.transform.TransformerException; import javax.xml.transform.sax.TemplatesHandler; /** * TemplatesHandlerImpl implements the javax.xml.transform.sax.TemplatesHandler * interface. It acts as a ContentHandler which receives a stream of * SAX events representing a stylesheet, and returns a Templates object that * represents the compiled form of this stylesheet. * @author Michael H. Kay */ public class TemplatesHandlerImpl extends ReceivingContentHandler implements TemplatesHandler { private TreeBuilder builder; private StyleNodeFactory nodeFactory; private Templates templates; private String systemId; /** * Create a TemplatesHandlerImpl and initialise variables. The constructor is protected, because * the Filter should be created using newTemplatesHandler() in the SAXTransformerFactory * class * @param config the Saxon configuration */ protected TemplatesHandlerImpl(Configuration config) { setPipelineConfiguration(config.makePipelineConfiguration()); nodeFactory = new StyleNodeFactory(config, getPipelineConfiguration().getErrorListener()); builder = new TreeBuilder(); builder.setPipelineConfiguration(getPipelineConfiguration()); builder.setNodeFactory(nodeFactory); builder.setLineNumbering(true); StartTagBuffer startTagBuffer = new StartTagBuffer(); UseWhenFilter useWhenFilter = new UseWhenFilter(startTagBuffer); useWhenFilter.setUnderlyingReceiver(builder); useWhenFilter.setPipelineConfiguration(getPipelineConfiguration()); startTagBuffer.setUnderlyingReceiver(useWhenFilter); startTagBuffer.setPipelineConfiguration(getPipelineConfiguration()); StylesheetStripper styleStripper = new StylesheetStripper(); styleStripper.setUnderlyingReceiver(startTagBuffer); styleStripper.setPipelineConfiguration(getPipelineConfiguration()); CommentStripper commentStripper = new CommentStripper(); commentStripper.setUnderlyingReceiver(styleStripper); commentStripper.setPipelineConfiguration(getPipelineConfiguration()); setReceiver(commentStripper); } /** * Get the Templates object to be used for a transformation */ public Templates getTemplates() { if (templates==null) { DocumentImpl doc = (DocumentImpl)builder.getCurrentRoot(); builder.reset(); if (doc==null) { return null; } final Configuration config = getConfiguration(); CompilerInfo info = new CompilerInfo(); info.setURIResolver(config.getURIResolver()); info.setErrorListener(config.getErrorListener()); info.setCompileWithTracing(config.isCompileWithTracing()); PreparedStylesheet sheet = new PreparedStylesheet(config, info); try { sheet.setStylesheetDocument(doc, nodeFactory); templates = sheet; } catch (XPathException tce) { if (!tce.hasBeenReported()) { try { info.getErrorListener().fatalError(tce); } catch (TransformerException e2) { // } } // don't know why we aren't allowed to just throw it! throw new IllegalStateException(tce.getMessage()); } } return templates; } /** * Set the SystemId of the document. Note that if this method is called, any locator supplied * to the setDocumentLocator() method is ignored. This also means that no line number information * will be available. * @param url the system ID (base URI) of the stylesheet document, which will be used in any error * reporting and also for resolving relative URIs in xsl:include and xsl:import. It will also form * the static base URI in the static context of XPath expressions. */ public void setSystemId(String url) { systemId = url; builder.setSystemId(url); super.setDocumentLocator(new Locator() { public int getColumnNumber() { return -1; } public int getLineNumber() { return -1; } public String getPublicId() { return null; } public String getSystemId() { return systemId; } }); } /** * Callback interface for SAX: not for application use */ public void setDocumentLocator (final Locator locator) { // If the user has called setSystemId(), we use that system ID in preference to this one, // which probably comes from the XML parser possibly via some chain of SAX filters if (systemId == null) { super.setDocumentLocator(locator); } } /** * Get the systemId of the document */ public String getSystemId() { return systemId; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): None // saxonb-9.1.0.8/bj/net/sf/saxon/StandardErrorListener.java0000644000175000017500000005247411033112257022536 0ustar eugeneeugenepackage net.sf.saxon; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.instruct.*; import net.sf.saxon.om.Navigator; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.om.StandardNames; import net.sf.saxon.om.StructuredQName; import net.sf.saxon.trace.ContextStackFrame; import net.sf.saxon.trace.ContextStackIterator; import net.sf.saxon.trace.InstructionInfo; import net.sf.saxon.trace.Location; import net.sf.saxon.trans.KeyDefinition; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ValidationException; import org.xml.sax.SAXException; import javax.xml.transform.ErrorListener; import javax.xml.transform.SourceLocator; import javax.xml.transform.TransformerException; import javax.xml.transform.dom.DOMLocator; import java.io.PrintStream; import java.io.Serializable; import java.util.Iterator; /** * StandardErrorListener is the standard error handler for XSLT processing * errors, used if no other ErrorListener is nominated. * * @author Michael H. Kay */ public class StandardErrorListener implements ErrorListener, Serializable { private int recoveryPolicy = Configuration.RECOVER_WITH_WARNINGS; private int warningCount = 0; protected transient PrintStream errorOutput = System.err; private boolean doStackTrace = true; /** * Create a Standard Error Listener */ public StandardErrorListener() { } /** * Make a clean copy of this ErrorListener. This is necessary because the * standard error listener is stateful (it remembers how many errors there have been) * * @param hostLanguage the host language (not used by this implementation) * @return a copy of this error listener */ public StandardErrorListener makeAnother(int hostLanguage) { return new StandardErrorListener(); } // Note, when the standard error listener is used, a new // one is created for each transformation, because it holds // the recovery policy and the warning count. /** * Set output destination for error messages (default is System.err) * * @param writer The PrintStream to use for error messages */ public void setErrorOutput(PrintStream writer) { errorOutput = writer; } /** * Get the error output stream * * @return the error output stream */ public PrintStream getErrorOutput() { return errorOutput; } /** * Set the recovery policy * * @param policy the recovery policy for XSLT recoverable errors. One of * {@link Configuration#RECOVER_SILENTLY}, * {@link Configuration#RECOVER_WITH_WARNINGS}, * {@link Configuration#DO_NOT_RECOVER}. */ public void setRecoveryPolicy(int policy) { recoveryPolicy = policy; } /** * Get the recovery policy * * @return the recovery policy for XSLT recoverable errors. One of * {@link Configuration#RECOVER_SILENTLY}, * {@link Configuration#RECOVER_WITH_WARNINGS}, * {@link Configuration#DO_NOT_RECOVER}. */ public int getRecoveryPolicy() { return recoveryPolicy; } /** * Receive notification of a warning. *

    *

    Transformers can use this method to report conditions that * are not errors or fatal errors. The default behaviour is to * take no action.

    *

    *

    After invoking this method, the Transformer must continue with * the transformation. It should still be possible for the * application to process the document through to the end.

    * * @param exception The warning information encapsulated in a * transformer exception. * @throws javax.xml.transform.TransformerException * if the application * chooses to discontinue the transformation. * @see javax.xml.transform.TransformerException */ public void warning(TransformerException exception) throws TransformerException { if (recoveryPolicy == Configuration.RECOVER_SILENTLY) { // do nothing return; } if (errorOutput == null) { // can happen after deserialization errorOutput = System.err; } String message = ""; if (exception.getLocator() != null) { message = getLocationMessage(exception) + "\n "; } message += wordWrap(getExpandedMessage(exception)); if (exception instanceof ValidationException) { errorOutput.println("Validation error " + message); } else { errorOutput.println("Warning: " + message); warningCount++; if (warningCount > 25) { errorOutput.println("No more warnings will be displayed"); recoveryPolicy = Configuration.RECOVER_SILENTLY; warningCount = 0; } } } /** * Receive notification of a recoverable error. *

    *

    The transformer must continue to provide normal parsing events * after invoking this method. It should still be possible for the * application to process the document through to the end.

    *

    *

    The action of the standard error listener depends on the * recovery policy that has been set, which may be one of RECOVER_SILENTLY, * RECOVER_WITH_WARNING, or DO_NOT_RECOVER * * @param exception The error information encapsulated in a * transformer exception. * @throws TransformerException if the application * chooses to discontinue the transformation. * @see TransformerException */ public void error(TransformerException exception) throws TransformerException { if (recoveryPolicy == Configuration.RECOVER_SILENTLY) { // do nothing return; } if (errorOutput == null) { // can happen after deserialization errorOutput = System.err; } String message; if (exception instanceof ValidationException) { String explanation = getExpandedMessage(exception); String constraintReference = ((ValidationException)exception).getConstraintReferenceMessage(); if (constraintReference != null) { explanation += " (" + constraintReference + ')'; } message = "Validation error " + getLocationMessage(exception) + "\n " + wordWrap(explanation); } else { String prefix = (recoveryPolicy == Configuration.RECOVER_WITH_WARNINGS ? "Recoverable error " : "Error "); message = prefix + getLocationMessage(exception) + "\n " + wordWrap(getExpandedMessage(exception)); } if (exception instanceof ValidationException) { errorOutput.println(message); } else if (recoveryPolicy == Configuration.RECOVER_WITH_WARNINGS) { errorOutput.println(message); warningCount++; if (warningCount > 25) { errorOutput.println("No more warnings will be displayed"); recoveryPolicy = Configuration.RECOVER_SILENTLY; warningCount = 0; } } else { errorOutput.println(message); errorOutput.println("Processing terminated because error recovery is disabled"); throw XPathException.makeXPathException(exception); } } /** * Receive notification of a non-recoverable error. *

    *

    The application must assume that the transformation cannot * continue after the Transformer has invoked this method, * and should continue (if at all) only to collect * addition error messages. In fact, Transformers are free * to stop reporting events once this method has been invoked.

    * * @param exception The error information encapsulated in a * transformer exception. * @throws TransformerException if the application * chooses to discontinue the transformation. * @see TransformerException */ public void fatalError(TransformerException exception) throws TransformerException { if (exception instanceof XPathException && ((XPathException)exception).hasBeenReported()) { // don't report the same error twice return; } if (errorOutput == null) { // can happen after deserialization errorOutput = System.err; } String message; if (exception instanceof ValidationException) { String explanation = getExpandedMessage(exception); String constraintReference = ((ValidationException)exception).getConstraintReferenceMessage(); if (constraintReference != null) { explanation += " (" + constraintReference + ')'; } message = "Validation error " + getLocationMessage(exception) + "\n " + wordWrap(explanation); } else { message = "Error " + getLocationMessage(exception) + "\n " + wordWrap(getExpandedMessage(exception)); } errorOutput.println(message); if (exception instanceof XPathException) { ((XPathException)exception).setHasBeenReported(); // probably redundant. It's the caller's job to set this flag, because there might be // a non-standard error listener in use. } if (exception instanceof XPathException) { XPathContext context = ((XPathException)exception).getXPathContext(); if (context != null && doStackTrace && getRecoveryPolicy() != Configuration.RECOVER_SILENTLY) { printStackTrace(errorOutput, context); } } } /** * Get a string identifying the location of an error. * * @param err the exception containing the location information * @return a message string describing the location */ public String getLocationMessage(TransformerException err) { SourceLocator loc = err.getLocator(); while (loc == null) { if (err.getException() instanceof TransformerException) { err = (TransformerException)err.getException(); loc = err.getLocator(); } else if (err.getCause() instanceof TransformerException) { err = (TransformerException)err.getCause(); loc = err.getLocator(); } else { return ""; } } XPathContext context = null; if (err instanceof XPathException) { context = ((XPathException)err).getXPathContext(); } return getLocationMessageText(loc, context); } private static String getLocationMessageText(SourceLocator loc, XPathContext context) { String locMessage = ""; String systemId = null; NodeInfo node = null; String nodeMessage = null; int lineNumber = -1; if (loc instanceof DOMLocator) { nodeMessage = "at " + ((DOMLocator)loc).getOriginatingNode().getNodeName() + ' '; } else if (loc instanceof NodeInfo) { node = (NodeInfo)loc; nodeMessage = "at " + node.getDisplayName() + ' '; } else if (loc instanceof ValidationException && ((ValidationException)loc).getNode() != null) { node = ((ValidationException)loc).getNode(); nodeMessage = "at " + node.getDisplayName() + ' '; } else if (loc instanceof Instruction) { String instructionName = getInstructionName(((Instruction)loc), context); if (!"".equals(instructionName)) { nodeMessage = "at " + instructionName + ' '; } systemId = loc.getSystemId(); lineNumber = loc.getLineNumber(); } else if (loc instanceof Procedure) { String kind = "procedure"; if (loc instanceof UserFunction) { kind = "function"; } else if (loc instanceof Template) { kind = "template"; } else if (loc instanceof AttributeSet) { kind = "attribute-set"; } else if (loc instanceof KeyDefinition) { kind = "key"; } systemId = loc.getSystemId(); lineNumber = loc.getLineNumber(); nodeMessage = "at " + kind + " " + ((InstructionInfo)loc).getObjectName(); } if (lineNumber == -1) { lineNumber = loc.getLineNumber(); } boolean containsLineNumber = lineNumber != -1; if (node != null && !containsLineNumber) { nodeMessage = "at " + Navigator.getPath(node) + ' '; } if (nodeMessage != null) { locMessage += nodeMessage; } if (containsLineNumber) { locMessage += "on line " + lineNumber + ' '; if (loc.getColumnNumber() != -1) { locMessage += "column " + loc.getColumnNumber() + ' '; } } if (systemId != null && systemId.length() == 0) { systemId = null; } if (systemId == null) { systemId = loc.getSystemId(); } if (systemId != null && systemId.length() != 0) { locMessage += (containsLineNumber ? "of " : "in ") + abbreviatePath(systemId) + ':'; } return locMessage; } /** * Abbreviate a URI (if requested) * @param uri the URI to be abbreviated * @return the abbreviated URI, unless full path names were requested, in which case * the URI as supplied */ public static String abbreviatePath(String uri) { int slash = uri.lastIndexOf('/'); if (slash >= 0 && slash < uri.length()-1) { return uri.substring(slash+1); } else { return uri; } } /** * Get a string containing the message for this exception and all contained exceptions * * @param err the exception containing the required information * @return a message that concatenates the message of this exception with its contained exceptions, * also including information about the error code and location. */ public static String getExpandedMessage(TransformerException err) { String code = null; if (err instanceof XPathException) { code = ((XPathException)err).getErrorCodeLocalPart(); } if (code == null && err.getException() instanceof XPathException) { code = ((XPathException)err.getException()).getErrorCodeLocalPart(); } String message = ""; if (code != null) { message = code; } Throwable e = err; while (true) { if (e == null) { break; } String next = e.getMessage(); if (next == null) { next = ""; } if (next.startsWith("net.sf.saxon.trans.XPathException: ")) { next = next.substring(next.indexOf(": ") + 2); } if (!("TRaX Transform Exception".equals(next) || message.endsWith(next))) { if (!"".equals(message) && !message.trim().endsWith(":")) { message += ": "; } message += next; } if (e instanceof TransformerException) { e = ((TransformerException)e).getException(); } else if (e instanceof SAXException) { e = ((SAXException)e).getException(); } else { // e.printStackTrace(); break; } } return message; } /** * Extract a name identifying the instruction at which an error occurred * * @param inst the provider of information * @param context the dynamic evaluation context * @return the name of the containing instruction or expression, in user-meaningful terms */ private static String getInstructionName(Instruction inst, XPathContext context) { // TODO: subclass this for XSLT and XQuery if (context == null) { return ""; } try { //InstructionInfo info = inst.getInstructionInfo(); int construct = inst.getInstructionNameCode(); if (construct < 0) { return ""; } if (construct < 1024 && construct != StandardNames.XSL_FUNCTION && construct != StandardNames.XSL_TEMPLATE) { // it's a standard name if (context.getController().getExecutable().getHostLanguage() == Configuration.XSLT) { return StandardNames.getDisplayName(construct); } else { String s = StandardNames.getDisplayName(construct); int colon = s.indexOf(':'); if (colon > 0) { String local = s.substring(colon + 1); if (local.equals("document")) { return "document node constructor"; } else if (local.equals("text") || s.equals("value-of")) { return "text node constructor"; } else if (local.equals("element")) { return "computed element constructor"; } else if (local.equals("attribute")) { return "computed attribute constructor"; } else if (local.equals("variable")) { return "variable declaration"; } else if (local.equals("param")) { return "external variable declaration"; } else if (local.equals("comment")) { return "comment constructor"; } else if (local.equals("processing-instruction")) { return "processing-instruction constructor"; } } return s; } } switch (construct) { case Location.LITERAL_RESULT_ELEMENT: { StructuredQName qName = inst.getObjectName(); String name = "element constructor"; if (context != null) { name += " <" + qName.getDisplayName() + '>'; } return name; } case Location.LITERAL_RESULT_ATTRIBUTE: { StructuredQName qName = inst.getObjectName(); String name = "attribute constructor"; if (context != null) { name += ' ' + qName.getDisplayName() + "=\"{...}\""; } return name; } default: return ""; } } catch (Exception err) { return ""; } } /** * Wordwrap an error message into lines of 72 characters or less (if possible) * * @param message the message to be word-wrapped * @return the message after applying word-wrapping */ private static String wordWrap(String message) { int nl = message.indexOf('\n'); if (nl < 0) { nl = message.length(); } if (nl > 100) { int i = 90; while (message.charAt(i) != ' ' && i > 0) { i--; } if (i > 10) { return message.substring(0, i) + "\n " + wordWrap(message.substring(i + 1)); } else { return message; } } else if (nl < message.length()) { return message.substring(0, nl) + '\n' + wordWrap(message.substring(nl + 1)); } else { return message; } } /** * Print a stack trace to a specified output destination * @param out the print stream to which the stack trace will be output * @param context the XPath dynamic execution context (which holds the head of a linked * list of context objects, representing the execution stack) */ public static void printStackTrace(PrintStream out, XPathContext context) { Iterator iterator = new ContextStackIterator(context); while (iterator.hasNext()) { ContextStackFrame frame = (ContextStackFrame)iterator.next(); if (frame == null) { break; } frame.print(out); } } } // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/s9api/0000755000175000017500000000000012216261742016434 5ustar eugeneeugenesaxonb-9.1.0.8/bj/net/sf/saxon/s9api/MessageListenerProxy.java0000644000175000017500000000766211033112257023436 0ustar eugeneeugenepackage net.sf.saxon.s9api; import net.sf.saxon.event.SequenceWriter; import net.sf.saxon.event.ReceiverOptions; import net.sf.saxon.event.LocationProvider; import net.sf.saxon.trans.XPathException; import net.sf.saxon.om.Item; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.expr.ExpressionLocation; /** * This class implements a Receiver that can receive xsl:message output and send it to a * user-supplied MessageListener. */ class MessageListenerProxy extends SequenceWriter { private MessageListener listener; private boolean terminate; private int locationId = -1; protected MessageListenerProxy(MessageListener listener) { this.listener = listener; } /** * Get the wrapped MessageListener */ public MessageListener getMessageListener() { return listener; } /** * Start of a document node. */ public void startDocument(int properties) throws XPathException { terminate = (properties & ReceiverOptions.TERMINATE) != 0; locationId = -1; super.startDocument(properties); } /** * Output an element start tag. * * @param nameCode The element name code - a code held in the Name Pool * @param typeCode Integer code identifying the type of this element. Zero identifies the default * type, that is xs:anyType * @param properties bit-significant flags indicating any special information */ public void startElement(int nameCode, int typeCode, int locationId, int properties) throws XPathException { if (this.locationId == -1) { this.locationId = locationId; } super.startElement(nameCode, typeCode, locationId, properties); } /** * Produce text content output.
    * * @param s The String to be output * @param properties bit-significant flags for extra information, e.g. disable-output-escaping * @throws net.sf.saxon.trans.XPathException * for any failure */ public void characters(CharSequence s, int locationId, int properties) throws XPathException { if (this.locationId == -1) { this.locationId = locationId; } super.characters(s, locationId, properties); } /** * Append an item to the sequence, performing any necessary type-checking and conversion */ public void append(Item item, int locationId, int copyNamespaces) throws XPathException { if (this.locationId == -1) { this.locationId = locationId; } super.append(item, locationId, copyNamespaces); } /** * Abstract method to be supplied by subclasses: output one item in the sequence. * * @param item the item to be written to the sequence */ public void write(Item item) throws XPathException { ExpressionLocation loc = new ExpressionLocation(); if (locationId != -1) { LocationProvider provider = getPipelineConfiguration().getLocationProvider(); loc.setSystemId(provider.getSystemId(locationId)); loc.setLineNumber(provider.getLineNumber(locationId)); } listener.message(new XdmNode((NodeInfo)item), terminate, loc); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/s9api/XsltTransformer.java0000644000175000017500000002762111107267241022462 0ustar eugeneeugenepackage net.sf.saxon.s9api; import net.sf.saxon.Controller; import net.sf.saxon.Configuration; import net.sf.saxon.event.Receiver; import net.sf.saxon.event.TransformerReceiver; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.om.ValueRepresentation; import net.sf.saxon.trans.XPathException; import javax.xml.transform.TransformerException; import javax.xml.transform.Source; /** * An XsltTransformer represents a compiled and loaded stylesheet ready for execution. * The XsltTransformer holds details of the dynamic evaluation context for the stylesheet. * *

    An XsltTransformer must not be used concurrently in multiple threads. * It is safe, however, to reuse the object within a single thread to run the same * stylesheet several times. Running the stylesheet does not change the context * that has been established.

    * *

    An XsltTransformer is always constructed by running the Load * method of an {@link XsltExecutable}.

    * *

    An XsltTransformer is itself a Destination. This means it is possible to use * one XsltTransformer as the destination to receive the results of another transformation, * this providing a simple way for transformations to be chained into a pipeline.

    * @since 9.0 */ public class XsltTransformer implements Destination { private Processor processor; private Controller controller; private NodeInfo initialContextNode; private Destination destination; /** * Protected constructor * @param processor the S9API processor * @param controller the Saxon controller object */ protected XsltTransformer(Processor processor, Controller controller) { this.processor = processor; this.controller = controller; } /** * Set the initial named template for the transformation * @param templateName the name of the initial template, or null to indicate * that there should be no initial named template * @throws SaxonApiException if there is no named template with this name */ public void setInitialTemplate(QName templateName) throws SaxonApiException { try { controller.setInitialTemplate( templateName == null ? null : templateName.getClarkName()); } catch (XPathException e) { throw new SaxonApiException(e); } } /** * Get the initial named template for the transformation, if one has been set * @return the name of the initial template, or null if none has been set */ public QName getInitialTemplate() { String template = controller.getInitialTemplate(); return (template == null ? null : QName.fromClarkName(template)); } /** * Set the initial mode for the transformation * @param modeName the name of the initial mode, or null to indicate the default * (unnamed) mode */ public void setInitialMode(QName modeName) { controller.setInitialMode(modeName == null ? null : modeName.getClarkName()); } /** * Get the initial mode for the transformation, if one has been set. * @return the initial mode for the transformation. Returns null if no mode has been set, * or if the mode was set to null to represent the default (unnamed) mode */ public QName getInitialMode() { String mode = controller.getInitialMode(); if (mode == null) { return null; } else { return QName.fromClarkName(mode); } } /** * Set the source document for the transformation. This method is equivalent to building * a document from the supplied source object, and then supplying the document node of * the resulting document as the initial context node. * @param source the principal source document for the transformation */ public void setSource(Source source) throws SaxonApiException { setInitialContextNode(processor.newDocumentBuilder().build(source)); } /** * Set the initial context node for the transformation. *

    This is ignored in the case where the {@link XsltTransformer} is used as the * {@link Destination} of another process. In that case the initial context node will always * be the document node of the document that is being streamed to this destination.

    * @param node the initial context node, or null if there is to be no initial context node */ public void setInitialContextNode(XdmNode node) { initialContextNode = (node == null ? null : node.getUnderlyingNode()); } /** * Get the initial context node for the transformation, if one has been set * @return the initial context node, or null if none has been set. This will not necessarily * be the same {@link XdmNode} instance as was supplied, but it will be an XdmNode object that represents * the same underlying node. */ public XdmNode getInitialContextNode() { return (XdmNode)XdmValue.wrap(initialContextNode); } /** * Set the value of a stylesheet parameter * @param name the name of the stylesheet parameter, as a QName * @param value the value of the stylesheet parameter, or null to clear a previously set value */ public void setParameter(QName name, XdmValue value) { controller.setParameter(name.getStructuredQName(), (value == null ? null : value.getUnderlyingValue())); } /** * Get the value that has been set for a stylesheet parameter * @param name the parameter whose name is required * @return the value that has been set for the parameter, or null if no value has been set */ public XdmValue getParameter(QName name) { Object oval = controller.getParameter(name.getClarkName()); if (oval == null) { return null; } if (oval instanceof ValueRepresentation) { return XdmValue.wrap((ValueRepresentation)oval); } throw new IllegalStateException(oval.getClass().getName()); } /** * Set the destination to be used for the transformation. *

    This method can be used to chain transformations into a pipeline, by using one * {@link XsltTransformer} as the destination of another

    * @param destination the destination to be used */ public void setDestination(Destination destination) { this.destination = destination; } /** * Get the destination that was specified in a previous call of {@link #setDestination} * @return the destination, or null if none has been supplied */ public Destination getDestination() { return destination; } /** * Set the MessageListener to be notified whenever the stylesheet evaluates an * xsl:message instruction. If no MessageListener is nominated, * the output of xsl:message instructions will be serialized and sent * to the standard error stream. * @param listener the MessageListener to be used * @since 9.1 */ public void setMessageListener(MessageListener listener) { controller.setMessageEmitter(new MessageListenerProxy(listener)); } /** * Get the MessageListener to be notified whenever the stylesheet evaluates an * xsl:message instruction. If no MessageListener has been nominated, * return null * @return the user-supplied MessageListener, or null if none has been supplied * @since 9.1 */ public MessageListener getMessageListener() { Receiver r = controller.getMessageEmitter(); if (r instanceof MessageListenerProxy) { return ((MessageListenerProxy)r).getMessageListener(); } else { return null; } } /** * Perform the transformation. If this method is used, a destination must have been supplied * previously * @throws SaxonApiException if any dynamic error occurs during the transformation * @throws IllegalStateException if no destination has been supplied */ public void transform() throws SaxonApiException { if (destination == null) { throw new IllegalStateException("No destination has been supplied"); } try { Receiver receiver; if (destination instanceof Serializer) { receiver = ((Serializer)destination).getReceiver( controller.getConfiguration(), controller, controller.getOutputProperties()); } else { receiver = destination.getReceiver(controller.getConfiguration()); } controller.transform(initialContextNode, receiver); } catch (TransformerException e) { throw new SaxonApiException(e); } } /** * Return a Receiver which can be used to supply the principal source document for the transformation. * This method is intended primarily for internal use, though it can also * be called by a user application that wishes to feed events into the transformation engine. * *

    Saxon calls this method to obtain a Receiver, to which it then sends * a sequence of events representing the content of an XML document. This method is provided so that * XsltTransformer implements Destination, allowing one transformation * to receive the results of another in a pipeline.

    * *

    Before calling this method, the {@link #setDestination} method must be called to supply a destination * for the transformation.

    * *

    Note that when an XsltTransformer is used as a Destination, the initial * context node set on that XsltTransformer is ignored.

    * * @param config The Saxon configuration. This is supplied so that the destination can * use information from the configuration (for example, a reference to the name pool) * to construct or configure the returned Receiver. * @return the Receiver to which events are to be sent. * @throws SaxonApiException if the Receiver cannot be created * @throws IllegalStateException if no Destination has been supplied */ public Receiver getReceiver(Configuration config) throws SaxonApiException { if (destination == null) { throw new IllegalStateException("No destination has been supplied"); } TransformerReceiver tr = new TransformerReceiver(controller); tr.setResult(destination.getReceiver(config)); tr.setPipelineConfiguration(controller.makePipelineConfiguration()); return tr; } /** * Get the underlying Controller used to implement this XsltTransformer. This provides access * to lower-level methods not otherwise available in the s9api interface. Note that classes * and methods obtained by this route cannot be guaranteed stable from release to release. * @since 9.0.0.4 */ public Controller getUnderlyingController() { return controller; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/s9api/SchemaManager.java0000644000175000017500000001310311033112257021760 0ustar eugeneeugenepackage net.sf.saxon.s9api; import net.sf.saxon.Configuration; import net.sf.saxon.event.Receiver; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.SchemaException; import net.sf.saxon.type.SchemaURIResolver; import javax.xml.transform.ErrorListener; import javax.xml.transform.Source; /** * The SchemaManager is used to load schema documents, and to set options for the way in which they are loaded. * At present all the resulting schema components are held in a single pool owned by the Processor object. */ public class SchemaManager { private Configuration config; private ErrorListener errorListener; protected SchemaManager(Configuration config) { this.config = config; this.errorListener = null; } /** * Set the ErrorListener to be used while loading and validating schema documents * @param listener The error listener to be used. This is notified of all errors detected during the * compilation. */ public void setErrorListener(ErrorListener listener) { this.errorListener = listener; } /** * Get the ErrorListener being used while loading and validating schema documents * @return listener The error listener in use. This is notified of all errors detected during the * compilation. Returns null if no user-supplied ErrorListener has been set. */ public ErrorListener getErrorListener() { return errorListener; } /** * Set the SchemaURIResolver to be used during schema loading. This SchemaURIResolver, despite its name, * is not used for resolving relative URIs against a base URI; it is used for dereferencing * an absolute URI (after resolution) to return a {@link javax.xml.transform.Source} representing the * location where a schema document can be found. * *

    This SchemaURIResolver is used to dereference the URIs appearing in xs:import, * xs:include, and xs:redefine declarations. * * @param resolver the SchemaURIResolver to be used during schema loading. */ public void setSchemaURIResolver(SchemaURIResolver resolver) { config.setSchemaURIResolver(resolver); } /** * Get the SchemaURIResolver to be used during schema loading. * * @return the URIResolver used during stylesheet compilation. Returns null if no user-supplied * URIResolver has been set. */ public SchemaURIResolver getSchemaURIResolver() { return config.getSchemaURIResolver(); } /** * Load a schema document from a given Source. The schema components derived from this schema * document are added to the cache of schema components maintained by this SchemaManager * @param source the document containing the schema. The getSystemId() method applied to this Source * must return a base URI suitable for resolving xs:include and xs:import * directives. * @throws SaxonApiException if the schema document is not valid, or if its contents are inconsistent * with the schema components already held by this SchemaManager. */ public void load(Source source) throws SaxonApiException { try { config.addSchemaSource(source, errorListener); } catch (SchemaException e) { throw new SaxonApiException(e); } } /** * Import a precompiled Schema Component Model from a given Source. The schema components derived from this schema * document are added to the cache of schema components maintained by this SchemaManager * @param source the XML file containing the schema component model, as generated by a previous call on * {@link #exportComponents} */ public void importComponents(Source source) throws SaxonApiException { try { config.importComponents(source); } catch (XPathException err) { throw new SaxonApiException(err); } } /** * Export a precompiled Schema Component Model containing all the components (except built-in components) * that have been loaded into this Processor. * @param destination the destination to recieve the precompiled Schema Component Model in the form of an * XML document */ public void exportComponents(Destination destination) throws SaxonApiException { try { Receiver out = destination.getReceiver(config); config.exportComponents(out); } catch (XPathException e) { throw new SaxonApiException(e); } } /** * Create a SchemaValidator which can be used to validate instance documents against the schema held by this * SchemaManager * @return a new SchemaValidator */ public SchemaValidator newSchemaValidator() { return new SchemaValidator(config); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/s9api/SaxonApiUncheckedException.java0000644000175000017500000000304311033112257024502 0ustar eugeneeugenepackage net.sf.saxon.s9api; /** * An unchecked exception thrown by the Saxon API. Unchecked exceptions are used only when errors occur in a method * for which the interface specification defines no checked exception, for example {@link java.util.Iterator#next()}. * The exception always wraps some underlying exception, which can be retrieved using {@link #getCause()} */ public class SaxonApiUncheckedException extends RuntimeException { /** * Create an unchecked exception * @param err the underlying cause */ public SaxonApiUncheckedException(Throwable err) { super(err); } /** * Returns the detail message string of this throwable. * * @return the detail message string of this Throwable instance * (which may be null). */ public String getMessage() { return getCause().getMessage(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/s9api/DOMDestination.java0000644000175000017500000000442111033112257022111 0ustar eugeneeugenepackage net.sf.saxon.s9api; import net.sf.saxon.Configuration; import net.sf.saxon.dom.DOMWriter; import net.sf.saxon.event.Receiver; /** * This class represents a Destination (for example, the destination of the output of a transformation) * in which the results are written to a newly constructed DOM tree in memory. The caller must supply * a Document node, which will be used as the root of the constructed tree */ public class DOMDestination implements Destination { private DOMWriter domWriter; /** * Create a DOMDestination, supplying the root of a DOM document to which the * content of the result tree will be appended. * @param root the root node for the new tree. */ public DOMDestination(org.w3c.dom.Document root) { domWriter = new DOMWriter(); domWriter.setNode(root); } /** * Return a Receiver. Saxon calls this method to obtain a Receiver, to which it then sends * a sequence of events representing the content of an XML document. * * @param config The Saxon configuration. This is supplied so that the destination can * use information from the configuration (for example, a reference to the name pool) * to construct or configure the returned Receiver. * @return the Receiver to which events are to be sent. * @throws SaxonApiException * if the Receiver cannot be created */ public Receiver getReceiver(Configuration config) throws SaxonApiException { domWriter.setPipelineConfiguration(config.makePipelineConfiguration()); return domWriter; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/s9api/XdmAtomicValue.java0000644000175000017500000002661711033112257022165 0ustar eugeneeugenepackage net.sf.saxon.s9api; import net.sf.saxon.Configuration; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.AtomicType; import net.sf.saxon.type.BuiltInAtomicType; import net.sf.saxon.type.ConversionResult; import net.sf.saxon.type.ValidationException; import net.sf.saxon.value.*; import java.math.BigDecimal; import java.net.URI; /** * The class XdmAtomicValue represents an item in an XPath 2.0 sequence that is an atomic value. * The value may belong to any of the 19 primitive types defined in XML Schema, or to a type * derived from these primitive types, or the XPath 2.0 type xs:untypedAtomic. The type may * be either a built-in type or a user-defined type. * *

    An XdmAtomicValue is immutable.

    */ public class XdmAtomicValue extends XdmItem { protected XdmAtomicValue(AtomicValue value) { super(value); } /** * Create an xs:boolean atomic value * @param value the boolean value, true or false */ public XdmAtomicValue(boolean value) { super(BooleanValue.get(value)); } /** * Create an xs:integer atomic value * @param value the xs:integer value, as a long */ public XdmAtomicValue(long value) { super(Int64Value.makeIntegerValue(value)); } /** * Create an xs:decimal atomic value * @param value the xs:decimal value, as a BigDecimal */ public XdmAtomicValue(BigDecimal value) { super(new DecimalValue(value)); } /** * Create an xs:double atomic value * @param value the xs:double value, as a double */ public XdmAtomicValue(double value) { super(new DoubleValue(value)); } /** * Create an xs:float atomic value * @param value the xs:float value, as a float */ public XdmAtomicValue(float value) { super(new FloatValue(value)); } /** * Create an xs:string atomic value * @param value the xs:string value, as a string */ public XdmAtomicValue(String value) { super(new StringValue(value)); } /** * Create an xs:anyURI atomic value * @param value the xs:anyURI value, as a URI */ public XdmAtomicValue(URI value) { super(new AnyURIValue(value.toString())); } /** * Create an xs:QName atomic value * @param value the xs:QName value, as a QName */ public XdmAtomicValue(QName value) { super(new QNameValue(value.getStructuredQName(), BuiltInAtomicType.QNAME)); } /** * Construct an atomic value given its lexical representation and the name of the required * built-in atomic type. *

    This method cannot be used to construct values that are namespace-sensitive (QNames and Notations)

    * @param lexicalForm the value in the lexical space of the target data type. More strictly, the input * value before the actions of the whitespace facet for the target data type are applied. * @param type the required atomic type. This must either be one of the built-in * atomic types defined in XML Schema, or a user-defined type whose definition appears * in a schema that is known to the Processor. It must not be an abstract type. * @throws SaxonApiException if the type is unknown, or is not atomic, or is namespace-sensitive; * or if the value supplied in lexicalForm is not in the lexical space of the specified atomic * type. */ public XdmAtomicValue(String lexicalForm, ItemType type) throws SaxonApiException { net.sf.saxon.type.ItemType it = type.getUnderlyingItemType(); if (!it.isAtomicType()) { throw new SaxonApiException("Requested type is not atomic"); } if (((AtomicType)it).isAbstract()) { throw new SaxonApiException("Requested type is an abstract type"); } Configuration config = type.getProcessor().getUnderlyingConfiguration(); ConversionResult result = new StringValue(lexicalForm).convert( (AtomicType)it, true, config.getConversionContext()); try { setValue(result.asAtomic()); } catch (ValidationException e) { throw new SaxonApiException(e); } } /** * Get the result of converting the atomic value to a string. This has the same * effect as the XPath string() function. */ public String toString() { return getStringValue(); } /** * Get the primitive type of this atomic value, as a QName. The primitive types for this purpose are * the 19 primitive types of XML Schema, plus xs:integer, xs:dayTimeDuration and xs:yearMonthDuration, * and xs:untypedAtomic. For external objects, the result is xs:anyAtomicType. * @return a QName naming the primitive type of this atomic value. This will always be an atomic type. */ public QName getPrimitiveTypeName() { AtomicValue value = (AtomicValue)getUnderlyingValue(); BuiltInAtomicType type = value.getPrimitiveType(); return new QName(type.getQualifiedName()); } /** * Get the value as a Java object of the nearest equivalent type. * *

    The result type is as follows:

    * * * * * * * * * * * * * *
    XPath type Java class
    xs:string String
    xs:integer java.math.BigInteger
    xs:decimal java.math.BigDecimal
    xs:double Double
    xs:float Float
    xs:boolean Boolean
    xs:QName QName
    xs:anyURI String
    xs:untypedAtomicString
    Other types currently String, but this may change in the future
    * @return the value, converted to a Java object of a suitable type */ @SuppressWarnings({"AutoBoxing"}) public Object getValue() { AtomicValue av = (AtomicValue)getUnderlyingValue(); if (av instanceof StringValue) { return av.getStringValue(); } else if (av instanceof IntegerValue) { return ((IntegerValue)av).asBigInteger(); } else if (av instanceof DoubleValue) { return ((DoubleValue)av).getDoubleValue(); } else if (av instanceof FloatValue) { return ((FloatValue)av).getFloatValue(); } else if (av instanceof BooleanValue) { return ((BooleanValue)av).getBooleanValue(); } else if (av instanceof DecimalValue) { return ((DecimalValue)av).getDecimalValue(); } else if (av instanceof QNameValue) { QNameValue q = (QNameValue)av; return new QName(q.getPrefix(), q.getNamespaceURI(), q.getLocalName()); } else { return av.getStringValue(); } } /** * Get the value converted to a boolean using the XPath casting rules * @return the result of converting to a boolean (Note: this is not the same as the * effective boolean value). * @throws SaxonApiException if the value cannot be cast to a boolean */ public boolean getBooleanValue() throws SaxonApiException { AtomicValue av = (AtomicValue)getUnderlyingValue(); if (av instanceof BooleanValue) { return ((BooleanValue)av).getBooleanValue(); } else if (av instanceof NumericValue) { return !av.isNaN() && ((NumericValue)av).signum() != 0; } else if (av instanceof StringValue) { String s = ((StringValue)av).getStringValue(); return "1".equals(s) || "true".equals(s); } else { throw new SaxonApiException("Cannot cast item to a boolean"); } } /** * Get the value converted to an integer using the XPath casting rules * @return the result of converting to an integer * @throws SaxonApiException if the value cannot be cast to an integer */ public long getLongValue() throws SaxonApiException { AtomicValue av = (AtomicValue)getUnderlyingValue(); if (av instanceof BooleanValue) { return ((BooleanValue)av).getBooleanValue() ? 0L : 1L; } else if (av instanceof NumericValue) { try { return ((NumericValue)av).longValue(); } catch (XPathException e) { throw new SaxonApiException("Cannot cast item to an integer"); } } else if (av instanceof StringValue) { return (long)Value.stringToNumber(av.getStringValueCS()); } else { throw new SaxonApiException("Cannot cast item to an integer"); } } /** * Get the value converted to a double using the XPath casting rules * @return the result of converting to a double * @throws SaxonApiException if the value cannot be cast to a double */ public double getDoubleValue() throws SaxonApiException { AtomicValue av = (AtomicValue)getUnderlyingValue(); if (av instanceof BooleanValue) { return ((BooleanValue)av).getBooleanValue() ? 0.0 : 1.0; } else if (av instanceof NumericValue) { return ((NumericValue)av).getDoubleValue(); } else if (av instanceof StringValue) { return Value.stringToNumber(av.getStringValueCS()); } else { throw new SaxonApiException("Cannot cast item to a double"); } } /** * Get the value converted to a decimal using the XPath casting rules * @return the result of converting to a decimal * @throws SaxonApiException if the value cannot be cast to a double */ public BigDecimal getDecimalValue() throws SaxonApiException { AtomicValue av = (AtomicValue)getUnderlyingValue(); if (av instanceof BooleanValue) { return ((BooleanValue)av).getBooleanValue() ? BigDecimal.ZERO : BigDecimal.ONE; } else if (av instanceof NumericValue) { try { return ((NumericValue)av).getDecimalValue(); } catch (XPathException e) { throw new SaxonApiException("Cannot cast item to a decimal"); } } else if (av instanceof StringValue) { return new BigDecimal(av.getStringValueCS().toString()); } else { throw new SaxonApiException("Cannot cast item to a decimal"); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/s9api/XsltCompiler.java0000644000175000017500000001652311033112257021723 0ustar eugeneeugenepackage net.sf.saxon.s9api; import net.sf.saxon.Configuration; import net.sf.saxon.PreparedStylesheet; import net.sf.saxon.trans.CompilerInfo; import javax.xml.transform.ErrorListener; import javax.xml.transform.Source; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.URIResolver; /** * An XsltCompiler object allows XSLT 2.0 stylesheets to be compiled. The compiler holds information that * represents the static context for the compilation. * *

    To construct an XsltCompiler, use the factory method {@link Processor#newXsltCompiler} on the Processor object.

    * *

    An XsltCompiler may be used repeatedly to compile multiple queries. Any changes made to the * XsltCompiler (that is, to the static context) do not affect queries that have already been compiled. * An XsltCompiler may be used concurrently in multiple threads, but it should not then be modified once * initialized.

    */ public class XsltCompiler { private Processor processor; private Configuration config; private CompilerInfo compilerInfo; /** * Protected constructor * @param processor the Saxon processor */ protected XsltCompiler(Processor processor) { this.processor = processor; this.config = processor.getUnderlyingConfiguration(); compilerInfo = new CompilerInfo(); compilerInfo.setURIResolver(config.getURIResolver()); compilerInfo.setErrorListener(config.getErrorListener()); compilerInfo.setCompileWithTracing(config.isCompileWithTracing()); } /** * Set the URIResolver to be used during stylesheet compilation. This URIResolver, despite its name, * is not used for resolving relative URIs against a base URI; it is used for dereferencing * an absolute URI (after resolution) to return a {@link javax.xml.transform.Source} representing the * location where a stylesheet module can be found. * *

    This URIResolver is used to dereference the URIs appearing in xsl:import, * xsl:include, and xsl:import-schema declarations. * It is not used at run-time for resolving requests to the document() or similar functions.

    * * @param resolver the URIResolver to be used during stylesheet compilation. */ public void setURIResolver(URIResolver resolver) { compilerInfo.setURIResolver(resolver); } /** * Get the URIResolver to be used during stylesheet compilation. * * @return the URIResolver used during stylesheet compilation. Returns null if no user-supplied * URIResolver has been set. */ public URIResolver getURIResolver() { return compilerInfo.getURIResolver(); } /** * Set the ErrorListener to be used during this compilation episode * @param listener The error listener to be used. This is notified of all errors detected during the * compilation. */ public void setErrorListener(ErrorListener listener) { compilerInfo.setErrorListener(listener); } /** * Get the ErrorListener being used during this compilation episode * @return listener The error listener in use. This is notified of all errors detected during the * compilation. Returns null if no user-supplied ErrorListener has been set. */ public ErrorListener getErrorListener() { return compilerInfo.getErrorListener(); } /** * Set whether trace hooks are to be included in the compiled code. To use tracing, it is necessary * both to compile the code with trace hooks included, and to supply a TraceListener at run-time * @param option true if trace code is to be compiled in, false otherwise */ public void setCompileWithTracing(boolean option) { compilerInfo.setCompileWithTracing(option); // TODO: no method yet for supplying a TraceListener } /** * Ask whether trace hooks are included in the compiled code. * @return true if trace hooks are included, false if not. */ public boolean isCompileWithTracing() { return compilerInfo.isCompileWithTracing(); } /** * Compile a stylesheet. * *

    Note: the term "compile" here indicates that the stylesheet is converted into an executable * form. There is no implication that this involves code generation.

    * *

    The source argument identifies the XML document holding the principal stylesheet module. Other * modules will be located relative to this module by resolving against the base URI that is defined * as the systemId property of the supplied Source.

    * *

    The following kinds of {@link javax.xml.transform.Source} are recognized:

    * *
      *
    • {@link javax.xml.transform.stream.StreamSource}, allowing the stylesheet to be supplied as a * URI, as a {@link java.io.File}, as an {@link java.io.InputStream}, or as a {@link java.io.Reader}
    • *
    • {@link javax.xml.transform.sax.SAXSource}, allowing the stylesheet to be supplied as a stream * of SAX events from a SAX2-compliant XML parser (or any other source of SAX events)
    • *
    • {@link javax.xml.transform.dom.DOMSource}, allowing the stylesheet to be supplied as a * DOM tree. This option is available only if saxon9-dom.jar is on the classpath.
    • *
    • Document wrappers for XOM, JDOM, or DOM4J trees, provided the appropriate support libraries * are on the classpath
    • *
    • A Saxon NodeInfo, representing the root of a tree in any of the native tree formats supported * by Saxon
    • *
    • An {@link XdmNode} representing the document node of the stylesheet module
    • *
    * @param source Source object representing the principal stylesheet module to be compiled * @return an XsltExecutable, which represents the compiled stylesheet. * @throws SaxonApiException if the stylesheet contains static errors or if it cannot be read. Note that * the exception that is thrown will not contain details of the actual errors found in the stylesheet. These * will instead be notified to the registered ErrorListener. The default ErrorListener displays error messages * on the standard error output. */ public XsltExecutable compile(Source source) throws SaxonApiException { try { PreparedStylesheet pss = PreparedStylesheet.compile(source, config, compilerInfo); return new XsltExecutable(processor, pss); } catch (TransformerConfigurationException e) { throw new SaxonApiException(e); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/s9api/WhitespaceStrippingPolicy.java0000644000175000017500000000267411033112257024454 0ustar eugeneeugenepackage net.sf.saxon.s9api; /** * WhitespaceStrippingPolicy is an enumeration class defining the possible policies for handling * whitespace text nodes in a source document. */ public enum WhitespaceStrippingPolicy { /** * The value NONE indicates that all whitespace text nodes are retained */ NONE, /** * The value IGNORABLE indicates that whitespace text nodes in element-only content are * discarded. Content is element-only if it is defined by a schema or DTD definition that * does not allow mixed or PCDATA content. */ IGNORABLE, /** * The value ALL indicates that all whitespace-only text nodes are discarded. */ ALL, /** * UNSPECIFIED means that no other value has been specifically requested. */ UNSPECIFIED } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/s9api/MessageListener.java0000644000175000017500000000420611033112257022363 0ustar eugeneeugenepackage net.sf.saxon.s9api; import javax.xml.transform.SourceLocator; /** * A user-written implementation of the MessageListener interface may be registered with the XsltTransformer * to receive notification of xsl:message output. Each xsl:message instruction that is evaluated results in * a single call to the MessageListener */ public interface MessageListener { /** * Notify a message written using the xsl:message instruction * @param content a document node representing the message content. Note that the output of * xsl:message is always an XML document node. It can be flattened to obtain the * string value if required by calling getStringValue(). * @param terminate Set to true if terminate="yes" was specified or to false otherwise. * The message listener does not need to take any special action based on this parameter, but the information * is available if required. If terminate="yes" was specified, then the transformation will abort * with an exception immediately on return from this callback. * @param locator an object that contains the location of the xsl:message instruction in the * stylesheet that caused this message to be output. This provides access to the URI of the stylesheet module * and the line number of the xsl:message instruction. */ public void message(XdmNode content, boolean terminate, SourceLocator locator); } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/s9api/Destination.java0000644000175000017500000000510711033112257021553 0ustar eugeneeugenepackage net.sf.saxon.s9api; import net.sf.saxon.Configuration; import net.sf.saxon.event.Receiver; /** * A Destination represents a place where XML can be sent. It is used, for example, * to define the output of a transformation or query. * *

    The interface Destination has some similarities with the JAXP * {@link javax.xml.transform.Result} class. It differs, however, in that implementations * of this interface can be written by users or third parties to define new kinds of * destination, and any such implementation can be supplied to the Saxon methods that * take a Destination as an argument.

    * *

    Implementing a new Destination, however, will generally require access * to implementation-level classes and methods within the Saxon product. The only method that * needs to be supplied is {@link #getReceiver}, which returns an instance of * {@link net.sf.saxon.event.Receiver}, and unless you use an existing implementation of * Receiver, you will need to handle internal Saxon concepts such as name codes * and name pools.

    */ public interface Destination { /** * Return a Receiver. Saxon calls this method to obtain a Receiver, to which it then sends * a sequence of events representing the content of an XML document. * @param config The Saxon configuration. This is supplied so that the destination can * use information from the configuration (for example, a reference to the name pool) * to construct or configure the returned Receiver. * @return the Receiver to which events are to be sent. It is the caller's responsibility to * initialize this Receiver with a {@link net.sf.saxon.event.PipelineConfiguration} before calling * its open() method. * @throws SaxonApiException if the Receiver cannot be created */ public Receiver getReceiver(Configuration config) throws SaxonApiException; } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/s9api/DocumentBuilder.java0000644000175000017500000003540711033112257022365 0ustar eugeneeugenepackage net.sf.saxon.s9api; import net.sf.saxon.AugmentedSource; import net.sf.saxon.Configuration; import net.sf.saxon.expr.EarlyEvaluationContext; import net.sf.saxon.expr.JPConverter; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.om.Validation; import net.sf.saxon.trans.XPathException; import javax.xml.transform.Source; import javax.xml.transform.stream.StreamSource; import java.io.File; import java.net.URI; /** * A document builder holds properties controlling how a Saxon document tree should be built, and * provides methods to invoke the tree construction. *

    *

    This class has no public constructor. Users should construct a DocumentBuilder * by calling the factory method {@link net.sf.saxon.s9api.Processor#newDocumentBuilder()}.

    *

    *

    All documents used in a single Saxon query, transformation, or validation episode must * be built with the same {@link Configuration}. However, there is no requirement that they * should use the same DocumentBuilder.

    * * @since 9.0 */ public class DocumentBuilder { private Configuration config; private SchemaValidator schemaValidator; private boolean retainPSVI = true; private boolean dtdValidation; private boolean lineNumbering; private WhitespaceStrippingPolicy whitespacePolicy; private URI baseURI; /** * Create a DocumentBuilder. This is a protected constructor. Users should construct a DocumentBuilder * by calling the factory method {@link net.sf.saxon.s9api.Processor#newDocumentBuilder()}. * * @param config the Saxon configuration */ protected DocumentBuilder(Configuration config) { this.config = config; } /** * Set whether line numbering is to be enabled for documents constructed using this DocumentBuilder. * This has the effect that the line number in the original source document is maintained in the constructed * tree, for each element node (and only for elements). The line number in question is generally the line number * on which the closing ">" of the element start tag appears. *

    *

    By default, line numbers are not maintained.

    *

    *

    Errors relating to document parsing and validation will generally contain line numbers whether or not * this option is set, because such errors are detected during document construction.

    *

    *

    Line numbering is not available for all kinds of source: for example, * it is not available when loading from an existing DOM Document.

    *

    *

    The resulting line numbers are accessible to applications using the * XPath extension function saxon:line-number() applied to a node, or using the * Java method {@link net.sf.saxon.om.NodeInfo#getLineNumber()}

    *

    *

    Line numbers are maintained only for element nodes; the line number * returned for any other node will be that of the most recent element. For an element node, the * line number is generally that of the closing angle bracket at the end of the start tag * (this is what a SAX parser notifies)

    * * @param option true if line numbers are to be maintained, false otherwise. */ public void setLineNumbering(boolean option) { lineNumbering = option; } /** * Ask whether line numbering is enabled for documents loaded using this * DocumentBuilder. *

    *

    By default, line numbering is disabled.

    *

    *

    Line numbering is not available for all kinds of source: in particular, * it is not available when loading from an existing XmlDocument.

    *

    *

    The resulting line numbers are accessible to applications using the * extension function saxon:line-number() applied to a node, or using the * Java method {@link net.sf.saxon.om.NodeInfo#getLineNumber()}

    *

    *

    Line numbers are maintained only for element nodes; the line number * returned for any other node will be that of the most recent element. For an element node, the * line number is generally that of the closing angle bracket at the end of the start tag * (this is what a SAX parser notifies)

    * * @return true if line numbering is enabled */ public boolean isLineNumbering() { return lineNumbering; } /** * Set the schemaValidator to be used. This determines whether schema validation is applied to an input * document and whether type annotations in a supplied document are retained. If no schemaValidator * is supplied, then schema validation does not take place. *

    *

    This option requires the schema-aware version of the Saxon product (Saxon-SA).

    * * @param validator the SchemaValidator to be used */ public void setSchemaValidator(SchemaValidator validator) { schemaValidator = validator; } /** * Get the SchemaValidator used to validate documents loaded using this * DocumentBuilder. * * @return the SchemaValidator if one has been set; otherwise null. */ public SchemaValidator getSchemaValidator() { return schemaValidator; } /** * Set whether the constructed tree should contain information derived from schema * validation, specifically whether it should contain type annotations and expanded * defaults of missing element and attribute content. If no schema validator is set * then this option has no effect. The default value is true. *

    Not yet implemented.

    * @param retainPSVI if true, the constructed tree will contain type annotations * and expanded defaults of missing element and attribute content. If false, the * tree that is returned will be the same as if schema validation did not take place * (except that if the document is invalid, no tree will be constructed) */ public void setRetainPSVI(boolean retainPSVI) { // TODO: not implemented this.retainPSVI = retainPSVI; } /** * Ask whether the constructed tree should contain information derived from schema * validation, specifically whether it should contain type annotations and expanded * defaults of missing element and attribute content. If no schema validator is set * then this option has no effect. * *

    Not yet implemented.

    * @return true, if the constructed tree will contain type annotations * and expanded defaults of missing element and attribute content. Return false, if the * tree that is returned will be the same as if schema validation did not take place * (except that if the document is invalid, no tree will be constructed) */ public boolean isRetainPSVI() { return retainPSVI; } /** * Set whether DTD validation should be applied to documents loaded using this * DocumentBuilder. *

    *

    By default, no DTD validation takes place.

    * * @param option true if DTD validation is to be applied to the document */ public void setDTDValidation(boolean option) { dtdValidation = option; } /** * Ask whether DTD validation is to be applied to documents loaded using this DocumentBuilder * * @return true if DTD validation is to be applied */ public boolean isDTDValidation() { return dtdValidation; } /** * Set the whitespace stripping policy applied when loading a document * using this DocumentBuilder. *

    *

    By default, whitespace text nodes appearing in element-only content * are stripped, and all other whitespace text nodes are retained.

    * * @param policy the policy for stripping whitespace-only text nodes from * source documents */ public void setWhitespaceStrippingPolicy(WhitespaceStrippingPolicy policy) { whitespacePolicy = policy; } /** * Get the white whitespace stripping policy applied when loading a document * using this DocumentBuilder. * * @return the policy for stripping whitespace-only text nodes */ public WhitespaceStrippingPolicy getWhitespaceStrippingPolicy() { return whitespacePolicy; } /** * Set the base URI of a document loaded using this DocumentBuilder. *

    *

    This is used for resolving any relative URIs appearing * within the document, for example in references to DTDs and external entities.

    *

    *

    This information is required when the document is loaded from a source that does not * provide an intrinsic URI, notably when loading from a Stream or a DOMSource. The value is * ignored when loading from a source that does have an intrinsic base URI.

    * * @param uri the base URI of documents loaded using this DocumentBuilder. This * must be an absolute URI. * @throws IllegalArgumentException if the baseURI supplied is not an absolute URI */ public void setBaseURI(URI uri) { if (!uri.isAbsolute()) { throw new IllegalArgumentException("Supplied base URI must be absolute"); } baseURI = uri; } /** * Get the base URI of documents loaded using this DocumentBuilder when no other URI is available. * * @return the base URI to be used, or null if no value has been set. */ public URI getBaseURI() { return baseURI; } /** * Load an XML document, to create a tree representation of the document in memory. * * @param source A JAXP Source object identifying the source of the document. This can always be * a {@link javax.xml.transform.stream.StreamSource} or a {@link javax.xml.transform.sax.SAXSource}. * Some kinds of Source are consumed by this method, and should only be used once. *

    *

    If a SAXSource is supplied, the XMLReader held within the SAXSource may be modified (by setting * features and properties) to reflect the options selected on this DocumentBuilder.

    *

    An instance of {@link javax.xml.transform.dom.DOMSource} is accepted provided that the Saxon support * code for DOM (in saxon9-dom.jar) is on the classpath.

    *

    *

    If the source is an instance of {@link net.sf.saxon.om.NodeInfo} then the subtree rooted at this node * will be copied (applying schema validation if requested) to create a new tree.

    *

    *

    Saxon also accepts an instance of {@link net.sf.saxon.pull.PullSource}, which can be used to supply * a document that is to be parsed using a StAX parser.

    * @return An XdmNode. This will be * the document node at the root of the tree of the resulting in-memory document. */ public XdmNode build(Source source) throws SaxonApiException { AugmentedSource as = AugmentedSource.makeAugmentedSource(source); as.setDTDValidationMode(dtdValidation ? Validation.STRICT : Validation.STRIP); if (schemaValidator != null) { as.setSchemaValidationMode(schemaValidator.isLax() ? Validation.LAX : Validation.STRICT); if (schemaValidator.getDocumentElementName() != null) { as.setTopLevelElement(schemaValidator.getDocumentElementName().getStructuredQName()); } if (schemaValidator.getDocumentElementType() != null) { as.setTopLevelType(schemaValidator.getDocumentElementType()); } } if (whitespacePolicy != null) { as.setStripSpace(whitespacePolicy.ordinal()); } as.setLineNumbering(lineNumbering); if (source.getSystemId() == null && baseURI != null) { source.setSystemId(baseURI.toString()); } try { NodeInfo doc = config.buildDocument(as); return new XdmNode(doc); } catch (XPathException e) { throw new SaxonApiException(e); } } /** * Build a document from a supplied XML file * @param file the supplied file * @return the XdmNode representing the root of the document tree * @throws SaxonApiException if any failure occurs retrieving or parsing the document */ public XdmNode build(File file) throws SaxonApiException { return build(new StreamSource(file)); } /** * Create a node by wrapping a recognized external node from a supported object model. * The support module for the external object model must be on the class path and registered * with the Saxon configuration. * *

    It is best to avoid calling this method repeatedly to wrap different nodes in the same document. * Each such wrapper conceptually creates a new XDM tree instance with its own identity. Although the * memory is shared, operations that rely on node identity might not have the expected result. It is * best to create a single wrapper for the document node, and then to navigate to the other nodes in the * tree using S9API interfaces.

    * * @param node the node in the external tree representation * @return the supplied node wrapped as an XdmNode * @throws IllegalArgumentException if the type of object supplied is not recognized. This may be because * the required code is not on the class path */ public XdmNode wrap(Object node) throws IllegalArgumentException { try { JPConverter converter = JPConverter.allocate(node.getClass(), config); NodeInfo nodeInfo = (NodeInfo)converter.convert(node, new EarlyEvaluationContext(config, null)); return (XdmNode)XdmItem.wrapItem(nodeInfo); } catch (XPathException e) { throw new IllegalArgumentException(e.getMessage()); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/s9api/XQueryEvaluator.java0000644000175000017500000003512011107267241022416 0ustar eugeneeugenepackage net.sf.saxon.s9api; import net.sf.saxon.om.Item; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.om.ValueRepresentation; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.query.DynamicQueryContext; import net.sf.saxon.query.XQueryExpression; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.SequenceExtent; import net.sf.saxon.value.AtomicValue; import net.sf.saxon.value.EmptySequence; import net.sf.saxon.trace.TraceListener; import net.sf.saxon.event.Receiver; import javax.xml.transform.TransformerException; import javax.xml.transform.URIResolver; import javax.xml.transform.ErrorListener; import javax.xml.transform.Source; import java.util.Iterator; import java.util.Set; import java.util.HashSet; import java.io.PrintStream; /** * An XQueryEvaluator represents a compiled and loaded stylesheet ready for execution. * The XQueryEvaluator holds details of the dynamic evaluation context for the stylesheet. *

    *

    An XQueryEvaluator must not be used concurrently in multiple threads. * It is safe, however, to reuse the object within a single thread to run the same * stylesheet several times. Running the stylesheet does not change the context * that has been established.

    *

    *

    An XQueryEvaluator is always constructed by running the Load * method of an {@link net.sf.saxon.s9api.XQueryExecutable}.

    *

    *

    An XQueryEvaluator is itself a Iterable. This makes it possible to * evaluate the results in a for-each expression.

    */ public class XQueryEvaluator implements Iterable { private Processor processor; private XQueryExpression expression; private DynamicQueryContext context; private Destination destination; private Set updatedDocuments; /** * Protected constructor * @param processor the Saxon processor * @param expression the XQuery expression */ protected XQueryEvaluator(Processor processor, XQueryExpression expression) { this.processor = processor; this.expression = expression; this.context = new DynamicQueryContext(expression.getExecutable().getConfiguration()); } /** * Set the source document for the query. This method is equivalent to building * a document from the supplied source object, and then supplying the document node of * the resulting document as the initial context node. * @param source the principal source document for the transformation */ public void setSource(Source source) throws SaxonApiException { setContextItem(processor.newDocumentBuilder().build(source)); } /** * Set the initial context item for the query * @param item the initial context item, or null if there is to be no initial context item */ public void setContextItem(XdmItem item) { context.setContextItem(item == null ? null : (Item)item.getUnderlyingValue()); } /** * Get the initial context item for the query, if one has been set * @return the initial context item, or null if none has been set. This will not necessarily * be the same object as was supplied, but it will be an XdmItem object that represents * the same underlying node or atomic value. */ public XdmItem getContextItem() { return (XdmItem)XdmValue.wrap(context.getContextItem()); } /** * Set the value of external variable defined in the query * @param name the name of the external variable, as a QName * @param value the value of the external variable, or null to clear a previously set value */ public void setExternalVariable(QName name, XdmValue value) { context.setParameter(name.getClarkName(), (value == null ? null : value.getUnderlyingValue())); } /** * Get the value that has been set for an external variable * @param name the name of the external variable whose value is required * @return the value that has been set for the external variable, or null if no value has been set */ public XdmValue getExternalVariable(QName name) { Object oval = context.getParameter(name.getClarkName()); if (oval == null) { return null; } if (oval instanceof ValueRepresentation) { return XdmValue.wrap((ValueRepresentation)oval); } throw new IllegalStateException(oval.getClass().getName()); } /** * Set an object that will be used to resolve URIs used in * fn:doc() and related functions. * @param resolver An object that implements the URIResolver interface, or * null. */ public void setURIResolver(URIResolver resolver) { context.setURIResolver(resolver); } /** * Get the URI resolver. * @return the user-supplied URI resolver if there is one, or the * system-defined one otherwise */ public URIResolver getURIResolver() { return context.getURIResolver(); } /** * Set the error listener. The error listener receives reports of all run-time * errors and can decide how to report them. * @param listener the ErrorListener to be used */ public void setErrorListener(ErrorListener listener) { context.setErrorListener(listener); } /** * Get the error listener. * @return the ErrorListener in use */ public ErrorListener getErrorListener() { return context.getErrorListener(); } /** * Set a TraceListener which will receive messages relating to the evaluation of all expressions. * This option has no effect unless the query was compiled to enable tracing. * @param listener the TraceListener to use */ public void setTraceListener(TraceListener listener) { context.setTraceListener(listener); } /** * Get the registered TraceListener, if any * @return listener the TraceListener in use, or null if none has been set */ public TraceListener getTraceListener() { return context.getTraceListener(); } /** * Set the destination for output from the fn:trace() function. * By default, the destination is System.err. If a TraceListener is in use, * this is ignored, and the trace() output is sent to the TraceListener. * @param stream the PrintStream to which trace output will be sent. If set to * null, trace output is suppressed entirely. It is the caller's responsibility * to close the stream after use. * @since 9.1 */ public void setTraceFunctionDestination(PrintStream stream) { context.setTraceFunctionDestination(stream); } /** * Get the destination for output from the fn:trace() function. * @return the PrintStream to which trace output will be sent. If no explicitly * destination has been set, returns System.err. If the destination has been set * to null to suppress trace output, returns null. * @since 9.1 */ public PrintStream getTraceFunctionDestination() { return context.getTraceFunctionDestination(); } /** * Set the destination to be used for the query results * @param destination the destination to which the results of the query will be sent */ public void setDestination(Destination destination) { this.destination = destination; } /** * Perform the query. *

    *

    • In the case of a non-updating query, the results are sent to the * registered Destination.
    • *
    • In the case of an updating query, all updated documents will be available after query * execution as the result of the {@link #getUpdatedDocuments} method.
    • *
    * @throws net.sf.saxon.s9api.SaxonApiException * if any dynamic error occurs during the query * @throws IllegalStateException if this is a non-updating query and no Destination has been * supplied for the query results */ public void run() throws SaxonApiException { try { if (expression.isUpdateQuery()) { Set docs = expression.runUpdate(context); updatedDocuments = new HashSet(); for (Iterator iter = docs.iterator(); iter.hasNext();) { NodeInfo root = (NodeInfo)iter.next(); updatedDocuments.add((XdmNode)XdmNode.wrapItem(root)); } } else { if (destination == null) { throw new IllegalStateException("No destination supplied"); } Receiver receiver; if (destination instanceof Serializer) { receiver = ((Serializer)destination).getReceiver( expression.getExecutable().getConfiguration(), null, expression.getExecutable().getDefaultOutputProperties()); } else { receiver = destination.getReceiver(expression.getExecutable().getConfiguration()); } expression.run(context, receiver, null); } } catch (TransformerException e) { throw new SaxonApiException(e); } } /** * Perform the query, sending the results to a specified destination. This method * must not be used with an updating query * @param destination The destination where the result document will be sent * @throws net.sf.saxon.s9api.SaxonApiException * if any dynamic error occurs during the query * @throws IllegalStateException if this is an updating query */ public void run(Destination destination) throws SaxonApiException { if (expression.isUpdateQuery()) { throw new IllegalStateException("Query is updating"); } try { Receiver receiver; if (destination instanceof Serializer) { receiver = ((Serializer)destination).getReceiver( expression.getExecutable().getConfiguration(), null, expression.getExecutable().getDefaultOutputProperties()); } else { receiver = destination.getReceiver(expression.getExecutable().getConfiguration()); } expression.run(context, receiver, null); } catch (TransformerException e) { throw new SaxonApiException(e); } } /** * Perform the query, returning the results as an XdmValue. This method * must not be used with an updating query * @return an XdmValue representing the results of the query * @throws SaxonApiException if the query fails with a dynamic error * @throws IllegalStateException if this is an updating query */ public XdmValue evaluate() throws SaxonApiException { if (expression.isUpdateQuery()) { throw new IllegalStateException("Query is updating"); } try { SequenceIterator iter = expression.iterator(context); ValueRepresentation result = SequenceExtent.makeSequenceExtent(iter); if (result instanceof NodeInfo) { return new XdmNode((NodeInfo)result); } else if (result instanceof AtomicValue) { return new XdmAtomicValue((AtomicValue)result); } else if (result instanceof EmptySequence) { return XdmEmptySequence.getInstance(); } else { return new XdmValue(result); } } catch (XPathException e) { throw new SaxonApiException(e); } } /** * Get an iterator over the results of the query. This method * must not be used with an updating query * @throws SaxonApiUncheckedException if a dynamic error is detected while constructing the iterator. * It is also possible for an SaxonApiUncheckedException to be thrown by the hasNext() method of the * returned iterator if a dynamic error occurs while evaluating the result sequence. * @throws IllegalStateException if this is an updating query */ public Iterator iterator() throws SaxonApiUncheckedException { if (expression.isUpdateQuery()) { throw new IllegalStateException("Query is updating"); } try { return new XdmSequenceIterator(expression.iterator(context)); } catch (XPathException e) { throw new SaxonApiUncheckedException(e); } } /** * After executing an updating query using the {@link #run()} method, iterate over the root * nodes of the documents updated by the query. *

    *

    The results remain available until a new query is executed. This method returns the results * of the most recently executed query. It does not consume the results.

    * @return an iterator over the root nodes of documents (or other trees) that were updated by the query * @since 9.1 */ public Iterator getUpdatedDocuments() { return updatedDocuments.iterator(); } /** * Get the underlying dynamic context object. This provides an escape hatch to the underlying * implementation classes, which contain methods that may change from one release to another. * @return the underlying object representing the dynamic context for query execution */ public DynamicQueryContext getUnderlyingQueryContext() { return context; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/s9api/XQueryCompiler.java0000644000175000017500000003005011033112257022215 0ustar eugeneeugenepackage net.sf.saxon.s9api; import net.sf.saxon.query.ModuleURIResolver; import net.sf.saxon.query.StaticQueryContext; import net.sf.saxon.trans.XPathException; import javax.xml.transform.ErrorListener; import java.io.*; import java.net.URI; import java.net.URISyntaxException; /** * An XQueryCompiler object allows XQuery 1.0 queries to be compiled. The compiler holds information that * represents the static context for the compilation. * *

    To construct an XQueryCompiler, use the factory method {@link Processor#newXQueryCompiler}.

    * *

    An XQueryCompiler may be used repeatedly to compile multiple queries. Any changes made to the * XQueryCompiler (that is, to the static context) do not affect queries that have already been compiled. * An XQueryCompiler may be used concurrently in multiple threads, but it should not then be modified once * initialized.

    * * @since 9.0 */ public class XQueryCompiler { private Processor processor; private StaticQueryContext env; private ItemType requiredContextItemType; private String encoding; /** * Protected constructor * @param processor the Saxon Processor */ protected XQueryCompiler(Processor processor) { this.processor = processor; this.env = new StaticQueryContext(processor.getUnderlyingConfiguration()); } /** * Set the static base URI for the query * @param baseURI the static base URI */ public void setBaseURI(URI baseURI) { if (!baseURI.isAbsolute()) { throw new IllegalArgumentException("Base URI must be an absolute URI"); } env.setBaseURI(baseURI.toString()); } /** * Get the static base URI for the query * @return the static base URI */ public URI getBaseURI() { try { return new URI(env.getBaseURI()); } catch (URISyntaxException err) { throw new IllegalStateException(err); } } /** * Set the ErrorListener to be used during this query compilation episode * @param listener The error listener to be used. This is notified of all errors detected during the * compilation. */ public void setErrorListener(ErrorListener listener) { env.setErrorListener(listener); } /** * Get the ErrorListener being used during this compilation episode * @return listener The error listener in use. This is notified of all errors detected during the * compilation. If no user-supplied ErrorListener has been set, returns the system-supplied * ErrorListener. */ public ErrorListener getErrorListener() { return env.getErrorListener(); } /** * Set whether trace hooks are to be included in the compiled code. To use tracing, it is necessary * both to compile the code with trace hooks included, and to supply a TraceListener at run-time * @param option true if trace code is to be compiled in, false otherwise */ public void setCompileWithTracing(boolean option) { env.setCompileWithTracing(option); } /** * Ask whether trace hooks are included in the compiled code. * @return true if trace hooks are included, false if not. */ public boolean isCompileWithTracing() { return env.isCompileWithTracing(); } /** * Set a user-defined ModuleURIResolver for resolving URIs used in import module * declarations in the XQuery prolog. * This will override any ModuleURIResolver that was specified as part of the configuration. * @param resolver the ModuleURIResolver to be used */ public void setModuleURIResolver(ModuleURIResolver resolver) { env.setModuleURIResolver(resolver); } /** * Get the user-defined ModuleURIResolver for resolving URIs used in import module * declarations in the XQuery prolog; returns null if none has been explicitly set either * here or in the Saxon Configuration. * @return the registered ModuleURIResolver */ public ModuleURIResolver getModuleURIResolver() { return env.getModuleURIResolver(); } /** * Set the encoding of the supplied query. This is ignored if the query is supplied * in character form, that is, as a String or as a Reader. If no value * is set, the query processor will attempt to infer the encoding, defaulting to UTF-8 if no * information is available. * @param encoding the encoding of the supplied query, for example "iso-8859-1" * @since 9.1 */ public void setEncoding(String encoding) { this.encoding = encoding; } /** * Get the encoding of the supplied query. * @param encoding the encoding previously set using {@link #setEncoding(String)}, or null * if no value has been set * @since 9.1 */ /** * Say whether the query is allowed to be updating. XQuery update syntax will be rejected * during query compilation unless this flag is set. XQuery Update is supported only under Saxon-SA. * @param updating true if the query is allowed to use the XQuery Update facility * (requires Saxon-SA). If set to false, the query must not be an updating query. If set * to true, it may be either an updating or a non-updating query. * @since 9.1 */ public void setUpdatingEnabled(boolean updating) { env.setUpdatingEnabled(updating); } /** * Ask whether the query is allowed to use XQuery Update syntax * @return true if the query is allowed to use the XQuery Update facility. Note that this * does not necessarily mean that the query is an updating query; but if the value is false, * the it must definitely be non-updating. * @since 9.1 */ public boolean isUpdatingEnabled() { return env.isUpdatingEnabled(); } /** * Declare a namespace binding as part of the static context for queries compiled using this * XQueryCompiler. This binding may be overridden by a binding that appears in the query prolog. * The namespace binding will form part of the static context of the query, but it will not be copied * into result trees unless the prefix is actually used in an element or attribute name. * * @param prefix The namespace prefix. If the value is a zero-length string, this method sets the default * namespace for elements and types. * @param uri The namespace URI. It is possible to specify a zero-length string to "undeclare" a namespace; * in this case the prefix will not be available for use, except in the case where the prefix * is also a zero length string, in which case the absence of a prefix implies that the name * is in no namespace. * @throws NullPointerException if either the prefix or uri is null. * @throws IllegalArgumentException in the event of an invalid declaration of the XML namespace */ public void declareNamespace(String prefix, String uri) { env.declareNamespace(prefix, uri); } /** * Declare the static type of the context item. If this type is declared, and if a context item * is supplied when the query is invoked, then the context item must conform to this type (no * type conversion will take place to force it into this type). * @param type the required type of the context item */ public void setRequiredContextItemType(ItemType type) { requiredContextItemType = type; env.setRequiredContextItemType(type.getUnderlyingItemType()); } /** * Get the required type of the context item. If no type has been explicitly declared for the context * item, an instance of AnyItemType (representing the type item()) is returned. * @return the required type of the context item */ public ItemType getRequiredContextItemType() { return requiredContextItemType; } /** * Compile a query supplied as a string. *

    The base URI of the query should be supplied by calling {@link #setBaseURI(java.net.URI)}

    * @param query the text of the query * @return an XQueryExecutable representing the compiled query * @throws SaxonApiException if the query compilation fails with a static error */ public XQueryExecutable compile(String query) throws SaxonApiException { try { return new XQueryExecutable(processor, env.compileQuery(query)); } catch (XPathException e) { throw new SaxonApiException(e); } } /** * Compile a query supplied as a file * @param query the file containing the query. The URI corresponding to this file will be used as the * base URI of the query, overriding any URI supplied using {@link #setBaseURI(java.net.URI)} (but not * overriding any base URI specified within the query prolog) * @return an XQueryExecutable representing the compiled query * @throws SaxonApiException if the query compilation fails with a static error * @throws IOException if the file does not exist or cannot be read * @since 9.1 */ public XQueryExecutable compile(File query) throws SaxonApiException, IOException { try { String savedBaseUri = env.getBaseURI(); env.setBaseURI(query.toURI().toString()); XQueryExecutable exec = new XQueryExecutable(processor, env.compileQuery(new FileInputStream(query), encoding)); env.setBaseURI(savedBaseUri); return exec; } catch (XPathException e) { throw new SaxonApiException(e); } } /** * Compile a query supplied as an InputStream *

    The base URI of the query should be supplied by calling {@link #setBaseURI(java.net.URI)}

    * @param query the input stream on which the query is supplied. This will be consumed by this method * @return an XQueryExecutable representing the compiled query * @throws SaxonApiException if the query compilation fails with a static error * @throws IOException if the file does not exist or cannot be read * @since 9.1 */ public XQueryExecutable compile(InputStream query) throws SaxonApiException, IOException { try { return new XQueryExecutable(processor, env.compileQuery(query, encoding)); } catch (XPathException e) { throw new SaxonApiException(e); } } /** * Compile a query supplied as a Reader *

    The base URI of the query should be supplied by calling {@link #setBaseURI(java.net.URI)}

    * @param query the input stream on which the query is supplied. This will be consumed by this method * @return an XQueryExecutable representing the compiled query * @throws SaxonApiException if the query compilation fails with a static error * @throws IOException if the file does not exist or cannot be read * @since 9.1 */ public XQueryExecutable compile(Reader query) throws SaxonApiException, IOException { try { return new XQueryExecutable(processor, env.compileQuery(query)); } catch (XPathException e) { throw new SaxonApiException(e); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/s9api/Axis.java0000644000175000017500000000355711033112257020205 0ustar eugeneeugenepackage net.sf.saxon.s9api; /** * This is an enumeration class containaing constants representing the thirteen XPath axes */ public enum Axis { ANCESTOR (net.sf.saxon.om.Axis.ANCESTOR), ANCESTOR_OR_SELF (net.sf.saxon.om.Axis.ANCESTOR_OR_SELF), ATTRIBUTE (net.sf.saxon.om.Axis.ATTRIBUTE), CHILD (net.sf.saxon.om.Axis.CHILD), DESCENDANT (net.sf.saxon.om.Axis.DESCENDANT), DESCENDANT_OR_SELF (net.sf.saxon.om.Axis.DESCENDANT_OR_SELF), FOLLOWING (net.sf.saxon.om.Axis.FOLLOWING), FOLLOWING_SIBLING (net.sf.saxon.om.Axis.FOLLOWING_SIBLING), PARENT (net.sf.saxon.om.Axis.PARENT), PRECEDING (net.sf.saxon.om.Axis.PRECEDING), PRECEDING_SIBLING (net.sf.saxon.om.Axis.PRECEDING_SIBLING), SELF (net.sf.saxon.om.Axis.SELF), NAMESPACE (net.sf.saxon.om.Axis.NAMESPACE); private byte number; /** * Create an Axis * @param number the internal axis number as defined in class {@link net.sf.saxon.om.Axis} */ private Axis(byte number) { this.number = number; } /** * Get the axis number, as defined in class {@link net.sf.saxon.om.Axis} * @return the axis number */ public byte getAxisNumber() { return number; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/s9api/ItemType.java0000644000175000017500000001114611034646411021037 0ustar eugeneeugenepackage net.sf.saxon.s9api; import net.sf.saxon.om.Item; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.pattern.AnyNodeTest; import net.sf.saxon.pattern.NodeTest; import net.sf.saxon.type.AnyItemType; import net.sf.saxon.type.AtomicType; import net.sf.saxon.type.BuiltInAtomicType; import net.sf.saxon.type.TypeHierarchy; import net.sf.saxon.value.AtomicValue; /** * An item type, as defined in the XPath/XQuery specifications. * *

    This class contains a number of static properties * to obtain instances representing simple item types, such as * item(), node(), and xs:anyAtomicType.

    * *

    More complicated item types, especially those that are dependent on information in a schema, * are available using factory methods on the {@link ItemTypeFactory} object.

    */ public class ItemType { /** * ItemType representing the type item(), that is, any item at all */ public static ItemType ANY_ITEM = new ItemType(AnyItemType.getInstance(), null) { public boolean matches(XdmItem item) { return true; } public boolean subsumes(ItemType other) { return true; } }; /** * ItemType representing the type node(), that is, any node */ public static ItemType ANY_NODE = new ItemType(AnyNodeTest.getInstance(), null) { public boolean matches(XdmItem item) { return item.getUnderlyingValue() instanceof NodeInfo; } public boolean subsumes(ItemType other) { return other.getUnderlyingItemType() instanceof NodeTest; } }; /** * ItemType representing the type xs:anyAtomicType, that is, any atomic value */ public static ItemType ANY_ATOMIC_VALUE = new ItemType(BuiltInAtomicType.ANY_ATOMIC, null) { public boolean matches(XdmItem item) { return item.getUnderlyingValue() instanceof AtomicValue; } public boolean subsumes(ItemType other) { return other.getUnderlyingItemType() instanceof AtomicType; } }; private net.sf.saxon.type.ItemType underlyingType; private Processor processor; protected ItemType(net.sf.saxon.type.ItemType underlyingType, Processor processor) { this.processor = processor; this.underlyingType = underlyingType; } /** * Determine whether this item type matches a given item. * * @param item the item to be tested against this item type * @return true if the item matches this item type, false if it does not match. */ public boolean matches(XdmItem item) { return underlyingType.matchesItem( (Item)item.getUnderlyingValue(), false, processor.getUnderlyingConfiguration()); } /** * Determine whether this ItemType subsumes another ItemType. Specifically, * A.subsumes(B) is true if every value that matches the ItemType B also matches * the ItemType A. * @param other the other ItemType * @return true if this ItemType subsumes the other ItemType. This includes the case where A and B * represent the same ItemType. * @since 9.1 */ public boolean subsumes(ItemType other) { TypeHierarchy th = processor.getUnderlyingConfiguration().getTypeHierarchy(); return th.isSubType(other.getUnderlyingItemType(), underlyingType); } /** * Method to get the underlying Saxon implementation object * *

    This gives access to Saxon methods that may change from one release to another.

    * @return the underlying Saxon implementation object */ public net.sf.saxon.type.ItemType getUnderlyingItemType() { return underlyingType; } /** * Get the underlying Processor * @return the processor used to create this ItemType, if any */ protected Processor getProcessor() { return processor; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/s9api/XsltExecutable.java0000644000175000017500000000570011033112257022225 0ustar eugeneeugenepackage net.sf.saxon.s9api; import net.sf.saxon.Controller; import net.sf.saxon.PreparedStylesheet; import net.sf.saxon.Configuration; import net.sf.saxon.trace.ExpressionPresenter; /** * An XsltExecutable represents the compiled form of a stylesheet. * To execute the stylesheet, it must first be loaded to form an {@link XsltTransformer}. * *

    An XsltExecutable is immutable, and therefore thread-safe. * It is simplest to load a new XsltTransformer each time the stylesheet is to be run. * However, the XsltTransformer is serially reusable within a single thread.

    * *

    An XsltExecutable is created by using one of the compile methods on the * {@link XsltCompiler} class.

    */ public class XsltExecutable { Processor processor; PreparedStylesheet pss; protected XsltExecutable(Processor processor, PreparedStylesheet pss) { this.processor = processor; this.pss = pss; } /** * Load the stylesheet to prepare it for execution. * @return An XsltTransformer. The returned XsltTransformer can be used to set up the * dynamic context for stylesheet evaluation, and to run the stylesheet. */ public XsltTransformer load() { return new XsltTransformer(processor, (Controller)pss.newTransformer()); } /** * Produce a diagnostic representation of the compiled stylesheet, in XML form. *

    The detailed form of this representation is not stable (or even documented).

    * @param destination the destination for the XML document containing the diagnostic representation * of the compiled stylesheet * @since 9.1 */ public void explain(Destination destination) throws SaxonApiException { Configuration config = processor.getUnderlyingConfiguration(); pss.explain(new ExpressionPresenter(config, destination.getReceiver(config))); } /** * Get the underlying implementation object representing the compiled stylesheet. This provides * an escape hatch into lower-level APIs. The object returned by this method may change from release * to release. * @return the underlying implementation of the compiled stylesheet */ public PreparedStylesheet getUnderlyingCompiledStylesheet() { return pss; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/s9api/XdmDestination.java0000644000175000017500000001063011033112257022221 0ustar eugeneeugenepackage net.sf.saxon.s9api; import net.sf.saxon.Configuration; import net.sf.saxon.event.Receiver; import net.sf.saxon.tinytree.TinyBuilder; import java.net.URI; import java.net.URISyntaxException; /** * An XdmDestination is a {@link Destination} in which an {@link XdmNode} * is constructed to hold the output of a query or transformation: * that is, a tree using Saxon's implementation of the XDM data model * *

    No data needs to be supplied to the XdmDestination object. The query or transformation * populates an XmlNode, which may then be retrieved using the getXdmNode * method.

    * *

    An XdmDestination can be reused to hold the results of a second transformation only * if the {@link #reset} method is first called to reset its state.

    */ public class XdmDestination implements Destination { TinyBuilder builder; public XdmDestination() { builder = new TinyBuilder(); } /** * Set the base URI for the document node that will be created when the XdmDestination is written to. * This method must be called before writing to the destination; it has no effect on an XdmNode that * has already been constructed. * @param baseURI the base URI for the node that will be constructed when the XdmDestination is written to. * This must be an absolute URI * @throws IllegalArgumentException if the baseURI supplied is not an absolute URI * @since 9.1 */ public void setBaseURI(URI baseURI) { if (!baseURI.isAbsolute()) { throw new IllegalArgumentException("Supplied base URI must be absolute"); } builder.setBaseURI(baseURI.toString()); } /** * Get the base URI that will be used for the document node when the XdmDestination is written to. * @return the base URI that will be used for the node that is constructed when the XdmDestination is written to. * @throws IllegalStateException if the a base URI has been configured using internal interfaces, and is not * a valid URI * @since 9.1 */ public URI getBaseURI() { try { return new URI(builder.getBaseURI()); } catch (URISyntaxException err) { throw new IllegalStateException(err.getMessage()); } } /** * Return a Receiver. Saxon calls this method to obtain a Receiver, to which it then sends * a sequence of events representing the content of an XML document. * * @param config The Saxon configuration. This is supplied so that the destination can * use information from the configuration (for example, a reference to the name pool) * to construct or configure the returned Receiver. * @return the Receiver to which events are to be sent. * @throws net.sf.saxon.s9api.SaxonApiException * if the Receiver cannot be created */ public Receiver getReceiver(Configuration config) throws SaxonApiException { return builder; } /** * Return the node at the root of the tree, after it has been constructed. * *

    This method should not be called while the tree is under construction.

    * * @return the root node of the tree (normally a document node). Returns null if the * construction of the tree has not yet started. The result is undefined if tree construction * has started but is not complete. */ public XdmNode getXdmNode() { return (XdmNode)XdmValue.wrap(builder.getCurrentRoot()); } /** * Allow the XdmDestination to be reused */ public void reset() { builder = new TinyBuilder(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/s9api/ItemTypeFactory.java0000644000175000017500000004115711033112257022367 0ustar eugeneeugenepackage net.sf.saxon.s9api; import net.sf.saxon.Configuration; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.value.AtomicValue; import net.sf.saxon.value.ObjectValue; import net.sf.saxon.expr.Token; import net.sf.saxon.pattern.*; import net.sf.saxon.type.*; /** * This class is used for creating ItemType objects. */ public class ItemTypeFactory { private Processor processor; /** * Create an ItemTypeFactory * @param processor the processor used by this ItemTypeFactory. This must be supplied * in the case of user-defined types or types that reference element or attribute names; * for built-in types it can be omitted. */ public ItemTypeFactory(Processor processor) { this.processor = processor; } /** * Get an item type representing an atomic type. This may be a built-in type in the * XML Schema namespace, or a user-defined atomic type. * *

    It is undefined whether two calls supplying the same QName will return the same ItemType * object.

    * @param name the name of the built-in atomic type required * @return an ItemType object representing this built-in atomic type * @throws SaxonApiException if the type name is not known, or if the type identified by the * name is not an atomic type. */ public ItemType getAtomicType(QName name) throws SaxonApiException { Configuration config = processor.getUnderlyingConfiguration(); int fp = config.getNamePool().allocate("", name.getNamespaceURI(), name.getLocalName()); SchemaType type = config.getSchemaType(fp); if (type == null || !type.isAtomicType()) { throw new SaxonApiException("Unknown atomic type " + name.getClarkName()); } return new ItemType((AtomicType)type, processor); } /** * Get an item type that matches any node of a specified kind. * *

    This corresponds to the XPath syntactic forms element(), attribute(), * document-node(), text(), comment(), processing-instruction(). It also provides * an option, not available in the XPath syntax, that matches namespace nodes.

    * *

    It is undefined whether two calls supplying the same argument value will * return the same ItemType object.

    * * @param kind the kind of node for which a NodeTest is required * @return an item type corresponding to the specified kind of node */ public ItemType getNodeKindTest(XdmNodeKind kind) { switch (kind) { case DOCUMENT: return new ItemType(NodeKindTest.DOCUMENT, processor); case ELEMENT: return new ItemType(NodeKindTest.ELEMENT, processor); case ATTRIBUTE: return new ItemType(NodeKindTest.ATTRIBUTE, processor); case TEXT: return new ItemType(NodeKindTest.TEXT, processor); case COMMENT: return new ItemType(NodeKindTest.COMMENT, processor); case PROCESSING_INSTRUCTION: return new ItemType(NodeKindTest.PROCESSING_INSTRUCTION, processor); case NAMESPACE: return new ItemType(NodeKindTest.NAMESPACE, processor); default: throw new IllegalArgumentException("XdmNodeKind"); } } /** * Get an item type that matches nodes of a specified kind with a specified name. * *

    This corresponds to the XPath syntactic forms element(name), attribute(name), * and processing-instruction(name). In the case of processing-instruction, the supplied * QName must have no namespace.

    * *

    It is undefined whether two calls supplying the same argument values will * return the same ItemType object.

    * * @param kind the kind of nodes that match * @param name the name of the nodes that match * @return an ItemType that matches nodes of a given node kind with a given name * @throws IllegalArgumentException if the node kind is other than element, attribute, or * processing instruction, or if the node kind is processing instruction and the name is in a namespace. */ public ItemType getItemType(XdmNodeKind kind, QName name) { int k = kind.getNumber(); if (k == Type.ELEMENT || k == Type.ATTRIBUTE || k == Type.PROCESSING_INSTRUCTION) { if (k == Type.PROCESSING_INSTRUCTION && name.getNamespaceURI().length()==0) { throw new IllegalArgumentException("The name of a processing instruction must not be in a namespace"); } NameTest type = new NameTest(k, name.getNamespaceURI(), name.getLocalName(), processor.getUnderlyingConfiguration().getNamePool()); return new ItemType(type, processor); } else { throw new IllegalArgumentException("Node kind must be element, attribute, or processing-instruction"); } } /** * Make an ItemType representing an element declaration in the schema. This is the * equivalent of the XPath syntax schema-element(element-name) * *

    It is undefined whether two calls supplying the same argument values will * return the same ItemType object.

    * * @param name the element name * @return the ItemType * @throws SaxonApiException if the schema does not contain a global element declaration * for the given name */ public ItemType getSchemaElementTest(QName name) throws SaxonApiException { Configuration config = processor.getUnderlyingConfiguration(); int fingerprint = config.getNamePool().allocate("", name.getNamespaceURI(), name.getLocalName()); SchemaDeclaration decl = config.getElementDeclaration(fingerprint); if (decl == null) { throw new SaxonApiException("No global declaration found for element " + name.getClarkName()); } CombinedNodeTest combo = new CombinedNodeTest( new NameTest(Type.ELEMENT, fingerprint, config.getNamePool()), Token.INTERSECT, new ContentTypeTest(Type.ELEMENT, decl.getType(), config)); combo.setGlobalComponentTest(true); return new ItemType(combo, processor); } /** * Make an ItemType that tests an element name and/or schema type. This is the * equivalent of the XPath syntax element(element-name, type) * *

    It is undefined whether two calls supplying the same argument values will * return the same ItemType object.

    * * @param name the element name, or null if there is no constraint on the name (equivalent to * specifying element(*, type)) * @param schemaType the name of the required schema type, or null of there is no constraint * on the type (equivalent to specifying element(name)) * @param nillable if a nilled element is allowed to match the type (equivalent to specifying * "?" after the type name). The value is ignored if schemaType is null. * @return the constructed ItemType * @throws SaxonApiException if the schema does not contain a global element declaration * for the given name */ public ItemType getElementTest(QName name, QName schemaType, boolean nillable) throws SaxonApiException { Configuration config = processor.getUnderlyingConfiguration(); NameTest nameTest = null; ContentTypeTest contentTest = null; if (name != null) { int elementFP = config.getNamePool().allocate("", name.getNamespaceURI(), name.getLocalName()); nameTest = new NameTest(Type.ELEMENT, elementFP, config.getNamePool()); } if (schemaType != null) { int typeFP = config.getNamePool().allocate("", schemaType.getNamespaceURI(), schemaType.getLocalName()); SchemaType type = config.getSchemaType(typeFP); if (type == null) { throw new SaxonApiException("Unknown schema type " + schemaType.getClarkName()); } contentTest = new ContentTypeTest(Type.ELEMENT, type, config); contentTest.setNillable(nillable); } if (contentTest == null) { if (nameTest == null) { return getNodeKindTest(XdmNodeKind.ELEMENT); } else { return new ItemType(nameTest, processor); } } else { if (nameTest == null) { return new ItemType(contentTest, processor); } else { CombinedNodeTest combo = new CombinedNodeTest( nameTest, Token.INTERSECT, contentTest); return new ItemType(combo, processor); } } } /** * Get an ItemType representing an attribute declaration in the schema. This is the * equivalent of the XPath syntax schema-attribute(attribute-name) * *

    It is undefined whether two calls supplying the same argument values will * return the same ItemType object.

    * * @param name the attribute name * @return the ItemType * @throws SaxonApiException if the schema does not contain a global attribute declaration * for the given name */ public ItemType getSchemaAttributeTest(QName name) throws SaxonApiException { Configuration config = processor.getUnderlyingConfiguration(); int fingerprint = config.getNamePool().allocate("", name.getNamespaceURI(), name.getLocalName()); SchemaDeclaration decl = config.getAttributeDeclaration(fingerprint); if (decl == null) { throw new SaxonApiException("No global declaration found for attribute " + name.getClarkName()); } CombinedNodeTest combo = new CombinedNodeTest( new NameTest(Type.ATTRIBUTE, fingerprint, config.getNamePool()), Token.INTERSECT, new ContentTypeTest(Type.ATTRIBUTE, decl.getType(), config)); combo.setGlobalComponentTest(true); return new ItemType(combo, processor); } /** * Get an ItemType that tests an element name and/or schema type. This is the * equivalent of the XPath syntax element(element-name, type) * *

    It is undefined whether two calls supplying the same argument values will * return the same ItemType object.

    * * @param name the element name, or null if there is no constraint on the name (equivalent to * specifying element(*, type)) * @param schemaType the name of the required schema type, or null of there is no constraint * on the type (equivalent to specifying element(name)) * @return the constructed ItemType * @throws SaxonApiException if the schema does not contain a global element declaration * for the given name */ public ItemType getAttributeTest(QName name, QName schemaType) throws SaxonApiException { NameTest nameTest = null; ContentTypeTest contentTest = null; Configuration config = processor.getUnderlyingConfiguration(); if (name != null) { int attributeFP = config.getNamePool().allocate("", name.getNamespaceURI(), name.getLocalName()); nameTest = new NameTest(Type.ATTRIBUTE, attributeFP, config.getNamePool()); } if (schemaType != null) { int typeFP = config.getNamePool().allocate("", schemaType.getNamespaceURI(), schemaType.getLocalName()); SchemaType type = config.getSchemaType(typeFP); if (type == null) { throw new SaxonApiException("Unknown schema type " + schemaType.getClarkName()); } contentTest = new ContentTypeTest(Type.ATTRIBUTE, type, config); } if (contentTest == null) { if (nameTest == null) { return getNodeKindTest(XdmNodeKind.ATTRIBUTE); } else { return new ItemType(nameTest, processor); } } else { if (nameTest == null) { return new ItemType(contentTest, processor); } else { CombinedNodeTest combo = new CombinedNodeTest( nameTest, Token.INTERSECT, contentTest); return new ItemType(combo, processor); } } } /** * Make an ItemType representing a document-node() test with an embedded element test. * This reflects the XPath syntax document-node(element(N, T)) or * document-node(schema-element(N)). * *

    It is undefined whether two calls supplying the same argument values will * return the same ItemType object.

    * * @param elementTest the elementTest. An IllegalArgumentException is thrown if the supplied * ItemTest is not an elementTest or schemaElementTest. * @return a new ItemType representing the document test */ public ItemType getDocumentTest(ItemType elementTest) { net.sf.saxon.type.ItemType test = elementTest.getUnderlyingItemType(); if (test.getPrimitiveType() != Type.ELEMENT) { throw new IllegalArgumentException("Supplied itemType is not an element test"); } DocumentNodeTest docTest = new DocumentNodeTest((NodeTest)test); return new ItemType(docTest, processor); } /** * Get an ItemType representing the type of a Java object when used as an external object * for use in conjuunction with calls on extension/external functions. * @param externalClass a Java class * @return the ItemType representing the type of external objects of this class */ public ItemType getExternalObjectType(Class externalClass) { ExternalObjectType type = new ExternalObjectType(externalClass, processor.getUnderlyingConfiguration()); return new ItemType(type, processor); } /** * Factory method to construct an "external object". This is an XDM value that wraps a Java * object. Such values can be passed as parameters to stylesheets or queries, for use in conjunction * with external (extension) functions. * @param object the value to be wrapped as an external object * @return the object, wrapped as an XdmAtomicValue */ public XdmAtomicValue getExternalObject(Object object) { ExternalObjectType type = new ExternalObjectType(object.getClass(), processor.getUnderlyingConfiguration()); return (XdmAtomicValue)XdmItem.wrap(new ObjectValue(object, type)); } /** * Get an ItemType representing the type of a supplied XdmItem. If the supplied item is * an atomic value, the returned ItemType will reflect the most specific atomic type of the * item. If the supplied item is a node, the returned item type will reflect the node kind, * and if the node has a name, then its name. It will not reflect the type annotation. * @param item the supplied item whose type is required * @return the type of the supplied item */ public ItemType getItemType(XdmItem item) { Configuration config = processor.getUnderlyingConfiguration(); if (item.isAtomicValue()) { AtomicValue value = (AtomicValue)item.getUnderlyingValue(); AtomicType type = (AtomicType)value.getItemType(config.getTypeHierarchy()); return new ItemType(type, processor); } else { NodeInfo node = (NodeInfo)item.getUnderlyingValue(); int kind = node.getNodeKind(); int fp = node.getFingerprint(); if (fp == -1) { return new ItemType(NodeKindTest.makeNodeKindTest(kind), processor); } else { return new ItemType(new NameTest(kind, fp, config.getNamePool()), processor); } } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/s9api/XdmSequenceIterator.java0000644000175000017500000001003611033112257023222 0ustar eugeneeugenepackage net.sf.saxon.s9api; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.trans.XPathException; import java.util.Iterator; /** * An iterator over an XPath sequence. * *

    This class implements the standard Java Iterator interface.

    * *

    Because the Iterator interface does not define any checked * exceptions, the hasNext() method of this iterator throws an unchecked * exception if a dynamic error occurs while evaluating the expression. Applications * wishing to control error handling should take care to catch this exception.

    */ public class XdmSequenceIterator implements Iterator { private XdmItem next = null; private int state = BEFORE_ITEM; private SequenceIterator base; private final static int BEFORE_ITEM = 0; private final static int ON_ITEM = 1; private final static int FINISHED = 2; protected XdmSequenceIterator(SequenceIterator base) { this.base = base; this.state = BEFORE_ITEM; } /** * Returns true if the iteration has more elements. (In other * words, returns true if next would return an element * rather than throwing an exception.) * * @return true if the iterator has more elements. * * @throws SaxonApiUncheckedException if a dynamic error occurs during XPath evaluation that * is detected at this point. */ public boolean hasNext() throws SaxonApiUncheckedException { switch (state) { case ON_ITEM: return true; case FINISHED: return false; case BEFORE_ITEM: try { next = XdmItem.wrapItem(base.next()); if (next == null) { state = FINISHED; return false; } else { state = ON_ITEM; return true; } } catch (XPathException err) { throw new SaxonApiUncheckedException(err); } default: throw new IllegalStateException(); } } /** * Returns the next element in the iteration. Calling this method * repeatedly until the {@link #hasNext()} method returns false will * return each element in the underlying collection exactly once. * * @return the next element in the iteration. * @throws java.util.NoSuchElementException * iteration has no more elements. */ public XdmItem next() { switch (state) { case ON_ITEM: state = BEFORE_ITEM; return next; case FINISHED: throw new java.util.NoSuchElementException(); case BEFORE_ITEM: if (hasNext()) { state = BEFORE_ITEM; return next; } else { throw new java.util.NoSuchElementException(); } default: throw new IllegalStateException(); } } /** * Not supported on this implementation. * * @throws UnsupportedOperationException always */ public void remove() { throw new UnsupportedOperationException(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/s9api/SaxonApiException.java0000644000175000017500000000300511033112257022666 0ustar eugeneeugenepackage net.sf.saxon.s9api; import net.sf.saxon.trans.XPathException; /** * An exception thrown by the Saxon s9api API. This is always a wrapper for some other underlying exception */ public class SaxonApiException extends Exception { /** * Create a SaxonApiException * @param e the underlying exception */ public SaxonApiException(Throwable e) { super(e); } /** * Create a SaxonApiException * @param message the message */ public SaxonApiException(String message) { super(new XPathException(message)); } /** * Returns the detail message string of this throwable. * * @return the detail message string of this Throwable instance * (which may be null). */ public String getMessage() { return getCause().getMessage(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/s9api/XPathExecutable.java0000644000175000017500000001047611033112257022325 0ustar eugeneeugenepackage net.sf.saxon.s9api; import net.sf.saxon.expr.StaticContext; import net.sf.saxon.sxpath.IndependentContext; import net.sf.saxon.sxpath.XPathExpression; import net.sf.saxon.sxpath.XPathVariable; import java.util.ArrayList; /** * An XPathExecutable represents the compiled form of an XPath expression. * To evaluate the expression, it must first be loaded to form an {@link XPathSelector}. * *

    An XPathExecutable is immutable, and therefore thread-safe. It is simplest to load * a new XPathSelector each time the expression is to be evaluated. However, the XPathSelector * is serially reusable within a single thread.

    * *

    An XPathExecutable is created by using the {@link XPathCompiler#compile} method * on the {@link XPathCompiler} class.

    */ public class XPathExecutable { private XPathExpression exp; private Processor processor; private IndependentContext env; private ArrayList declaredVariables; // protected constructor protected XPathExecutable(XPathExpression exp, Processor processor, IndependentContext env, ArrayList declaredVariables) { this.exp = exp; this.processor = processor; this.env = env; this.declaredVariables = declaredVariables; } /** * Load the compiled XPath expression to prepare it for execution. * @return An XPathSelector. The returned XPathSelector can be used to set up the * dynamic context, and then to evaluate the expression. */ public XPathSelector load() { return new XPathSelector(exp, declaredVariables); } /** * Get the ItemType of the items in the result of the expression, as determined by static analysis. This * is the most precise ItemType that the processor is able to determine from static examination of the * expression; the actual items in the expression result are guaranteed to belong to this ItemType or to a subtype * of this ItemType. * @return the statically-determined ItemType of the result of the expression * @since 9.1 */ public ItemType getResultItemType() { net.sf.saxon.type.ItemType it = exp.getInternalExpression().getItemType(processor.getUnderlyingConfiguration().getTypeHierarchy()); return new ItemType(it, processor); } /** * Get the statically-determined cardinality of the result of the expression. This is the most precise cardinality * that the processor is able to determine from static examination of the expression. * @return the statically-determined cardinality of the result of the expression * @since 9.1 */ public OccurrenceIndicator getResultCardinality() { int card = exp.getInternalExpression().getCardinality(); return OccurrenceIndicator.getOccurrenceIndicator(card); } /** * Get the underlying implementation object representing the compiled XPath expression. * This method provides access to lower-level Saxon classes and methods which may be subject to change * from one release to the next. * @return the underlying compiled XPath expression. */ public XPathExpression getUnderlyingExpression() { return exp; } /** * Get the underlying implementation object representing the static context of the compiled * XPath expression. This method provides access to lower-level Saxon classes and methods which may be * subject to change from one release to the next. * @return the underlying static context. */ public StaticContext getUnderlyingStaticContext() { return env; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/s9api/XPathCompiler.java0000644000175000017500000002707211033112257022016 0ustar eugeneeugenepackage net.sf.saxon.s9api; import net.sf.saxon.expr.StaticContext; import net.sf.saxon.sxpath.IndependentContext; import net.sf.saxon.sxpath.XPathEvaluator; import net.sf.saxon.sxpath.XPathExpression; import net.sf.saxon.sxpath.XPathVariable; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.SequenceType; import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; /** * An XPathCompiler object allows XPath queries to be compiled. The compiler holds information that * represents the static context for an XPath expression. * *

    To construct an XPathCompiler, use the factory method * {@link Processor#newXPathCompiler}.

    * *

    An XPathCompiler may be used repeatedly to compile multiple * queries. Any changes made to the XPathCompiler (that is, to the * static context) do not affect queries that have already been compiled. * An XPathCompiler may be used concurrently in multiple threads, but * it should not then be modified once initialized.

    * *

    Changes to an XPathCompiler are cumulative. There is no simple way to reset * the XPathCompiler to its initial state; instead, simply create a new * XPathCompiler.

    * * @since 9.0 */ public class XPathCompiler { private Processor processor; private IndependentContext env; private ArrayList declaredVariables = new ArrayList(); /** * Protected constructor * @param processor the s9api Processor */ protected XPathCompiler(Processor processor) { this.processor = processor; env = new IndependentContext(processor.getUnderlyingConfiguration()); } /** * Set whether XPath 1.0 backwards compatibility mode is to be used. In backwards compatibility * mode, more implicit type conversions are allowed in XPath expressions, for example it * is possible to compare a number with a string. The default is false (backwards compatibility * mode is off). * * @param option true if XPath 1.0 backwards compatibility is to be enabled, false if it is to * be disabled. */ public void setBackwardsCompatible(boolean option) { env.setBackwardsCompatibilityMode(option); } /** * Ask whether XPath 1.0 backwards compatibility mode is in force. * * @return true if XPath 1.0 backwards compatibility is enabled, false if it is disabled. */ public boolean isBackwardsCompatible() { return env.isInBackwardsCompatibleMode(); } /** * Set the static base URI for XPath expressions compiled using this XPathCompiler. The base URI * is part of the static context, and is used to resolve any relative URIs appearing within an XPath * expression, for example a relative URI passed as an argument to the doc() function. If no * static base URI is supplied, then the current working directory is used. * * @param uri the base URI to be set in the static context. This must be an absolute URI. */ public void setBaseURI(URI uri) { if (!uri.isAbsolute()) { throw new IllegalArgumentException("Supplied base URI must be absolute"); } env.setBaseURI(uri.toString()); } /** * Get the static base URI for XPath expressions compiled using this XPathCompiler. The base URI * is part of the static context, and is used to resolve any relative URIs appearing within an XPath * expression, for example a relative URI passed as an argument to the doc() function. If no * static base URI has been explicitly set, this method returns null. * * @return the base URI from the static context */ public URI getBaseURI() { try { return new URI(env.getBaseURI()); } catch (URISyntaxException err) { throw new IllegalStateException(err); } } /** * Declare a namespace binding as part of the static context for XPath expressions compiled using this * XPathCompiler * * @param prefix The namespace prefix. If the value is a zero-length string, this method sets the default * namespace for elements and types. * @param uri The namespace URI. It is possible to specify a zero-length string to "undeclare" a namespace; * in this case the prefix will not be available for use, except in the case where the prefix * is also a zero length string, in which case the absence of a prefix implies that the name * is in no namespace. * @throws NullPointerException if either the prefix or uri is null. */ public void declareNamespace(String prefix, String uri) { env.declareNamespace(prefix, uri); } /** * Import a schema namespace: that is, add the element and attribute declarations and type definitions * contained in a given namespace to the static context for the XPath expression. * *

    This method will not cause the schema to be loaded. That must be done separately, using the * {@link SchemaManager}. This method will not fail if the schema has not been loaded (but in that case * the set of declarations and definitions made available to the XPath expression is empty). The schema * document for the specified namespace may be loaded before or after this method is called.

    * *

    This method does not bind a prefix to the namespace. That must be done separately, using the * {@link #declareNamespace(String, String)} method.

    * * @param uri The schema namespace to be imported. To import declarations in a no-namespace schema, * supply a zero-length string. * @since 9.1 */ public void importSchemaNamespace(String uri) { env.getImportedSchemaNamespaces().add(uri); } /** * Declare a variable as part of the static context for XPath expressions compiled using this * XPathCompiler. It is an error for the XPath expression to refer to a variable unless it has been * declared. This method declares the existence of the variable, but it does not * bind any value to the variable; that is done later, when the XPath expression is evaluated. * The variable is allowed to have any type (that is, the required type is item()*). * * @param qname The name of the variable, expressions as a QName */ public void declareVariable(QName qname) { XPathVariable var = env.declareVariable(qname.getNamespaceURI(), qname.getLocalName()); declaredVariables.add(var); } /** * Declare a variable as part of the static context for XPath expressions compiled using this * XPathCompiler. It is an error for the XPath expression to refer to a variable unless it has been * declared. This method declares the existence of the variable, and defines the required type * of the variable, but it does not bind any value to the variable; that is done later, * when the XPath expression is evaluated. * * @param qname The name of the variable, expressed as a QName * @param itemType The required item type of the value of the variable * @param occurrences The allowed number of items in the sequence forming the value of the variable * @throws SaxonApiException if the requiredType is syntactically invalid or if it refers to namespace * prefixes or schema components that are not present in the static context */ public void declareVariable(QName qname, ItemType itemType, OccurrenceIndicator occurrences) throws SaxonApiException { XPathVariable var = env.declareVariable(qname.getNamespaceURI(), qname.getLocalName()); var.setRequiredType( SequenceType.makeSequenceType( itemType.getUnderlyingItemType(), occurrences.getCardinality())); declaredVariables.add(var); } /** * Compile an XPath expression, supplied as a character string. * * @param source A string containing the source text of the XPath expression * @return An XPathExecutable which represents the compiled xpath expression object. * The XPathExecutable may be run as many times as required, in the same or a different thread. * The XPathExecutable is not affected by any changes made to the XPathCompiler once it has been compiled. * @throws SaxonApiException if any static error is detected while analyzing the expression */ public XPathExecutable compile(String source) throws SaxonApiException { try { XPathEvaluator eval = new XPathEvaluator(processor.getUnderlyingConfiguration()); eval.setStaticContext(env); XPathExpression cexp = eval.createExpression(source); return new XPathExecutable(cexp, processor, env, declaredVariables); } catch (XPathException e) { throw new SaxonApiException(e); } } /** * Compile an XSLT 2.0 pattern, supplied as a character string. The compiled pattern behaves as a boolean * expression which, when evaluated in a particular context, returns true if the context node matches * the pattern, and false if it does not. An error is reported if there is no context item or it the context * item is not a node. * @param source A string conforming to the syntax of XSLT 2.0 patterns * @return An XPathExecutable representing an expression which evaluates to true when the context node matches * the pattern, and false when it does not. * @throws SaxonApiException if the pattern contains static errors: for example, if its syntax is incorrect, * or if it refers to undeclared variables or namespaces * @since 9.1 */ public XPathExecutable compilePattern(String source) throws SaxonApiException { try { XPathEvaluator eval = new XPathEvaluator(processor.getUnderlyingConfiguration()); eval.setStaticContext(env); XPathExpression cexp = eval.createPattern(source); return new XPathExecutable(cexp, processor, env, declaredVariables); } catch (XPathException e) { throw new SaxonApiException(e); } } /** * Escape-hatch method to get the underlying static context object used by the implementation. * @return the underlying static context object. In the current implementation this will always * be an instance of {@link IndependentContext}. * *

    This method provides an escape hatch to internal Saxon implementation objects that offer a finer and * lower-level degree of control than the s9api classes and methods. Some of these classes and methods may change * from release to release.

    * @since 9.1 */ public StaticContext getUnderlyingStaticContext() { return env; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/s9api/XdmValue.java0000644000175000017500000001365111033112257021022 0ustar eugeneeugenepackage net.sf.saxon.s9api; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.om.SingletonIterator; import net.sf.saxon.om.ValueRepresentation; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.AtomicValue; import net.sf.saxon.value.EmptySequence; import net.sf.saxon.value.SequenceExtent; import net.sf.saxon.value.Value; import java.util.ArrayList; import java.util.List; /** * An value in the XDM data model. A value is a sequence of zero or more items, * each item being either an atomic value or a node. * *

    An XdmValue is immutable.

    * *

    A sequence consisting of a single item may be represented as an instance of {@link XdmItem}, * which is a subtype of XdmValue. However, there is no guarantee that a sequence of length one * will always be an instance of XdmItem.

    * *

    Similarly, a zero-length sequence may be represented as an instance of {@link XdmEmptySequence}, * but there is no guarantee that every sequence of length zero will always be an instance of * XdmEmptySequence.

    * * @since 9.0 */ public class XdmValue implements Iterable { private ValueRepresentation value; // this must be a materialized value protected XdmValue() { // must be followed by setValue() } /** * Create an XdmValue as a sequence of XdmItem objects * @param items a sequence of XdmItem objects. Note that if this is supplied as a list or similar * collection, subsequent changes to the list/collection will have no effect on the XdmValue. * @since 9.0.0.4 */ public XdmValue(Iterable items) { List values = new ArrayList(); for (XdmItem item : items) { values.add(item.getUnderlyingValue()); } value = new SequenceExtent(values); } protected XdmValue(ValueRepresentation value) { this.value = value; } protected void setValue(ValueRepresentation value) { this.value = value; } protected static XdmValue wrap(ValueRepresentation value) { if (value == null) { return null; } else if (value instanceof NodeInfo) { return new XdmNode((NodeInfo)value); } else if (value instanceof AtomicValue) { return new XdmAtomicValue((AtomicValue)value); } else if (value instanceof EmptySequence) { return XdmEmptySequence.getInstance(); } else { return new XdmValue(value); } } /** * Get the number of items in the sequence * @return the number of items in the value * @throws SaxonApiUncheckedException if the value is lazily evaluated and the delayed * evaluation fails with a dynamic error. */ public int size() { try { if (value instanceof Value) { return ((Value)value).getLength(); } else { return 1; } } catch (XPathException err) { throw new SaxonApiUncheckedException(err); } } /** * Get the n'th item in the value, counting from zero. * @param n the item that is required, counting the first item in the sequence as item zero * @return the n'th item in the sequence making up the value, counting from zero * @throws IndexOutOfBoundsException if n is less than zero or greater than or equal to the number * of items in the value * @throws SaxonApiUncheckedException if the value is lazily evaluated and the delayed * evaluation fails with a dynamic error. */ public XdmItem itemAt(int n) throws IndexOutOfBoundsException, SaxonApiUncheckedException { if (n < 0 || n >= size()) { throw new IndexOutOfBoundsException(""+n); } if (value instanceof Value) { try { return (XdmItem)XdmItem.wrap(((Value)value).itemAt(n)); } catch (XPathException e) { throw new SaxonApiUncheckedException(e); } } else { return (XdmNode)XdmNode.wrap((NodeInfo)value); } } /** * Returns an iterator over the items in this value. * @return an Iterator over the items in this value. * @throws SaxonApiUncheckedException if the value is lazily evaluated and the delayed * evaluation fails with a dynamic error. */ public XdmSequenceIterator iterator() throws SaxonApiUncheckedException { try { ValueRepresentation v = getUnderlyingValue(); if (v instanceof Value) { return new XdmSequenceIterator(((Value)v).iterate()); } else { return new XdmSequenceIterator(SingletonIterator.makeIterator((NodeInfo)v)); } } catch (XPathException e) { throw new SaxonApiUncheckedException(e); } } /** * Get the underlying implementation object representing the value. This method allows * access to lower-level Saxon functionality, including classes and methods that offer * no guarantee of stability across releases. * @return the underlying implementation object representing the value */ public ValueRepresentation getUnderlyingValue() { return value; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/s9api/OccurrenceIndicator.java0000644000175000017500000000557211033112257023225 0ustar eugeneeugenepackage net.sf.saxon.s9api; import net.sf.saxon.expr.StaticProperty; import net.sf.saxon.value.Cardinality; /** * Represents one of the possible occurrence indicators in a SequenceType. The four standard values are * ONE (no occurrence indicator), ZERO_OR_ONE (?), ZERO_OR_MORE (*), ONE_OR_MORE (+). In addition the * value ZERO is supported, this is used only in the type empty-sequence() which matches an empty sequence * and nothing else. */ public enum OccurrenceIndicator { ZERO, ZERO_OR_ONE, ZERO_OR_MORE, ONE, ONE_OR_MORE; protected int getCardinality() { switch(this) { case ZERO: return StaticProperty.EMPTY; case ZERO_OR_ONE: return StaticProperty.ALLOWS_ZERO_OR_ONE; case ZERO_OR_MORE: return StaticProperty.ALLOWS_ZERO_OR_MORE; case ONE: return StaticProperty.ALLOWS_ONE; case ONE_OR_MORE: return StaticProperty.ALLOWS_ONE_OR_MORE; default: return StaticProperty.EMPTY; } } protected static OccurrenceIndicator getOccurrenceIndicator(int cardinality) { switch (cardinality) { case StaticProperty.EMPTY: return ZERO; case StaticProperty.ALLOWS_ZERO_OR_ONE: return ZERO_OR_ONE; case StaticProperty.ALLOWS_ZERO_OR_MORE: return ZERO_OR_MORE; case StaticProperty.ALLOWS_ONE: return ONE; case StaticProperty.ALLOWS_ONE_OR_MORE: return ONE_OR_MORE; default: return ZERO_OR_MORE; } } /** * Determine whether one occurrence indicator subsumes another. Specifically, * A.subsumes(B) is true if every sequence that satisfies the occurrence * indicator B also satisfies the occurrence indicator A. * @param other The other occurrence indicator * @return true if this occurrence indicator subsumes the other occurrence indicator * @since 9.1 */ public boolean subsumes(OccurrenceIndicator other) { return Cardinality.subsumes(getCardinality(), other.getCardinality()); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/s9api/XdmEmptySequence.java0000644000175000017500000000366011033112257022534 0ustar eugeneeugenepackage net.sf.saxon.s9api; import net.sf.saxon.value.EmptySequence; /** * The class XdmEmptySequence represents an empty sequence in the XDM Data Model. * *

    This is a singleton class: there is only one instance, which may be obtained * using the {@link #getInstance} method.

    * *

    An empty sequence may also be represented by an {@link XdmValue} whose length happens to be zero. * Applications should therefore not test to see whether an object is an instance of this class * in order to decide whether it is empty.

    * *

    Note: in interfaces that expect an {@link XdmItem}, an empty sequence is represented by a * Java null value.

    */ public class XdmEmptySequence extends XdmValue { private static XdmEmptySequence THE_INSTANCE = new XdmEmptySequence(); /** * Return the singleton instance of this class * @return an XdmValue representing an empty sequence */ public static XdmEmptySequence getInstance() { return THE_INSTANCE; } private XdmEmptySequence() { super(EmptySequence.getInstance()); } /** * Get the number of items in the sequence * @return the number of items in the value - always zero */ @Override public int size() { return 0; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/s9api/QName.java0000644000175000017500000004531311033112257020276 0ustar eugeneeugenepackage net.sf.saxon.s9api; import net.sf.saxon.om.*; import net.sf.saxon.trans.XPathException; /** * The QName class represents an instance of xs:QName, as defined in the XPath 2.0 data model. * Internally, it has three components, a namespace URI, a local name, and a prefix. The prefix * is intended to be used only when converting the value back to a string. * *

    This class also defines a number of QName-valued constants relating to built-in types in * XML Schema

    * *

    A QName is immutable.

    * *

    Note that a QName is not itself an {@link XdmItem} in this model; however it can be wrapped in an * XdmItem.

    */ public class QName { private StructuredQName sqName; /** * Construct a QName using a namespace prefix, a namespace URI, and a local name (in that order). *

    This constructor does not check that the components of the QName are lexically valid.

    * * @param prefix The prefix of the name. Use either the string "" or null for names that have * no prefix (that is, they are in the default namespace) * @param uri The namespace URI. Use either the string "" or null for names that are not in any namespace. * @param localName The local part of the name */ public QName(String prefix, String uri, String localName) { sqName = new StructuredQName(prefix, uri, localName); } /** * Construct a QName using a namespace URI and a lexical representation. The lexical representation * may be a local name on its own, or it may be in the form prefix:local-name. *

    This constructor does not check that the components of the QName are lexically valid.

    * * @param uri The namespace URI. Use either the string "" or null for names that are not in any namespace. * @param lexical Either the local part of the name, or the prefix and local part in the format prefix:local */ public QName(String uri, String lexical) { uri = (uri == null ? "" : uri); int colon = lexical.indexOf(':'); if (colon < 0) { sqName = new StructuredQName("", uri, lexical); } else { String prefix = lexical.substring(0, colon); String local = lexical.substring(colon + 1); sqName = new StructuredQName(prefix, uri, local); } } /** * Construct a QName from a localName alone. The localName must not contain a colon. * The resulting QName represents a name in no namespace (which therefore has no prefix)

    * * @param localName The local name. This must be a valid NCName, in particular it must contain no colon */ public QName(String localName) { int colon = localName.indexOf(':'); if (colon < 0) { sqName = new StructuredQName("", "", localName); } else { throw new IllegalArgumentException("Local name contains a colon"); } } /** * Construct a QName from a lexical QName, supplying an element node whose * in-scope namespaces are to be used to resolve any prefix contained in the QName. * *

    This constructor checks that the components of the QName are * lexically valid.

    *

    If the lexical QName has no prefix, the name is considered to be in the * default namespace, as defined by xmlns="...".

    *

    If the prefix of the lexical QName is not in scope, returns null.

    * * @param lexicalQName The lexical QName, in the form prefix:local * or simply local. * @param element The element node whose in-scope namespaces are to be used * to resolve the prefix part of the lexical QName. * @throws IllegalArgumentException If the prefix of the lexical QName is not in scope * or if the lexical QName is invalid (for example, if it contains invalid characters) */ public QName(String lexicalQName, XdmNode element) { try { NodeInfo node = (NodeInfo) element.getUnderlyingValue(); sqName = StructuredQName.fromLexicalQName(lexicalQName, true, node.getConfiguration().getNameChecker(), new InscopeNamespaceResolver(node)); } catch (XPathException err) { throw new IllegalArgumentException(err); } } /** * Construct a QName from a JAXP QName object * * @param qName the JAXP QName object */ public QName(javax.xml.namespace.QName qName) { sqName = new StructuredQName(qName.getPrefix(), qName.getNamespaceURI(), qName.getLocalPart()); } /** * Protected constructor accepting a StructuredQName * @param sqName the StructuredQName */ protected QName(StructuredQName sqName) { this.sqName = sqName; } /** * Factory method to construct a QName from a string containing the expanded * QName in Clark notation, that is, {uri}local *

    * The prefix part of the QName will be set to an empty string. *

    * * @param expandedName The URI in Clark notation: {uri}local if the * name is in a namespace, or simply local if not. * @return the QName corresponding to the supplied name in Clark notation. This will always * have an empty prefix. */ public static QName fromClarkName(String expandedName) { String namespaceURI; String localName; if (expandedName.charAt(0) == '{') { int closeBrace = expandedName.indexOf('}'); if (closeBrace < 0) { throw new IllegalArgumentException("No closing '}' in Clark name"); } namespaceURI = expandedName.substring(1, closeBrace - 1); if (closeBrace == expandedName.length()) { throw new IllegalArgumentException("Missing local part in Clark name"); } localName = expandedName.substring(closeBrace + 1); } else { namespaceURI = ""; localName = expandedName; } return new QName("", namespaceURI, localName); } /** * Validate the QName against the XML 1.0 or XML 1.1 rules for valid names. * * @param processor The Processor in which the name is to be validated. * This determines whether the XML 1.0 or XML 1.1 rules for forming names are used. * @return true if the name is valid, false if not */ public boolean isValid(Processor processor) { NameChecker nc = processor.getUnderlyingConfiguration().getNameChecker(); String prefix = getPrefix(); if (prefix.length() > 0) { if (!nc.isValidNCName(prefix)) { return false; } } return nc.isValidNCName(getLocalName()); } /** * Get the prefix of the QName. This plays no role in operations such as comparison * of QNames for equality, but is retained (as specified in XPath) so that a string representation * can be reconstructed. *

    * Returns the zero-length string in the case of a QName that has no prefix. *

    * @return the prefix part of the QName, or "" if the name has no known prefix */ public String getPrefix() { return sqName.getPrefix(); } /** * The namespace URI of the QName. Returns "" (the zero-length string) if the * QName is not in a namespace. * @return the namespace part of the QName, or "" for a name in no namespace */ public String getNamespaceURI() { return sqName.getNamespaceURI(); } /** * The local part of the QName * @return the local part of the QName */ public String getLocalName() { return sqName.getLocalName(); } /** * The expanded name, as a string using the notation devised by James Clark. * If the name is in a namespace, the resulting string takes the form {uri}local. * Otherwise, the value is the local part of the name. * @return the name in Clark notation. If the name is not in a namespace, returns the * local part of the name. Otherwise returns the concatenation of "{", the namespace part * of the QName, "}", and the local part of the QName. */ public String getClarkName() { String uri = getNamespaceURI(); if (uri.length() == 0) { return getLocalName(); } else { return "{" + uri + "}" + getLocalName(); } } /** * Convert the value to a string. The resulting string is the lexical form of the QName, * using the original prefix if there was one. */ public String toString() { return sqName.getDisplayName(); } /** * Get a hash code for the QName, to support equality matching. This supports the * semantics of equality, which considers only the namespace URI and local name, and * not the prefix. * @return a hashCode for the QName */ public int hashCode() { return sqName.hashCode(); } /** * Test whether two QNames are equal. This supports the * semantics of equality, which considers only the namespace URI and local name, and * not the prefix. * @return true if the namespace URIs are equal and the local parts are equal, when * compared character-by-character. */ public boolean equals(Object other) { return other instanceof QName && sqName.equals(((QName)other).sqName); } /** * Get the underlying StructuredQName * @return the underlying StructuredQName */ protected StructuredQName getStructuredQName() { return sqName; } /** QName denoting the schema type xs:string **/ public static final QName XS_STRING = new QName("xs", NamespaceConstant.SCHEMA, "string"); /** QName denoting the schema type xs:boolean **/ public static final QName XS_BOOLEAN = new QName("xs", NamespaceConstant.SCHEMA, "boolean"); /** QName denoting the schema type xs:decimal **/ public static final QName XS_DECIMAL = new QName("xs", NamespaceConstant.SCHEMA, "decimal"); /** QName denoting the schema type xs:float **/ public static final QName XS_FLOAT = new QName("xs", NamespaceConstant.SCHEMA, "float"); /** QName denoting the schema type xs:double **/ public static final QName XS_DOUBLE = new QName("xs", NamespaceConstant.SCHEMA, "double"); /** QName denoting the schema type xs:duration **/ public static final QName XS_DURATION = new QName("xs", NamespaceConstant.SCHEMA, "duration"); /** QName denoting the schema type xs:dateTime **/ public static final QName XS_DATE_TIME = new QName("xs", NamespaceConstant.SCHEMA, "dateTime"); /** QName denoting the schema type xs:time **/ public static final QName XS_TIME = new QName("xs", NamespaceConstant.SCHEMA, "time"); /** QName denoting the schema type xs:date **/ public static final QName XS_DATE = new QName("xs", NamespaceConstant.SCHEMA, "date"); /** QName denoting the schema type xs:gYearMonth **/ public static final QName XS_G_YEAR_MONTH = new QName("xs", NamespaceConstant.SCHEMA, "gYearMonth"); /** QName denoting the schema type xs:gYear **/ public static final QName XS_G_YEAR = new QName("xs", NamespaceConstant.SCHEMA, "gYear"); /** QName denoting the schema type xs:gMonthDay **/ public static final QName XS_G_MONTH_DAY = new QName("xs", NamespaceConstant.SCHEMA, "gMonthDay"); /** QName denoting the schema type xs:gDay **/ public static final QName XS_G_DAY = new QName("xs", NamespaceConstant.SCHEMA, "gDay"); /** QName denoting the schema type xs:gMonth **/ public static final QName XS_G_MONTH = new QName("xs", NamespaceConstant.SCHEMA, "gMonth"); /** QName denoting the schema type xs:hexBinary **/ public static final QName XS_HEX_BINARY = new QName("xs", NamespaceConstant.SCHEMA, "hexBinary"); /** QName denoting the schema type xs:base64Binary **/ public static final QName XS_BASE64_BINARY = new QName("xs", NamespaceConstant.SCHEMA, "base64Binary"); /** QName denoting the schema type xs:anyURI **/ public static final QName XS_ANY_URI = new QName("xs", NamespaceConstant.SCHEMA, "anyURI"); /** QName denoting the schema type xs:QName **/ public static final QName XS_QNAME = new QName("xs", NamespaceConstant.SCHEMA, "QName"); /** QName denoting the schema type xs:NOTATION **/ public static final QName XS_NOTATION = new QName("xs", NamespaceConstant.SCHEMA, "NOTATION"); /** QName denoting the schema type xs:integer **/ public static final QName XS_INTEGER = new QName("xs", NamespaceConstant.SCHEMA, "integer"); /** QName denoting the schema type xs:nonPositiveInteger **/ public static final QName XS_NON_POSITIVE_INTEGER = new QName("xs", NamespaceConstant.SCHEMA, "nonPositiveInteger"); /** QName denoting the schema type xs:negativeInteger **/ public static final QName XS_NEGATIVE_INTEGER = new QName("xs", NamespaceConstant.SCHEMA, "negativeInteger"); /** QName denoting the schema type xs:long **/ public static final QName XS_LONG = new QName("xs", NamespaceConstant.SCHEMA, "long"); /** QName denoting the schema type xs:int **/ public static final QName XS_INT = new QName("xs", NamespaceConstant.SCHEMA, "int"); /** QName denoting the schema type xs:short **/ public static final QName XS_SHORT = new QName("xs", NamespaceConstant.SCHEMA, "short"); /** QName denoting the schema type xs:byte **/ public static final QName XS_BYTE = new QName("xs", NamespaceConstant.SCHEMA, "byte"); /** QName denoting the schema type xs:nonNegativeInteger **/ public static final QName XS_NON_NEGATIVE_INTEGER = new QName("xs", NamespaceConstant.SCHEMA, "nonNegativeInteger"); /** QName denoting the schema type xs:positiveInteger **/ public static final QName XS_POSITIVE_INTEGER = new QName("xs", NamespaceConstant.SCHEMA, "positiveInteger"); /** QName denoting the schema type xs:unsignedLong **/ public static final QName XS_UNSIGNED_LONG = new QName("xs", NamespaceConstant.SCHEMA, "unsignedLong"); /** QName denoting the schema type xs:unsignedInt **/ public static final QName XS_UNSIGNED_INT = new QName("xs", NamespaceConstant.SCHEMA, "unsignedInt"); /** QName denoting the schema type xs:unsignedShort **/ public static final QName XS_UNSIGNED_SHORT = new QName("xs", NamespaceConstant.SCHEMA, "unsignedShort"); /** QName denoting the schema type xs:unsignedByte **/ public static final QName XS_UNSIGNED_BYTE = new QName("xs", NamespaceConstant.SCHEMA, "unsignedByte"); /** QName denoting the schema type xs:normalizedString **/ public static final QName XS_NORMALIZED_STRING = new QName("xs", NamespaceConstant.SCHEMA, "normalizedString"); /** QName denoting the schema type xs:token **/ public static final QName XS_TOKEN = new QName("xs", NamespaceConstant.SCHEMA, "token"); /** QName denoting the schema type xs:language **/ public static final QName XS_LANGUAGE = new QName("xs", NamespaceConstant.SCHEMA, "language"); /** QName denoting the schema type xs:NMTOKEN **/ public static final QName XS_NMTOKEN = new QName("xs", NamespaceConstant.SCHEMA, "NMTOKEN"); /** QName denoting the schema type xs:NMTOKENS **/ public static final QName XS_NMTOKENS = new QName("xs", NamespaceConstant.SCHEMA, "NMTOKENS"); /** QName denoting the schema type xs:Name **/ public static final QName XS_NAME = new QName("xs", NamespaceConstant.SCHEMA, "Name"); /** QName denoting the schema type xs:NCName **/ public static final QName XS_NCNAME = new QName("xs", NamespaceConstant.SCHEMA, "NCName"); /** QName denoting the schema type xs:ID **/ public static final QName XS_ID = new QName("xs", NamespaceConstant.SCHEMA, "ID"); /** QName denoting the schema type xs:IDREF **/ public static final QName XS_IDREF = new QName("xs", NamespaceConstant.SCHEMA, "IDREF"); /** QName denoting the schema type xs:IDREFS **/ public static final QName XS_IDREFS = new QName("xs", NamespaceConstant.SCHEMA, "IDREFS"); /** QName denoting the schema type xs:ENTITY **/ public static final QName XS_ENTITY = new QName("xs", NamespaceConstant.SCHEMA, "ENTITY"); /** QName denoting the schema type xs:ENTITIES **/ public static final QName XS_ENTITIES = new QName("xs", NamespaceConstant.SCHEMA, "ENTITIES"); /** QName denoting the schema type xs:untyped **/ public static final QName XS_UNTYPED = new QName("xs", NamespaceConstant.SCHEMA, "untyped"); /** QName denoting the schema type xs:untypedAtomic **/ public static final QName XS_UNTYPED_ATOMIC = new QName("xs", NamespaceConstant.SCHEMA, "untypedAtomic"); /** QName denoting the schema type xs:anyAtomicType **/ public static final QName XS_ANY_ATOMIC_TYPE = new QName("xs", NamespaceConstant.SCHEMA, "anyAtomicType"); /** QName denoting the schema type xs:yearMonthDuration **/ public static final QName XS_YEAR_MONTH_DURATION = new QName("xs", NamespaceConstant.SCHEMA, "yearMonthDuration"); /** QName denoting the schema type xs:dayTimeDuration **/ public static final QName XS_DAY_TIME_DURATION = new QName("xs", NamespaceConstant.SCHEMA, "dayTimeDuration"); } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/s9api/Serializer.java0000644000175000017500000004170011107267241021410 0ustar eugeneeugenepackage net.sf.saxon.s9api; import net.sf.saxon.Configuration; import net.sf.saxon.Controller; import net.sf.saxon.event.PipelineConfiguration; import net.sf.saxon.event.Receiver; import net.sf.saxon.event.SaxonOutputKeys; import net.sf.saxon.event.SerializerFactory; import net.sf.saxon.om.Name11Checker; import net.sf.saxon.trans.XPathException; import javax.xml.transform.OutputKeys; import javax.xml.transform.stream.StreamResult; import java.io.File; import java.io.OutputStream; import java.io.Writer; import java.net.URI; import java.net.URISyntaxException; import java.util.Enumeration; import java.util.HashMap; import java.util.Map; import java.util.Properties; /** * A Serializer takes a tree representation of XML and turns it into lexical XML markup. * *

    Note that this is XML serialization in the sense of the W3C XSLT and XQuery specifications. * This has nothing to do with the serialization of Java objects, or the {@link java.io.Serializable} * interface.

    * *

    The serialization may be influenced by a number of serialization parameters. A parameter has a name, * which is an instance of {@link Serializer.Property}, and a value, which is expressed as a string. * The effect of most of the properties is as described in the W3C specification * XSLT 2.0 and XQuery 1.0 Serialization. * Saxon supports all the serialization parameters defined in that specification, together with some * additional parameters, whose property names are prefixed "SAXON_". */ @SuppressWarnings({"ForeachStatement"}) public class Serializer implements Destination { private Map properties = new HashMap(10); private StreamResult result = new StreamResult(); public enum Property { /** * Serialization method: xml, html, xhtml, or text */ METHOD (OutputKeys.METHOD), /** * Version of output method, for example "1.0" or "1.1" for XML */ VERSION (OutputKeys.VERSION), /** * Character encoding of output stream */ ENCODING (OutputKeys.ENCODING), /** * Set to "yes" if the XML declaration is to be omitted from the output file */ OMIT_XML_DECLARATION (OutputKeys.OMIT_XML_DECLARATION), /** * Set to "yes", "no", or "omit" to indicate the required value of the standalone attribute * in the XML declaration of the output file */ STANDALONE (OutputKeys.STANDALONE), /** * Set to any string to indicate that the output is to include a DOCTYPE declaration with this public id */ DOCTYPE_PUBLIC (OutputKeys.DOCTYPE_PUBLIC), /** * Set to any string to indicate that the output is to include a DOCTYPE declaration with this system id */ DOCTYPE_SYSTEM (OutputKeys.DOCTYPE_SYSTEM), /** * Space-separated list of QNames (in Clark form) of elements * whose content is to be wrapped in CDATA sections */ CDATA_SECTION_ELEMENTS (OutputKeys.CDATA_SECTION_ELEMENTS), /** * Set to "yes" or "no" to indicate whether indentation is required */ INDENT (OutputKeys.INDENT), /** * Set to indicate the media type (MIME type) of the output */ MEDIA_TYPE (OutputKeys.MEDIA_TYPE), /** * List of names of character maps to be used. Character maps can only be specified in an XSLT * stylesheet. */ USE_CHARACTER_MAPS (SaxonOutputKeys.USE_CHARACTER_MAPS), /** * For HTML and XHTML, set to "yes" or "no" to indicate whether a <meta> element is to be * written to indicate the content type and encoding */ INCLUDE_CONTENT_TYPE (SaxonOutputKeys.INCLUDE_CONTENT_TYPE), /** * Set to "yes" or "no" to indicate (for XML 1.1) whether namespace that go out of scope should * be undeclared */ UNDECLARE_PREFIXES (SaxonOutputKeys.UNDECLARE_PREFIXES), /** * Set to "yes" or "no" to indicate (for HTML and XHTML) whether URI-valued attributes should be * percent-encoded */ ESCAPE_URI_ATTRIBUTES (SaxonOutputKeys.ESCAPE_URI_ATTRIBUTES), /** * Set to "yes" or "no" to indicate whether a byte order mark is to be written */ BYTE_ORDER_MARK (SaxonOutputKeys.BYTE_ORDER_MARK), /** * Set to the name of a Unicode normalization form: "NFC", "NFD", "NFKC", or "NFKD", or * "none" to indicate no normalization */ NORMALIZATION_FORM (SaxonOutputKeys.NORMALIZATION_FORM), /** * Saxon extension: set to an integer (represented as a string) giving the number of spaces * by which each level of nesting should be indented. Default is 3. */ SAXON_INDENT_SPACES (SaxonOutputKeys.INDENT_SPACES), /** * Saxon extension: set to a space-separated list of element names, in Clark notation, * within which no content is to be indented. This is typically because the element contains * mixed content in which whitespace is significant. */ SAXON_SUPPRESS_INDENTATION (SaxonOutputKeys.SUPPRESS_INDENTATION), /** * Saxon extension: set to a space-separated list of element names, in Clark notation, * representing elements that will be preceded by an extra blank line in the output in addition * to normal indentation. */ SAXON_DOUBLE_SPACE (SaxonOutputKeys.DOUBLE_SPACE), /** * Saxon extension for internal use: used in XSLT to tell the serializer whether the * stylesheet used version="1.0" or version="2.0" */ SAXON_STYLESHEET_VERSION (SaxonOutputKeys.STYLESHEET_VERSION), /** * Saxon extension to indicate how characters outside the encoding should be represented, * for example "hex" for hexadecimal character references, "decimal" for decimal character references */ SAXON_CHARACTER_REPRESENTATION (SaxonOutputKeys.CHARACTER_REPRESENTATION), /** * Saxon extension to indicate that output should not be serialized, but should be further transformed. * The property gives the relative URI of a stylesheet to be applied. Note that the {@link Serializer} * class does not recognize this property. */ SAXON_NEXT_IN_CHAIN (SaxonOutputKeys.NEXT_IN_CHAIN), /** * Saxon extension, indicate the base URI against which {@link Property#SAXON_NEXT_IN_CHAIN} should be * resolved. */ SAXON_NEXT_IN_CHAIN_BASE_URI (SaxonOutputKeys.NEXT_IN_CHAIN_BASE_URI), /** * Saxon extension for use when output is sent to a SAX ContentHandler: indicates that the output * is required to be well-formed (exactly one top-level element) */ SAXON_REQUIRE_WELL_FORMED (SaxonOutputKeys.REQUIRE_WELL_FORMED), /** * Saxon extension, indicates that the output of a query is to be wrapped before serialization, * such that each item in the result sequence is enclosed in an element indicating its type */ SAXON_WRAP (SaxonOutputKeys.WRAP), /** * Saxon extension for internal use in XSLT, indicates that this output document is the implicitly * created result tree as distinct from a tree created using <xsl:result-document> */ SAXON_IMPLICIT_RESULT_DOCUMENT (SaxonOutputKeys.IMPLICIT_RESULT_DOCUMENT), /** * Saxon extension for interfacing with debuggers; indicates that the location information is * available for events in this output stream */ SAXON_SUPPLY_SOURCE_LOCATOR (SaxonOutputKeys.SUPPLY_SOURCE_LOCATOR); private String name; private Property(String name) { this.name = name; } /** * Get the name of the property expressed as a QName in Clark notation. * The namespace will be null for standard serialization properties, * and will be the Saxon namespace http://saxon.sf.net/ for Saxon extensions * @return the name of the serialization property as a QName in Clark notation, {uri}local */ public String toString() { return name; } } /** * Set the value of a serialization property. Any existing value of the property is overridden. * If the supplied value is null, any existing value of the property is removed. * *

    Example:

    *

    serializer.setOutputProperty(Serializer.Property.METHOD, "xml");

    * *

    Any serialization properties supplied via this interface take precedence over serialization * properties defined in the source stylesheet or query.

    * * @param property The name of the property to be set * @param value The value of the property, as a string. The format is generally as defined * in the xsl:output declaration in XSLT: this means that boolean properties, for * example, are represented using the strings "yes" and "no". Properties whose values are QNames, * such as cdata-section-elements are expressed using the Clark representation of * a QName, that is "{uri}local". Multi-valued properties (again, cdata-section-elements * is an example) are expressed as a space-separated list. * @throws IllegalArgumentException if the value of the property is invalid. The property is * validated individually; invalid combinations of properties will be detected only when the properties * are actually used to serialize an XML event stream. */ public void setOutputProperty(Property property, String value) { try { SaxonOutputKeys.checkOutputProperty(property.toString(), value, Name11Checker.getInstance()); } catch (XPathException e) { throw new IllegalArgumentException(e.getMessage()); } if (value == null) { properties.remove(property); } else { properties.put(property, value); } } /** * Get the value of a serialization property * @param property the name of the required property * @return the value of the required property as a string, or null if the property has * not been given any value. */ public String getOutputProperty(Property property) { return properties.get(property); } /** * Set the destination of the serialized output, as a Writer. * *

    Note that when this option is used, the serializer does not perform character * encoding. This also means that it never replaces special characters with XML numeric * character references. The final encoding is the responsibility of the supplied Writer.

    * *

    Closing the writer after use is the responsibility of the caller.

    * *

    Calling this method has the side-effect of setting the OutputStream and OutputFile to null.

    * * @param writer the Writer to which the serialized XML output will be written. */ public void setOutputWriter(Writer writer) { result.setOutputStream(null); result.setSystemId((String)null); result.setWriter(writer); } /** * Set the destination of the serialized output, as an OutputStream. * *

    Closing the output stream after use is the responsibility of the caller.

    * *

    Calling this method has the side-effect of setting the OutputWriter and OutputFile to null.

    * * @param stream the OutputStream to which the serialized XML output will be written. */ public void setOutputStream(OutputStream stream) { result.setWriter(null); result.setSystemId((String)null); result.setOutputStream(stream); } /** * Set the destination of the serialized output, as a File. * *

    Calling this method has the side-effect of setting the current OutputWriter * and OutputStream to null.

    * @param file the File to which the serialized XML output will be written. */ public void setOutputFile(File file) { result.setOutputStream(null); result.setWriter(null); result.setSystemId(file); } /** * Get the current output destination. * * @return an OutputStream, Writer, or File, depending on the previous calls to * {@link #setOutputStream}, {@link #setOutputWriter}, or {@link #setOutputFile} */ public Object getOutputDestination() { if (result.getOutputStream() != null) { return result.getOutputStream(); } if (result.getWriter() != null) { return result.getWriter(); } String systemId = result.getSystemId(); if (systemId != null) { try { return new File(new URI(systemId)); } catch (URISyntaxException e) { return null; } } else { return null; } } /** * Return a receiver to which Saxon will send events. This method is provided * primarily for system use, though it could also be called by user applications * wanting to make use of the Saxon serializer. * @param config The Saxon configuration. This is an internal implementation object * held within the {@link Processor} * @return a receiver to which XML events will be sent */ public Receiver getReceiver(Configuration config) throws SaxonApiException { return getReceiver(config, null, null); } /** * Return a receiver to which Saxon will send events. This method is provided * primarily for system use, though it could also be called by user applications * wanting to make use of the Saxon serializer. * @param config The Saxon configuration. * @param controller The Saxon controller (of the transformation). May be null. * @param predefinedProperties values of serialization properties defined within a query or stylesheet, * which will be used in the event that no value for the corresponding property has been defined in * the Serializer itself. May be null if no serialization properties have been predefined. * @return a receiver to which XML events will be sent */ protected Receiver getReceiver(Configuration config, Controller controller, Properties predefinedProperties) throws SaxonApiException { try { SerializerFactory sf = config.getSerializerFactory(); PipelineConfiguration pipe = (controller==null ? config.makePipelineConfiguration() : controller.makePipelineConfiguration()); Properties props = new Properties(); for (Property p : properties.keySet()) { String value = properties.get(p); props.setProperty(p.toString(), value); } if (predefinedProperties != null) { Enumeration eps = predefinedProperties.propertyNames(); while (eps.hasMoreElements()) { String name = (String)eps.nextElement(); String value = predefinedProperties.getProperty(name); if (props.getProperty(name) == null) { props.setProperty(name, value); } else if (name.equals(OutputKeys.CDATA_SECTION_ELEMENTS) || name.equals(SaxonOutputKeys.SUPPRESS_INDENTATION)) { props.setProperty(name, props.getProperty(name) + " " + value); } } } return sf.getReceiver(result, pipe, props); } catch (XPathException e) { throw new SaxonApiException(e); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/s9api/XPathSelector.java0000644000175000017500000002110111033112257022007 0ustar eugeneeugenepackage net.sf.saxon.s9api; import net.sf.saxon.om.Item; import net.sf.saxon.om.ValueRepresentation; import net.sf.saxon.om.StructuredQName; import net.sf.saxon.sxpath.XPathDynamicContext; import net.sf.saxon.sxpath.XPathExpression; import net.sf.saxon.sxpath.XPathVariable; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.SequenceExtent; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /** * An XPathSelector represents a compiled and loaded XPath expression ready for execution. * The XPathSelector holds details of the dynamic evaluation context for the XPath expression. */ @SuppressWarnings({"ForeachStatement"}) public class XPathSelector implements Iterable { private XPathExpression exp; private XPathDynamicContext dynamicContext; private List declaredVariables; // protected constructor protected XPathSelector(XPathExpression exp, ArrayList declaredVariables) { this.exp = exp; this.declaredVariables = declaredVariables; dynamicContext = exp.createDynamicContext(null); } /** * Set the context item for evaluating the XPath expression. * This may be either a node or an atomic value. Most commonly it will be a document node, * which might be constructed using the {@link DocumentBuilder#build} method. * * @param item The context item for evaluating the expression. Must not be null. */ public void setContextItem(XdmItem item) throws SaxonApiException { try { dynamicContext.setContextItem((Item)item.getUnderlyingValue()); } catch (XPathException e) { throw new SaxonApiException(e); } } /** * Get the context item used for evaluating the XPath expression. * This may be either a node or an atomic value. Most commonly it will be a document node, * which might be constructed using the Build method of the DocumentBuilder object. * * @return The context item for evaluating the expression, or null if no context item * has been set. */ public XdmItem getContextItem() { return XdmItem.wrapItem(dynamicContext.getContextItem()); } /** * Set the value of a variable * * @param name The name of the variable. This must match the name of a variable * that was declared to the XPathCompiler. No error occurs if the expression does not * actually reference a variable with this name. * @param value The value to be given to the variable. * @throws SaxonApiException if the variable has not been declared or if the type of the value * supplied does not conform to the required type that was specified when the variable was declared */ public void setVariable(QName name, XdmValue value) throws SaxonApiException { XPathVariable var = null; StructuredQName qn = name.getStructuredQName(); for (XPathVariable v : declaredVariables) { if (v.getVariableQName().equals(qn)) { var = v; break; } } if (var == null) { throw new SaxonApiException( new XPathException("Variable has not been declared: " + name)); } try { dynamicContext.setVariable(var, value.getUnderlyingValue()); } catch (XPathException e) { throw new SaxonApiException(e); } } /** * Evaluate the expression, returning the result as an XdmValue (that is, * a sequence of nodes and/or atomic values). * *

    Note: Although a singleton result may be represented as an XdmItem, there is * no guarantee that this will always be the case. If you know that the expression will return at * most one node or atomic value, it is best to use the evaluateSingle method, which * does guarantee that an XdmItem (or null) will be returned.

    * * @return An XdmValue representing the results of the expression. * @throws SaxonApiException if a dynamic error occurs during the expression evaluation. */ public XdmValue evaluate() throws SaxonApiException { ValueRepresentation value; try { value = SequenceExtent.makeSequenceExtent(exp.iterate(dynamicContext)); } catch (XPathException e) { throw new SaxonApiException(e); } return XdmValue.wrap(value); } /** * Evaluate the XPath expression, returning the result as an XdmItem (that is, * a single node or atomic value). * * @return an XdmItem representing the result of the expression, or null if the expression * returns an empty sequence. If the expression returns a sequence of more than one item, * any items after the first are ignored. * @throws SaxonApiException if a dynamic error occurs during the expression evaluation. */ public XdmItem evaluateSingle() throws SaxonApiException { try { Item i = exp.evaluateSingle(dynamicContext); if (i == null) { return null; } return (XdmItem) XdmValue.wrap(i); } catch (XPathException e) { throw new SaxonApiException(e); } } /** * Evaluate the expression, returning the result as an Iterator (that is, * an iterator over a sequence of nodes and/or atomic values). * *

    Because an XPathSelector is an {@link Iterable}, it is possible to * iterate over the result using a Java 5 "for each" expression, for example:

    * *

         * XPathCompiler compiler = processor.newXPathCompiler();
         * XPathSelector seq = compiler.compile("1 to 20").load();
         * for (XdmItem item : seq) {
         *   System.err.println(item);
         * }
         * 

    * * @return An iterator over the sequence that represents the results of the expression. * Each object in this sequence will be an instance of XdmItem. Note * that the expression may be evaluated lazily, which means that a successful response * from this method does not imply that the expression has executed successfully: failures * may be reported later while retrieving items from the iterator. * @throws SaxonApiUncheckedException * if a dynamic error occurs during XPath evaluation that * can be detected at this point. It is also possible that an SaxonApiUncheckedException will * be thrown by the hasNext() method of the returned iterator. */ public Iterator iterator() throws SaxonApiUncheckedException { try { return new XdmSequenceIterator(exp.iterate(dynamicContext)); } catch (XPathException e) { throw new SaxonApiUncheckedException(e); } } /** * Evaluate the XPath expression, returning the effective boolean value of the result. * * @return a boolean representing the effective boolean value of the result of evaluating * the expression, as defined by the rules for the fn:boolean() function. * @throws SaxonApiException if a dynamic error occurs during the expression evaluation, or if the result * of the expression is a value whose effective boolean value is not defined (for example, a date or a * sequence of three integers) * @since 9.1 */ public boolean effectiveBooleanValue() throws SaxonApiException { try { return exp.effectiveBooleanValue(dynamicContext); } catch (XPathException e) { throw new SaxonApiException(e); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/s9api/XQueryExecutable.java0000644000175000017500000000756711033112257022545 0ustar eugeneeugenepackage net.sf.saxon.s9api; import net.sf.saxon.query.XQueryExpression; /** * An XQueryExecutable represents the compiled form of a query. * To execute the query, it must first be loaded to form an {@link net.sf.saxon.s9api.XQueryEvaluator}. * *

    An XQueryExecutable is immutable, and therefore thread-safe. * It is simplest to load a new XsltTransformer each time the stylesheet is to be run. * However, the XsltTransformer is serially reusable within a single thread.

    * *

    An XQueryExecutable is created by using one of the compile methods on the * {@link net.sf.saxon.s9api.XQueryCompiler} class.

    * * @since 9.0 */ public class XQueryExecutable { Processor processor; XQueryExpression exp; protected XQueryExecutable(Processor processor, XQueryExpression exp) { this.processor = processor; this.exp = exp; } /** * Load the stylesheet to prepare it for execution. * @return An XsltTransformer. The returned XsltTransformer can be used to set up the * dynamic context for stylesheet evaluation, and to run the stylesheet. */ public XQueryEvaluator load() { return new XQueryEvaluator(processor, exp); } /** * Get the ItemType of the items in the result of the query, as determined by static analysis. This * is the most precise ItemType that the processor is able to determine from static examination of the * query; the actual items in the query result are guaranteed to belong to this ItemType or to a subtype * of this ItemType. * @return the statically-determined ItemType of the result of the query * @since 9.1 */ public ItemType getResultItemType() { net.sf.saxon.type.ItemType it = exp.getExpression().getItemType(processor.getUnderlyingConfiguration().getTypeHierarchy()); return new ItemType(it, processor); } /** * Get the statically-determined cardinality of the result of the query. This is the most precise cardinality * that the processor is able to determine from static examination of the query. * @return the statically-determined cardinality of the result of the query * @since 9.1 */ public OccurrenceIndicator getResultCardinality() { int card = exp.getExpression().getCardinality(); return OccurrenceIndicator.getOccurrenceIndicator(card); } /** * Ask whether the query is an updating query: that is, whether it returns a Pending Update List * rather than a Value. Note that queries using the XUpdate copy-modify syntax are not considered * to be updating queries. * @return true if the query is an updating query, false if not * @since 9.1 */ public boolean isUpdateQuery() { return exp.isUpdateQuery(); } /** * Get the underlying implementation object representing the compiled stylesheet. This provides * an escape hatch into lower-level APIs. The object returned by this method may change from release * to release. * @return the underlying implementation of the compiled stylesheet */ public XQueryExpression getUnderlyingCompiledQuery() { return exp; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/s9api/XdmNode.java0000644000175000017500000003256611042574476020660 0ustar eugeneeugenepackage net.sf.saxon.s9api; import net.sf.saxon.om.*; import net.sf.saxon.pattern.NameTest; import net.sf.saxon.query.QueryResult; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.Type; import javax.xml.transform.Source; import java.net.URI; import java.net.URISyntaxException; /** * This class represents a node in the XDM data model. A Node is an {@link XdmItem}, and is therefore an * {@link XdmValue} in its own right, and may also participate as one item within a sequence value. *

    *

    An XdmNode is implemented as a wrapper around an object of type {@link net.sf.saxon.om.NodeInfo}. * Because this is a key interface within Saxon, it is exposed via this API.

    *

    *

    The XdmNode interface exposes basic properties of the node, such as its name, its string value, and * its typed value. Navigation to other nodes is supported through a single method, {@link #axisIterator}, * which allows other nodes to be retrieved by following any of the XPath axes.

    *

    *

    Note that node identity cannot be inferred from object identity. The same node may be represented * by different XdmNode instances at different times, or even at the same time. The equals() * method on this class can be used to test for node identity.

    * @since 9.0 */ public class XdmNode extends XdmItem { protected XdmNode(NodeInfo node) { super(node); } /** * Get the kind of node. * @return the kind of node, for example {@link XdmNodeKind#ELEMENT} or {@link XdmNodeKind#ATTRIBUTE} */ public XdmNodeKind getNodeKind() { switch (getUnderlyingNode().getNodeKind()) { case Type.DOCUMENT: return XdmNodeKind.DOCUMENT; case Type.ELEMENT: return XdmNodeKind.ELEMENT; case Type.ATTRIBUTE: return XdmNodeKind.ATTRIBUTE; case Type.TEXT: return XdmNodeKind.TEXT; case Type.COMMENT: return XdmNodeKind.COMMENT; case Type.PROCESSING_INSTRUCTION: return XdmNodeKind.PROCESSING_INSTRUCTION; case Type.NAMESPACE: return XdmNodeKind.NAMESPACE; default: throw new IllegalStateException("nodeKind"); } } /** * Get the name of the node, as a QName * * @return the name of the node. In the case of unnamed nodes (for example, text and comment nodes) * return null. */ public QName getNodeName() { int nc = getUnderlyingNode().getNameCode(); if (nc == -1) { return null; } StructuredQName sqn = new StructuredQName(getUnderlyingNode().getNamePool(), nc); return new QName(sqn); } /** * Get the typed value of this node, as defined in XDM * * @return the typed value. If the typed value is atomic, this will be returned as an instance * of {@link XdmAtomicValue} * @throws SaxonApiException if an error occurs obtaining the typed value, for example because * the node is an element with element-only content */ public XdmValue getTypedValue() throws SaxonApiException { try { ValueRepresentation v = getUnderlyingNode().atomize(); return XdmValue.wrap(v); } catch (XPathException e) { throw new SaxonApiException(e); } } /** * Get the line number of the node in a source document. For a document constructed using the document * builder, this is available only if the line numbering option was set when the document was built (and * then only for element nodes). If the line number is not available, the value -1 is returned. Line numbers * will typically be as reported by a SAX parser: this means that the line number for an element node is the * line number containing the closing ">" of the start tag. * @return the line number of the node, or -1 if not available. */ public int getLineNumber() { return getUnderlyingNode().getLineNumber(); } /** * Get a JAXP Source object corresponding to this node, allowing the node to be * used as input to transformations or queries * @return a Source object corresponding to this node */ public Source asSource() { return getUnderlyingNode(); } /** * Get an iterator over the nodes reachable from this node via a given axis. * * @param axis identifies which axis is to be navigated * @return an iterator over the nodes on the specified axis, starting from this node as the * context node. The nodes are returned in axis order, that is, in document order for a forwards * axis and in reverse document order for a reverse axis. */ public XdmSequenceIterator axisIterator(Axis axis) { AxisIterator base = getUnderlyingNode().iterateAxis(axis.getAxisNumber()); return new XdmSequenceIterator(base); } /** * Get an iterator over the nodes reachable from this node via a given axis, selecting only * those nodes with a specified name. * * @param axis identifies which axis is to be navigated * @param name identifies the name of the nodes to be selected. The selected nodes will be those * whose node kind is the principal node kind of the axis (that is, attributes for the attribute * axis, namespaces for the namespace axis, and elements for all other axes) whose name matches * the specified name. *

    For example, specify new QName("", "item") to select nodes with local name * "item", in no namespace.

    * @return an iterator over the nodes on the specified axis, starting from this node as the * context node. The nodes are returned in axis order, that is, in document order for a forwards * axis and in reverse document order for a reverse axis. */ public XdmSequenceIterator axisIterator(Axis axis, QName name) { int kind; switch (axis) { case ATTRIBUTE: kind = Type.ATTRIBUTE; break; case NAMESPACE: kind = Type.NAMESPACE; break; default: kind = Type.ELEMENT; break; } NamePool pool = getUnderlyingNode().getNamePool(); int nameCode = pool.allocate("", name.getNamespaceURI(), name.getLocalName()); NameTest test = new NameTest(kind, nameCode, pool); AxisIterator base = getUnderlyingNode().iterateAxis(axis.getAxisNumber(), test); return new XdmSequenceIterator(base); } /** * Get the parent of this node * * @return the parent of this node (a document or element node), or null if this node has no parent. */ public XdmNode getParent() { return (XdmNode) XdmValue.wrap(getUnderlyingNode().getParent()); } /** * Get the string value of a named attribute of this element * @param name the name of the required attribute * @return null if this node is not an element, or if this element has no * attribute with the specified name. Otherwise return the string value of the * selected attribute node. */ public String getAttributeValue(QName name) { int fp = getUnderlyingNode().getNamePool().allocate("", name.getNamespaceURI(), name.getLocalName()); return getUnderlyingNode().getAttributeValue(fp); } /** * Get the base URI of this node * * @return the base URI, as defined in the XDM model */ public URI getBaseURI() { try { return new URI(getUnderlyingNode().getBaseURI()); } catch (URISyntaxException e) { throw new IllegalStateException("baseURI"); } } /** * Get the document URI of this node. * @return the document URI, as defined in the XDM model. Returns null if no document URI is known * @since 9.1 */ public URI getDocumentURI() { try { String systemId = getUnderlyingNode().getSystemId(); return (systemId == null || systemId.length() == 0 ? null : new URI(systemId)); } catch (URISyntaxException e) { throw new IllegalStateException("documentURI"); } } /** * The hashcode is such that two XdmNode instances have the same hashCode if they represent the same * node. Note that the same node might be represented by different XdmNode objects, but these will * compare equal. * * @return a hashCode representing node identity */ public int hashCode() { return getUnderlyingNode().hashCode(); } /** * The equals() relation between two XdmNode objects is true if they both represent the same * node. That is, it corresponds to the "is" operator in XPath. * * @param other the object to be compared * @return true if and only if the other object is an XdmNode instance representing the same node */ public boolean equals(Object other) { return other instanceof XdmNode && getUnderlyingNode().isSameNodeInfo(((XdmNode) other).getUnderlyingNode()); } /** * The toString() method returns a simple XML serialization of the node * with defaulted serialization parameters. * *

    In the case of an element node, the result will be a well-formed * XML document serialized as defined in the W3C XSLT/XQuery serialization specification, * using options method="xml", indent="yes", omit-xml-declaration="yes".

    * *

    In the case of a document node, the result will be a well-formed * XML document provided that the document node contains exactly one element child, * and no text node children. In other cases it will be a well-formed external * general parsed entity.

    * *

    In the case of an attribute node, the output is a string in the form * name="value". The name will use the original namespace prefix.

    *

    Other nodes, such as text nodes, comments, and processing instructions, are * represented as they would appear in lexical XML.

    * *

    For more control over serialization, use the {@link Serializer} class.

    * * @return a simple XML serialization of the node. Under error conditions the method * may return an error message which will always begin with the label "Error: ". */ public String toString() { NodeInfo node = getUnderlyingNode(); if (node.getNodeKind() == Type.ATTRIBUTE) { String val = node.getStringValue().replace("\"", """); val = val.replace("<", "<"); val = val.replace("&", "&"); return node.getDisplayName() + "=\"" + val + '"'; } else if (node.getNodeKind() == Type.NAMESPACE) { String val = node.getStringValue().replace("\"", """); val = val.replace("<", "<"); val = val.replace("&", "&"); String name = node.getDisplayName(); name = (name.equals("") ? "xmlns" : "xmlns:" + name); return name + "=\"" + val + '"'; } try { return QueryResult.serialize(node); } catch (XPathException err) { return("Error: " + err.getMessage()); } } /** * Get the underlying Saxon implementation object representing this node. This provides * access to classes and methods in the Saxon implementation that may be subject to change * from one release to another. * * @return the underlying implementation object */ public NodeInfo getUnderlyingNode() { return (NodeInfo) getUnderlyingValue(); } /** * In the case of an XdmNode that wraps a node in an external object model such as DOM, JDOM, * XOM, or DOM4J, get the underlying wrapped node * @return the underlying external node if there is one, or null if this is not an XdmNode that * wraps such an external node * @since 9.1.0.2 */ public Object getExternalNode() { NodeInfo saxonNode = getUnderlyingNode(); if (saxonNode instanceof VirtualNode) { Object externalNode = ((VirtualNode)saxonNode).getUnderlyingNode(); return (externalNode instanceof NodeInfo ? null : externalNode); } else { return null; } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/s9api/SAXDestination.java0000644000175000017500000000507411033112257022132 0ustar eugeneeugenepackage net.sf.saxon.s9api; import net.sf.saxon.Configuration; import net.sf.saxon.event.ContentHandlerProxy; import net.sf.saxon.event.Receiver; import org.xml.sax.ContentHandler; /** * This class represents a Destination (for example, the destination of the output of a transformation) * in which events representing the XML document are sent to a user-supplied SAX2 ContentHandler, as * if the ContentHandler were receiving the document directly from an XML parser. */ public class SAXDestination implements Destination { private ContentHandler contentHandler; /** * Create a SAXDestination, supplying a SAX ContentHandler to which * events will be routed * @param handler the SAX ContentHandler that is to receive the output. If the * ContentHandler is also a {@link org.xml.sax.ext.LexicalHandler} then it will also receive * notification of events such as comments. */ public SAXDestination(ContentHandler handler) { contentHandler = handler; } /** * Return a Receiver. Saxon calls this method to obtain a Receiver, to which it then sends * a sequence of events representing the content of an XML document. * * @param config The Saxon configuration. This is supplied so that the destination can * use information from the configuration (for example, a reference to the name pool) * to construct or configure the returned Receiver. * @return the Receiver to which events are to be sent. * @throws net.sf.saxon.s9api.SaxonApiException * if the Receiver cannot be created */ public Receiver getReceiver(Configuration config) throws SaxonApiException { ContentHandlerProxy chp = new ContentHandlerProxy(); chp.setUnderlyingContentHandler(contentHandler); chp.setPipelineConfiguration(config.makePipelineConfiguration()); return chp; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/s9api/Processor.java0000644000175000017500000002334311151243710021253 0ustar eugeneeugenepackage net.sf.saxon.s9api; import net.sf.saxon.Configuration; import net.sf.saxon.Version; import net.sf.saxon.event.NamespaceReducer; import net.sf.saxon.event.Receiver; import net.sf.saxon.event.TreeReceiver; import net.sf.saxon.om.Item; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.trans.XPathException; import java.util.Iterator; /** * The Processor class serves three purposes: it allows global Saxon configuration options to be set; * it acts as a factory for generating XQuery, XPath, and XSLT compilers; and it owns certain shared * resources such as the Saxon NamePool and compiled schemas. This is the first object that a * Saxon application should create. Once established, a Processor may be used in multiple threads. * *

    It is possible to run more than one Saxon Processor concurrently, but only when running completely * independent workloads. Nothing can be shared between Processor instances. Within a query or transformation, * all source documents and schemas must be built using the same Processor, which must also be used to * compile the query or stylesheet.

    */ public class Processor { // TODO: extension functions // TODO: external object models private Configuration config; private SchemaManager schemaManager; /** * Create a Processor * @param schemaAware indicates whether the Processor is schema-aware or not. To create a schema-aware * processor, the Saxon-SA product is required. This flag should be set if any Saxon-SA specific * functionality or optimization is required, whether or not schemas are used. */ public Processor(boolean schemaAware) { if (schemaAware) { config = Configuration.makeSchemaAwareConfiguration(null, null); schemaManager = new SchemaManager(config); } else { config = new Configuration(); } } /** * Create a DocumentBuilder. A DocumentBuilder is used to load source XML documents. * @return a newly created DocumentBuilder */ public DocumentBuilder newDocumentBuilder() { return new DocumentBuilder(config); } /** * Create an XPathCompiler. An XPathCompiler is used to compile XPath expressions. * @return a newly created XPathCompiler */ public XPathCompiler newXPathCompiler() { return new XPathCompiler(this); } /** * Create an XsltCompiler. An XsltCompiler is used to compile XSLT stylesheets. * @return a newly created XsltCompiler * @throws UnsupportedOperationException if this version of the Saxon product does not support XSLT processing */ public XsltCompiler newXsltCompiler() { if (isSchemaAware() && !config.isSchemaAware(Configuration.XSLT)) { throw new UnsupportedOperationException( "XSLT processing is not supported with this Saxon installation"); } return new XsltCompiler(this); } /** * Create an XQueryCompiler. An XQueryCompiler is used to compile XQuery queries. * @return a newly created XQueryCompiler * @throws UnsupportedOperationException if this version of the Saxon product does not support XQuery processing */ public XQueryCompiler newXQueryCompiler() { if (isSchemaAware() && !config.isSchemaAware(Configuration.XQUERY)) { throw new UnsupportedOperationException( "XQuery processing is not supported with this Saxon installation"); } return new XQueryCompiler(this); } /** * Get the associated SchemaManager. The SchemaManager provides capabilities to load and cache * XML schema definitions. There is exactly one SchemaManager in a schema-aware Processor, and none * in a Processor that is not schema-aware. The SchemaManager is created automatically by the system. * @return the associated SchemaManager, or null if the Processor is not schema-aware. */ public SchemaManager getSchemaManager() { return schemaManager; } /** * Test whether this processor is schema-aware * @return true if this is a schema-aware processor, false otherwise */ public boolean isSchemaAware() { return config.isSchemaAware(Configuration.XML_SCHEMA); } /** * Get the user-visible Saxon product version, for example "9.0.0.1" * @return the Saxon product version, as a string */ public String getSaxonProductVersion() { return Version.getProductVersion(); } /** * Set the version of XML used by this Processor. If the value is set to "1.0", then * output documents will be serialized as XML 1.0. This option also affects * the characters permitted to appear in queries and stylesheets, and the characters that can appear * in names (for example, in path expressions). * *

    Note that source documents specifying xml version="1.0" or "1.1" are accepted * regardless of this setting.

    * @param version must be one of the strings "1.0" or "1.1" * @throws IllegalArgumentException if any string other than "1.0" or "1.1" is supplied */ public void setXmlVersion(String version) { if (version.equals("1.0")) { config.setXMLVersion(Configuration.XML10); } else if (version.equals("1.1")) { config.setXMLVersion(Configuration.XML11); } else { throw new IllegalArgumentException("XmlVersion"); } } /** * Get the version of XML used by this Processor. If the value is "1.0", then input documents * must be XML 1.0 documents, and output documents will be serialized as XML 1.0. This option also affects * the characters permitted to appear in queries and stylesheets, and the characters that can appear * in names (for example, in path expressions). * @return one of the strings "1.0" or "1.1" */ public String getXmlVersion() { if (config.getXMLVersion() == Configuration.XML10) { return "1.0"; } else { return "1.1"; } } /** * Set a configuration property * @param name the name of the option to be set. The names of the options available are listed * as constants in class {@link net.sf.saxon.FeatureKeys}. * @param value the value of the option to be set. * @throws IllegalArgumentException if the property name is not recognized */ public void setConfigurationProperty(String name, Object value) { config.setConfigurationProperty(name, value); } /** * Get the value of a configuration property * @param name the name of the option required. The names of the properties available are listed * as constants in class {@link net.sf.saxon.FeatureKeys}. * @return the value of the property, if one is set; or null if the property is unset and there is * no default. * @throws IllegalArgumentException if the property name is not recognized */ public Object getConfigurationProperty(String name) { return config.getConfigurationProperty(name); } /** * Get the underlying {@link Configuration} object that underpins this Processor. This method * provides an escape hatch to internal Saxon implementation objects that offer a finer and lower-level * degree of control than the s9api classes and methods. Some of these classes and methods may change * from release to release. * @return the underlying Configuration object */ public Configuration getUnderlyingConfiguration() { return config; } /** * Write an XdmValue to a given destination. The sequence represented by the XdmValue is "normalized" * as defined in the serialization specification (this is equivalent to constructing a document node * in XSLT or XQuery with this sequence as the content expression), and the resulting document is * then copied to the destination. If the destination is a serializer this has the effect of serializing * the sequence as described in the W3C specifications. * @param value the value to be written * @param destination the destination to which the value is to be written */ public void writeXdmValue(XdmValue value, Destination destination) throws SaxonApiException { try { Receiver out = destination.getReceiver(config); out.setPipelineConfiguration(config.makePipelineConfiguration()); out = new NamespaceReducer(out); TreeReceiver tree = new TreeReceiver(out); tree.open(); tree.startDocument(0); for (Iterator it = value.iterator(); it.hasNext();) { XdmItem item = it.next(); tree.append((Item)item.getUnderlyingValue(), 0, NodeInfo.ALL_NAMESPACES); } tree.endDocument(); tree.close(); } catch (XPathException err) { throw new SaxonApiException(err); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/s9api/SchemaValidator.java0000644000175000017500000002662411033112257022347 0ustar eugeneeugenepackage net.sf.saxon.s9api; import net.sf.saxon.Configuration; import net.sf.saxon.FeatureKeys; import net.sf.saxon.event.PipelineConfiguration; import net.sf.saxon.event.Receiver; import net.sf.saxon.event.Sender; import net.sf.saxon.event.Sink; import net.sf.saxon.om.StructuredQName; import net.sf.saxon.om.Validation; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.SchemaType; import net.sf.saxon.value.Whitespace; import javax.xml.transform.ErrorListener; import javax.xml.transform.Source; /** * A SchemaValidator is an object that is used for validating instance documents against a schema. * The schema consists of the collection of schema components that are available within the schema * cache maintained by the SchemaManager, together with any additional schema components located * during the course of validation by means of an xsl:schemaLocation or xsi:noNamespaceSchemaLocation * attribute within the instance document. * *

    If validation fails, an exception is thrown. If validation succeeds, the validated document * can optionally be written to a specified destination. This will be a copy of the original document, * augmented with default values for absent elements and attributes, and carrying type annotations * derived from the schema processing. Expansion of defaults can be suppressed by means of the method * {@link #setExpandAttributeDefaults(boolean)}.

    * *

    A SchemaValidator is a Destination, which allows it to receive the output of a * query or transformation to be validated.

    * *

    Saxon does not deliver the full PSVI as described in the XML schema specifications, * only the subset of the PSVI properties featured in the XDM data model.

    * */ public class SchemaValidator implements Destination { private Configuration config; private boolean lax; private ErrorListener errorListener; private Destination destination; private QName documentElementName; private SchemaType documentElementType; private boolean expandAttributeDefaults = true; private boolean useXsiSchemaLocation; protected SchemaValidator(Configuration config) { this.config = config; this.useXsiSchemaLocation = ((Boolean)config.getConfigurationProperty( FeatureKeys.USE_XSI_SCHEMA_LOCATION)).booleanValue(); } /** * The validation mode may be either strict or lax. The default is strict; this method may be called * to indicate that lax validation is required. With strict validation, validation fails if no element * declaration can be located for the outermost element. With lax validation, the absence of an * element declaration results in the content being considered valid. * @param lax true if validation is to be lax, false if it is to be strict */ public void setLax(boolean lax) { this.lax = lax; } /** * Ask whether validation is to be in lax mode. * @return true if validation is to be in lax mode, false if it is to be in strict mode. */ public boolean isLax() { return lax; } /** * Set the ErrorListener to be used while validating instance documents. * @param listener The error listener to be used. This is notified of all errors detected during the * validation episode. */ public void setErrorListener(ErrorListener listener) { this.errorListener = listener; } /** * Get the ErrorListener being used while validating instance documents * @return listener The error listener in use. This is notified of all errors detected during the * validation episode. Returns null if no user-supplied ErrorListener has been set. */ public ErrorListener getErrorListener() { return errorListener; } /** * Say whether the schema processor is to take account of any xsi:schemaLocation and * xsi:noNamespaceSchemaLocation attributes encountered while validating an instance document * @param recognize true if these two attributes are to be recognized; false if they are to * be ignored. Default is true. */ public void setUseXsiSchemaLocation(boolean recognize) { useXsiSchemaLocation = recognize; } /** * Ask whether the schema processor is to take account of any xsi:schemaLocation and * xsi:noNamespaceSchemaLocation attributes encountered while validating an instance document * @return true if these two attributes are to be recognized; false if they are to * be ignored. Default is true. */ public boolean isUseXsiSchemaLocation() { return useXsiSchemaLocation; } /** * Set the Destination to receive the validated document. If no destination is supplied, the * validated document is discarded. * @param destination the destination to receive the validated document */ public void setDestination(Destination destination) { this.destination = destination; } /** * Get the Destination that will receive the validated document. Return null if no destination * has been set. * @return the destination to receive the validated document, or null if none has been supplied */ public Destination getDestination() { return destination; } /** * Set the name of the required top-level element of the document to be validated (that is, the * name of the outermost element of the document). If no value is supplied, there is no constraint * on the required element name * @param name the name of the document element, as a QName; or null to remove a previously-specified * value. */ public void setDocumentElementName(QName name) { documentElementName = name; } /** * Get the name of the required top-level element of the document to be validated. * @return the name of the required document element, or null if no value has been set. */ public QName getDocumentElementName() { return documentElementName; } /** * Set the name of the required type of the top-level element of the document to be validated. * If no value is supplied, there is no constraint on the required type * @param name the name of the type of the document element, as a QName; * or null to remove a previously-specified value. This must be the name of a type in the * schema (typically but not necessarily a complex type). * @throws SaxonApiException if there is no known type with this name */ public void setDocumentElementTypeName(QName name) throws SaxonApiException { int fp = config.getNamePool().allocate( "", name.getNamespaceURI(), name.getLocalName()); documentElementType = config.getSchemaType(fp); if (documentElementType == null) { throw new SaxonApiException("Unknown type " + name.getClarkName()); } } /** * Get the name of the required type of the top-level element of the document to be validated. * @return the name of the required type of the document element, or null if no value has been set. */ public QName getDocumentElementTypeName() { if (documentElementType == null) { return null; } else { int fp = documentElementType.getFingerprint(); return new QName(new StructuredQName(config.getNamePool(), fp)); } } /** * Get the schema type against which the document element is to be validated * @return the schema type */ protected SchemaType getDocumentElementType() { return documentElementType; } /** * Set whether attribute defaults defined in a schema are to be expanded or not * (by default, fixed and default attribute values are expanded, that is, they are inserted * into the document during validation as if they were present in the instance being validated) * @param expand true if defaults are to be expanded, false if not */ public void setExpandAttributeDefaults(boolean expand) { expandAttributeDefaults = expand; } /** * Ask whether attribute defaults defined in a schema are to be expanded or not * (by default, fixed and default attribute values are expanded, that is, they are inserted * into the document during validation as if they were present in the instance being validated) * @return true if defaults are to be expanded, false if not */ public boolean isExpandAttributeDefaults() { return expandAttributeDefaults; } /** * Validate an instance document supplied as a Source object * @param source the instance document to be validated. The call getSystemId() applied to * this source object must return the base URI used for dereferencing any xsi:schemaLocation * or xsi:noNamespaceSchemaLocation attributes * @throws SaxonApiException if the source document is found to be invalid */ public void validate(Source source) throws SaxonApiException { Receiver receiver = getReceiver(config, source.getSystemId()); PipelineConfiguration pipe = receiver.getPipelineConfiguration(); try { new Sender(pipe).send(source, receiver, true); } catch (XPathException e) { throw new SaxonApiException(e); } } public Receiver getReceiver(Configuration config) throws SaxonApiException { return getReceiver(config, null); } private Receiver getReceiver(Configuration config, String systemId) throws SaxonApiException { PipelineConfiguration pipe = config.makePipelineConfiguration(); pipe.setExpandAttributeDefaults(expandAttributeDefaults); pipe.setUseXsiSchemaLocation(useXsiSchemaLocation); pipe.setRecoverFromValidationErrors(true); Receiver output = (destination == null ? new Sink() : destination.getReceiver(config)); output.setPipelineConfiguration(pipe); int topLevelElement = -1; if (documentElementName != null) { topLevelElement = config.getNamePool().allocate( "", documentElementName.getNamespaceURI(), documentElementName.getLocalName()); } Receiver receiver = config.getDocumentValidator( output, systemId, (lax ? Validation.LAX : Validation.STRICT), Whitespace.NONE, documentElementType, topLevelElement); if (errorListener != null) { pipe.setErrorListener(errorListener); } return receiver; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/s9api/TeeDestination.java0000644000175000017500000000530411033112257022210 0ustar eugeneeugenepackage net.sf.saxon.s9api; import net.sf.saxon.Configuration; import net.sf.saxon.event.Receiver; import net.sf.saxon.event.TeeOutputter; /** * A TeeDestination allows writing to two destinations at once. For example the output of a transformation * can be written simultaneously to a Serializer and to a second Transformation. By chaining together a number * of TeeDestinations it is possible to write to any number of destinations at once. * @since 9.1 */ public class TeeDestination implements Destination { private Destination dest0; private Destination dest1; /** * Create a TeeDestination: a destination which copies everything that is sent to it to two * separate destinations * @param destination0 the first destination * @param destination1 the second destination */ public TeeDestination(Destination destination0, Destination destination1) { dest0 = destination0; dest1 = destination1; } /** * Return a Receiver. Saxon calls this method to obtain a Receiver, to which it then sends * a sequence of events representing the content of an XML document. * @param config The Saxon configuration. This is supplied so that the destination can * use information from the configuration (for example, a reference to the name pool) * to construct or configure the returned Receiver. * @return the Receiver to which events are to be sent. It is the caller's responsibility to * initialize this Receiver with a {@link net.sf.saxon.event.PipelineConfiguration} before calling * its open() method. * @throws net.sf.saxon.s9api.SaxonApiException * if the Receiver cannot be created */ public Receiver getReceiver(Configuration config) throws SaxonApiException { return new TeeOutputter(dest0.getReceiver(config), dest1.getReceiver(config)); } } // // The contents of this file are subject to the Mozilla Public License Version // 1.0 (the "License"); // you may not use this file except in compliance with the License. You may // obtain a copy of the License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations // under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael Kay, // // Portions created by (your name) are Copyright (C) (your legal entity). All // Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/s9api/XdmItem.java0000644000175000017500000000754011033112257020644 0ustar eugeneeugenepackage net.sf.saxon.s9api; import net.sf.saxon.om.Item; import net.sf.saxon.value.AtomicValue; /** * The class XdmItem represents an item in a sequence, as defined by the XDM data model. * An item is either an atomic value or a node. * *

    An item is a member of a sequence, but it can also be considered as a sequence * (of length one) in its own right. XdmItem is a subtype of XdmValue because every * Item in the XDM data model is also a value.

    * *

    It cannot be assumed that every sequence of length one will be represented by * an XdmItem. It is quite possible for an XdmValue that is not an XdmItem to hold * a singleton sequence.

    * *

    Saxon provides two concrete subclasses of XdmItem, namely * {@link XdmNode} and {@link XdmAtomicValue}. Users must not attempt to create * additional subclasses.

    */ public abstract class XdmItem extends XdmValue { // internal protected constructors protected XdmItem() { } protected XdmItem(Item item) { super(item); } // internal factory mathod to wrap an Item protected static XdmItem wrapItem(Item item) { return item == null ? null : (XdmItem)XdmValue.wrap(item); } /** * Factory method to construct an atomic value given its lexical representation and the * required item type * @param value the lexical representation of the required value * @param type the item type of the required value * @return the constructed item * @throws SaxonApiException if the supplied string is not in the lexical space of the target type, or * if the target type is not atomic * @deprecated since 9.1. This factory method duplicates the constructor * {@link XdmAtomicValue#XdmAtomicValue(String, ItemType)} which should be used in preference */ public static XdmItem newAtomicValue(String value, ItemType type) throws SaxonApiException { return new XdmAtomicValue(value, type); } /** * Get the string value of the item. For a node, this gets the string value * of the node. For an atomic value, it has the same effect as casting the value * to a string. In all cases the result is the same as applying the XPath string() * function. * *

    For atomic values, the result is the same as the result of calling * toString. This is not the case for nodes, where toString * returns an XML serialization of the node.

    * * @return the result of converting the item to a string. */ public String getStringValue() { //noinspection RedundantCast return ((Item)getUnderlyingValue()).getStringValue(); } /** * Determine whether the item is an atomic value or a node * @return true if the item is an atomic value, false if it is a node */ public boolean isAtomicValue() { return ((Item)getUnderlyingValue()) instanceof AtomicValue; } /** * Get the number of items in the sequence * @return the number of items in the value - always one */ @Override public int size() { return 1; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/s9api/XdmNodeKind.java0000644000175000017500000000231011033112257021427 0ustar eugeneeugenepackage net.sf.saxon.s9api; import net.sf.saxon.type.Type; /** * Enumeration class defining the seven kinds of node defined in the XDM model */ public enum XdmNodeKind { DOCUMENT (Type.DOCUMENT), ELEMENT (Type.ELEMENT), ATTRIBUTE (Type.ATTRIBUTE), TEXT (Type.TEXT), COMMENT (Type.COMMENT), PROCESSING_INSTRUCTION (Type.PROCESSING_INSTRUCTION), NAMESPACE (Type.NAMESPACE); private int number; private XdmNodeKind(int number) { this.number = number; } protected int getNumber() { return number; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/s9api/package.html0000644000175000017500000000575711033112257020723 0ustar eugeneeugene Package overview for net.sf.saxon.s9api

    This package provides a Java API for Saxon that hides as much as possible of the detail of the implementation. However, the API architecture faithfully reflects the internal architecture of the Saxon product, unlike standard APIs such as JAXP and XQJ which in many cases force compromises in the design of the application.

    An application starts by loading a Processor, which allows configuration options to be set. As far as possible, an application should instantiate a single Processor.

    The interfaces for XSLT, XQuery, and XPath processing all follow the same pattern. There is a three-stage execution model: first a compiler is created using a factory method in the Processor object. The compiler holds compile-time options and the static context information. Then the compiler's compile() method is called to create an executable, a representation of the compiled stylesheet, query, or expression. This is thread-safe and immutable once created. To run the query or transformation, first call the load() method to create a run-time object called variously an XsltTransformer, XQueryEvaluator, or XPathSelector. This holds run-time context information such as parameter settings and the initial context node; the object is therefore not shareable and should only be run in a single thread; indeed it should normally only be used once. This object also provides methods allowing the transformation or query to be executed.

    In the schema-aware product the Processor owns a SchemaManager that holds the cache of schema components and can be used to load new schema components from source schema documents. It can also be used to create a SchemaValidator, which in turn is used to validate instance documents.

    Source documents can be constructed using a DocumentBuilder, which holds all the options and parameters to control document building.

    The output of a transformation, or of any other process that generates an XML tree, can be sent to a Destination. There are a number of implementations of this interface, including a Serializer which translates the XML document tree into lexical XML form.

    There are classes to represent the objects of the XDM data model, including XDMValue, XDMItem, XDMNode, and XDMAtomicValue.

    The s9api interface is designed to take advantage of Java 5 constructs such as generics and iterables. Although the main Saxon run-time continues to work under JDK 1.4, the s9api interface cannot be used without upgrading to Java 5. For this reason it is in a separate JAR file.


    Michael H. Kay
    Saxonica Limited
    27 September 2007

    saxonb-9.1.0.8/bj/net/sf/saxon/sxpath/0000755000175000017500000000000012216261746016722 5ustar eugeneeugenesaxonb-9.1.0.8/bj/net/sf/saxon/sxpath/AbstractStaticContext.java0000644000175000017500000003012311033112257024030 0ustar eugeneeugenepackage net.sf.saxon.sxpath; import net.sf.saxon.Configuration; import net.sf.saxon.event.LocationProvider; import net.sf.saxon.expr.*; import net.sf.saxon.functions.*; import net.sf.saxon.instruct.Executable; import net.sf.saxon.instruct.LocationMap; import net.sf.saxon.om.NamePool; import net.sf.saxon.om.NamespaceConstant; import net.sf.saxon.sort.StringCollator; import net.sf.saxon.type.BuiltInAtomicType; import javax.xml.transform.SourceLocator; /** * An abstract and configurable implementation of the StaticContext interface, * which defines the static context of an XPath expression. * *

    This class implements those parts of the functionality of a static context * that tend to be common to most implementations: simple-valued properties such * as base URI and default element namespace; availability of the standard * function library; and support for collations.

    */ public abstract class AbstractStaticContext implements StaticContext { private String baseURI = null; private Configuration config; private LocationMap locationMap = new LocationMap(); private Executable executable; private String defaultFunctionNamespace = NamespaceConstant.FN; private String defaultElementNamespace = NamespaceConstant.NULL; private boolean backwardsCompatible = false; /** * Set the Configuration. This is protected so it can be used only by subclasses; * the configuration will normally be set at construction time * @param config the configuration */ protected void setConfiguration(Configuration config) { this.config = config; executable = new Executable(config); executable.setHostLanguage(Configuration.XPATH); } /** * Get the system configuration */ public Configuration getConfiguration() { return config; } /** * Initialize the default function library for XPath. * This can be overridden using setFunctionLibrary(). */ protected final void setDefaultFunctionLibrary() { FunctionLibraryList lib = new FunctionLibraryList(); lib.addFunctionLibrary( SystemFunctionLibrary.getSystemFunctionLibrary(SystemFunctionLibrary.XPATH_ONLY)); lib.addFunctionLibrary(getConfiguration().getVendorFunctionLibrary()); lib.addFunctionLibrary(new ConstructorFunctionLibrary(getConfiguration())); //lib.addFunctionLibrary(new JavaExtensionLibrary(getConfiguration())); if (config.isAllowExternalFunctions()) { Configuration.getPlatform().addFunctionLibraries(lib, config, Configuration.XPATH); } setFunctionLibrary(lib); } /** * Add a function library to the list of function libraries * @param library the function library to be added */ protected final void addFunctionLibrary(FunctionLibrary library) { FunctionLibrary libraryList = executable.getFunctionLibrary(); if (libraryList instanceof FunctionLibraryList) { ((FunctionLibraryList)libraryList).addFunctionLibrary(library); } else { throw new IllegalStateException("Registered function library cannot be extended"); } } /** * Get the Executable (representing a complete stylesheet or query) * @return the executable */ public Executable getExecutable() { return executable; } /** * Get the host language (XSLT, XQuery, XPath) used to implement the code in this container * * @return the value {@link net.sf.saxon.Configuration#XPATH} */ public int getHostLanguage() { return Configuration.XPATH; } /** * Construct a dynamic context for early evaluation of constant subexpressions */ public XPathContext makeEarlyEvaluationContext() { return new EarlyEvaluationContext(getConfiguration(), executable.getCollationTable()); } public LocationMap getLocationMap() { return locationMap; } /** * Set the location map, which is used for translating location identifiers into URIs and line * numbers * @param locationMap the location map to be used */ public void setLocationMap(LocationMap locationMap) { this.locationMap = locationMap; } /** * Set the base URI in the static context * @param baseURI the base URI of the expression */ public void setBaseURI(String baseURI) { this.baseURI = baseURI; } /** * Get the Base URI, for resolving any relative URI's used * in the expression. Used by the document() function, resolve-uri(), etc. * @return "" if no base URI has been set */ public String getBaseURI() { return baseURI==null ? "" : baseURI; } /** * Get the function library containing all the in-scope functions available in this static * context. This method is called by the XPath parser when binding a function call in the * XPath expression to an implementation of the function. */ public FunctionLibrary getFunctionLibrary() { return executable.getFunctionLibrary(); } /** * Set the function library to be used * @param lib the function library */ public void setFunctionLibrary(FunctionLibrary lib) { executable.setFunctionLibrary(lib); } /** * Declare a named collation * @param name The name of the collation (technically, a URI) * @param comparator The StringCollator used to implement the collating sequence * @param isDefault True if this is to be used as the default collation */ public void declareCollation(String name, StringCollator comparator, boolean isDefault) { CollationMap collations = executable.getCollationTable(); collations.setNamedCollation(name, comparator); if (isDefault) { collations.setDefaultCollationName(name); } } /** * Get a named collation. * @return the collation identified by the given name, as set previously using declareCollation. * Return null if no collation with this name is found. */ public StringCollator getCollation(String name) { return executable.getCollationTable().getNamedCollation(name); } /** * Get the name of the default collation. * @return the name of the default collation; or the name of the codepoint collation * if no default collation has been defined */ public String getDefaultCollationName() { return executable.getCollationTable().getDefaultCollationName(); } /** * Get the NamePool used for compiling expressions */ public NamePool getNamePool() { return config.getNamePool(); } /** * Issue a compile-time warning. This method is used during XPath expression compilation to * output warning conditions. The default implementation writes the message to System.err. To * change the destination of messages, create a subclass of StandaloneContext that overrides * this method. */ public void issueWarning(String s, SourceLocator locator) { System.err.println("Warning: " + s); } /** * Get the system ID of the container of the expression. Used to construct error messages. * @return "" always */ public String getSystemId() { return ""; } /** * Get the line number of the expression within that container. * Used to construct error messages. * @return -1 always */ public int getLineNumber() { return -1; } /** * Get the default namespace URI for elements and types * Return NamespaceConstant.NULL (that is, the zero-length string) for the non-namespace * @return the default namespace for elements and type */ public String getDefaultElementNamespace() { return defaultElementNamespace; } /** * Set the default namespace for elements and types * @param uri the namespace to be used for unprefixed element and type names. * The value "" (or NamespaceConstant.NULL) represents the non-namespace */ public void setDefaultElementNamespace(String uri) { defaultElementNamespace = uri; } /** * Set the default function namespace * @param uri the namespace to be used for unprefixed function names. * The value "" (or NamespaceConstant.NULL) represents the non-namespace */ public void setDefaultFunctionNamespace(String uri) { defaultFunctionNamespace = uri; } /** * Get the default function namespace. * The value "" (or NamespaceConstant.NULL) represents the non-namespace * @return the default namesapce for functions */ public String getDefaultFunctionNamespace() { return defaultFunctionNamespace; } /** * Set XPath 1.0 compatibility mode on or off (by default, it is false) * @param compatible true if XPath 1.0 compatibility mode is to be set to true, false * if it is to be set to false. */ public void setBackwardsCompatibilityMode(boolean compatible) { backwardsCompatible = compatible; } /** * Determine whether Backwards Compatible Mode is used * @return true if XPath 1.0 backwards compatibility has been selected (by default, * it is false) */ public boolean isInBackwardsCompatibleMode() { return backwardsCompatible; } /** * Determine whether a built-in type is available in this context. This method caters for differences * between host languages as to which set of types are built in. * * @param type the supposedly built-in type. This will always be a type in the XS namespace. * @return true if this type can be used in this static context */ public boolean isAllowedBuiltInType(BuiltInAtomicType type) { return true; } /** * Get the LocationProvider allowing location identifiers to be resolved. * @return the LocationProvider that translates location identifiers into URIs and line numbers */ public LocationProvider getLocationProvider() { return locationMap; } /** * Replace one subexpression by a replacement subexpression * * @param original the original subexpression * @param replacement the replacement subexpression * @return true if the original subexpression was found * @throws UnsupportedOperationException (always) */ public boolean replaceSubExpression(Expression original, Expression replacement) { throw new UnsupportedOperationException(); } /** * Return the public identifier. *

    *

    The return value is the public identifier of the document * entity or of the external parsed entity in which the markup that * triggered the event appears.

    * * @return null (always). * @see #getSystemId */ public String getPublicId() { return null; } /** * Return the character position where the current document event ends. * @return -1 (no column number is available). * @see #getLineNumber */ public int getColumnNumber() { return -1; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/sxpath/XPathExpression.java0000644000175000017500000002600611033112257022661 0ustar eugeneeugenepackage net.sf.saxon.sxpath; import net.sf.saxon.expr.Expression; import net.sf.saxon.expr.XPathContextMajor; import net.sf.saxon.expr.PJConverter; import net.sf.saxon.instruct.SlotManager; import net.sf.saxon.om.Item; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.SequenceExtent; import net.sf.saxon.value.Value; import javax.xml.transform.Source; import java.util.ArrayList; import java.util.Collections; import java.util.List; /** * This class is a representation of an XPath Expression for use with the {@link XPathEvaluator} class. * It is modelled on the XPath API defined in JAXP 1.3, but is cut down to remove any dependencies on JAXP 1.3, * making it suitable for use on vanilla JDK 1.4 installations. * * @author Michael H. Kay */ public class XPathExpression { private XPathEvaluator evaluator; private Expression expression; private SlotManager stackFrameMap; private int numberOfExternalVariables; /** * The constructor is protected, to ensure that instances can only be * created using the createExpression() method of XPathEvaluator * @param evaluator the creating XPathEvaluator * @param exp the internal representation of the compiled expression */ protected XPathExpression(XPathEvaluator evaluator, Expression exp) { expression = exp; this.evaluator = evaluator; } /** * Define the number of slots needed for local variables within the expression * @param map the stack frame map identifying all the variables used by the expression, both * those declared internally, and references to variables declared externally * @param numberOfExternalVariables the number of slots in the stack frame allocated to * externally-declared variables. These must be assigned a value before execution starts */ protected void setStackFrameMap(SlotManager map, int numberOfExternalVariables) { stackFrameMap = map; this.numberOfExternalVariables = numberOfExternalVariables; } /** * Create a dynamic context suitable for evaluating this expression * @param contextItem the initial context item, which may be null if no * context item is required, or if it is to be supplied later * @return an XPathDynamicContext object representing a suitable dynamic context. This will * be initialized with a stack frame suitable for holding the variables used by the * expression. */ public XPathDynamicContext createDynamicContext(Item contextItem) { XPathContextMajor context = new XPathContextMajor(contextItem, evaluator.getExecutable()); context.openStackFrame(stackFrameMap); return new XPathDynamicContext(context, stackFrameMap); } /** * Execute the expression, returning the result as a {@link SequenceIterator}, whose members will be instances * of the class {@link net.sf.saxon.om.Item} * *

    Note that if evaluation of the expression fails with a dynamic error, this will generally * be reported in the form of an exception thrown by the next() method of the {@link SequenceIterator} * @param context the XPath dynamic context * @return an iterator over the result of the expression */ public SequenceIterator iterate(XPathDynamicContext context) throws XPathException { context.checkExternalVariables(stackFrameMap, numberOfExternalVariables); return expression.iterate(context.getXPathContextObject()); } /** * Execute the expression, returning the result as a List, whose members will be instances * of the class {@link net.sf.saxon.om.Item} * @param context the XPath dynamic context * @return a list of items representing the result of the expression */ public List evaluate(XPathDynamicContext context) throws XPathException { SequenceIterator iter = expression.iterate(context.getXPathContextObject()); List list = new ArrayList(20); while (true) { Item item = iter.next(); if (item == null) { break; } list.add(item); } return list; } /** * Execute the expression, returning the result as a single {@link net.sf.saxon.om.Item} * If the result of the expression is a sequence containing more than one item, items after * the first are discarded. If the result is an empty sequence, the method returns null. * @param context the XPath dynamic context * @return the first item in the result of the expression, or null */ public Item evaluateSingle(XPathDynamicContext context) throws XPathException { return expression.iterate(context.getXPathContextObject()).next(); } /** * Evaluate the expression, returning its effective boolean value * @param context the XPath dynamic context * @return the effective boolean value of the result, as defined by the fn:boolean() function * @throws XPathException if a dynamic error occurs, or if the result is a value for which * no effective boolean value is defined */ public boolean effectiveBooleanValue(XPathDynamicContext context) throws XPathException { return expression.effectiveBooleanValue(context.getXPathContextObject()); } /** * Execute a prepared XPath expression, returning the results as a List in which items have been converted * to the appropriate Java object. * * @param source the document or other node against which the XPath expression * will be evaluated. This may be a Saxon NodeInfo object, representing a node in an * existing tree, or it may be any kind of JAXP Source object such as a StreamSource * SAXSource or DOMSource. For the way in which the source document is built, see * {@link net.sf.saxon.Configuration#buildDocument} * @return The results of the expression, as a List. The List represents the sequence * of items returned by the expression. Each item in the list will either be an instance * of net.sf.saxon.om.NodeInfo, representing a node, or a Java object representing an atomic value. */ public List evaluate(Source source) throws XPathException { NodeInfo origin; if (source instanceof NodeInfo) { origin = (NodeInfo)source; } else { origin = evaluator.getConfiguration().buildDocument(source); } XPathDynamicContext dynamicContext = createDynamicContext(origin); SequenceIterator iter = iterate(dynamicContext); SequenceExtent extent = new SequenceExtent(iter); //List result = (List)extent.convertToJava(List.class, dynamicContext.getXPathContextObject()); List result = (List)PJConverter.ToCollection.INSTANCE.convert( extent, List.class, dynamicContext.getXPathContextObject()); if (result == null) { result = Collections.EMPTY_LIST; } return result; } /** * Execute a prepared XPath expression, returning the first item in the result. * This is useful where it is known that the expression will only return * a singleton value (for example, a single node, or a boolean). * @param source the document or other node against which the XPath expression * will be evaluated. This may be a Saxon NodeInfo object, representing a node in an * existing tree, or it may be any kind of JAXP Source object such as a StreamSource * SAXSource or DOMSource. For the way in which the source document is built, see * {@link net.sf.saxon.Configuration#buildDocument} * * @return The first item in the sequence returned by the expression. If the expression * returns an empty sequence, this method returns null. Otherwise, it returns the first * item in the result sequence, represented as a Java object using the same mapping as for * the evaluate() method */ public Object evaluateSingle(Source source) throws XPathException { NodeInfo origin; if (source instanceof NodeInfo) { origin = (NodeInfo)source; } else { origin = evaluator.getConfiguration().buildDocument(source); } XPathDynamicContext context = createDynamicContext(origin); SequenceIterator iterator = iterate(context); Item item = iterator.next(); if (item == null) { return null; } else { return Value.convertToJava(item); } } /** * Get a raw iterator over the results of the expression. This returns results without * any conversion of the returned items to "native" Java classes. This method is intended * for use by applications that need to process the results of the expression using * internal Saxon interfaces. * @param source the document or other node against which the XPath expression * will be evaluated. This may be a Saxon NodeInfo object, representing a node in an * existing tree, or it may be any kind of JAXP Source object such as a StreamSource * SAXSource or DOMSource. For the way in which the source document is built, see * {@link net.sf.saxon.Configuration#buildDocument} * @return an iterator over the results of the expression * @deprecated since 8.9 - use {@link #iterate} */ public SequenceIterator rawIterator(Source source) throws XPathException { NodeInfo origin; if (source instanceof NodeInfo) { origin = (NodeInfo)source; } else { origin = evaluator.getConfiguration().buildDocument(source); } XPathDynamicContext context = createDynamicContext(origin); return iterate(context); } /** * Low-level method to get the internal Saxon expression object. This exposes a wide range of * internal methods that may be needed by specialized applications, and allows greater control * over the dynamic context for evaluating the expression. * * @return the underlying Saxon expression object. */ public Expression getInternalExpression() { return expression; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // The Initial Developer of the Original Code is // Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/sxpath/XPathEvaluator.java0000644000175000017500000003052711173041341022467 0ustar eugeneeugenepackage net.sf.saxon.sxpath; import net.sf.saxon.AugmentedSource; import net.sf.saxon.Configuration; import net.sf.saxon.pattern.Pattern; import net.sf.saxon.pattern.PatternSponsor; import net.sf.saxon.expr.Expression; import net.sf.saxon.expr.ExpressionTool; import net.sf.saxon.expr.ExpressionVisitor; import net.sf.saxon.instruct.Executable; import net.sf.saxon.instruct.SlotManager; import net.sf.saxon.om.Item; import net.sf.saxon.om.NamespaceResolver; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.Type; import net.sf.saxon.value.Whitespace; import javax.xml.transform.Source; import javax.xml.transform.stream.StreamSource; import java.io.File; /** * This class provide a native Saxon API for free-standing evaluation of XPath expressions. Unlike the * JAXP API offered by {@link net.sf.saxon.xpath.XPathEvaluator} it exposes Saxon classes and interfaces * and thus provides a more strongly-typed interface with greater control over the detailed behaviour. * * @author Michael H. Kay * @since 8.4 */ public class XPathEvaluator { private XPathStaticContext staticContext; private boolean stripSpace = false; /** * Default constructor. Creates an XPathEvaluator with a default configuration and name pool. * Note that any source documents used by an XPath expression under this XPathEvaluator must * be built using the {@link Configuration} that is implicitly created by this constructor, * which is accessible using the {@link #getConfiguration} method. */ public XPathEvaluator() { this(new Configuration()); } /** * Construct an XPathEvaluator with a specified configuration. * @param config the configuration to be used. If the XPathEvaluator is * to be used to run schema-aware XPath expressions this must be an instance * of {@link com.saxonica.validate.SchemaAwareConfiguration} */ public XPathEvaluator(Configuration config) { staticContext = new IndependentContext(config); } /** * Get the Configuration in use. * @return the Saxon configuration */ public Configuration getConfiguration() { return staticContext.getConfiguration(); } /** * Indicate whether all whitespace text nodes in source documents are to be * removed. This affects the action of the {@link #build} method, and of all * other methods that take a Source as input. * @param strip True if all whitespace text nodes are to be stripped from the source document, * false otherwise. The default if the method is not called is false. * @deprecated since 8.9. The preferred way to build a source document is to use * {@link Configuration#buildDocument} */ public void setStripSpace(boolean strip) { stripSpace = strip; } /** * Build a source document. *

    This method is retained for backwards compability. The preferred way to build a document * tree is to call the method {@link Configuration#buildDocument}

    * @param source a JAXP Source object. This may be any implementation of Source that Saxon recognizes: * not only the standard kinds of source such as StreamSource, SAXSource, and DOMSource, but also for * example a JDOM or XOM DocumentWrapper. For the way in which the source document is built, see * {@link net.sf.saxon.Configuration#buildDocument} * @return the NodeInfo representing the root of the constructed tree. * @throws XPathException if, for example, XML parsing fails. * @deprecated since 8.9. The preferred way to build a source document is to use * {@link Configuration#buildDocument} */ public NodeInfo build(Source source) throws XPathException { if (stripSpace) { AugmentedSource as = AugmentedSource.makeAugmentedSource(source); as.setStripSpace(Whitespace.ALL); source = as; } else if (source instanceof NodeInfo) { return (NodeInfo)source; } return getConfiguration().buildDocument(source); } /** * Declare a variable, making it available for use within a subsequently-compiled XPath expression. * The variable may subsequently be assigned a value using the method * {@link XPathDynamicContext#setVariable(XPathVariable, net.sf.saxon.om.ValueRepresentation)}. * Any external variable used in an XPath expression must be declared before the XPath expression * is compiled. * @param uri The namespace URI of the variable name. Use "" for the null namespace. * @param localName The local part of the variable name. * @return an object representing the variable */ public XPathVariable declareVariable(String uri, String localName) { return staticContext.declareVariable(uri, localName); } /** * Set the static context for compiling XPath expressions. This provides more detailed control over the * environment in which the expression is compiled, for example it allows namespace prefixes to * be declared, variables to be bound and functions to be defined. For most purposes, the static * context can be defined by providing and tailoring an instance of the {@link IndependentContext} class. * Until this method is called, a default static context is used, in which no namespaces are defined * other than the standard ones (xml, xslt, and saxon), and no variables or functions (other than the * core XPath functions) are available. * @param context the XPath static context *

    Setting a new static context clears any variables and namespaces that have previously been declared.

    */ public void setStaticContext(XPathStaticContext context) { staticContext = context; } /** * Get the current static context. This will always return a value; if no static context has been * supplied by the user, the system will have created its own. A system-created static context * will always be an instance of {@link IndependentContext} * @return the static context object */ public XPathStaticContext getStaticContext() { return staticContext; } /** * Get the executable * @return the executable. This holds details of function bindings and collations. */ public Executable getExecutable() { return staticContext.getExecutable(); } /** * Prepare (compile) an XPath expression for subsequent evaluation. * @param expression The XPath expression to be compiled, supplied as a string. * @return an XPathExpression object representing the prepared expression * @throws XPathException if the syntax of the expression is wrong, or if it references namespaces, * variables, or functions that have not been declared. */ public XPathExpression createExpression(String expression) throws XPathException { Expression exp = ExpressionTool.make(expression, staticContext, 0, -1, 1, false); exp.setContainer(staticContext); ExpressionVisitor visitor = ExpressionVisitor.make(staticContext); visitor.setExecutable(getExecutable()); exp = visitor.typeCheck(exp, Type.ITEM_TYPE); exp = visitor.optimize(exp, Type.ITEM_TYPE); SlotManager map = staticContext.getStackFrameMap(); int numberOfExternalVariables = map.getNumberOfVariables(); ExpressionTool.allocateSlots(exp, numberOfExternalVariables, map); XPathExpression xpe = new XPathExpression(this, exp); xpe.setStackFrameMap(map, numberOfExternalVariables); return xpe; } /** * Prepare (compile) an XSLT pattern for subsequent evaluation. The result is an XPathExpression * object representing a (pseudo-) expression that when evaluated returns a boolean result: true * if the context node matches the pattern, false if it does not. * @param pattern the XSLT pattern to be compiled, supplied as a string * @return an XPathExpression object representing the pattern, wrapped as an expression * @throws XPathException if the syntax of the expression is wrong, or if it references namespaces, * variables, or functions that have not been declared. * @since 9.1 */ public XPathExpression createPattern(String pattern) throws XPathException { Pattern pat = Pattern.make(pattern, staticContext, staticContext.getExecutable()); ExpressionVisitor visitor = ExpressionVisitor.make(staticContext); pat.analyze(visitor, Type.NODE_TYPE); SlotManager map = staticContext.getStackFrameMap(); int slots = map.getNumberOfVariables(); slots = pat.allocateSlots(staticContext, map, slots); PatternSponsor sponsor = new PatternSponsor(pat); XPathExpression xpe = new XPathExpression(this, sponsor); xpe.setStackFrameMap(map, slots); return xpe; } /** * Set the external namespace resolver to be used. The NamespaceResolver is stored * as part of the static context. It overrides any namespaces declared directly * using declareNamespace on the staticContext object * @param namespaceResolver The namespace resolver, which maintains a mapping of prefixes to URIs. * Any namespace prefix used in the XPath expression is resolved using this namespaceResolver. */ public void setNamespaceResolver(NamespaceResolver namespaceResolver) { staticContext.setNamespaceResolver(namespaceResolver); } /** * Get the external namespace resolver, if one has been set using {@link #setNamespaceResolver} * @return the namespace resolver supplied by the user if set, or a system-defined namespace resolver * otherwise. By default, the {@link IndependentContext} object used as the {@link XPathStaticContext} * also acts as the {@link NamespaceResolver}. */ public NamespaceResolver getNamespaceResolver() { return staticContext.getNamespaceResolver(); } /** * Set the default namespace for elements and types * @param uri The namespace to be used to qualify unprefixed element names and type names appearing * in the XPath expression. */ public void setDefaultElementNamespace(String uri) { staticContext.setDefaultElementNamespace(uri); } /** * For testing only */ public static void main(String[] args) throws Exception { XPathEvaluator xpe = new XPathEvaluator(); // XPathVariable in = xpe.declareVariable("", "in"); XPathExpression exp = xpe.createExpression( "for $v in distinct-values(tokenize($in, '/')) return concat(' +', $v)"); NodeInfo doc = xpe.getConfiguration().buildDocument(new StreamSource(new File(args[0]))); XPathDynamicContext context = exp.createDynamicContext(doc); //context.setVariable(in, new StringValue(args[1])); SequenceIterator results = exp.iterate(context); while (true) { Item item = results.next(); if (item == null) break; System.err.println(item); } // if (args.length != 2) { // System.err.println("format: java XPathEvaluator source.xml \"expression\""); // return; // } // XPathEvaluator xpe = new XPathEvaluator(); // XPathExpression exp = xpe.createExpression(args[1]); // List results = exp.evaluate(new StreamSource(new File(args[0]))); // for (int i = 0; i < results.size(); i++) { // Object o = results.get(i); // System.err.println(o); // } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/sxpath/IndependentContext.java0000644000175000017500000003164011033436435023366 0ustar eugeneeugenepackage net.sf.saxon.sxpath; import net.sf.saxon.Configuration; import net.sf.saxon.expr.Container; import net.sf.saxon.expr.VariableReference; import net.sf.saxon.instruct.SlotManager; import net.sf.saxon.om.*; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.Type; import net.sf.saxon.value.QNameValue; import java.io.Serializable; import java.util.*; /** * An IndependentContext provides a context for parsing an XPath expression appearing * in a context other than a stylesheet. * *

    This class is used in a number of places where freestanding XPath expressions occur. * These include the native Saxon XPath API, the .NET XPath API, XPath expressions used * in XML Schema identity constraints, and XPath expressions supplied to saxon:evaluate(). * It is not used by the JAXP XPath API (though it shares code with that API through * the common superclass AbstractStaticContext).

    * *

    This class currently provides no mechanism for binding user-defined functions.

    */ public class IndependentContext extends AbstractStaticContext implements XPathStaticContext, NamespaceResolver, Serializable, Container { private HashMap namespaces = new HashMap(10); private HashMap variables = new HashMap(20); private NamespaceResolver externalResolver = null; private Set importedSchemaNamespaces = new HashSet(); /** * Create an IndependentContext along with a new (non-schema-aware) Saxon Configuration */ public IndependentContext() { this(new Configuration()); } /** * Create an IndependentContext using a specific Configuration * @param config the Saxon configuration to be used */ public IndependentContext(Configuration config) { setConfiguration(config); clearNamespaces(); setDefaultFunctionLibrary(); } /** * Create a copy of this IndependentContext. All aspects of the context are copied * except for declared variables. * @return the new copy */ public IndependentContext copy() { IndependentContext ic = new IndependentContext(getConfiguration()); ic.setBaseURI(getBaseURI()); ic.setLocationMap(getLocationMap()); ic.setDefaultElementNamespace(getDefaultElementNamespace()); ic.setDefaultFunctionNamespace(getDefaultFunctionNamespace()); ic.namespaces = new HashMap(namespaces); ic.variables = new HashMap(10); ic.importedSchemaNamespaces = importedSchemaNamespaces; ic.externalResolver = externalResolver; return ic; } /** * Declare a namespace whose prefix can be used in expressions * @param prefix The namespace prefix. Must not be null. Supplying "" sets the * default element namespace. * @param uri The namespace URI. Must not be null. */ public void declareNamespace(String prefix, String uri) { if (prefix==null) { throw new NullPointerException("Null prefix supplied to declareNamespace()"); } if (uri==null) { throw new NullPointerException("Null namespace URI supplied to declareNamespace()"); } if ("".equals(prefix)) { setDefaultElementNamespace(uri); } else { namespaces.put(prefix, uri); getNamePool().allocateNamespaceCode(prefix, uri); } } /** * Clear all the declared namespaces, except for the standard ones (xml, xslt, saxon, xdt). * This also resets the default element namespace to the "null" namespace */ public void clearNamespaces() { namespaces.clear(); declareNamespace("xml", NamespaceConstant.XML); declareNamespace("xsl", NamespaceConstant.XSLT); declareNamespace("saxon", NamespaceConstant.SAXON); declareNamespace("xs", NamespaceConstant.SCHEMA); declareNamespace("", ""); } /** * Clear all the declared namespaces, including the standard ones (xml, xslt, saxon). * Leave only the XML namespace and the default namespace (xmlns=""). * This also resets the default element namespace to the "null" namespace. */ public void clearAllNamespaces() { namespaces.clear(); declareNamespace("xml", NamespaceConstant.XML); declareNamespace("", ""); } /** * Declares all the namespaces that are in-scope for a given node, removing all previous * namespace declarations. * In addition, the standard namespaces (xml, xslt, saxon) are declared. This method also * sets the default element namespace to be the same as the default namespace for this node. * @param node The node whose in-scope namespaces are to be used as the context namespaces. * If the node is an attribute, text node, etc, then the namespaces of its parent element are used. */ public void setNamespaces(NodeInfo node) { namespaces.clear(); int kind = node.getNodeKind(); if (kind == Type.ATTRIBUTE || kind == Type.TEXT || kind == Type.COMMENT || kind == Type.PROCESSING_INSTRUCTION || kind == Type.NAMESPACE) { node = node.getParent(); } if (node == null) { return; } AxisIterator iter = node.iterateAxis(Axis.NAMESPACE); while (true) { NodeInfo ns = (NodeInfo)iter.next(); if (ns == null) { return; } String prefix = ns.getLocalPart(); if ("".equals(prefix)) { setDefaultElementNamespace(ns.getStringValue()); } else { declareNamespace(ns.getLocalPart(), ns.getStringValue()); } } } /** * Set an external namespace resolver. If this is set, then all resolution of namespace * prefixes is delegated to the external namespace resolver, and namespaces declared * individually on this IndependentContext object are ignored. * @param resolver the external NamespaceResolver */ public void setNamespaceResolver(NamespaceResolver resolver) { externalResolver = resolver; } /** * Declare a variable. A variable must be declared before an expression referring * to it is compiled. The initial value of the variable will be the empty sequence * @param qname The name of the variable * @return an XPathVariable object representing information about the variable that has been * declared. */ public XPathVariable declareVariable(QNameValue qname) { return declareVariable(qname.getNamespaceURI(), qname.getLocalName()); } /** * Declare a variable. A variable must be declared before an expression referring * to it is compiled. The initial value of the variable will be the empty sequence * @param namespaceURI The namespace URI of the name of the variable. Supply "" to represent * names in no namespace (null is also accepted) * @param localName The local part of the name of the variable (an NCName) * @return an XPathVariable object representing information about the variable that has been * declared. */ public XPathVariable declareVariable(String namespaceURI, String localName) { XPathVariable var = XPathVariable.make(new StructuredQName("", namespaceURI, localName)); StructuredQName qName = var.getVariableQName(); int slot = variables.size(); var.setSlotNumber(slot); variables.put(qName, var); return var; } /** * Get the slot number allocated to a particular variable * @param qname the name of the variable * @return the slot number, or -1 if the variable has not been declared */ public int getSlotNumber(QNameValue qname) { StructuredQName sq = qname.toStructuredQName(); XPathVariable var = (XPathVariable)variables.get(sq); if (var == null) { return -1; } return var.getLocalSlotNumber(); } /** * Get the URI for a prefix, using the declared namespaces as * the context for namespace resolution. The default namespace is NOT used * when the prefix is empty. * This method is provided for use by the XPath parser. * @param prefix The prefix * @throws net.sf.saxon.trans.XPathException if the prefix is not declared */ public String getURIForPrefix(String prefix) throws XPathException { String uri = getURIForPrefix(prefix, false); if (uri==null) { throw new XPathException("Prefix " + prefix + " has not been declared"); } return uri; } public NamespaceResolver getNamespaceResolver() { if (externalResolver != null) { return externalResolver; } else { return this; } } /** * Get the namespace URI corresponding to a given prefix. Return null * if the prefix is not in scope. * @param prefix the namespace prefix * @param useDefault true if the default namespace is to be used when the * prefix is "" * @return the uri for the namespace, or null if the prefix is not in scope. * Return "" if the prefix maps to the null namespace. */ public String getURIForPrefix(String prefix, boolean useDefault) { if (externalResolver != null) { return externalResolver.getURIForPrefix(prefix, useDefault); } if (prefix.length() == 0) { return useDefault ? getDefaultElementNamespace() : ""; } else { return (String)namespaces.get(prefix); } } /** * Get an iterator over all the prefixes declared in this namespace context. This will include * the default namespace (prefix="") and the XML namespace where appropriate */ public Iterator iteratePrefixes() { if (externalResolver != null) { return externalResolver.iteratePrefixes(); } else { return namespaces.keySet().iterator(); } } /** * Bind a variable used in an XPath Expression to the XSLVariable element in which it is declared. * This method is provided for use by the XPath parser, and it should not be called by the user of * the API, or overridden, unless variables are to be declared using a mechanism other than the * declareVariable method of this class. * @param qName the name of the variable * @return the resulting variable reference */ public VariableReference bindVariable(StructuredQName qName) throws XPathException { XPathVariable var = (XPathVariable)variables.get(qName); if (var==null) { throw new XPathException("Undeclared variable in XPath expression: $" + qName.getClarkName()); } else { return new VariableReference(var); } } /** * Get a Stack Frame Map containing definitions of all the declared variables. This will return a newly * created object that the caller is free to modify by adding additional variables, without affecting * the static context itself. */ public SlotManager getStackFrameMap() { SlotManager map = getConfiguration().makeSlotManager(); XPathVariable[] va = new XPathVariable[variables.size()]; for (Iterator v = variables.values().iterator(); v.hasNext();) { XPathVariable var = (XPathVariable)v.next(); va[var.getLocalSlotNumber()] = var; } for (int i=0; iThis object is always created via the method * {@link net.sf.saxon.sxpath.XPathExpression#createDynamicContext(net.sf.saxon.om.Item)}

    */ public class XPathDynamicContext { private XPathContextMajor contextObject; private SlotManager stackFrameMap; protected XPathDynamicContext(XPathContextMajor contextObject, SlotManager stackFrameMap) { this.contextObject = contextObject; this.stackFrameMap = stackFrameMap; } /** * Set the context item to a node derived from a supplied Source object. This may be * any implementation of the Source interface recognized by Saxon. Note that the * Saxon {@link NodeInfo} interface, representing a node in a tree, is one such * implementation; others include {@link javax.xml.transform.stream.StreamSource}, * {@link javax.xml.transform.sax.SAXSource}, and {@link javax.xml.transform.dom.DOMSource} * * @param source The source object representing the node that will be used as the context item * @throws XPathException if a failure occurs reading or parsing a Source object to build an input tree, * or if the source is a document that was built under the wrong configuration */ public void setContextNode(Source source) throws XPathException { NodeInfo origin; if (source instanceof NodeInfo) { origin = (NodeInfo)source; if (!origin.getConfiguration().isCompatible(contextObject.getConfiguration())) { throw new XPathException( "Supplied node must be built using the same or a compatible Configuration", SaxonErrorCode.SXXP0004); } } else { origin = contextObject.getConfiguration().buildDocument(source); } setContextItem(origin); } /** * Set the context item for evaluation of the XPath Expression * @param item the context item * @throws XPathException if the node is in a document that was built under the wrong configuration */ public void setContextItem(Item item) throws XPathException { if (item instanceof NodeInfo) { if (!((NodeInfo)item).getConfiguration().isCompatible(contextObject.getConfiguration())) { throw new XPathException( "Supplied node must be built using the same or a compatible Configuration", SaxonErrorCode.SXXP0004); } } UnfailingIterator iter = SingletonIterator.makeIterator(item); iter.next(); contextObject.setCurrentIterator(iter); } /** * Get the context item * @return the context item if there is one, or null otherwise */ public Item getContextItem() { return contextObject.getContextItem(); } /** * Set the value of an external variable used within the XPath expression * @param variable the object representing the variable, as returned by the * {@link net.sf.saxon.sxpath.XPathEvaluator#declareVariable(String, String)} method. * Note that setting the value of a variable does not modify the {@link XPathVariable} * object itself, which means that this method is thread-safe. * @param value The value of the variable. * @throws XPathException if the supplied value does not conform to the required type of the * variable; or if the supplied value contains a node that does not belong to this Configuration * (or another Configuration that shares the same namePool) */ public void setVariable(XPathVariable variable, ValueRepresentation value) throws XPathException { SequenceType requiredType = variable.getRequiredType(); if (requiredType != SequenceType.ANY_SEQUENCE) { XPathException err = TypeChecker.testConformance(value, requiredType, contextObject); if (err != null) { throw err; } } SequenceIterator iter = Value.asIterator(value); while (true) { Item item = iter.next(); if (item == null) { break; } if (item instanceof NodeInfo) { if (!((NodeInfo)item).getConfiguration().isCompatible(contextObject.getConfiguration())) { throw new XPathException( "Supplied node must be built using the same or a compatible Configuration", SaxonErrorCode.SXXP0004); } } } int slot = variable.getLocalSlotNumber(); StructuredQName expectedName = (slot >= stackFrameMap.getNumberOfVariables() ? null : (StructuredQName)stackFrameMap.getVariableMap().get(slot)); if (!variable.getVariableQName().equals(expectedName)) { throw new XPathException( "Supplied XPathVariable is bound to the wrong slot: perhaps it was created using a different static context"); } contextObject.setLocalVariable(slot, value); } /** * For system use: get the wrapped XPathContext object * @return the underlying XPathContext object */ public XPathContext getXPathContextObject() { return contextObject; } /** * Check that all external variables have been given a value * @param stackFrameMap describes the stack frame * @param numberOfExternals the number of variables that need to be supplied * @throws XPathException if required variables have not been given a value */ protected void checkExternalVariables(SlotManager stackFrameMap, int numberOfExternals) throws XPathException { ValueRepresentation[] stack = contextObject.getStackFrame().getStackFrameValues(); for (int i=0; iA variable can be given a value by calling * {@link XPathDynamicContext#setVariable(XPathVariable, net.sf.saxon.om.ValueRepresentation)}. * Note that the value of the variable is not held in the XPathVariable object, but in the * XPathDynamicContext, which means that the XPathVariable itself can be used in multiple threads. */ public final class XPathVariable implements VariableDeclaration, Binding, Serializable { private StructuredQName name; private SequenceType requiredType = SequenceType.ANY_SEQUENCE; private int slotNumber; /** * Private constructor: for use only by the protected factory method make() */ private XPathVariable() {} /** * Factory method, for use by the declareVariable method of class IndependentContext * @param name the name of the variable to create * @return the constructed XPathVariable */ protected static XPathVariable make(StructuredQName name) { XPathVariable v = new XPathVariable(); v.name = name; return v; } /** * Ask whether the binding is local or global. A global binding is one that has a fixed * value for the life of a query or transformation; any other binding is local. An XPath * variable is treated as a local variable (largely because it is held on the stack frame) * @return false (always) */ public boolean isGlobal() { return false; } /** * Test whether it is permitted to assign to the variable using the saxon:assign * extension element. This will only be for an XSLT global variable where the extra * attribute saxon:assignable="yes" is present. * @return false (always) */ public final boolean isAssignable() { return false; } /** * Set the required type of this variable. If no required type is specified, * the type item()* is assumed. * @param requiredType the required type */ public void setRequiredType(SequenceType requiredType) { this.requiredType = requiredType; } /** * Get the required type of this variable. If no required type has been specified, * the type item()* is returned. * @return the required type of the variable */ public SequenceType getRequiredType() { return requiredType; } /** * Set the slot number allocated to this variable. This method is for internal use. * @param slotNumber the slot number to be allocated */ public void setSlotNumber(int slotNumber) { this.slotNumber = slotNumber; } /** * If this is a local variable held on the local stack frame, return the corresponding slot number. * In other cases, return -1. */ public int getLocalSlotNumber() { return slotNumber; } /** * Get the name of the variable as a QNameValue. * @return the name of the variable, as a QNameValue */ public StructuredQName getVariableQName() { return name; } /** * Method called by the XPath expression parser to register a reference to this variable. * This method should not be called by users of the API. */ public void registerReference(BindingReference ref) { ref.setStaticType(requiredType, null, 0); ref.fixup(this); } /** * Get the value of the variable. This method is used by the XPath execution engine * to retrieve the value. Note that the value is not held within the variable itself, * but within the dunamic context. * @param context The dynamic evaluation context * @return The value of the variable */ public ValueRepresentation evaluateVariable(XPathContext context) { return context.evaluateLocalVariable(slotNumber); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/sxpath/XPathStaticContext.java0000644000175000017500000001003411033112257023310 0ustar eugeneeugenepackage net.sf.saxon.sxpath; import net.sf.saxon.expr.Container; import net.sf.saxon.expr.StaticContext; import net.sf.saxon.instruct.Executable; import net.sf.saxon.instruct.SlotManager; import net.sf.saxon.om.NamespaceResolver; import net.sf.saxon.value.QNameValue; /** * This interface defines methods that must be provided when Saxon's free-standing XPath API is used. * The default implementation of this interface is {@link net.sf.saxon.sxpath.IndependentContext}, and * that implementation should be adequate for most purposes; but for extra customization, a user-written * implementation of this interface may be used instead. */ public interface XPathStaticContext extends StaticContext, Container { /** * Get the executable associated with this static context. The Executable generally holds details * of function libraries and collations. For freestanding XPath expressions, there will generally * be a single executable corresponding one-to-one with the static context object, and which can be * created as soon as the Configuration is known. * @return the Executable */ public Executable getExecutable(); /** * Set the default namespace for elements and types * @param uri The namespace to be used to qualify unprefixed element names and type names appearing * in the XPath expression. */ public void setDefaultElementNamespace(String uri); /** * Set an external namespace resolver. If this is set, then all resolution of namespace * prefixes is delegated to the external namespace resolver, and namespaces declared * individually on this IndependentContext object are ignored. * @param resolver the external namespace resolver */ public void setNamespaceResolver(NamespaceResolver resolver); /** * Declare a variable. A variable must be declared before an expression referring * to it is compiled. The initial value of the variable will be the empty sequence. * This method backs up the {@link XPathEvaluator#declareVariable} method. * @param qname The name of the variable * @return a Variable object representing information about the variable that has been * declared. */ public XPathVariable declareVariable(QNameValue qname); /** * Declare a variable. A variable must be declared before an expression referring * to it is compiled. The initial value of the variable will be the empty sequence. * This method backs up the {@link XPathEvaluator#declareVariable} method. * @param namespaceURI The namespace URI of the name of the variable. Supply "" to represent * names in no namespace (null is also accepted) * @param localName The local part of the name of the variable (an NCName) * @return an XPathVariable object representing information about the variable that has been * declared. */ public XPathVariable declareVariable(String namespaceURI, String localName); /** * Get a Stack Frame Map containing definitions of all the declared variables. This will return a newly * created object that the caller is free to modify by adding additional variables, without affecting * the static context itself. * @return a SlotManager object holding details of the allocation of variables on the stack frame. */ public SlotManager getStackFrameMap(); } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/sxpath/package.html0000644000175000017500000000266711033112257021202 0ustar eugeneeugene Package overview for net.sf.saxon.sxpath

    This package provides an alternative API for executing XPath expressions directly from a Java application: unlike the API in package net.sf.saxon.xpath, these interfaces are not dependent on JAXP 1.3. The API can be used either in a free-standing Java application (that is, where there is no XSLT stylesheet), or it can be used from within Java extension functions called from XPath expressions within a stylesheet.

    If you have JDK 1.5 installed, you should probably be using the standard XPath API defined in JAXP 1.3, which is available in package net.sf.saxon.xpath, distributed in a separate JAR file saxon8-xpath.jar. This interface is provided for use it situations where installing JAXP 1.3 is inconvenient. It provides less functionality than the JAXP API, for example it does not allow XPath expressions to reference variables or functions, and it gives no control over the result type of the expression (you can control this by including casts or conversion functions within the expression itself).

    The method XPathEvaluator.build(Source) is probably the most convenient way of building a Saxon tree, and can be used quite independently of the XPath API.

    Michael H. Kay
    Saxonica Limited
    9 February 2005

    saxonb-9.1.0.8/bj/net/sf/saxon/tree/0000755000175000017500000000000012216261747016353 5ustar eugeneeugenesaxonb-9.1.0.8/bj/net/sf/saxon/tree/AttributeImpl.java0000644000175000017500000002503011033112257021766 0ustar eugeneeugenepackage net.sf.saxon.tree; import net.sf.saxon.event.Receiver; import net.sf.saxon.om.*; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.Type; import net.sf.saxon.type.TypeHierarchy; /** * A node in the "linked" tree representing an attribute. Note that this is * generated only "on demand", when the attribute is selected by a path expression.

    * @author Michael H. Kay */ final class AttributeImpl extends NodeImpl { private int nameCode; private int typeCode; private String value; /** * Construct an Attribute node for the n'th attribute of a given element * @param element The element containing the relevant attribute * @param index The index position of the attribute starting at zero */ public AttributeImpl(ElementImpl element, int index) { parent = element; this.index = index; AttributeCollection atts = element.getAttributeList(); this.nameCode = atts.getNameCode(index); this.value = atts.getValue(index); this.typeCode = atts.getTypeAnnotation(index); } /** * Get the name code, which enables the name to be located in the name pool */ public int getNameCode() { return nameCode; } /** * Get the type annotation of this node, if any */ public int getTypeAnnotation() { return typeCode; } /** * Determine whether this node has the is-id property * @return true if the node is an ID */ public boolean isId() { if (getFingerprint() == StandardNames.XML_ID) { return true; } TypeHierarchy th = getConfiguration().getTypeHierarchy(); return th.isIdCode(typeCode); } /** * Determine whether this node has the is-idref property * @return true if the node is an IDREF or IDREFS element or attribute */ public boolean isIdref() { TypeHierarchy th = getConfiguration().getTypeHierarchy(); return th.isIdrefsCode(typeCode); } /** * Determine whether the node has the is-nilled property * @return true if the node has the is-nilled property */ public boolean isNilled() { return false; } /** * Determine whether this is the same node as another node * @return true if this Node object and the supplied Node object represent the * same node in the tree. */ public boolean isSameNodeInfo(NodeInfo other) { if (!(other instanceof AttributeImpl)) return false; if (this==other) return true; AttributeImpl otherAtt = (AttributeImpl)other; return (parent.isSameNodeInfo(otherAtt.parent) && ((nameCode&0xfffff)==(otherAtt.nameCode&0xfffff))); } /** * The hashCode() method obeys the contract for hashCode(): that is, if two objects are equal * (represent the same node) then they must have the same hashCode() * @since 8.7 Previously, the effect of the equals() and hashCode() methods was not defined. Callers * should therefore be aware that third party implementations of the NodeInfo interface may * not implement the correct semantics. */ public int hashCode() { return parent.hashCode() ^ getFingerprint(); } /** * Get the node sequence number (in document order). Sequence numbers are monotonic but not * consecutive. In the current implementation, parent nodes (elements and roots) have a zero * least-significant word, while namespaces, attributes, text nodes, comments, and PIs have * the top word the same as their owner and the bottom half reflecting their relative position. */ protected long getSequenceNumber() { long parseq = parent.getSequenceNumber(); return (parseq == -1L ? parseq : parseq + 0x8000 + index); // note the 0x8000 is to leave room for namespace nodes } /** * Return the type of node. * @return Node.ATTRIBUTE */ public final int getNodeKind() { return Type.ATTRIBUTE; } /** * Return the character value of the node. * @return the attribute value */ public String getStringValue() { return value; } /** * Get next sibling - not defined for attributes */ public NodeInfo getNextSibling() { return null; } /** * Get previous sibling - not defined for attributes */ public NodeInfo getPreviousSibling() { return null; } /** * Get the previous node in document order (skipping attributes) */ public NodeImpl getPreviousInDocument() { return (NodeImpl)getParent(); } /** * Get the next node in document order (skipping attributes) */ public NodeImpl getNextInDocument(NodeImpl anchor) { if (anchor==this) return null; return ((NodeImpl)getParent()).getNextInDocument(anchor); } /** * Get sequential key. Returns key of owning element with the attribute index as a suffix * @param buffer a buffer to which the generated ID will be written */ public void generateId(FastStringBuffer buffer) { getParent().generateId(buffer); buffer.append('a'); buffer.append(Integer.toString(index)); } /** * Copy this node to a given outputter */ public void copy(Receiver out, int whichNamespaces, boolean copyAnnotations, int locationId) throws XPathException { int nameCode = getNameCode(); int typeCode = (copyAnnotations ? getTypeAnnotation() : -1); out.attribute(nameCode, typeCode, getStringValue(), locationId, 0); } /** * Delete this node (that is, detach it from its parent) */ public void delete() { if (parent != null) { ((ElementImpl)parent).removeAttribute(getNameCode()); } parent = null; // TODO: allow for the fact that transiently during an update operation, several attributes may have the same // name. } /** * Replace this node with a given sequence of nodes * @param replacement the replacement nodes (which for this version of the method mut be attribute * nodes). The target attribute node is deleted, and the replacement nodes are added to the * parent element; if they have the same names as existing nodes, then the existing nodes will be * overwritten. * @param inherit set to true if new child elements are to inherit the in-scope namespaces * of their new parent. Not used when replacing attribute nodes. * @throws IllegalArgumentException if any of the replacement nodes is not an attribute */ public void replace(NodeInfo[] replacement, boolean inherit) { ParentNodeImpl element = parent; delete(); for (int i=0; i>20) != 0) { // new attribute name is in a namespace int nscode = getNamePool().getNamespaceCode(newNameCode); int prefixCode = nscode>>16 & 0xffff; short uc = ((ElementImpl)parent).getURICodeForPrefixCode(prefixCode); if (uc == -1) { parent.addNamespace(nscode, false); } else if (uc != (nscode&0xffff)) { throw new IllegalArgumentException( "Namespace binding of new name conflicts with existing namespace binding"); } } } nameCode = newNameCode; } public void replaceStringValue(CharSequence stringValue) { value = stringValue.toString(); // The attribute node itself is transient; we need to update the attribute collection held in the parent if (parent != null) { AttributeCollectionImpl atts = (AttributeCollectionImpl)((ElementImpl)parent).getAttributeList(); atts.replaceAttribute(nameCode, stringValue); } } /** * Remove type information from this node (and its ancestors, recursively). * This method implements the upd:removeType() primitive defined in the XQuery Update specification * */ public void removeTypeAnnotation() { typeCode = StandardNames.XS_UNTYPED_ATOMIC; if (parent != null) { AttributeCollectionImpl atts = (AttributeCollectionImpl)((ElementImpl)parent).getAttributeList(); atts.setTypeAnnotation(nameCode, StandardNames.XS_UNTYPED_ATOMIC); parent.removeTypeAnnotation(); } } /** * Set the type annotation on a node. This must only be called when the caller has verified (by validation) * that the node is a valid instance of the specified type. The call is ignored if the node is not an element * or attribute node. * * @param typeCode the type annotation (possibly including high bits set to indicate the isID, isIDREF, and * isNilled properties) */ public void setTypeAnnotation(int typeCode) { this.typeCode = typeCode; if (parent != null) { AttributeCollectionImpl atts = (AttributeCollectionImpl)((ElementImpl)parent).getAttributeList(); atts.setTypeAnnotation(nameCode, typeCode); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/tree/ProcInstImpl.java0000644000175000017500000001026211033112257021565 0ustar eugeneeugenepackage net.sf.saxon.tree; import net.sf.saxon.event.Receiver; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.Type; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.om.SingletonIterator; import net.sf.saxon.value.StringValue; import net.sf.saxon.value.Value; /** * ProcInstImpl is an implementation of ProcInstInfo used by the Propagator to construct * its trees. * @author Michael H. Kay */ class ProcInstImpl extends NodeImpl { String content; int nameCode; String systemId; int lineNumber = -1; public ProcInstImpl(int nameCode, String content) { this.nameCode = nameCode; this.content = content; } /** * Get the nameCode of the node. This is used to locate the name in the NamePool */ public int getNameCode() { return nameCode; } public String getStringValue() { return content; } /** * Get the typed value of this node. * Returns the string value, as an instance of xs:string */ public SequenceIterator getTypedValue() { return SingletonIterator.makeIterator(new StringValue(getStringValue())); } /** * Get the typed value of this node. * Returns the string value, as an instance of xs:string */ public Value atomize() { return new StringValue(getStringValue()); } public final int getNodeKind() { return Type.PROCESSING_INSTRUCTION; } /** * Set the system ID and line number * @param uri the system identifier * @param lineNumber the line number */ public void setLocation(String uri, int lineNumber) { this.systemId = uri; this.lineNumber = lineNumber; } /** * Get the system ID for the entity containing this node. * @return the system identifier */ public String getSystemId() { return systemId; } /** * Get the line number of the node within its source entity */ public int getLineNumber() { return lineNumber; } /** * Copy this node to a given outputter */ public void copy(Receiver out, int whichNamespaces, boolean copyAnnotations, int locationId) throws XPathException { out.processingInstruction(getLocalPart(), content, locationId, 0); } // DOM methods /** * The target of this processing instruction. XML defines this as being * the first token following the markup that begins the processing * instruction. * @return the processing instruction name */ public String getTarget() { return getLocalPart(); } /** * The content of this processing instruction. This is from the first non * white space character after the target to the character immediately * preceding the ?> . * @return the string value of the processing instruction node */ public String getData() { return content; } /** * Rename this node * * @param newNameCode the NamePool code of the new name */ public void rename(int newNameCode) { nameCode = newNameCode; } /** * Replace the string-value of this node * * @param stringValue the new string value */ public void replaceStringValue(CharSequence stringValue) { content = stringValue.toString(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/tree/FollowingSiblingEnumeration.java0000644000175000017500000000246511033112257024667 0ustar eugeneeugenepackage net.sf.saxon.tree; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.pattern.NodeTest; final class FollowingSiblingEnumeration extends TreeEnumeration { public FollowingSiblingEnumeration(NodeImpl node, NodeTest nodeTest) { super(node, nodeTest); advance(); } protected void step() { next = (NodeImpl)next.getNextSibling(); } /** * Get another enumeration of the same nodes */ public SequenceIterator getAnother() { return new FollowingSiblingEnumeration(start, nodeTest); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/tree/ElementImpl.java0000644000175000017500000007010211157427346021433 0ustar eugeneeugenepackage net.sf.saxon.tree; import net.sf.saxon.event.CopyInformee; import net.sf.saxon.event.Receiver; import net.sf.saxon.event.ReceiverOptions; import net.sf.saxon.om.*; import net.sf.saxon.pattern.NodeKindTest; import net.sf.saxon.sort.IntArraySet; import net.sf.saxon.sort.IntHashSet; import net.sf.saxon.sort.IntIterator; import net.sf.saxon.sort.IntSet; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.Type; import net.sf.saxon.value.Whitespace; import java.util.Iterator; /** * ElementImpl implements an element with no attributes or namespace declarations.

    * This class is an implementation of NodeInfo. For elements with attributes or * namespace declarations, class ElementWithAttributes is used. * @author Michael H. Kay */ public class ElementImpl extends ParentNodeImpl implements NamespaceResolver { private static final AttributeCollectionImpl emptyAtts = new AttributeCollectionImpl(null); protected int nameCode; protected int typeCode; protected AttributeCollection attributeList; // this excludes namespace attributes protected int[] namespaceList = null; // list of namespace codes /** * Construct an empty ElementImpl */ public ElementImpl() {} /** * Set the name code. Used when creating a dummy element in the Stripper * @param nameCode the integer name code representing the element name */ public void setNameCode(int nameCode) { this.nameCode = nameCode; } /** * Initialise a new ElementImpl with an element name * @param nameCode Integer representing the element name, with namespaces resolved * @param typeCode Integer representing the schema type of the element node * @param atts The attribute list: always null * @param parent The parent node * @param sequenceNumber Integer identifying this element within the document */ public void initialise(int nameCode, int typeCode, AttributeCollectionImpl atts, NodeInfo parent, int sequenceNumber) { this.nameCode = nameCode; this.typeCode = (typeCode == -1 ? StandardNames.XS_UNTYPED : typeCode); this.parent = (ParentNodeImpl)parent; sequence = sequenceNumber; attributeList = atts; } /** * Set location information for this node * @param systemId the base URI * @param line the line number if known * @param column the column number if known */ public void setLocation(String systemId, int line, int column) { DocumentImpl root = parent.getPhysicalRoot(); root.setLineAndColumn(sequence, line, column); root.setSystemId(sequence, systemId); } /** * Set the system ID of this node. This method is provided so that a NodeInfo * implements the javax.xml.transform.Source interface, allowing a node to be * used directly as the Source of a transformation */ public void setSystemId(String uri) { getPhysicalRoot().setSystemId(sequence, uri); } /** * Get the root node */ public NodeInfo getRoot() { ParentNodeImpl up = parent; if (up == null || (up instanceof DocumentImpl && ((DocumentImpl)up).isImaginary())) { return this; } else { return up.getRoot(); } } /** * Get the root node, if it is a document node. * * @return the DocumentInfo representing the containing document. If this * node is part of a tree that does not have a document node as its * root, returns null. * @since 8.4 */ public DocumentInfo getDocumentRoot() { NodeInfo root = getRoot(); if (root instanceof DocumentInfo) { return (DocumentInfo)root; } else { return null; } } /** * Get the system ID of the entity containing this element node. */ public final String getSystemId() { DocumentImpl root = getPhysicalRoot(); return (root == null ? null : root.getSystemId(sequence)); } /** * Get the base URI of this element node. This will be the same as the System ID unless * xml:base has been used. */ public String getBaseURI() { return Navigator.getBaseURI(this); } /** * Determine whether the node has the is-nilled property * * @return true if the node has the is-nilled property */ public boolean isNilled() { return (typeCode & NodeInfo.IS_NILLED) != 0; } /** * Set the type annotation on a node. This must only be called when the caller has verified (by validation) * that the node is a valid instance of the specified type. The call is ignored if the node is not an element * or attribute node. * * @param typeCode the type annotation (possibly including high bits set to indicate the isID, isIDREF, and * isNilled properties) */ public void setTypeAnnotation(int typeCode) { if (typeCode == -1) { typeCode = StandardNames.XS_UNTYPED; } this.typeCode = typeCode; } /** * Get the type annotation of this node, if any * @return the type annotation, as the integer name code of the type name */ public int getTypeAnnotation() { return typeCode & NamePool.FP_MASK; } /** * Set the line number of the element within its source document entity * @param line the line number * @param column the column number */ public void setLineAndColumn(int line, int column) { DocumentImpl root = getPhysicalRoot(); if (root != null) { root.setLineAndColumn(sequence, line, column); } } /** * Get the line number of the node within its source document entity */ public int getLineNumber() { DocumentImpl root = getPhysicalRoot(); if (root == null) { return -1; } else { return root.getLineNumber(sequence); } } /** * Get the line number of the node within its source document entity */ public int getColumnNumber() { DocumentImpl root = getPhysicalRoot(); if (root == null) { return -1; } else { return root.getColumnNumber(sequence); } } /** * Get the nameCode of the node. This is used to locate the name in the NamePool */ public int getNameCode() { return nameCode; } /** * Get a character string that uniquely identifies this node * @param buffer to contain the generated ID */ public void generateId(FastStringBuffer buffer) { if (sequence >= 0) { getPhysicalRoot().generateId(buffer); buffer.append("e"); buffer.append(Integer.toString(sequence)); } else { parent.generateId(buffer); buffer.append("f"); buffer.append(Integer.toString(index)); } } /** * Return the kind of node. * @return Type.ELEMENT */ public final int getNodeKind() { return Type.ELEMENT; } /** * Copy this node to a given outputter (supporting xsl:copy-of) * @param out The outputter * @param whichNamespaces indicates which namespaces should be output: all, none, or local * namespaces only (those not declared on the parent element) */ public void copy(Receiver out, int whichNamespaces, boolean copyAnnotations, int locationId) throws XPathException { int typeCode = (copyAnnotations ? getTypeAnnotation() : StandardNames.XS_UNTYPED); if (locationId == 0 && out instanceof CopyInformee) { ((CopyInformee)out).notifyElementNode(this); } out.startElement(getNameCode(), typeCode, locationId, 0); // output the namespaces switch (whichNamespaces) { case NodeInfo.NO_NAMESPACES: break; case NodeInfo.LOCAL_NAMESPACES: int[] localNamespaces = getDeclaredNamespaces(null); for (int i=0; i>16 & 0xffff; short uc = getURICodeForPrefixCode(prefixCode); if (uc == -1) { addNamespace(nscode, false); } else if (uc != (nscode&0xffff)) { throw new IllegalArgumentException( "Namespace binding of new name conflicts with existing namespace binding"); } } /** * Add a namespace binding (that is, a namespace node) to this element. This call has no effect if applied * to a node other than an element. * @param nscode The namespace code representing the (prefix, uri) pair of the namespace binding to be * added. If the target element already has a namespace binding with this (prefix, uri) pair, the call has * no effect. If the target element currently has a namespace binding with this prefix and a different URI, an * exception is raised. * @param inherit If true, the new namespace binding will be inherited by any children of the target element * that do not already have a namespace binding for the specified prefix, recursively. * If false, the new namespace binding will not be inherited. * @throws IllegalArgumentException if the target element already has a namespace binding for this prefix, * or if the namespace code represents a namespace undeclaration */ public void addNamespace(int nscode, boolean inherit) { if ((nscode&0xffff) == 0) { throw new IllegalArgumentException("Cannot add a namespace undeclaration"); } addNamespaceInternal(nscode, true); // The data model is such that namespaces are inherited by default. If inheritance is NOT requested, // we must process the children to add namespace undeclarations if (hasChildNodes() && !inherit) { int undecl = nscode & 0xffff0000; AxisIterator kids = enumerateChildren(NodeKindTest.ELEMENT); while (true) { ElementImpl child = (ElementImpl)kids.next(); if (child == null) { break; } child.addNamespaceInternal(undecl, false); } } } private void addNamespaceInternal(int nscode, boolean externalCall) { if (namespaceList == null) { namespaceList = new int[]{nscode}; } else { for (int i=0; i *

    If this node is not an element, or if the supplied node is not an attribute, the method * takes no action. If the element already has an attribute with this name, the existing attribute * is replaced.

    * * @param nameCode the name of the new attribute * @param typeCode the type annotation of the new attribute * @param value the string value of the new attribute * @param properties properties including IS_ID and IS_IDREF properties */ public void putAttribute(int nameCode, int typeCode, CharSequence value, int properties) { if (attributeList == null || attributeList.getLength() == 0) { attributeList = new AttributeCollectionImpl(getConfiguration()); } AttributeCollectionImpl atts = (AttributeCollectionImpl)attributeList; int index = atts.getIndexByFingerprint(nameCode & NamePool.FP_MASK); if (index == -1) { atts.addAttribute(nameCode, typeCode, value.toString(), 0, 0); } else { if (atts.isId(index)) { DocumentImpl root = getPhysicalRoot(); root.deregisterID(atts.getValue(index)); } atts.setAttribute(index, nameCode, typeCode, value.toString(), 0, 0); } if ((properties & ReceiverOptions.IS_ID) != 0) { DocumentImpl root = getPhysicalRoot(); if (root != null) { root.registerID(this, Whitespace.trim(value)); } } } /** * Remove an attribute from this element node * @param nameCode the name of the attribute to be removed */ public void removeAttribute(int nameCode) { AttributeCollectionImpl atts = (AttributeCollectionImpl)getAttributeList(); int fp = nameCode & NamePool.FP_MASK; int index = atts.getIndexByFingerprint(fp); if (index >= 0 && atts.isId(index)) { DocumentImpl root = getPhysicalRoot(); root.deregisterID(atts.getValue(index)); } atts.removeAttribute(fp); } /** * Remove type information from this node (and its ancestors, recursively). * This method implements the upd:removeType() primitive defined in the XQuery Update specification * */ public void removeTypeAnnotation() { int t = getTypeAnnotation(); if (t != StandardNames.XS_UNTYPED) { typeCode = StandardNames.XS_ANY_TYPE; parent.removeTypeAnnotation(); } } /** * Set the namespace declarations for the element * @param namespaces the list of namespace codes * @param namespacesUsed the number of entries in the list that are used */ public void setNamespaceDeclarations(int[] namespaces, int namespacesUsed) { namespaceList = new int[namespacesUsed]; System.arraycopy(namespaces, 0, namespaceList, 0, namespacesUsed); } /** * Get the namespace URI corresponding to a given prefix. Return null * if the prefix is not in scope. * * @param prefix the namespace prefix. May be the zero-length string, indicating * that there is no prefix. This indicates either the default namespace or the * null namespace, depending on the value of useDefault. * @param useDefault true if the default namespace is to be used when the * prefix is "". If false, the method returns "" when the prefix is "". * @return the uri for the namespace, or null if the prefix is not in scope. * The "null namespace" is represented by the pseudo-URI "". */ public String getURIForPrefix(String prefix, boolean useDefault) { if (prefix.equals("xml")) { return NamespaceConstant.XML; } if (prefix.length() == 0 && !useDefault) { return ""; } NamePool pool = getNamePool(); int prefixCode = pool.getCodeForPrefix(prefix); if (prefixCode==-1) { return null; } short uriCode = getURICodeForPrefixCode(prefixCode); if (uriCode == -1) { return null; } return pool.getURIFromURICode(uriCode); } /** * Get an iterator over all the prefixes declared in this namespace context. This will include * the default namespace (prefix="") and the XML namespace where appropriate */ public Iterator iteratePrefixes() { return new Iterator() { private NamePool pool = null; private IntIterator iter = NamespaceCodeIterator.iterateNamespaces(ElementImpl.this); public boolean hasNext() { return (pool == null || iter.hasNext()); } public Object next() { if (pool == null) { pool = getNamePool(); return "xml"; } else { return pool.getPrefixFromNamespaceCode(iter.next()); } } public void remove() { throw new UnsupportedOperationException("remove"); } }; } /** * Search the NamespaceList for a given prefix, returning the corresponding URI. * @param prefix The prefix to be matched. To find the default namespace, supply "" * @return The URI code corresponding to this namespace. If it is an unnamed default namespace, * return Namespace.NULL_CODE. * @throws net.sf.saxon.om.NamespaceException if the prefix has not been declared on this NamespaceList. */ public short getURICodeForPrefix(String prefix) throws NamespaceException { if (prefix.equals("xml")) return NamespaceConstant.XML_CODE; NamePool pool = getNamePool(); int prefixCode = pool.getCodeForPrefix(prefix); if (prefixCode==-1) { throw new NamespaceException(prefix); } short uc = getURICodeForPrefixCode(prefixCode); if (uc == -1) { throw new NamespaceException(getNamePool().getPrefixFromNamespaceCode(prefixCode<<16)); } return uc; } /** * Get the URI bound to a given prefix in the in-scope namespaces of this element * @param prefixCode the prefix code as a 16-bit integer * @return the uri code as a 16-bit integer, or -1 if there is no in-scope binding for this prefix */ protected short getURICodeForPrefixCode(int prefixCode) { if (namespaceList!=null) { for (int i=0; i>16) == prefixCode) { short u = (short)(namespaceList[i] & 0xffff); return (u==0 && prefixCode!=0 ? (short)-1 : u); } } } NodeInfo next = parent; if (next.getNodeKind()==Type.DOCUMENT) { // prefixCode==0 represents the empty namespace prefix "" if (prefixCode==0) { return NamespaceConstant.NULL_CODE; } return -1; } else { return ((ElementImpl)next).getURICodeForPrefixCode(prefixCode); } } /** * Search the NamespaceList for a given URI, returning the corresponding prefix. * @param uri The URI to be matched. * @return The prefix corresponding to this URI. If not found, return null. If there is * more than one prefix matching the URI, the first one found is returned. If the URI matches * the default namespace, return an empty string. */ public String getPrefixForURI(String uri) { if (uri.equals(NamespaceConstant.XML)) return "xml"; NamePool pool = getNamePool(); int uriCode = pool.getCodeForURI(uri); if (uriCode<0) return null; return getPrefixForURICode(uriCode); } private String getPrefixForURICode(int code) { if (namespaceList!=null) { for (int i=0; i *

    For a node other than an element, the method returns null.

    */ public int[] getDeclaredNamespaces(int[] buffer) { return (namespaceList == null ? IntArraySet.EMPTY_INT_ARRAY : namespaceList); } /** * Get the list of in-scope namespaces for this element as an array of * namespace codes. (Used by LiteralResultElement) * @return the list of namespaces */ public int[] getInScopeNamespaceCodes() { return NamespaceIterator.getInScopeNamespaceCodes(this); } /** * Ensure that a child element being inserted into a tree has the right namespace declarations. * Redundant declarations should be removed. If the child is in the null namespace but the parent has a default * namespace, xmlns="" should be added. If inherit is false, namespace undeclarations should be added for all * namespaces that are declared on the parent but not on the child. * @param inherit true if the child is to inherit the inscope namespaces of its new parent */ protected void fixupInsertedNamespaces(boolean inherit) { if (parent.getNodeKind() == Type.DOCUMENT) { return; } IntSet childNamespaces = new IntHashSet(); if (namespaceList != null) { for (int i=0; i * A Factory for nodes used to build a tree.
    * Currently only allows Element nodes to be user-constructed. * @author Michael H. Kay * @version 25 February 2000 */ public interface NodeFactory { /** * Create an Element node * @param parent The parent element * @param nameCode The element name * @param typeCode * @param attlist The attribute collection, excluding any namespace attributes * @param namespaces List of new namespace declarations for this element, as a sequence * of namespace codes representing pairs of strings: (prefix1, uri1), (prefix2, uri2)... * @param namespacesUsed the number of elemnts of the namespaces array actually used * @param locator Indicates the source document and line number containing the node * @param locationId Indicates the source document and line number containing the node * @param sequenceNumber Sequence number to be assigned to represent document order. */ public ElementImpl makeElementNode( NodeInfo parent, int nameCode, int typeCode, AttributeCollectionImpl attlist, int[] namespaces, int namespacesUsed, LocationProvider locator, int locationId, int sequenceNumber); } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/tree/AttributeEnumeration.java0000644000175000017500000001053511033112257023357 0ustar eugeneeugenepackage net.sf.saxon.tree; import net.sf.saxon.om.*; import net.sf.saxon.pattern.NameTest; import net.sf.saxon.pattern.NodeTest; import net.sf.saxon.type.Type; /** * AttributeEnumeration is an enumeration of all the attribute nodes of an Element. */ final class AttributeEnumeration extends AxisIteratorImpl implements LookaheadIterator { private ElementImpl element; private NodeTest nodeTest; private NodeInfo next; private int index; private int length; /** * Constructor * @param node: the element whose attributes are required. This may be any type of node, * but if it is not an element the enumeration will be empty * @param nodeTest: condition to be applied to the names of the attributes selected */ public AttributeEnumeration(NodeImpl node, NodeTest nodeTest) { this.nodeTest = nodeTest; if (node.getNodeKind()==Type.ELEMENT) { element = (ElementImpl)node; AttributeCollection attlist = element.getAttributeList(); index = 0; if (nodeTest instanceof NameTest) { NameTest test = (NameTest)nodeTest; index = attlist.getIndexByFingerprint(test.getFingerprint()); if (index<0) { next = null; } else { next = new AttributeImpl(element, index); index = 0; length = 0; // force iteration to select one node only } } else { index = 0; length = attlist.getLength(); advance(); } } else { // if it's not an element, or if we're not looking for attributes, // then there's nothing to find next = null; index = 0; length = 0; } } /** * Test if there are mode nodes still to come. * ("elements" is used here in the sense of the Java enumeration class, not in the XML sense) */ public boolean hasNext() { return next != null; } /** * Get the next node in the iteration, or null if there are no more. */ public Item next() { if (next == null) { current = null; position = -1; return null; } else { current = next; position++; advance(); return current; } } /** * Move to the next node in the enumeration. */ private void advance() { do { if (index1 child protected int sequence; // sequence number allocated during original tree creation. // set to -1 for nodes added subsequently by XQuery update /** * Get the node sequence number (in document order). Sequence numbers are monotonic but not * consecutive. In the current implementation, parent nodes (elements and document nodes) have a zero * least-significant word, while namespaces, attributes, text nodes, comments, and PIs have * the top word the same as their owner and the bottom half reflecting their relative position. * For nodes added by XQUery Update, the sequence number is -1L * @return the sequence number if there is one, or -1L otherwise. */ protected final long getSequenceNumber() { return (sequence == -1 ? -1L : ((long)sequence)<<32); } /** * Determine if the node has any children. */ public final boolean hasChildNodes() { return (children!=null); } /** * Determine how many children the node has * @return the number of children of this parent node */ public int getNumberOfChildren() { if (children == null) { return 0; } else if (children instanceof NodeImpl) { return 1; } else { return ((NodeInfo[])children).length; } } /** * Get an enumeration of the children of this node * @param test A NodeTest to be satisfied by the child nodes, or null * if all child node are to be returned * @return an iterator over the children of this node */ protected final AxisIterator enumerateChildren(NodeTest test) { if (children==null) { return EmptyIterator.getInstance(); } else if (children instanceof NodeImpl) { NodeImpl child = (NodeImpl)children; if (test == null || test instanceof AnyNodeTest) { return SingleNodeIterator.makeIterator(child); } else { return Navigator.filteredSingleton(child, test); } } else { if (test == null || test instanceof AnyNodeTest) { return new NodeArrayIterator((NodeImpl[])children); } else { return new ChildEnumeration(this, test); } } } /** * Get the first child node of the element * @return the first child node of the required type, or null if there are no children */ public final NodeInfo getFirstChild() { if (children==null) return null; if (children instanceof NodeImpl) return (NodeImpl)children; return ((NodeImpl[])children)[0]; } /** * Get the last child node of the element * @return the last child of the element, or null if there are no children */ public final NodeInfo getLastChild() { if (children==null) return null; if (children instanceof NodeImpl) return (NodeImpl)children; NodeImpl[] n = (NodeImpl[])children; return n[n.length-1]; } /** * Get the nth child node of the element (numbering from 0) * @param n identifies the required child * @return the last child of the element, or null if there is no n'th child */ protected final NodeImpl getNthChild(int n) { if (children==null) return null; if (children instanceof NodeImpl) { return (n==0 ? (NodeImpl)children : null); } NodeImpl[] nodes = (NodeImpl[])children; if (n<0 || n>=nodes.length) return null; return nodes[n]; } /** * Remove a given child * @param child the child to be removed */ protected void removeChild(NodeImpl child) { if (children == null) { return; } if (children == child) { children = null; return; } NodeImpl[] nodes = (NodeImpl[])children; for (int i=0; i 0) { System.arraycopy(nodes, 0, n2, 0, i); } if (i < nodes.length - 1) { System.arraycopy(nodes, i+1, n2, i, nodes.length-i-1); } children = cleanUpChildren(n2); } break; } } } /** * Tidy up the children of the node. Merge adjacent text nodes; remove zero-length text nodes; * reallocate index numbers to each of the children * @param children the existing children * @return the replacement array of children */ private NodeImpl[] cleanUpChildren(NodeImpl[] children) { boolean prevText = false; int j = 0; NodeImpl[] c2 = new NodeImpl[children.length]; for (int i=0; i 0) { prevText = true; node.index = j; c2[j++] = node; } } else { node.index = j; c2[j++] = node; prevText = false; } } if (j == c2.length) { return c2; } else { NodeImpl[] c3 = new NodeImpl[j]; System.arraycopy(c2, 0, c3, 0, j); return c3; } } /** * Return the string-value of the node, that is, the concatenation * of the character content of all descendent elements and text nodes. * @return the accumulated character content of the element, including descendant elements. */ public String getStringValue() { return getStringValueCS().toString(); } public CharSequence getStringValueCS() { FastStringBuffer sb = null; NodeImpl next = (NodeImpl)getFirstChild(); while (next!=null) { if (next instanceof TextImpl) { if (sb==null) { sb = new FastStringBuffer(1024); } sb.append(next.getStringValueCS()); } next = next.getNextInDocument(this); } if (sb==null) return ""; return sb.condense(); } /** * Supply an array to be used for the array of children. For system use only. * @param array the array to be used */ protected void useChildrenArray(NodeImpl[] array) { children = array; } /** * Add a child node to this node. For system use only. Note: normalizing adjacent text nodes * is the responsibility of the caller. * @param node the node to be added as a child of this node * @param index the position where the child is to be added */ public synchronized void addChild(NodeImpl node, int index) { NodeImpl[] c; if (children == null) { c = new NodeImpl[10]; } else if (children instanceof NodeImpl) { c = new NodeImpl[10]; c[0] = (NodeImpl)children; } else { c = (NodeImpl[])children; } if (index >= c.length) { NodeImpl[] kids = new NodeImpl[c.length * 2]; System.arraycopy(c, 0, kids, 0, c.length); c = kids; } c[index] = node; node.parent = this; node.index = index; children = c; } /** * Insert copies of a sequence of nodes as children of this node. *

    *

    This method takes no action unless the target node is a document node or element node. It also * takes no action in respect of any supplied nodes that are not elements, text nodes, comments, or * processing instructions.

    *

    *

    The supplied nodes will be copied to form the new children. Adjacent text nodes will be merged, and * zero-length text nodes removed.

    * * @param source the nodes to be inserted * @param atStart true if the new nodes are to be inserted before existing children; false if they are * @param inherit true if the inserted nodes are to inherit the namespaces that are in-scope for their * new parent; false if such namespaces should be undeclared on the children */ public void insertChildren(NodeInfo[] source, boolean atStart, boolean inherit) { if (atStart) { insertChildrenAt(source, 0, inherit); } else { insertChildrenAt(source, getNumberOfChildren(), inherit); } } /** * Insert children before or after a given existing child * @param source the children to be inserted * @param index the position before which they are to be inserted: 0 indicates insertion before the * first child, 1 insertion before the second child, and so on. * @param inherit true if the inserted nodes are to inherit the namespaces that are in-scope for their * new parent; false if such namespaces should be undeclared on the children */ protected synchronized void insertChildrenAt(NodeInfo[] source, int index, boolean inherit) { if (source.length == 0) { return; } for (int i=0; i allocated) { condense(); } int index = Arrays.binarySearch(sequenceNumbers, sequence); if (index < 0) { index = -index - 1; } return lineNumbers[index]; } /** * Get the column number corresponding to a given sequence number * @param sequence the sequence number held in the node * @return the corresponding column number */ public int getColumnNumber(int sequence) { if (sequenceNumbers.length > allocated) { condense(); } int index = Arrays.binarySearch(sequenceNumbers, sequence); if (index < 0) { index = -index - 1; } return columnNumbers[index]; } private synchronized void condense() { int[] s = new int[allocated]; int[] l = new int[allocated]; int[] c = new int[allocated]; System.arraycopy(sequenceNumbers, 0, s, 0, allocated); System.arraycopy(lineNumbers, 0, l, 0, allocated); System.arraycopy(columnNumbers, 0, c, 0, allocated); sequenceNumbers = s; lineNumbers = l; columnNumbers = c; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/tree/TextImpl.java0000644000175000017500000000374611033112257020761 0ustar eugeneeugenepackage net.sf.saxon.tree; import net.sf.saxon.event.Receiver; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.Type; /** * A node in the XML parse tree representing character content

    * @author Michael H. Kay */ final class TextImpl extends NodeImpl { private String content; public TextImpl(ParentNodeImpl parent, String content) { this.parent = parent; this.content = content; } /** * Return the character value of the node. * @return the string value of the node */ public String getStringValue() { return content; } /** * Return the type of node. * @return Type.TEXT */ public final int getNodeKind() { return Type.TEXT; } /** * Copy this node to a given outputter */ public void copy(Receiver out, int whichNamespaces, boolean copyAnnotations, int locationId) throws XPathException { out.characters(content, locationId, 0); } /** * Replace the string-value of this node * * @param stringValue the new string value */ public void replaceStringValue(CharSequence stringValue) { if (stringValue.length() == 0) { delete(); } else { content = stringValue.toString(); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. //saxonb-9.1.0.8/bj/net/sf/saxon/tree/SystemIdMap.java0000644000175000017500000000527611033112257021412 0ustar eugeneeugenepackage net.sf.saxon.tree; /** * System IDs are not held in nodes in the tree, because they are usually the same * for a whole document. * This class provides a map from element sequence numbers to System IDs: it is * linked to the root node of the tree. * Note that the System ID is not necessarily the same as the Base URI. The System ID relates * to the external entity in which a node was physically located; this provides a default for * the Base URI, but this may be modified by specifying an xml:base attribute * * @author Michael H. Kay */ public class SystemIdMap { private int[] sequenceNumbers; private String[] uris; private int allocated; public SystemIdMap() { sequenceNumbers = new int[4]; uris = new String[4]; allocated = 0; } /** * Set the system ID corresponding to a given sequence number */ public void setSystemId(int sequence, String uri) { // ignore it if same as previous if (allocated>0 && uri.equals(uris[allocated-1])) { return; } if (sequenceNumbers.length <= allocated + 1) { int[] s = new int[allocated * 2]; String[] u = new String[allocated * 2]; System.arraycopy(sequenceNumbers, 0, s, 0, allocated); System.arraycopy(uris, 0, u, 0, allocated); sequenceNumbers = s; uris = u; } sequenceNumbers[allocated] = sequence; uris[allocated] = uri; allocated++; } /** * Get the system ID corresponding to a given sequence number */ public String getSystemId(int sequence) { if (allocated==0) return null; // could use a binary chop, but it's not important for (int i=1; i sequence) { return uris[i-1]; } } return uris[allocated-1]; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/tree/CommentImpl.java0000644000175000017500000000455611033112257021437 0ustar eugeneeugenepackage net.sf.saxon.tree; import net.sf.saxon.event.Receiver; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.Type; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.om.SingletonIterator; import net.sf.saxon.value.StringValue; import net.sf.saxon.value.Value; /** * CommentImpl is an implementation of a Comment node * @author Michael H. Kay */ final class CommentImpl extends NodeImpl { String comment; public CommentImpl(String content) { this.comment = content; } public final String getStringValue() { return comment; } /** * Get the typed value of this node. * Returns the string value, as an instance of xs:string */ public SequenceIterator getTypedValue() { return SingletonIterator.makeIterator(new StringValue(getStringValue())); } /** * Get the typed value of this node. * Returns the string value, as an instance of xs:string */ public Value atomize() { return new StringValue(getStringValue()); } public final int getNodeKind() { return Type.COMMENT; } /** * Copy this node to a given outputter */ public void copy(Receiver out, int whichNamespaces, boolean copyAnnotations, int locationId) throws XPathException { out.comment(comment, locationId, 0); } /** * Replace the string-value of this node * * @param stringValue the new string value */ public void replaceStringValue(CharSequence stringValue) { comment = stringValue.toString(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/tree/TreeEnumeration.java0000644000175000017500000001361311033112257022313 0ustar eugeneeugenepackage net.sf.saxon.tree; import net.sf.saxon.om.AxisIterator; import net.sf.saxon.om.Item; import net.sf.saxon.om.LookaheadIterator; import net.sf.saxon.pattern.NodeTest; import net.sf.saxon.value.Value; import net.sf.saxon.trans.XPathException; abstract class TreeEnumeration implements AxisIterator, LookaheadIterator { protected NodeImpl start; protected NodeImpl next; protected NodeTest nodeTest; protected NodeImpl current = null; protected int position = 0; //protected int last = -1; /** * Create an axis enumeration for a given type and name of node, from a given * origin node * @param origin the node from which the axis originates * @param nodeTest test to be satisfied by the returned nodes, or null if all nodes * are to be returned. */ public TreeEnumeration(NodeImpl origin, NodeTest nodeTest) { next = origin; start = origin; this.nodeTest = nodeTest; } /** * Test whether a node conforms to the node type and name constraints. * Note that this returns true if the supplied node is null, this is a way of * terminating a loop. */ protected boolean conforms(NodeImpl node) { if (node==null || nodeTest==null) { return true; } return nodeTest.matches(node); } /** * Advance along the axis until a node is found that matches the required criteria */ protected final void advance() { do { step(); } while (!conforms(next)); } /** * Advance one step along the axis: the resulting node might not meet the required * criteria for inclusion */ protected abstract void step(); /** * Determine whether there are more items to come. Note that this operation * is stateless and it is not necessary (or usual) to call it before calling * next(). It is used only when there is an explicit need to tell if we * are at the last element. * * @return true if there are more items in the sequence */ public boolean hasNext() { return next != null; } /** * Move to the next node, without returning it. Returns true if there is * a next node, false if the end of the sequence has been reached. After * calling this method, the current node may be retrieved using the * current() function. */ public boolean moveNext() { return (next() != null); } /** * Return the next node in the enumeration */ public final Item next() { if (next==null) { current = null; position = -1; return null; } else { current = next; position++; advance(); return current; } } /** * Return the current Item */ public final Item current() { return current; } /** * Return the current position */ public final int position() { return position; } public void close() { } /** * Return an iterator over an axis, starting at the current node. * * @param axis the axis to iterate over, using a constant such as * {@link net.sf.saxon.om.Axis#CHILD} * @param test a predicate to apply to the nodes before returning them. * @throws NullPointerException if there is no current node */ public AxisIterator iterateAxis(byte axis, NodeTest test) { return current.iterateAxis(axis, test); } /** * Return the atomized value of the current node. * * @return the atomized value. * @throws NullPointerException if there is no current node */ public Value atomize() throws XPathException { return current.atomize(); } /** * Return the string value of the current node. * * @return the string value, as an instance of CharSequence. * @throws NullPointerException if there is no current node */ public CharSequence getStringValue() { return current.getStringValueCS(); } /** * Get properties of this iterator, as a bit-significant integer. * * @return the properties of this iterator. This will be some combination of * properties such as {@link GROUNDED}, {@link LAST_POSITION_FINDER}, * and {@link LOOKAHEAD}. It is always * acceptable to return the value zero, indicating that there are no known special properties. * It is acceptable for the properties of the iterator to change depending on its state. */ public int getProperties() { return LOOKAHEAD; } /** * Indicate that any nodes returned in the sequence will be atomized. This * means that if it wishes to do so, the implementation can return the typed * values of the nodes rather than the nodes themselves. The implementation * is free to ignore this hint. * @param atomizing true if the caller of this iterator will atomize any * nodes that are returned, and is therefore willing to accept the typed * value of the nodes instead of the nodes themselves. */ //public void setIsAtomizing(boolean atomizing) {} } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/tree/FollowingEnumeration.java0000644000175000017500000000357311033112257023360 0ustar eugeneeugenepackage net.sf.saxon.tree; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.pattern.NodeTest; import net.sf.saxon.type.Type; final class FollowingEnumeration extends TreeEnumeration { private NodeImpl root; public FollowingEnumeration(NodeImpl node, NodeTest nodeTest) { super(node, nodeTest); root = (DocumentImpl)node.getDocumentRoot(); // skip the descendant nodes if any int type = node.getNodeKind(); if (type==Type.ATTRIBUTE || type==Type.NAMESPACE) { next = ((NodeImpl)node.getParent()).getNextInDocument(root); } else { do { next = (NodeImpl)node.getNextSibling(); if (next==null) node = (NodeImpl)node.getParent(); } while (next==null && node!=null); } while (!conforms(next)) { step(); } } protected void step() { next = next.getNextInDocument(root); } /** * Get another enumeration of the same nodes */ public SequenceIterator getAnother() { return new FollowingEnumeration(start, nodeTest); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/tree/DocumentImpl.java0000644000175000017500000003711411033112257021607 0ustar eugeneeugenepackage net.sf.saxon.tree; import net.sf.saxon.Configuration; import net.sf.saxon.value.Whitespace; import net.sf.saxon.event.Receiver; import net.sf.saxon.event.Builder; import net.sf.saxon.om.*; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.Type; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.Collections; /** * A node in the XML parse tree representing the Document itself (or equivalently, the root * node of the Document). * *

    A DocumentImpl object may either represent a real document node, or it may represent an imaginary * container for a parentless element.

    * @author Michael H. Kay */ public final class DocumentImpl extends ParentNodeImpl implements DocumentInfo { //private static int nextDocumentNumber = 0; private ElementImpl documentElement; private HashMap idTable = null; private int documentNumber; private String baseURI; private HashMap entityTable = null; private HashMap elementList = null; //private StringBuffer characterBuffer; private Configuration config; private LineNumberMap lineNumberMap; private SystemIdMap systemIdMap = new SystemIdMap(); private boolean imaginary = false; /** * Create a DocumentImpl */ public DocumentImpl() { parent = null; } /** * Set the Configuration that contains this document * @param config the Saxon configuration */ public void setConfiguration(Configuration config) { this.config = config; documentNumber = config.getDocumentNumberAllocator().allocateDocumentNumber(); } /** * Get the configuration previously set using setConfiguration * @return the Saxon configuration */ public Configuration getConfiguration() { return config; } /** * Get the name pool used for the names in this document */ public NamePool getNamePool() { return config.getNamePool(); } /** * Get a Builder suitable for building nodes that can be attached to this document. * @return a new TreeBuilder */ public Builder newBuilder() { TreeBuilder builder = new TreeBuilder(); builder.setAllocateSequenceNumbers(false); return builder; } /** * Set whether this is an imaginary document node * @param imaginary if true, this is an imaginary node - the tree is really rooted at the topmost element */ public void setImaginary(boolean imaginary) { this.imaginary = imaginary; } /** * Ask whether this is an imaginary document node * @return true if this is an imaginary node - the tree is really rooted at the topmost element */ public boolean isImaginary() { return imaginary; } /** * Get the unique document number */ public int getDocumentNumber() { return documentNumber; } /** * Set the top-level element of the document (variously called the root element or the * document element). Note that a DocumentImpl may represent the root of a result tree * fragment, in which case there is no document element. * @param e the top-level element */ void setDocumentElement(ElementImpl e) { documentElement = e; } /** * Copy the system ID and line number map from another document * (used when grafting a simplified stylesheet) * @param original the document whose system ID and line number maps are to be grafted * onto this tree */ public void graftLocationMap(DocumentImpl original) { systemIdMap = original.systemIdMap; lineNumberMap = original.lineNumberMap; } /** * Set the system id (base URI) of this node */ public void setSystemId(String uri) { if (uri==null) { uri = ""; } systemIdMap.setSystemId(sequence, uri); } /** * Get the system id of this root node */ public String getSystemId() { return systemIdMap.getSystemId(sequence); } /** * Set the base URI of this document node * @param uri the new base URI */ public void setBaseURI(String uri) { baseURI = uri; } /** * Get the base URI of this root node. * @return the base URI */ public String getBaseURI() { if (baseURI != null) { return baseURI; } return getSystemId(); } /** * Set the system id of an element in the document * @param seq the sequence number of the element * @param uri the system identifier (base URI) of the element */ void setSystemId(int seq, String uri) { if (uri==null) { uri = ""; } systemIdMap.setSystemId(seq, uri); } /** * Get the system id of an element in the document * @param seq the sequence number of the element * @return the systemId (base URI) of the element */ String getSystemId(int seq) { return systemIdMap.getSystemId(seq); } /** * Set line numbering on */ public void setLineNumbering() { lineNumberMap = new LineNumberMap(); lineNumberMap.setLineAndColumn(sequence, 0, -1); } /** * Set the line number for an element. Ignored if line numbering is off. * @param sequence the sequence number of the element * @param line the line number of the element * @param column the column number of the element */ void setLineAndColumn(int sequence, int line, int column) { if (lineNumberMap != null && sequence >= 0) { lineNumberMap.setLineAndColumn(sequence, line, column); } } /** * Get the line number for an element. * @param sequence the sequence number of the element * @return the line number for an element. Return -1 if line numbering is off, or if * the element was added subsequent to document creation by use of XQuery update */ int getLineNumber(int sequence) { if (lineNumberMap != null && sequence >= 0) { return lineNumberMap.getLineNumber(sequence); } return -1; } /** * Get the column number for an element. * @param sequence the sequence number of the element * @return the column number for an element. Return -1 if line numbering is off, or if * the element was added subsequent to document creation by use of XQuery update */ int getColumnNumber(int sequence) { if (lineNumberMap != null && sequence >= 0) { return lineNumberMap.getColumnNumber(sequence); } return -1; } /** * Get the line number of this root node. * @return 0 always */ public int getLineNumber() { return 0; } /** * Return the type of node. * @return Type.DOCUMENT (always) */ public final int getNodeKind() { return Type.DOCUMENT; } /** * Get next sibling - always null * @return null */ public final NodeInfo getNextSibling() { return null; } /** * Get previous sibling - always null * @return null */ public final NodeInfo getPreviousSibling() { return null; } /** * Get the root (outermost) element. * @return the Element node for the outermost element of the document. */ public ElementImpl getDocumentElement() { return documentElement; } /** * Get the root node * @return the NodeInfo representing the root of this tree */ public NodeInfo getRoot() { return this; } /** * Get the root (document) node * @return the DocumentInfo representing this document */ public DocumentInfo getDocumentRoot() { return this; } /** * Get the physical root of the tree. This may be an imaginary document node: this method * should be used only when control information held at the physical root is required * @return the document node, which may be imaginary */ public DocumentImpl getPhysicalRoot() { return this; } /** * Get a character string that uniquely identifies this node * @param buffer a buffer into which will be placed a string based on the document number * */ public void generateId(FastStringBuffer buffer) { buffer.append('d'); buffer.append(Integer.toString(documentNumber)); } /** * Get a list of all elements with a given name fingerprint * @param fingerprint the fingerprint of the required element name * @return an iterator over all the elements with this name */ AxisIterator getAllElements(int fingerprint) { Integer elkey = new Integer(fingerprint); if (elementList==null) { elementList = new HashMap(500); } ArrayList list = (ArrayList)elementList.get(elkey); if (list==null) { list = new ArrayList(500); NodeImpl next = getNextInDocument(this); while (next!=null) { if (next.getNodeKind()==Type.ELEMENT && next.getFingerprint() == fingerprint) { list.add(next); } next = next.getNextInDocument(this); } elementList.put(elkey, list); } return new NodeListIterator(list); } /** * Remove a node from any indexes when it is detached from the tree * @param node the node to be removed from all indexes */ public void deIndex(NodeImpl node) { // TODO: remove from xsl:key indexes (can exist in XQuery as a result of optimization!) if (node instanceof ElementImpl) { if (elementList!=null) { Integer elkey = new Integer(node.getFingerprint()); ArrayList list = (ArrayList)elementList.get(elkey); if (list==null) { return; } list.remove(node); } if (node.isId()) { deregisterID(node.getStringValue()); } } else if (node instanceof AttributeImpl) { if (node.isId()) { deregisterID(node.getStringValue()); } } } /** * Index all the ID attributes. This is done the first time the id() function * is used on this document, or the first time that id() is called after a sequence of updates */ private void indexIDs() { if (idTable!=null) { return; // ID's are already indexed } idTable = new HashMap(256); NameChecker checker = getConfiguration().getNameChecker(); NodeImpl curr = this; NodeImpl root = curr; while(curr!=null) { if (curr.getNodeKind()==Type.ELEMENT) { //noinspection ConstantConditions ElementImpl e = (ElementImpl)curr; AttributeCollection atts = e.getAttributeList(); for (int i=0; i20 is so rare that we don't bother. while (depth >= arrays.size()) { arrays.add(new NodeImpl[20]); } elem.useChildrenArray((NodeImpl[])arrays.get(depth)); currentNode.addChild(elem, size[depth]++); if (depth >= size.length - 1) { int[] newsize = new int[size.length * 2]; System.arraycopy(size, 0, newsize, 0, size.length); size = newsize; } size[++depth] = 0; namespacesUsed = 0; if (currentNode instanceof DocumentInfo) { ((DocumentImpl)currentNode).setDocumentElement(elem); } currentNode = elem; } /** * Notify the end of an element */ public void endElement () throws XPathException { // System.err.println("End element depth=" + depth); currentNode.compact(size[depth]); depth--; currentNode = (ParentNodeImpl)currentNode.getParent(); } /** * Notify a text node. Adjacent text nodes must have already been merged */ public void characters (CharSequence chars, int locationId, int properties) throws XPathException { // System.err.println("Characters: " + chars.toString() + " depth=" + depth); if (chars.length()>0) { // we rely on adjacent chunks of text having already been merged //TextImpl n = new TextImpl(currentNode, bufferStart, length); TextImpl n = new TextImpl(currentNode, chars.toString()); currentNode.addChild(n, size[depth]++); } } /** * Notify a processing instruction */ public void processingInstruction (String name, CharSequence remainder, int locationId, int properties) { int nameCode = namePool.allocate("", "", name); ProcInstImpl pi = new ProcInstImpl(nameCode, remainder.toString()); currentNode.addChild(pi, size[depth]++); LocationProvider locator = pipe.getLocationProvider(); if (locator!=null) { pi.setLocation(locator.getSystemId(locationId), locator.getLineNumber(locationId)); } } /** * Notify a comment */ public void comment (CharSequence chars, int locationId, int properties) throws XPathException { CommentImpl comment = new CommentImpl(chars.toString()); currentNode.addChild(comment, size[depth]++); } /** * graftElement() allows an element node to be transferred from one tree to another. * This is a dangerous internal interface which is used only to contruct a stylesheet * tree from a stylesheet using the "literal result element as stylesheet" syntax. * The supplied element is grafted onto the current element as its only child. * @param element the element to be grafted in as a new child. */ public void graftElement(ElementImpl element) throws XPathException { currentNode.addChild(element, size[depth]++); } /** * Set an unparsed entity URI for the document */ public void setUnparsedEntity(String name, String uri, String publicId) { ((DocumentImpl)currentRoot).setUnparsedEntity(name, uri, publicId); } ////////////////////////////////////////////////////////////////////////////// // Inner class DefaultNodeFactory. This creates the nodes in the tree. // It can be overridden, e.g. when building the stylesheet tree ////////////////////////////////////////////////////////////////////////////// private static class DefaultNodeFactory implements NodeFactory { public ElementImpl makeElementNode( NodeInfo parent, int nameCode, int typeCode, AttributeCollectionImpl attlist, int[] namespaces, int namespacesUsed, LocationProvider locator, int locationId, int sequenceNumber) { ElementImpl e = new ElementImpl(); if (namespacesUsed > 0) { e.setNamespaceDeclarations(namespaces, namespacesUsed); } // String baseURI = null; // int lineNumber = -1; // // if (locator!=null) { // baseURI = locator.getSystemId(locationId); // lineNumber = locator.getLineNumber(locationId); // } e.initialise(nameCode, typeCode, attlist, parent, sequenceNumber); if (locator!=null) { String baseURI = locator.getSystemId(locationId); int lineNumber = locator.getLineNumber(locationId); int columnNumber = locator.getColumnNumber(locationId); e.setLocation(baseURI, lineNumber, columnNumber); } return e; } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/tree/NodeImpl.java0000644000175000017500000007752411157427346020746 0ustar eugeneeugenepackage net.sf.saxon.tree; import net.sf.saxon.Configuration; import net.sf.saxon.trans.Err; import net.sf.saxon.event.Builder; import net.sf.saxon.om.*; import net.sf.saxon.pattern.AnyNodeTest; import net.sf.saxon.pattern.NameTest; import net.sf.saxon.pattern.NodeTest; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.Type; import net.sf.saxon.type.SchemaType; import net.sf.saxon.value.UntypedAtomicValue; import net.sf.saxon.value.Value; import javax.xml.transform.SourceLocator; /** * A node in the "linked" tree representing any kind of node except a namespace node. * Specific node kinds are represented by concrete subclasses. * * @author Michael H. Kay */ public abstract class NodeImpl implements MutableNodeInfo, FingerprintedNode, SiblingCountingNode, SourceLocator { protected ParentNodeImpl parent; protected int index; /** * Chararacteristic letters to identify each type of node, indexed using the node type * values. These are used as the initial letter of the result of generate-id() */ public static final char[] NODE_LETTER = {'x', 'e', 'a', 't', 'x', 'x', 'x', 'p', 'c', 'r', 'x', 'x', 'x', 'n'}; /** * Get the value of the item as a CharSequence. This is in some cases more efficient than * the version of the method that returns a String. */ public CharSequence getStringValueCS() { return getStringValue(); } /** * Get the type annotation of this node, if any * @return the type annotation, as the integer name code of the type name */ public int getTypeAnnotation() { return StandardNames.XS_UNTYPED; } /** * Get the column number of the node. * The default implementation returns -1, meaning unknown */ public int getColumnNumber() { if (parent == null) { return -1; } else { return parent.getColumnNumber(); } } /** * Get the public identifier of the document entity containing this node. * The default implementation returns null, meaning unknown */ public String getPublicId() { return null; } /** * Get the document number of the document containing this node. For a free-standing * orphan node, just return the hashcode. */ public int getDocumentNumber() { return getPhysicalRoot().getDocumentNumber(); } /** * Get the index position of this node among its siblings (starting from 0) * @return 0 for the first child, 1 for the second child, etc. */ public int getSiblingPosition() { return index; } /** * Get the typed value of this node. * If there is no type annotation, we return the string value, as an instance * of xs:untypedAtomic */ public SequenceIterator getTypedValue() throws XPathException { int annotation = getTypeAnnotation(); if ((annotation & NodeInfo.IS_DTD_TYPE) != 0) { annotation = StandardNames.XS_UNTYPED_ATOMIC; } annotation &= NamePool.FP_MASK; if (annotation == -1 || annotation == StandardNames.XS_UNTYPED_ATOMIC || annotation == StandardNames.XS_UNTYPED) { return SingletonIterator.makeIterator(new UntypedAtomicValue(getStringValueCS())); } else { SchemaType stype = getConfiguration().getSchemaType(annotation); if (stype == null) { String typeName; try { typeName = getNamePool().getDisplayName(annotation); } catch (Exception err) { typeName = annotation + ""; } throw new XPathException("Unknown type annotation " + Err.wrap(typeName) + " in document instance"); } else { return stype.getTypedValue(this); } } } /** * Get the typed value. The result of this method will always be consistent with the method * {@link net.sf.saxon.om.Item#getTypedValue()}. However, this method is often more convenient and may be * more efficient, especially in the common case where the value is expected to be a singleton. * * @return the typed value. If requireSingleton is set to true, the result will always be an * AtomicValue. In other cases it may be a Value representing a sequence whose items are atomic * values. * @since 8.5 */ public Value atomize() throws XPathException { int annotation = getTypeAnnotation(); if ((annotation & NodeInfo.IS_DTD_TYPE) != 0) { annotation = StandardNames.XS_UNTYPED_ATOMIC; } if (annotation == -1 || annotation == StandardNames.XS_UNTYPED_ATOMIC || annotation == StandardNames.XS_UNTYPED) { return new UntypedAtomicValue(getStringValueCS()); } else { SchemaType stype = getConfiguration().getSchemaType(annotation); if (stype == null) { String typeName = getNamePool().getDisplayName(annotation); throw new XPathException("Unknown type annotation " + Err.wrap(typeName) + " in document instance"); } else { return stype.atomize(this); } } } /** * Set the system ID of this node. This method is provided so that a NodeInfo * implements the javax.xml.transform.Source interface, allowing a node to be * used directly as the Source of a transformation */ public void setSystemId(String uri) { // overridden in DocumentImpl and ElementImpl getParent().setSystemId(uri); } /** * Determine whether this is the same node as another node * * @return true if this Node object and the supplied Node object represent the * same node in the tree. */ public boolean isSameNodeInfo(NodeInfo other) { // default implementation: differs for attribute and namespace nodes return this == other; } /** * The equals() method compares nodes for identity. It is defined to give the same result * as isSameNodeInfo(). * @param other the node to be compared with this node * @return true if this NodeInfo object and the supplied NodeInfo object represent * the same node in the tree. * @since 8.7 Previously, the effect of the equals() method was not defined. Callers * should therefore be aware that third party implementations of the NodeInfo interface may * not implement the correct semantics. It is safer to use isSameNodeInfo() for this reason. * The equals() method has been defined because it is useful in contexts such as a Java Set or HashMap. */ public boolean equals(Object other) { return other instanceof NodeInfo && isSameNodeInfo((NodeInfo)other); } /** * The hashCode() method obeys the contract for hashCode(): that is, if two objects are equal * (represent the same node) then they must have the same hashCode() * @since 8.7 Previously, the effect of the equals() and hashCode() methods was not defined. Callers * should therefore be aware that third party implementations of the NodeInfo interface may * not implement the correct semantics. */ // public int hashCode() { // FastStringBuffer buff = new FastStringBuffer(20); // generateId(buff); // return buff.toString().hashCode(); // } /** * Get the nameCode of the node. This is used to locate the name in the NamePool */ public int getNameCode() { // default implementation: return -1 for an unnamed node return -1; } /** * Get the fingerprint of the node. This is used to compare whether two nodes * have equivalent names. Return -1 for a node with no name. */ public int getFingerprint() { int nameCode = getNameCode(); if (nameCode == -1) { return -1; } return nameCode & 0xfffff; } /** * Get a character string that uniquely identifies this node within this document * (The calling code will prepend a document identifier) */ public void generateId(FastStringBuffer buffer) { long seq = getSequenceNumber(); if (seq == -1L) { getPhysicalRoot().generateId(buffer); buffer.append(NODE_LETTER[getNodeKind()]); buffer.append(Long.toString(seq)); } else { parent.generateId(buffer); buffer.append(NODE_LETTER[getNodeKind()]); buffer.append(Integer.toString(index)); } } /** * Get the system ID for the node. Default implementation for child nodes. */ public String getSystemId() { return parent.getSystemId(); } /** * Get the base URI for the node. Default implementation for child nodes. */ public String getBaseURI() { return parent.getBaseURI(); } /** * Get the node sequence number (in document order). Sequence numbers are monotonic but not * consecutive. In the current implementation, parent nodes (elements and roots) have a zero * least-significant word, while namespaces, attributes, text nodes, comments, and PIs have * the top word the same as their owner and the bottom half reflecting their relative position. * This is the default implementation for child nodes. * For nodes added by XQUery Update, the sequence number is -1L * @return the sequence number if there is one, or -1L otherwise. */ protected long getSequenceNumber() { NodeImpl prev = this; for (int i = 0; ; i++) { if (prev instanceof ParentNodeImpl) { long prevseq = prev.getSequenceNumber(); return (prevseq == -1L ? prevseq : prevseq + 0x10000 + i); // note the 0x10000 is to leave room for namespace and attribute nodes. } prev = prev.getPreviousInDocument(); } } /** * Determine the relative position of this node and another node, in document order. * The other node will always be in the same document. * * @param other The other node, whose position is to be compared with this node * @return -1 if this node precedes the other node, +1 if it follows the other * node, or 0 if they are the same node. (In this case, isSameNode() will always * return true, and the two nodes will produce the same result for generateId()) */ public final int compareOrder(NodeInfo other) { if (other instanceof NamespaceIterator.NamespaceNodeImpl) { return 0 - other.compareOrder(this); } long a = getSequenceNumber(); long b = ((NodeImpl)other).getSequenceNumber(); if (a == -1L || b == -1L) { // Nodes added by XQuery Update do not have sequence numbers return Navigator.compareOrder(this, ((NodeImpl)other)); } if (a < b) { return -1; } if (a > b) { return +1; } return 0; } /** * Get the configuration */ public Configuration getConfiguration() { return getPhysicalRoot().getConfiguration(); } /** * Get the NamePool */ public NamePool getNamePool() { return getPhysicalRoot().getNamePool(); } /** * Get the prefix part of the name of this node. This is the name before the ":" if any. * * @return the prefix part of the name. For an unnamed node, return an empty string. */ public String getPrefix() { int nameCode = getNameCode(); if (nameCode == -1) { return ""; } if (NamePool.getPrefixIndex(nameCode) == 0) { return ""; } return getNamePool().getPrefix(nameCode); } /** * Get the URI part of the name of this node. This is the URI corresponding to the * prefix, or the URI of the default namespace if appropriate. * * @return The URI of the namespace of this node. For the null namespace, return an * empty string. For an unnamed node, return the empty string. */ public String getURI() { int nameCode = getNameCode(); if (nameCode == -1) { return ""; } return getNamePool().getURI(nameCode); } /** * Get the display name of this node. For elements and attributes this is [prefix:]localname. * For unnamed nodes, it is an empty string. * * @return The display name of this node. * For a node with no name, return an empty string. */ public String getDisplayName() { int nameCode = getNameCode(); if (nameCode == -1) { return ""; } return getNamePool().getDisplayName(nameCode); } /** * Get the local name of this node. * * @return The local name of this node. * For a node with no name, return "",. */ public String getLocalPart() { int nameCode = getNameCode(); if (nameCode == -1) { return ""; } return getNamePool().getLocalName(nameCode); } /** * Get the line number of the node within its source document entity */ public int getLineNumber() { return parent.getLineNumber(); } /** * Find the parent node of this node. * * @return The Node object describing the containing element or root node. */ public final NodeInfo getParent() { if (parent instanceof DocumentImpl && ((DocumentImpl)parent).isImaginary()) { return null; } return parent; } /** * Get the previous sibling of the node * * @return The previous sibling node. Returns null if the current node is the first * child of its parent. */ public NodeInfo getPreviousSibling() { if (parent == null) { return null; } return parent.getNthChild(index - 1); } /** * Get next sibling node * * @return The next sibling node of the required type. Returns null if the current node is the last * child of its parent. */ public NodeInfo getNextSibling() { if (parent == null) { return null; } return parent.getNthChild(index + 1); } /** * Get first child - default implementation used for leaf nodes * * @return null */ public NodeInfo getFirstChild() { return null; } /** * Get last child - default implementation used for leaf nodes * * @return null */ public NodeInfo getLastChild() { return null; } /** * Return an enumeration over the nodes reached by the given axis from this node * * @param axisNumber The axis to be iterated over * @return an AxisIterator that scans the nodes reached by the axis in turn. */ public AxisIterator iterateAxis(byte axisNumber) { // Fast path for child axis if (axisNumber == Axis.CHILD) { if (this instanceof ParentNodeImpl) { return ((ParentNodeImpl)this).enumerateChildren(null); } else { return EmptyIterator.getInstance(); } } else { return iterateAxis(axisNumber, AnyNodeTest.getInstance()); } } /** * Return an enumeration over the nodes reached by the given axis from this node * * @param axisNumber The axis to be iterated over * @param nodeTest A pattern to be matched by the returned nodes * @return an AxisIterator that scans the nodes reached by the axis in turn. */ public AxisIterator iterateAxis(byte axisNumber, NodeTest nodeTest) { switch (axisNumber) { case Axis.ANCESTOR: return new AncestorEnumeration(this, nodeTest, false); case Axis.ANCESTOR_OR_SELF: return new AncestorEnumeration(this, nodeTest, true); case Axis.ATTRIBUTE: if (getNodeKind() != Type.ELEMENT) { return EmptyIterator.getInstance(); } return new AttributeEnumeration(this, nodeTest); case Axis.CHILD: if (this instanceof ParentNodeImpl) { return ((ParentNodeImpl)this).enumerateChildren(nodeTest); } else { return EmptyIterator.getInstance(); } case Axis.DESCENDANT: if (getNodeKind() == Type.DOCUMENT && nodeTest instanceof NameTest && nodeTest.getPrimitiveType() == Type.ELEMENT) { return ((DocumentImpl)this).getAllElements(nodeTest.getFingerprint()); } else if (hasChildNodes()) { return new DescendantEnumeration(this, nodeTest, false); } else { return EmptyIterator.getInstance(); } case Axis.DESCENDANT_OR_SELF: return new DescendantEnumeration(this, nodeTest, true); case Axis.FOLLOWING: return new FollowingEnumeration(this, nodeTest); case Axis.FOLLOWING_SIBLING: return new FollowingSiblingEnumeration(this, nodeTest); case Axis.NAMESPACE: if (getNodeKind() != Type.ELEMENT) { return EmptyIterator.getInstance(); } return NamespaceIterator.makeIterator(this, nodeTest); case Axis.PARENT: NodeInfo parent = getParent(); if (parent == null) { return EmptyIterator.getInstance(); } return Navigator.filteredSingleton(parent, nodeTest); case Axis.PRECEDING: return new PrecedingEnumeration(this, nodeTest); case Axis.PRECEDING_SIBLING: return new PrecedingSiblingEnumeration(this, nodeTest); case Axis.SELF: return Navigator.filteredSingleton(this, nodeTest); case Axis.PRECEDING_OR_ANCESTOR: return new PrecedingOrAncestorEnumeration(this, nodeTest); default: throw new IllegalArgumentException("Unknown axis number " + axisNumber); } } /** * Find the value of a given attribute of this node.
    * This method is defined on all nodes to meet XSL requirements, but for nodes * other than elements it will always return null. * @param uri the namespace uri of an attribute * @param localName the local name of an attribute * @return the value of the attribute, if it exists, otherwise null */ // public String getAttributeValue( String uri, String localName ) { // return null; // } /** * Find the value of a given attribute of this node.
    * This method is defined on all nodes to meet XSL requirements, but for nodes * other than elements it will always return null. * @param name the name of an attribute. This must be an unqualified attribute name, * i.e. one with no namespace prefix. * @return the value of the attribute, if it exists, otherwise null */ //public String getAttributeValue( String name ) { // return null; //} /** * Get the value of a given attribute of this node * * @param fingerprint The fingerprint of the attribute name * @return the attribute value if it exists or null if not */ public String getAttributeValue(int fingerprint) { return null; } /** * Get the root node * @return the NodeInfo representing the logical root of the tree. For this tree implementation the * root will either be a document node or an element node. */ public NodeInfo getRoot() { NodeInfo parent = getParent(); if (parent == null) { return this; } else { return parent.getRoot(); } } /** * Get the root (document) node * @return the DocumentInfo representing the containing document. If this * node is part of a tree that does not have a document node as its * root, returns null. */ public DocumentInfo getDocumentRoot() { NodeInfo parent = getParent(); if (parent == null) { return null; } else { return parent.getDocumentRoot(); } } /** * Get the physical root of the tree. This may be an imaginary document node: this method * should be used only when control information held at the physical root is required * @return the document node, which may be imaginary. In the case of a node that has been detached * from the tree by means of a delete() operation, this method returns null. */ public DocumentImpl getPhysicalRoot() { ParentNodeImpl up = parent; while (up != null && !(up instanceof DocumentImpl)) { up = up.parent; } return (DocumentImpl)up; } /** * Get the next node in document order * * @param anchor the scan stops when it reaches a node that is not a descendant of the specified * anchor node * @return the next node in the document, or null if there is no such node */ public NodeImpl getNextInDocument(NodeImpl anchor) { // find the first child node if there is one; otherwise the next sibling node // if there is one; otherwise the next sibling of the parent, grandparent, etc, up to the anchor element. // If this yields no result, return null. NodeImpl next = (NodeImpl)getFirstChild(); if (next != null) { return next; } if (this == anchor) { return null; } next = (NodeImpl)getNextSibling(); if (next != null) { return next; } NodeImpl parent = this; while (true) { parent = (NodeImpl)parent.getParent(); if (parent == null) { return null; } if (parent == anchor) { return null; } next = (NodeImpl)parent.getNextSibling(); if (next != null) { return next; } } } /** * Get the previous node in document order * * @return the previous node in the document, or null if there is no such node */ public NodeImpl getPreviousInDocument() { // finds the last child of the previous sibling if there is one; // otherwise the previous sibling element if there is one; // otherwise the parent, up to the anchor element. // If this reaches the document root, return null. NodeImpl prev = (NodeImpl)getPreviousSibling(); if (prev != null) { return prev.getLastDescendantOrSelf(); } return (NodeImpl)getParent(); } private NodeImpl getLastDescendantOrSelf() { NodeImpl last = (NodeImpl)getLastChild(); if (last == null) { return this; } return last.getLastDescendantOrSelf(); } /** * Get all namespace undeclarations and undeclarations defined on this element. * * @param buffer If this is non-null, and the result array fits in this buffer, then the result * may overwrite the contents of this array, to avoid the cost of allocating a new array on the heap. * @return An array of integers representing the namespace declarations and undeclarations present on * this element. For a node other than an element, return null. Otherwise, the returned array is a * sequence of namespace codes, whose meaning may be interpreted by reference to the name pool. The * top half word of each namespace code represents the prefix, the bottom half represents the URI. * If the bottom half is zero, then this is a namespace undeclaration rather than a declaration. * The XML namespace is never included in the list. If the supplied array is larger than required, * then the first unused entry will be set to -1. *

    *

    For a node other than an element, the method returns null.

    */ public int[] getDeclaredNamespaces(int[] buffer) { return null; } /** * Copy nodes. Copying type annotations is not yet supported for this tree * structure, so we simply map the new interface onto the old */ // public final void copy(Receiver out, int whichNamespaces, boolean copyAnnotations, int locationId) // throws XPathException { // copy(out, whichNamespaces); // } // // public abstract void copy(Receiver out, int whichNamespaces) throws XPathException; // implement DOM Node methods /** * Determine whether the node has any children. * * @return true if the node has any children, * false if the node has no children. */ public boolean hasChildNodes() { return getFirstChild() != null; } /** * Determine whether this node has the is-id property * * @return true if the node is an ID */ public boolean isId() { return false; } /** * Determine whether this node has the is-idref property * * @return true if the node is an IDREF or IDREFS element or attribute */ public boolean isIdref() { return false; } /** * Determine whether the node has the is-nilled property * * @return true if the node has the is-nilled property */ public boolean isNilled() { return false; } /** * Set the type annotation on a node. This must only be called when the caller has verified (by validation) * that the node is a valid instance of the specified type. The call is ignored if the node is not an element * or attribute node. * * @param typeCode the type annotation (possibly including high bits set to indicate the isID, isIDREF, and * isNilled properties) */ public void setTypeAnnotation(int typeCode) { // no action } /** * Delete this node (that is, detach it from its parent) */ public void delete() { // Overridden for attribute nodes if (parent != null) { parent.removeChild(this); DocumentImpl newRoot = new DocumentImpl(); newRoot.setConfiguration(parent.getConfiguration()); newRoot.setImaginary(true); parent = newRoot; } index = -1; } /** * Remove an attribute from this element node * *

    If this node is not an element, or if it has no attribute with the specified name, * this method takes no action.

    * *

    The attribute node itself is not modified in any way.

    * @param nameCode the name of the attribute to be removed */ public void removeAttribute(int nameCode) { // no action (overridden in subclasses) } /** * Add an attribute to this element node. *

    *

    If this node is not an element, or if the supplied node is not an attribute, the method * takes no action. If the element already has an attribute with this name, the existing attribute * is replaced.

    * * @param nameCode the name of the new attribute * @param typeCode the type annotation of the new attribute * @param value the string value of the new attribute * @param properties properties including IS_ID and IS_IDREF properties */ public void putAttribute(int nameCode, int typeCode, CharSequence value, int properties) { // No action, unless this is an element node } /** * Rename this node * @param newNameCode the NamePool code of the new name */ public void rename(int newNameCode) { // implemented for node kinds that have a name } public void addNamespace(int nscode, boolean inherit) { // implemented for element nodes only } /** * Replace this node with a given sequence of nodes * * @param replacement the replacement nodes * @param inherit set to true if new child elements are to inherit the in-scope namespaces * of their new parent * @throws IllegalArgumentException if any of the replacement nodes is not an element, text, * comment, or processing instruction node */ public void replace(NodeInfo[] replacement, boolean inherit) { parent.replaceChildrenAt(replacement, index, inherit); } /** * Insert copies of a sequence of nodes as children of this node. *

    *

    This method takes no action unless the target node is a document node or element node. It also * takes no action in respect of any supplied nodes that are not elements, text nodes, comments, or * processing instructions.

    *

    *

    The supplied nodes will be copied to form the new children. Adjacent text nodes will be merged, and * zero-length text nodes removed.

    * * @param source the nodes to be inserted * @param atStart true if the new nodes are to be inserted before existing children; false if they are * @param inherit true if the inserted nodes are to inherit the namespaces that are in-scope for their * new parent; false if such namespaces should be undeclared on the children */ public void insertChildren(NodeInfo[] source, boolean atStart, boolean inherit) { throw new UnsupportedOperationException("insertChildren() can only be applied to a parent node"); } /** * Insert copies of a sequence of nodes as siblings of this node. *

    *

    This method takes no action unless the target node is an element, text node, comment, or * processing instruction, and one that has a parent node. It also * takes no action in respect of any supplied nodes that are not elements, text nodes, comments, or * processing instructions.

    *

    *

    The supplied nodes must use the same data model implementation as the tree into which they * will be inserted.

    * * @param source the nodes to be inserted * @param before true if the new nodes are to be inserted before the target node; false if they are * @param inherit */ public void insertSiblings(NodeInfo[] source, boolean before, boolean inherit) { if (parent == null) { throw new IllegalStateException("Cannot add siblings if there is no parent"); } parent.insertChildrenAt(source, (before ? index : index+1), inherit); } /** * Remove type information from this node (and its ancestors, recursively). * This method implements the upd:removeType() primitive defined in the XQuery Update specification */ public void removeTypeAnnotation() { // no action } /** * Get a Builder suitable for building nodes that can be attached to this document. * @return a new Builder that constructs nodes using the same object model implementation * as this one, suitable for attachment to this tree */ public Builder newBuilder() { return getPhysicalRoot().newBuilder(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/tree/package.html0000644000175000017500000000266511033112257020630 0ustar eugeneeugene Package overview for net.sf.saxon.tree

    This package defines the implementation of the so-called "standard tree" structure. This structure can be used to represent both the source document and the stylesheet. It is no longer the default structure for source documents, but is always used for stylesheets and for schema documents, because it allows each element to be represented by a subclass of Element with application-specific functionality.

    The classes represent the various kinds of node on the tree. Most of them are not visible outside the package, with the notable exception of ElementImpl, which can be subclassed to contain properties for a particular kind of element. This capability is exploited especially in the stylesheet tree.

    As well as classes representing nodes, there are classes representing iterators over the various XPath axes, for example ChildEnumeration and PrecedingEnumeration.

    The TreeBuilder performs the work of constructing a tree, from a sequence of SAX-like Receiver events.

    The package also contains some helper classes such as SystemIdMap and LineNumberMap that are used also by the TinyTree implementation.

    Michael H. Kay
    Saxonica Limited
    9 February 2005

    saxonb-9.1.0.8/bj/net/sf/saxon/om/0000755000175000017500000000000012216261746016026 5ustar eugeneeugenesaxonb-9.1.0.8/bj/net/sf/saxon/om/NamespaceDeclarationsImpl.java0000644000175000017500000001257011033112257023731 0ustar eugeneeugenepackage net.sf.saxon.om; /** * An implementation of the NamespaceDeclarations interface, * based on encapsulating an array of namespace codes. */ public class NamespaceDeclarationsImpl implements NamespaceDeclarations { private NamePool namePool; private int[] namespaceCodes; private int used; private static final int[] emptyArray = new int[0]; /** * Create an uninitialized instance */ public NamespaceDeclarationsImpl() {} /** * Construct a set of namespace declarations * @param pool the name pool * @param codes an integer array holding the namespace codes. These * codes are allocated by the name pool, and can be used to look up * a prefix and uri in the name pool. If the array contains the integer * -1, this acts as a terminator for the list. This is the format * returned by the method {@link NodeInfo#getDeclaredNamespaces(int[])}. * A value of null is equivalent to supplying an empty array. */ public NamespaceDeclarationsImpl(NamePool pool, int[] codes) { namePool = pool; setNamespaceCodes(codes); } /** * Set the name pool * @param pool the NamePool */ public void setNamePool(NamePool pool) { namePool = pool; } /** * Set the namespace codes. * @param codes an integer array holding the namespace codes. These * codes are allocated by the name pool, and can be used to look up * a prefix and uri in the name pool. If the array contains the integer * -1, this acts as a terminator for the list. This is the format * returned by the method {@link NodeInfo#getDeclaredNamespaces(int[])}. * A value of null is equivalent to supplying an empty array. */ public void setNamespaceCodes(int[] codes) { if (codes == null) { codes = emptyArray; } namespaceCodes = codes; used = codes.length; for (int i=0; i * Note: a.isSameNode(b) if and only if generateId(a)==generateId(b) * @return true if this Node object and the supplied Node object represent the * same node in the tree. */ public boolean isSameNodeInfo(NodeInfo other) { if (other instanceof StrippedNode) { return node.isSameNodeInfo(((StrippedNode)other).node); } else { return node.isSameNodeInfo(other); } } /** * The equals() method compares nodes for identity. It is defined to give the same result * as isSameNodeInfo(). * @param other the node to be compared with this node * @return true if this NodeInfo object and the supplied NodeInfo object represent * the same node in the tree. * @since 8.7 Previously, the effect of the equals() method was not defined. Callers * should therefore be aware that third party implementations of the NodeInfo interface may * not implement the correct semantics. It is safer to use isSameNodeInfo() for this reason. * The equals() method has been defined because it is useful in contexts such as a Java Set or HashMap. */ public boolean equals(Object other) { return other instanceof NodeInfo && isSameNodeInfo((NodeInfo)other); } /** * The hashCode() method obeys the contract for hashCode(): that is, if two objects are equal * (represent the same node) then they must have the same hashCode() * @since 8.7 Previously, the effect of the equals() and hashCode() methods was not defined. Callers * should therefore be aware that third party implementations of the NodeInfo interface may * not implement the correct semantics. */ public int hashCode() { return node.hashCode() ^ 0x3c3c3c3c; } /** * Get the System ID for the node. * @return the System Identifier of the entity in the source document containing the node, * or null if not known. Note this is not the same as the base URI: the base URI can be * modified by xml:base, but the system ID cannot. */ public String getSystemId() { return node.getSystemId(); } public void setSystemId(String uri) { node.setSystemId(uri); } /** * Get the Base URI for the node, that is, the URI used for resolving a relative URI contained * in the node. In the JDOM model, base URIs are held only an the document level. We don't * currently take any account of xml:base attributes. */ public String getBaseURI() { return node.getBaseURI(); } /** * Get line number * @return the line number of the node in its original source document; or -1 if not available */ public int getLineNumber() { return node.getLineNumber(); } /** * Get column number * @return the column number of the node in its original source document; or -1 if not available */ public int getColumnNumber() { return node.getColumnNumber(); } /** * Determine the relative position of this node and another node, in document order. * The other node will always be in the same document. * @param other The other node, whose position is to be compared with this node * @return -1 if this node precedes the other node, +1 if it follows the other * node, or 0 if they are the same node. (In this case, isSameNode() will always * return true, and the two nodes will produce the same result for generateId()) */ public int compareOrder(NodeInfo other) { if (other instanceof StrippedNode) { return node.compareOrder(((StrippedNode)other).node); } else { return node.compareOrder(other); } } /** * Return the string value of the node. The interpretation of this depends on the type * of node. For an element it is the accumulated character content of the element, * including descendant elements. * @return the string value of the node */ public String getStringValue() { return getStringValueCS().toString(); } /** * Get the value of the item as a CharSequence. This is in some cases more efficient than * the version of the method that returns a String. */ public CharSequence getStringValueCS() { // Might not be the same as the string value of the underlying node because of space stripping switch (getNodeKind()) { case Type.DOCUMENT: case Type.ELEMENT: AxisIterator iter = iterateAxis(Axis.DESCENDANT, NodeKindTest.makeNodeKindTest(Type.TEXT)); FastStringBuffer sb = new FastStringBuffer(1024); while(true) { NodeInfo it = (NodeInfo)iter.next(); if (it == null) { break; } sb.append(it.getStringValueCS()); } return sb.condense(); default: return node.getStringValueCS(); } } /** * Get name code. The name code is a coded form of the node name: two nodes * with the same name code have the same namespace URI, the same local name, * and the same prefix. By masking the name code with &0xfffff, you get a * fingerprint: two nodes with the same fingerprint have the same local name * and namespace URI. * @see NamePool#allocate allocate */ public int getNameCode() { return node.getNameCode(); } /** * Get fingerprint. The fingerprint is a coded form of the expanded name * of the node: two nodes * with the same name code have the same namespace URI and the same local name. * A fingerprint of -1 should be returned for a node with no name. */ public int getFingerprint() { return node.getFingerprint(); } /** * Get the local part of the name of this node. This is the name after the ":" if any. * @return the local part of the name. For an unnamed node, returns null, except for * un unnamed namespace node, which returns "". */ public String getLocalPart() { return node.getLocalPart(); } /** * Get the URI part of the name of this node. This is the URI corresponding to the * prefix, or the URI of the default namespace if appropriate. * @return The URI of the namespace of this node. For an unnamed node, return null. * For a node with an empty prefix, return an empty string. */ public String getURI() { return node.getURI(); } /** * Get the prefix of the name of the node. This is defined only for elements and attributes. * If the node has no prefix, or for other kinds of node, return a zero-length string. * * @return The prefix of the name of the node. */ public String getPrefix() { return node.getPrefix(); } /** * Get the display name of this node. For elements and attributes this is [prefix:]localname. * For unnamed nodes, it is an empty string. * @return The display name of this node. * For a node with no name, return an empty string. */ public String getDisplayName() { return node.getDisplayName(); } /** * Get the NodeInfo object representing the parent of this node */ public NodeInfo getParent() { if (parent==null) { NodeInfo realParent = node.getParent(); if (realParent != null) { parent = makeWrapper(realParent, docWrapper, null); } } return parent; } /** * Return an iteration over the nodes reached by the given axis from this node * @param axisNumber the axis to be used * @return a SequenceIterator that scans the nodes reached by the axis in turn. */ public AxisIterator iterateAxis(byte axisNumber) { switch (axisNumber) { case Axis.ATTRIBUTE: case Axis.NAMESPACE: return new WrappingIterator(node.iterateAxis(axisNumber), this); case Axis.CHILD: return new StrippingIterator(node.iterateAxis(axisNumber), this); case Axis.FOLLOWING_SIBLING: case Axis.PRECEDING_SIBLING: StrippedNode parent = (StrippedNode)getParent(); if (parent == null) { return EmptyIterator.getInstance(); } else { return new StrippingIterator(node.iterateAxis(axisNumber), parent); } default: return new StrippingIterator(node.iterateAxis(axisNumber), null); } } /** * Return an iteration over the nodes reached by the given axis from this node * @param axisNumber the axis to be used * @param nodeTest A pattern to be matched by the returned nodes * @return a SequenceIterator that scans the nodes reached by the axis in turn. */ public AxisIterator iterateAxis(byte axisNumber, NodeTest nodeTest) { return new Navigator.AxisFilter(iterateAxis(axisNumber), nodeTest); } /** * Get the value of a given attribute of this node * @param fingerprint The fingerprint of the attribute name * @return the attribute value if it exists or null if not */ public String getAttributeValue(int fingerprint) { return node.getAttributeValue(fingerprint); } /** * Get the root node - always a document node with this tree implementation * @return the NodeInfo representing the containing document */ public NodeInfo getRoot() { return docWrapper; } /** * Get the root (document) node * @return the DocumentInfo representing the containing document */ public DocumentInfo getDocumentRoot() { return docWrapper; } /** * Determine whether the node has any children.
    * Note: the result is equivalent to
    * getEnumeration(Axis.CHILD, AnyNodeTest.getInstance()).hasNext() */ public boolean hasChildNodes() { return node.hasChildNodes(); } /** * Get a character string that uniquely identifies this node. * Note: a.isSameNode(b) if and only if generateId(a)==generateId(b) * @param buffer a buffer, into which will be placed * a string that uniquely identifies this node, within this * document. The calling code prepends information to make the result * unique across all documents. */ public void generateId(FastStringBuffer buffer) { node.generateId(buffer); } /** * Get the document number of the document containing this node. For a free-standing * orphan node, just return the hashcode. */ public int getDocumentNumber() { return docWrapper.getDocumentNumber(); } /** * Copy this node to a given outputter (deep copy) */ public void copy(Receiver out, int whichNamespaces, boolean copyAnnotations, int locationId) throws XPathException { // The underlying code does not do whitespace stripping. So we need to interpose // a stripper. Stripper stripper = docWrapper.getStripper().getAnother(); stripper.setUnderlyingReceiver(out); node.copy(stripper, whichNamespaces, copyAnnotations, locationId); } /** * Get all namespace undeclarations and undeclarations defined on this element. * * @param buffer If this is non-null, and the result array fits in this buffer, then the result * may overwrite the contents of this array, to avoid the cost of allocating a new array on the heap. * @return An array of integers representing the namespace declarations and undeclarations present on * this element. For a node other than an element, return null. Otherwise, the returned array is a * sequence of namespace codes, whose meaning may be interpreted by reference to the name pool. The * top half word of each namespace code represents the prefix, the bottom half represents the URI. * If the bottom half is zero, then this is a namespace undeclaration rather than a declaration. * The XML namespace is never included in the list. If the supplied array is larger than required, * then the first unused entry will be set to -1. *

    *

    For a node other than an element, the method returns null.

    */ public int[] getDeclaredNamespaces(int[] buffer) { return node.getDeclaredNamespaces(buffer); } /** * Determine whether this node has the is-id property * * @return true if the node is an ID */ public boolean isId() { return false; } /** * Determine whether this node has the is-idref property * * @return true if the node is an IDREF or IDREFS element or attribute */ public boolean isIdref() { return false; } /** * Determine whether the node has the is-nilled property * * @return true if the node has the is-nilled property */ public boolean isNilled() { return false; } /** * A WrappingIterator delivers wrappers for the nodes delivered * by its underlying iterator. It is used when no whitespace stripping * is actually needed, e.g. for the attribute axis. But we still need to * create wrappers, so that further iteration remains in the virtual layer * rather than switching to the real nodes. */ private final class WrappingIterator implements AxisIterator { AxisIterator base; StrippedNode parent; NodeInfo current; boolean atomizing = false; /** * Create a WrappingIterator * @param base The underlying iterator * @param parent If all the nodes to be wrapped have the same parent, * it can be specified here. Otherwise specify null. */ public WrappingIterator(AxisIterator base, StrippedNode parent) { this.base = base; this.parent = parent; } /** * Move to the next node, without returning it. Returns true if there is * a next node, false if the end of the sequence has been reached. After * calling this method, the current node may be retrieved using the * current() function. */ public boolean moveNext() { return (next() != null); } public Item next() { Item n = base.next(); if (n instanceof NodeInfo && !atomizing) { current = makeWrapper((NodeInfo)n, docWrapper, parent); } else { current = (NodeInfo)n; } return current; } public Item current() { return current; } public int position() { return base.position(); } public void close() { base.close(); } /** * Return an iterator over an axis, starting at the current node. * * @param axis the axis to iterate over, using a constant such as * {@link Axis#CHILD} * @param test a predicate to apply to the nodes before returning them. * @throws NullPointerException if there is no current node */ public AxisIterator iterateAxis(byte axis, NodeTest test) { return current.iterateAxis(axis, test); } /** * Return the atomized value of the current node. * * @return the atomized value. * @throws NullPointerException if there is no current node */ public Value atomize() throws XPathException { return current.atomize(); } /** * Return the string value of the current node. * * @return the string value, as an instance of CharSequence. * @throws NullPointerException if there is no current node */ public CharSequence getStringValue() { return current.getStringValueCS(); } public SequenceIterator getAnother() { return new WrappingIterator((AxisIterator)base.getAnother(), parent); } /** * Get properties of this iterator, as a bit-significant integer. * * @return the properties of this iterator. This will be some combination of * properties such as {@link #GROUNDED}, {@link #LAST_POSITION_FINDER}, * and {@link #LOOKAHEAD}. It is always * acceptable to return the value zero, indicating that there are no known special properties. * It is acceptable for the properties of the iterator to change depending on its state. */ public int getProperties() { return 0; } /** * Indicate that any nodes returned in the sequence will be atomized. This * means that if it wishes to do so, the implementation can return the typed * values of the nodes rather than the nodes themselves. The implementation * is free to ignore this hint. * @param atomizing true if the caller of this iterator will atomize any * nodes that are returned, and is therefore willing to accept the typed * value of the nodes instead of the nodes themselves. */ // public void setIsAtomizing(boolean atomizing) { // this.atomizing = true; // if (base instanceof AtomizableIterator) { // ((AtomizableIterator)base).setIsAtomizing(atomizing); // } // } } // end of class WrappingIterator /** * A StrippingIterator delivers wrappers for the nodes delivered * by its underlying iterator. It is used when whitespace stripping * may be needed, e.g. for the child axis. It examines all text nodes * encountered to see if they need to be stripped, and if so, it * skips them. */ private final class StrippingIterator implements AxisIterator { AxisIterator base; StrippedNode parent; NodeInfo currentVirtualNode; int position; /** * Create a StrippingIterator * @param base The underlying iterator * @param parent If all the nodes to be wrapped have the same parent, * it can be specified here. Otherwise specify null. */ public StrippingIterator(AxisIterator base, StrippedNode parent) { this.base = base; this.parent = parent; position = 0; } /** * Move to the next node, without returning it. Returns true if there is * a next node, false if the end of the sequence has been reached. After * calling this method, the current node may be retrieved using the * current() function. */ public boolean moveNext() { return (next() != null); } public Item next() { NodeInfo nextRealNode; while (true) { nextRealNode = (NodeInfo)base.next(); if (nextRealNode==null) { return null; } if (isPreserved(nextRealNode)) { break; } // otherwise skip this whitespace text node } currentVirtualNode = makeWrapper(nextRealNode, docWrapper, parent); position++; return currentVirtualNode; } private boolean isPreserved(NodeInfo nextRealNode) { if (nextRealNode.getNodeKind() != Type.TEXT) { return true; } if (!Whitespace.isWhite(nextRealNode.getStringValueCS())) { return true; } NodeInfo actualParent = (parent==null ? nextRealNode.getParent() : parent.node); if (docWrapper.containsPreserveSpace()) { NodeInfo p = actualParent; // the document contains one or more xml:space="preserve" attributes, so we need to see // if one of them is on an ancestor of this node while (p.getNodeKind() == Type.ELEMENT) { String val = p.getAttributeValue(StandardNames.XML_SPACE); if (val != null) { if ("preserve".equals(val)) { return true; } else if ("default".equals(val)) { break; } } p = p.getParent(); } } try { if (docWrapper.getStripper().isSpacePreserving(actualParent) == Stripper.ALWAYS_PRESERVE) { return true; } } catch (XPathException e) { return true; } return false; } public Item current() { return currentVirtualNode; } public int position() { return position; } public void close() { base.close(); } /** * Return an iterator over an axis, starting at the current node. * * @param axis the axis to iterate over, using a constant such as * {@link Axis#CHILD} * @param test a predicate to apply to the nodes before returning them. * @throws NullPointerException if there is no current node */ public AxisIterator iterateAxis(byte axis, NodeTest test) { return currentVirtualNode.iterateAxis(axis, test); } /** * Return the atomized value of the current node. * * @return the atomized value. * @throws NullPointerException if there is no current node */ public Value atomize() throws XPathException { return currentVirtualNode.atomize(); } /** * Return the string value of the current node. * * @return the string value, as an instance of CharSequence. * @throws NullPointerException if there is no current node */ public CharSequence getStringValue() { return currentVirtualNode.getStringValue(); } public SequenceIterator getAnother() { return new StrippingIterator((AxisIterator)base.getAnother(), parent); } /** * Get properties of this iterator, as a bit-significant integer. * * @return the properties of this iterator. This will be some combination of * properties such as {@link #GROUNDED}, {@link #LAST_POSITION_FINDER}, * and {@link #LOOKAHEAD}. It is always * acceptable to return the value zero, indicating that there are no known special properties. * It is acceptable for the properties of the iterator to change depending on its state. */ public int getProperties() { return 0; } } // end of class StrippingIterator } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is // Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/om/Item.java0000644000175000017500000001034411033112257017555 0ustar eugeneeugenepackage net.sf.saxon.om; import net.sf.saxon.trans.XPathException; import net.sf.saxon.evpull.PullEvent; /** * An Item is an object that can occur as a member of a sequence. * It corresponds directly to the concept of an item in the XPath 2.0 data model. * There are two kinds of Item: atomic values, and nodes. *

    * This interface is part of the public Saxon API. As such (starting from Saxon 8.4), * methods that form part of the stable API are labelled with a JavaDoc "since" tag * to identify the Saxon release at which they were introduced. *

    * Note: there is no method getItemType(). This is to avoid having to implement it * on every implementation of NodeInfo. Instead, use the static method Type.getItemType(Item). * * @author Michael H. Kay * @since 8.4 */ public interface Item extends ValueRepresentation, PullEvent { /** * Get the value of the item as a string. For nodes, this is the string value of the * node as defined in the XPath 2.0 data model, except that all nodes are treated as being * untyped: it is not an error to get the string value of a node with a complex type. * For atomic values, the method returns the result of casting the atomic value to a string. *

    * If the calling code can handle any CharSequence, the method {@link #getStringValueCS} should * be used. If the caller requires a string, this method is preferred. * * @return the string value of the item * @see #getStringValueCS * @since 8.4 */ public String getStringValue(); /** * Get the string value of the item as a CharSequence. This is in some cases more efficient than * the version of the method that returns a String. The method satisfies the rule that * X.getStringValueCS().toString() returns a string that is equal to * X.getStringValue(). *

    * Note that two CharSequence values of different types should not be compared using equals(), and * for the same reason they should not be used as a key in a hash table. *

    * If the calling code can handle any CharSequence, this method should * be used. If the caller requires a string, the {@link #getStringValue} method is preferred. * * @return the string value of the item * @see #getStringValue * @since 8.4 */ public CharSequence getStringValueCS(); /** * Get the typed value of the item. *

    * For a node, this is the typed value as defined in the XPath 2.0 data model. Since a node * may have a list-valued data type, the typed value is in general a sequence, and it is returned * in the form of a SequenceIterator. *

    * If the node has not been validated against a schema, the typed value * will be the same as the string value, either as an instance of xs:string or as an instance * of xs:untypedAtomic, depending on the node kind. *

    * For an atomic value, this method returns an iterator over a singleton sequence containing * the atomic value itself. * * @return an iterator over the items in the typed value of the node or atomic value. The * items returned by this iterator will always be atomic values. * @throws XPathException where no typed value is available, for example in the case of * an element with complex content * @since 8.4 */ public SequenceIterator getTypedValue() throws XPathException; } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/om/GroundedIterator.java0000644000175000017500000000266411033112257022146 0ustar eugeneeugenepackage net.sf.saxon.om; import net.sf.saxon.trans.XPathException; /** * This interface is an extension to the SequenceIterator interface; it represents * a SequenceIterator that is based on an in-memory representation of a sequence, * and that is therefore capable of returned a SequenceValue containing all the items * in the sequence. */ public interface GroundedIterator extends SequenceIterator { /** * Return a GroundedValue containing all the items in the sequence returned by this * SequenceIterator. This should be an "in-memory" value, not a Closure. * @return the corresponding Value */ public GroundedValue materialize() throws XPathException; } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/om/Orphan.java0000644000175000017500000006713711034666253020135 0ustar eugeneeugenepackage net.sf.saxon.om; import net.sf.saxon.Configuration; import net.sf.saxon.trans.Err; import net.sf.saxon.event.Receiver; import net.sf.saxon.event.Builder; import net.sf.saxon.pattern.NodeTest; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.SchemaType; import net.sf.saxon.type.Type; import net.sf.saxon.value.UntypedAtomicValue; import net.sf.saxon.value.Value; import net.sf.saxon.value.StringValue; /** * A node (implementing the NodeInfo interface) representing an attribute, text node, * comment, processing instruction, or namespace that has no parent (and of course no children). * Exceptionally it is also used (during whitespace stripping) to represent a standalone element. * @author Michael H. Kay */ public final class Orphan implements MutableNodeInfo, FingerprintedNode { private short kind; private int nameCode = -1; private CharSequence stringValue; private int typeAnnotation = -1; private Configuration config; private String systemId; private boolean isId; private boolean isIdref; /** * Create an Orphan node * @param config the Saxon configuration */ public Orphan(Configuration config) { this.config = config; } /** * Set the node kind * @param kind the kind of node, for example {@link Type#ELEMENT} or {@link Type#ATTRIBUTE} */ public void setNodeKind(short kind) { this.kind = kind; } /** * Set the name of the node * @param nameCode the integer code representing the name of the node in the NamePool */ public void setNameCode(int nameCode) { this.nameCode = nameCode; } /** * Set the string value of the node * @param stringValue the string value of the node */ public void setStringValue(CharSequence stringValue) { this.stringValue = stringValue; } /** * Set the type annotation of the node * @param typeAnnotation the type annotation, and integer code representing the fingerprint of the type name */ public void setTypeAnnotation(int typeAnnotation) { this.typeAnnotation = typeAnnotation; } /** * Set the base URI of the node * @param systemId the base URI of the node */ public void setSystemId(String systemId) { this.systemId = systemId; } /** * Set the isId property * @param id the isId property */ public void setIsId(boolean id) { this.isId = id; } /** * Set the isIdref property * @param idref the isIdref property */ public void setIsIdref(boolean idref) { this.isIdref = idref; } /** * Return the kind of node. * @return one of the values Type.ELEMENT, Type.TEXT, Type.ATTRIBUTE, etc. */ public int getNodeKind() { return kind; } /** * Get the typed value of the node * @return an iterator over the items making up the typed value */ public SequenceIterator getTypedValue() throws XPathException { switch (getNodeKind()) { case Type.COMMENT: case Type.PROCESSING_INSTRUCTION: return SingletonIterator.makeIterator(new StringValue(stringValue)); case Type.TEXT: case Type.DOCUMENT: case Type.NAMESPACE: return SingletonIterator.makeIterator(new UntypedAtomicValue(stringValue)); default: if (typeAnnotation == -1 || typeAnnotation == StandardNames.XS_UNTYPED || typeAnnotation == StandardNames.XS_UNTYPED_ATOMIC) { return SingletonIterator.makeIterator(new UntypedAtomicValue(stringValue)); } else { SchemaType stype = config.getSchemaType(typeAnnotation); if (stype == null) { String typeName = config.getNamePool().getDisplayName(typeAnnotation); throw new IllegalStateException("Unknown type annotation " + Err.wrap(typeName) + " in standalone node"); } else { return stype.getTypedValue(this); } } } } /** * Get the typed value. The result of this method will always be consistent with the method * {@link Item#getTypedValue()}. However, this method is often more convenient and may be * more efficient, especially in the common case where the value is expected to be a singleton. * * @return the typed value. If requireSingleton is set to true, the result will always be an * AtomicValue. In other cases it may be a Value representing a sequence whose items are atomic * values. * @since 8.5 */ public Value atomize() throws XPathException { switch (getNodeKind()) { case Type.COMMENT: case Type.PROCESSING_INSTRUCTION: return new StringValue(stringValue); case Type.TEXT: case Type.DOCUMENT: case Type.NAMESPACE: return new UntypedAtomicValue(stringValue); default: if (typeAnnotation == -1 || typeAnnotation == StandardNames.XS_UNTYPED || typeAnnotation == StandardNames.XS_UNTYPED_ATOMIC) { return new UntypedAtomicValue(stringValue); } else { SchemaType stype = config.getSchemaType(typeAnnotation); if (stype == null) { String typeName = config.getNamePool().getDisplayName(typeAnnotation); throw new IllegalStateException("Unknown type annotation " + Err.wrap(typeName) + " in standalone node"); } else { return stype.atomize(this); } } } } /** * Get the configuration * @return the Saxon configuration object */ public Configuration getConfiguration() { return config; } /** * Get the name pool */ public NamePool getNamePool() { return config.getNamePool(); } /** * Get the type annotation */ public int getTypeAnnotation() { if (typeAnnotation == -1) { if (kind == Type.ELEMENT) { return StandardNames.XS_UNTYPED; } else if (kind == Type.ATTRIBUTE) { return StandardNames.XS_UNTYPED_ATOMIC; } } return typeAnnotation; } /** * Determine whether this is the same node as another node.
    * Note: a.isSameNode(b) if and only if generateId(a)==generateId(b) * @return true if this Node object and the supplied Node object represent the * same node in the tree. */ public boolean isSameNodeInfo(NodeInfo other) { return this==other; } /** * The equals() method compares nodes for identity. It is defined to give the same result * as isSameNodeInfo(). * @param other the node to be compared with this node * @return true if this NodeInfo object and the supplied NodeInfo object represent * the same node in the tree. * @since 8.7 Previously, the effect of the equals() method was not defined. Callers * should therefore be aware that third party implementations of the NodeInfo interface may * not implement the correct semantics. It is safer to use isSameNodeInfo() for this reason. * The equals() method has been defined because it is useful in contexts such as a Java Set or HashMap. */ public boolean equals(Object other) { return other instanceof NodeInfo && isSameNodeInfo((NodeInfo)other); } /** * The hashCode() method obeys the contract for hashCode(): that is, if two objects are equal * (represent the same node) then they must have the same hashCode() * @since 8.7 Previously, the effect of the equals() and hashCode() methods was not defined. Callers * should therefore be aware that third party implementations of the NodeInfo interface may * not implement the correct semantics. */ public int hashCode() { return super.hashCode(); } /** * Get the System ID for the node. * @return the System Identifier of the entity in the source document containing the node, * or null if not known. Note this is not the same as the base URI: the base URI can be * modified by xml:base, but the system ID cannot. */ public String getSystemId() { return systemId; } /** * Get the Base URI for the node, that is, the URI used for resolving a relative URI contained * in the node. This will be the same as the System ID unless xml:base has been used. */ public String getBaseURI() { if (kind == Type.PROCESSING_INSTRUCTION) { return systemId; } else { return null; } } /** * Get line number * @return the line number of the node in its original source document; or -1 if not available */ public int getLineNumber() { return -1; } /** * Get column number * @return the column number of the node in its original source document; or -1 if not available */ public int getColumnNumber() { return -1; } /** * Determine the relative position of this node and another node, in document order. * The other node will always be in the same document. * @param other The other node, whose position is to be compared with this node * @return -1 if this node precedes the other node, +1 if it follows the other * node, or 0 if they are the same node. (In this case, isSameNode() will always * return true, and the two nodes will produce the same result for generateId()) */ public int compareOrder(NodeInfo other) { // are they the same node? if (this.isSameNodeInfo(other)) { return 0; } return (this.hashCode() < other.hashCode() ? -1 : +1); } /** * Return the string value of the node. * @return the string value of the node */ public String getStringValue() { return stringValue.toString(); } /** * Get the value of the item as a CharSequence. This is in some cases more efficient than * the version of the method that returns a String. */ public CharSequence getStringValueCS() { return stringValue; } /** * Get name code. The name code is a coded form of the node name: two nodes * with the same name code have the same namespace URI, the same local name, * and the same prefix. By masking the name code with &0xfffff, you get a * fingerprint: two nodes with the same fingerprint have the same local name * and namespace URI. * @see net.sf.saxon.om.NamePool#allocate allocate */ public int getNameCode() { return nameCode; } /** * Get fingerprint. The fingerprint is a coded form of the expanded name * of the node: two nodes * with the same name code have the same namespace URI and the same local name. * A fingerprint of -1 should be returned for a node with no name. */ public int getFingerprint() { if (nameCode == -1) { return -1; } else { return getNameCode()&0xfffff; } } /** * Get the local part of the name of this node. This is the name after the ":" if any. * @return the local part of the name. For an unnamed node, returns "". */ public String getLocalPart() { if (nameCode == -1) { return ""; } else { return config.getNamePool().getLocalName(nameCode); } } /** * Get the URI part of the name of this node. This is the URI corresponding to the * prefix, or the URI of the default namespace if appropriate. * @return The URI of the namespace of this node. For an unnamed node, return null. * For a node with an empty prefix, return an empty string. */ public String getURI() { if (nameCode == -1) { return ""; } else { return config.getNamePool().getURI(nameCode); } } /** * Get the prefix of the name of the node. This is defined only for elements and attributes. * If the node has no prefix, or for other kinds of node, return a zero-length string. * * @return The prefix of the name of the node. */ public String getPrefix() { if (nameCode == -1) { return ""; } else { return config.getNamePool().getPrefix(nameCode); } } /** * Get the display name of this node. For elements and attributes this is [prefix:]localname. * For unnamed nodes, it is an empty string. * @return The display name of this node. * For a node with no name, return an empty string. */ public String getDisplayName() { if (nameCode == -1) { return ""; } else { return config.getNamePool().getDisplayName(nameCode); } } /** * Get the NodeInfo object representing the parent of this node * @return null - an Orphan has no parent. */ public NodeInfo getParent() { return null; } /** * Return an iteration over the nodes reached by the given axis from this node * @param axisNumber the axis to be searched, e.g. Axis.CHILD or Axis.ANCESTOR * @return a SequenceIterator that scans the nodes reached by the axis in turn. */ public AxisIterator iterateAxis(byte axisNumber) { switch (axisNumber) { case Axis.ANCESTOR_OR_SELF: case Axis.DESCENDANT_OR_SELF: case Axis.SELF: return SingleNodeIterator.makeIterator(this); case Axis.ANCESTOR: case Axis.ATTRIBUTE: case Axis.CHILD: case Axis.DESCENDANT: case Axis.FOLLOWING: case Axis.FOLLOWING_SIBLING: case Axis.NAMESPACE: case Axis.PARENT: case Axis.PRECEDING: case Axis.PRECEDING_SIBLING: case Axis.PRECEDING_OR_ANCESTOR: return EmptyIterator.getInstance(); default: throw new IllegalArgumentException("Unknown axis number " + axisNumber); } } /** * Return an iteration over the nodes reached by the given axis from this node * @param axisNumber the axis to be searched, e.g. Axis.CHILD or Axis.ANCESTOR * @param nodeTest A pattern to be matched by the returned nodes * @return a SequenceIterator that scans the nodes reached by the axis in turn. */ public AxisIterator iterateAxis(byte axisNumber, NodeTest nodeTest) { switch (axisNumber) { case Axis.ANCESTOR_OR_SELF: case Axis.DESCENDANT_OR_SELF: case Axis.SELF: return Navigator.filteredSingleton(this, nodeTest); case Axis.ANCESTOR: case Axis.ATTRIBUTE: case Axis.CHILD: case Axis.DESCENDANT: case Axis.FOLLOWING: case Axis.FOLLOWING_SIBLING: case Axis.NAMESPACE: case Axis.PARENT: case Axis.PRECEDING: case Axis.PRECEDING_SIBLING: case Axis.PRECEDING_OR_ANCESTOR: return EmptyIterator.getInstance(); default: throw new IllegalArgumentException("Unknown axis number " + axisNumber); } } /** * Get the value of a given attribute of this node * @param fingerprint The fingerprint of the attribute name * @return the attribute value if it exists or null if not */ public String getAttributeValue(int fingerprint) { return null; } /** * Get the root node of this tree (not necessarily a document node). * Always returns this node in the case of an Orphan node. */ public NodeInfo getRoot() { return this; } /** * Get the root (document) node * @return the DocumentInfo representing the containing document, or null if the * node is not part of a document. Always null for an Orphan node. */ public DocumentInfo getDocumentRoot() { return null; } /** * Determine whether the node has any children. * @return false - an orphan node never has any children */ public boolean hasChildNodes() { return false; } /** * Get a character string that uniquely identifies this node. * Note: a.isSameNode(b) if and only if generateId(a)==generateId(b) * @param buffer a buffer, into which will be placed * a string that uniquely identifies this node, within this * document. The calling code prepends information to make the result * unique across all documents. */ public void generateId(FastStringBuffer buffer) { buffer.append('Q'); buffer.append(Integer.toString(hashCode())); } /** * Get the document number of the document containing this node. For a free-standing * orphan node, just return the hashcode. */ public int getDocumentNumber() { return hashCode() & 0xffffff; // lose the top bits because we need to subtract these values for comparison } /** * Copy this node to a given outputter (deep copy) */ public void copy(Receiver out, int whichNamespaces, boolean copyAnnotations, int locationId) throws XPathException { Navigator.copy(this, out, config.getNamePool(), whichNamespaces, copyAnnotations, locationId); } /** * Get all namespace undeclarations and undeclarations defined on this element. * * @param buffer If this is non-null, and the result array fits in this buffer, then the result * may overwrite the contents of this array, to avoid the cost of allocating a new array on the heap. * @return An array of integers representing the namespace declarations and undeclarations present on * this element. For a node other than an element, return null. Otherwise, the returned array is a * sequence of namespace codes, whose meaning may be interpreted by reference to the name pool. The * top half word of each namespace code represents the prefix, the bottom half represents the URI. * If the bottom half is zero, then this is a namespace undeclaration rather than a declaration. * The XML namespace is never included in the list. If the supplied array is larger than required, * then the first unused entry will be set to -1. *

    *

    For a node other than an element, the method returns null.

    */ public int[] getDeclaredNamespaces(int[] buffer) { return null; } /** * Determine whether this node has the is-id property * * @return true if the node is an ID */ public boolean isId() { return isId || (kind == Type.ATTRIBUTE && (nameCode & NamePool.FP_MASK) == StandardNames.XML_ID); } /** * Determine whether this node has the is-idref property * * @return true if the node is an IDREF or IDREFS element or attribute */ public boolean isIdref() { return isIdref; } /** * Determine whether the node has the is-nilled property * * @return true if the node has the is-nilled property */ public boolean isNilled() { return false; } /** * Insert copies of a sequence of nodes as children of this node. *

    *

    This method takes no action unless the target node is a document node or element node. It also * takes no action in respect of any supplied nodes that are not elements, text nodes, comments, or * processing instructions.

    *

    *

    The supplied nodes will be copied to form the new children. Adjacent text nodes will be merged, and * zero-length text nodes removed.

    * @param source the nodes to be inserted * @param atStart true if the new nodes are to be inserted before existing children; false if they are * @param inherit true if the insert nodes are to inherit the namespaces of their new parent; false * if such namespaces are to be undeclared */ public void insertChildren(NodeInfo[] source, boolean atStart, boolean inherit) { // no action: node is not a document or element node } /** * Insert copies of a sequence of nodes as siblings of this node. *

    *

    This method takes no action unless the target node is an element, text node, comment, or * processing instruction, and one that has a parent node. It also * takes no action in respect of any supplied nodes that are not elements, text nodes, comments, or * processing instructions.

    *

    *

    The supplied nodes must use the same data model implementation as the tree into which they * will be inserted.

    * @param source the nodes to be inserted * @param before true if the new nodes are to be inserted before the target node; false if they are * @param inherit true if the insert nodes are to inherit the namespaces of their new parent; false * if such namespaces are to be undeclared */ public void insertSiblings(NodeInfo[] source, boolean before, boolean inherit) { // no action: node has no parent } /** * Remove an attribute from this element node *

    *

    If this node is not an element, or if it has no attribute with the specified name, * this method takes no action.

    *

    *

    The attribute node itself is not modified in any way.

    * @param nameCode the name of the attribute to be removed */ public void removeAttribute(int nameCode) { // no action: node is not an element } /** * Add an attribute to this element node. *

    *

    If this node is not an element, or if the supplied node is not an attribute, the method * takes no action. If the element already has an attribute with this name, the existing attribute * is replaced.

    * @param nameCode the name of the new attribute * @param typeCode the type annotation of the new attribute * @param value the string value of the new attribute * @param properties properties including IS_ID and IS_IDREF properties */ public void putAttribute(int nameCode, int typeCode, CharSequence value, int properties) { // no action: node is not an element } /** * Delete this node (that is, detach it from its parent). *

    If this node has preceding and following siblings that are both text nodes, * the two text nodes will be joined into a single text node (the identity of this node * with respect to its predecessors is undefined).

    */ public void delete() { // no action: node has no parent from which it can be detached } /** * Replace this node with a given sequence of nodes * @param replacement the replacement nodes * @param inherit true if the replacement nodes are to inherit the namespaces of their new parent; false * if such namespaces are to be undeclared * @throws IllegalArgumentException if any of the replacement nodes is of the wrong kind. When replacing * a child node, the replacement nodes must all be elements, text, comment, or PI nodes; when replacing * an attribute, the replacement nodes must all be attributes. */ public void replace(NodeInfo[] replacement, boolean inherit) { // no action, node has no parent } /** * Replace the string-value of this node. If applied to an element or document node, this * causes all existing children to be deleted, and replaced with a new text node * whose string value is the value supplied. The caller is responsible for checking * that the value is valid, for example that comments do not contain a double hyphen; the * implementation is not required to check for such conditions. * @param stringValue the new string value */ public void replaceStringValue(CharSequence stringValue) { this.stringValue = stringValue; } /** * Rename this node. *

    This call has no effect if applied to a nameless node, such as a text node or comment.

    *

    If necessary, a new namespace binding will be added to the target element, or to the element * parent of the target attribute

    * @param newNameCode the namecode of the new name in the name pool * @throws IllegalArgumentException if the new name code is not present in the name pool, or if * it has a (prefix, uri) pair in which the * prefix is the same as that of an existing in-scope namespace binding and the uri is different from that * namespace binding. */ public void rename(int newNameCode) { if (kind==Type.ATTRIBUTE || kind==Type.PROCESSING_INSTRUCTION) { nameCode = newNameCode; } } /** * Add a namespace binding (that is, a namespace node) to this element. This call has no effect if applied * to a node other than an element. * @param nscode The namespace code representing the (prefix, uri) pair of the namespace binding to be * added. If the target element already has a namespace binding with this (prefix, uri) pair, the call has * no effect. If the target element currently has a namespace binding with this prefix and a different URI, an * exception is raised. * @param inherit If true, the new namespace binding will be inherited by any children of the target element * that do not already have a namespace binding for the specified prefix, recursively. * If false, the new namespace binding will not be inherited. * @throws IllegalArgumentException if the namespace code is not present in the namepool, or if the target * element already has a namespace binding for this prefix */ public void addNamespace(int nscode, boolean inherit) { // no action: node is not an element } /** * Remove type information from this node (and its ancestors, recursively). * This method implements the upd:removeType() primitive defined in the XQuery Update specification. * (Note: the caller is responsible for updating the set of nodes marked for revalidation) */ public void removeTypeAnnotation() { typeAnnotation = StandardNames.XS_UNTYPED_ATOMIC; } /** * Get a Builder suitable for building nodes that can be attached to this document. * This implementation always throws an exception: the method should only be called on a document or element * node when creating new children. */ public Builder newBuilder() { throw new UnsupportedOperationException("Cannot create children for an Orphan node"); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is // Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/om/AttributeCollectionImpl.java0000644000175000017500000005226011033112257023463 0ustar eugeneeugenepackage net.sf.saxon.om; import net.sf.saxon.Configuration; import net.sf.saxon.event.LocationProvider; import org.xml.sax.Attributes; /** * AttributeCollectionImpl is an implementation of both the SAX2 interface Attributes * and the Saxon equivalent AttributeCollection. * *

    As well as providing the information required by the SAX2 interface, an * AttributeCollection can hold type information (as needed to support the JAXP 1.3 * {@link javax.xml.validation.ValidatorHandler} interface), and location information * for debugging. The location information is used in the case of attributes on a result * tree to identify the location in the query or stylesheet from which they were * generated. */ public final class AttributeCollectionImpl implements Attributes, AttributeCollection { // Attribute values are maintained as an array of Strings. Everything else is maintained // in the form of integers. private Configuration config; private LocationProvider locationProvider; private String[] values = null; private int[] codes = null; private int used = 0; // Empty attribute collection. The caller is trusted not to try and modify it. public static final AttributeCollection EMPTY_ATTRIBUTE_COLLECTION = new AttributeCollectionImpl(null); // Layout of the integer array. There are RECSIZE integers for each attribute. private static final int RECSIZE = 4; //private static final int NAMECODE = 0; private static final int TYPECODE = 1; private static final int LOCATIONID = 2; private static final int PROPERTIES = 3; /** * Create an empty attribute list. * @param config the Saxon Configuration */ public AttributeCollectionImpl(Configuration config) { this.config = config; used = 0; } /** * Set the location provider. This must be set if the methods getSystemId() and getLineNumber() * are to be used to get location information for an attribute. * @param provider the location provider */ public void setLocationProvider(LocationProvider provider) { locationProvider = provider; } /** * Add an attribute to an attribute list. The parameters correspond * to the parameters of the {@link net.sf.saxon.event.Receiver#attribute(int,int,CharSequence,int,int)} * method. There is no check that the name of the attribute is distinct from other attributes * already in the collection: this check must be made by the caller. * * @param nameCode Integer representing the attribute name. * @param typeCode The attribute type code * @param value The attribute value (must not be null) * @param locationId Identifies the attribtue location. * @param properties Attribute properties */ public void addAttribute(int nameCode, int typeCode, String value, long locationId, int properties) { if (values == null) { values = new String[5]; codes = new int[5 * RECSIZE]; used = 0; } if (values.length == used) { int newsize = (used == 0 ? 5 : used * 2); String[] v2 = new String[newsize]; int[] c2 = new int[newsize * RECSIZE]; System.arraycopy(values, 0, v2, 0, used); System.arraycopy(codes, 0, c2, 0, used*RECSIZE); values = v2; codes = c2; } int n = used*RECSIZE; codes[n] = nameCode; codes[n+TYPECODE] = typeCode; codes[n+LOCATIONID] = (int)locationId; codes[n+PROPERTIES] = properties; values[used++] = value; } /** * Set (overwrite) an attribute in the attribute list. The parameters correspond * to the parameters of the {@link net.sf.saxon.event.Receiver#attribute(int,int,CharSequence,int,int)} * method. * @param index Identifies the entry to be replaced * @param nameCode Integer representing the attribute name. * @param typeCode The attribute type code * @param value The attribute value (must not be null) * @param locationId Identifies the attribtue location. * @param properties Attribute properties */ public void setAttribute(int index, int nameCode, int typeCode, String value, long locationId, int properties) { int n = index*RECSIZE; codes[n] = nameCode; codes[n+TYPECODE] = typeCode; codes[n+LOCATIONID] = (int)locationId; codes[n+PROPERTIES] = properties; values[index] = value; } /** * Clear the attribute list. This removes the values but doesn't free the memory used. * free the memory, use clear() then compact(). */ public void clear() { used = 0; } /** * Compact the attribute list to avoid wasting memory */ public void compact() { if (used == 0) { codes = null; values = null; } else if (values.length > used) { String[] v2 = new String[used]; int[] c2 = new int[used * RECSIZE]; System.arraycopy(values, 0, v2, 0, used); System.arraycopy(codes, 0, c2, 0, used*RECSIZE); values = v2; codes = c2; } } /** * Return the number of attributes in the list. * * @return The number of attributes in the list. */ public int getLength() { return (values == null ? 0 : used); } /** * Get the namecode of an attribute (by position). * * @param index The position of the attribute in the list. * @return The display name of the attribute as a string, or null if there * is no attribute at that position. */ public int getNameCode(int index) { if (codes == null) { return -1; } if (index < 0 || index >= used) { return -1; } return codes[(index * RECSIZE)]; } /** * Get the namecode of an attribute (by position). * * @param index The position of the attribute in the list. * @return The type annotation, as the fingerprint of the type name. * The bit {@link net.sf.saxon.om.NodeInfo#IS_DTD_TYPE} represents a DTD-derived type. */ public int getTypeAnnotation(int index) { if (codes == null) { return StandardNames.XS_UNTYPED_ATOMIC; } if (index < 0 || index >= used) { return StandardNames.XS_UNTYPED_ATOMIC; } return codes[index * RECSIZE + TYPECODE]; } /** * Get the locationID of an attribute (by position) * @param index The position of the attribute in the list. * @return The location identifier of the attribute. This can be supplied * to a {@link net.sf.saxon.event.LocationProvider} in order to obtain the * actual system identifier and line number of the relevant location */ public int getLocationId(int index) { if (codes == null) { return -1; } if (index < 0 || index >= used) { return -1; } return codes[index * RECSIZE + LOCATIONID]; } /** * Get the systemId part of the location of an attribute, at a given index. * *

    Attribute location information is not available from a SAX parser, so this method * is not useful for getting the location of an attribute in a source document. However, * in a Saxon result document, the location information represents the location in the * stylesheet of the instruction used to generate this attribute, which is useful for * debugging.

    * @param index the required attribute * @return the systemId of the location of the attribute */ public String getSystemId(int index) { return locationProvider.getSystemId(getLocationId(index)); } /** * Get the line number part of the location of an attribute, at a given index. * *

    Attribute location information is not available from a SAX parser, so this method * is not useful for getting the location of an attribute in a source document. However, * in a Saxon result document, the location information represents the location in the * stylesheet of the instruction used to generate this attribute, which is useful for * debugging.

    * @param index the required attribute * @return the line number of the location of the attribute */ public int getLineNumber(int index) { return locationProvider.getLineNumber(getLocationId(index)); } /** * Get the properties of an attribute (by position) * @param index The position of the attribute in the list. * @return The properties of the attribute. This is a set * of bit-settings defined in class {@link net.sf.saxon.event.ReceiverOptions}. The * most interesting of these is {{@link net.sf.saxon.event.ReceiverOptions#DEFAULTED_ATTRIBUTE}, * which indicates an attribute that was added to an element as a result of schema validation. */ public int getProperties(int index) { if (codes == null) { return -1; } if (index < 0 || index >= used) { return -1; } return codes[index * RECSIZE + PROPERTIES]; } /** * Get the prefix of the name of an attribute (by position). * * @param index The position of the attribute in the list. * @return The prefix of the attribute name as a string, or null if there * is no attribute at that position. Returns "" for an attribute that * has no prefix. */ public String getPrefix(int index) { if (codes == null) { return null; } if (index < 0 || index >= used) { return null; } return config.getNamePool().getPrefix(getNameCode(index)); } /** * Get the lexical QName of an attribute (by position). * * @param index The position of the attribute in the list. * @return The lexical QName of the attribute as a string, or null if there * is no attribute at that position. */ public String getQName(int index) { if (codes == null) { return null; } if (index < 0 || index >= used) { return null; } return config.getNamePool().getDisplayName(getNameCode(index)); } /** * Get the local name of an attribute (by position). * * @param index The position of the attribute in the list. * @return The local name of the attribute as a string, or null if there * is no attribute at that position. */ public String getLocalName(int index) { if (codes == null) { return null; } if (index < 0 || index >= used) { return null; } return config.getNamePool().getLocalName(getNameCode(index)); } /** * Get the namespace URI of an attribute (by position). * * @param index The position of the attribute in the list. * @return The local name of the attribute as a string, or null if there * is no attribute at that position. */ public String getURI(int index) { if (codes == null) { return null; } if (index < 0 || index >= used) { return null; } return config.getNamePool().getURI(getNameCode(index)); } /** * Get the type of an attribute (by position). This is a SAX2 method, * so it gets the type name as a DTD attribute type, mapped from the * schema type code. * * @param index The position of the attribute in the list. * @return The attribute type as a string ("NMTOKEN" for an * enumeration, and "CDATA" if no declaration was * read), or null if there is no attribute at * that position. */ public String getType(int index) { int typeCode = getTypeAnnotation(index) & NamePool.FP_MASK; switch (typeCode) { case StandardNames.XS_ID: return "ID"; case StandardNames.XS_IDREF: return "IDREF"; case StandardNames.XS_NMTOKEN: return "NMTOKEN"; case StandardNames.XS_ENTITY: return "ENTITY"; case StandardNames.XS_IDREFS: return "IDREFS"; case StandardNames.XS_NMTOKENS: return "NMTOKENS"; case StandardNames.XS_ENTITIES: return "ENTITIES"; default: return "CDATA"; } } /** * Get the type of an attribute (by name). * * @param uri The namespace uri of the attribute. * @param localname The local name of the attribute. * @return The index position of the attribute */ public String getType(String uri, String localname) { int index = findByName(uri, localname); return (index < 0 ? null : getType(index)); } /** * Get the value of an attribute (by position). * * @param index The position of the attribute in the list. * @return The attribute value as a string, or null if * there is no attribute at that position. */ public String getValue(int index) { if (values == null) { return null; } if (index < 0 || index >= used) { return null; } return values[index]; } /** * Get the value of an attribute (by name). * * @param uri The namespace uri of the attribute. * @param localname The local name of the attribute. * @return The index position of the attribute */ public String getValue(String uri, String localname) { int index = findByName(uri, localname); return (index < 0 ? null : getValue(index)); } /** * Get the attribute value using its fingerprint */ public String getValueByFingerprint(int fingerprint) { int index = findByFingerprint(fingerprint); return (index < 0 ? null : getValue(index)); } /** * Get the index of an attribute, from its lexical QName * * @param qname The lexical QName of the attribute. The prefix must match. * @return The index position of the attribute */ public int getIndex(String qname) { if (codes == null) { return -1; } if (qname.indexOf(':') < 0) { return findByName("", qname); } // Searching using prefix+localname is not recommended, but SAX allows it... String[] parts; try { parts = Name11Checker.getInstance().getQNameParts(qname); } catch (QNameException err) { return -1; } String prefix = parts[0]; if (prefix.length() == 0) { return findByName("", qname); } else { String localName = parts[1]; for (int i = 0; i < used; i++) { String lname = config.getNamePool().getLocalName(getNameCode(i)); String ppref = config.getNamePool().getPrefix(getNameCode(i)); if (localName.equals(lname) && prefix.equals(ppref)) { return i; } } return -1; } } /** * Get the index of an attribute (by name). * * @param uri The namespace uri of the attribute. * @param localname The local name of the attribute. * @return The index position of the attribute */ public int getIndex(String uri, String localname) { return findByName(uri, localname); } /** * Get the index, given the fingerprint. * Return -1 if not found. */ public int getIndexByFingerprint(int fingerprint) { return findByFingerprint(fingerprint); } /** * Get the type of an attribute (by lexical QName). * * @param name The lexical QName of the attribute. * @return The attribute type as a string (e.g. "NMTOKEN", or * "CDATA" if no declaration was read). */ public String getType(String name) { int index = getIndex(name); return getType(index); } /** * Get the value of an attribute (by lexical QName). * * @param name The attribute name (a lexical QName). * The prefix must match the prefix originally used. This method is defined in SAX, but is * not recommended except where the prefix is null. */ public String getValue(String name) { int index = getIndex(name); return getValue(index); } /** * Find an attribute by expanded name * @param uri the namespace uri * @param localName the local name * @return the index of the attribute, or -1 if absent */ private int findByName(String uri, String localName) { if (config == null) { return -1; // indicates an empty attribute set } NamePool namePool = config.getNamePool(); int f = namePool.getFingerprint(uri, localName); if (f == -1) { return -1; } return findByFingerprint(f); } /** * Find an attribute by fingerprint * @param fingerprint the fingerprint representing the name of the required attribute * @return the index of the attribute, or -1 if absent */ private int findByFingerprint(int fingerprint) { if (codes == null) { return -1; } for (int i = 0; i < used; i++) { if (fingerprint == (codes[(i * RECSIZE)] & NamePool.FP_MASK)) { return i; } } return -1; } /** * Determine whether a given attribute has the is-ID property set */ public boolean isId(int index) { return (codes[index * RECSIZE] & NamePool.FP_MASK) == StandardNames.XML_ID || config.getTypeHierarchy().isIdCode(getTypeAnnotation(index)); // return getType(index).equals("ID") || // ((getNameCode(index) & NamePool.FP_MASK) == StandardNames.XML_ID); } /** * Determine whether a given attribute has the is-idref property set */ public boolean isIdref(int index) { return config.getTypeHierarchy().isIdrefsCode(getTypeAnnotation(index)); } /** * Delete the attribute with a given fingerprint * @param fingerprint The fingerprint of the attribute to be removed */ public void removeAttribute(int fingerprint) { int index = findByFingerprint(fingerprint); if (index == -1) { // no action } else if (index == used-1) { used--; } else { System.arraycopy(values, index+1, values, index, used-index-1); System.arraycopy(codes, (index+1)*RECSIZE, codes, index*RECSIZE, (used-index-1)*RECSIZE); used--; } } /** * Rename an attribute * @param oldName the namecode of the existing name * @param newName the namecode of the new name */ public void renameAttribute(int oldName, int newName) { int index = findByFingerprint(oldName & NamePool.FP_MASK); if (index == -1) { // no action } else { codes[index*RECSIZE] = newName; } } /** * Replace the value of an attribute * @param nameCode the name code of the attribute name * @param newValue the new string value of the attribute */ public void replaceAttribute(int nameCode, CharSequence newValue) { int index = findByFingerprint(nameCode & NamePool.FP_MASK); if (index == -1) { // no action } else { values[index] = newValue.toString(); } } /** * Set the type annotation of an attribute * @param nameCode the name code of the attribute name * @param typeCode the new type code for the attribute */ public void setTypeAnnotation(int nameCode, int typeCode) { int index = findByFingerprint(nameCode & NamePool.FP_MASK); if (index == -1) { // no action } else { codes[index*RECSIZE + TYPECODE] = typeCode; } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/om/QNameException.java0000644000175000017500000000211611033112257021535 0ustar eugeneeugenepackage net.sf.saxon.om; /** * A QNameException represents an error condition whereby a QName (for example a variable * name or template name) is malformed */ public class QNameException extends Exception { String message; public QNameException (String message) { this.message = message; } public String getMessage() { return message; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none //saxonb-9.1.0.8/bj/net/sf/saxon/om/DocumentNumberAllocator.java0000644000175000017500000000253011033112257023445 0ustar eugeneeugenepackage net.sf.saxon.om; import java.io.Serializable; /** * This class (which has one instance per Configuration) is used to allocate unique document * numbers. It's a separate class so that it can act as a monitor for synchronization */ public class DocumentNumberAllocator implements Serializable { private int nextDocumentNumber = 0; /** * Allocate a unique document number * @return a unique document number */ public synchronized int allocateDocumentNumber() { return nextDocumentNumber++; } } // // The contents of this file are subject to the Mozilla Public License Version // 1.0 (the "License"); // you may not use this file except in compliance with the License. You may // obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations // under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael Kay, with extensive // rewriting by Wolfgang Hoschek // // Portions created by (your name) are Copyright (C) (your legal entity). All // Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/om/StrippedDocument.java0000644000175000017500000001021311033112257022143 0ustar eugeneeugenepackage net.sf.saxon.om; import net.sf.saxon.Configuration; import net.sf.saxon.event.Stripper; import net.sf.saxon.pattern.NodeKindTest; import java.util.Iterator; /** * A StrippedDocument represents a view of a real Document in which selected * whitespace text nodes are treated as having been stripped. */ public class StrippedDocument extends StrippedNode implements DocumentInfo { private Stripper stripper; private boolean preservesSpace; public StrippedDocument(DocumentInfo doc, Stripper stripper) { node = doc; parent = null; docWrapper = this; this.stripper = stripper; preservesSpace = findPreserveSpace(doc); } /** * Create a wrapped node within this document */ public StrippedNode wrap(NodeInfo node) { return makeWrapper(node, this, null); } /** * Get the document's stripper */ public Stripper getStripper() { return stripper; } /** * Get the configuration previously set using setConfiguration */ public Configuration getConfiguration() { return node.getConfiguration(); } /** * Get the name pool used for the names in this document */ public NamePool getNamePool() { return node.getNamePool(); } /** * Get the unique document number */ public int getDocumentNumber() { return node.getDocumentNumber(); } /** * Get the element with a given ID, if any * @param id the required ID value * @return the element with the given ID value, or null if there is none. */ public NodeInfo selectID(String id) { NodeInfo n = ((DocumentInfo)node).selectID(id); if (n==null) { return null; } else { return makeWrapper(n, this, null); } } /** * Get the list of unparsed entities defined in this document * @return an Iterator, whose items are of type String, containing the names of all * unparsed entities defined in this document. If there are no unparsed entities or if the * information is not available then an empty iterator is returned */ public Iterator getUnparsedEntityNames() { return ((DocumentInfo)node).getUnparsedEntityNames(); } /** * Get the unparsed entity with a given name * @param name the name of the entity */ public String[] getUnparsedEntity(String name) { return ((DocumentInfo)node).getUnparsedEntity(name); } /** * Determine whether the wrapped document contains any xml:space="preserve" attributes. If it * does, we will look for them when stripping individual nodes. It's more efficient to scan * the document in advance checking for xml:space attributes than to look for them every time * we hit a whitespace text node. */ private static boolean findPreserveSpace(DocumentInfo doc) { AxisIterator iter = doc.iterateAxis(Axis.DESCENDANT, NodeKindTest.ELEMENT); while (true) { NodeInfo node = (NodeInfo)iter.next(); if (node == null) { return false; } String val = node.getAttributeValue(StandardNames.XML_SPACE); if ("preserve".equals(val)) { return true; } } } /** * Does the stripped document contain any xml:space="preserve" attributes? */ public boolean containsPreserveSpace() { return preservesSpace; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is // Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/om/NamespaceResolverAsDeclarations.java0000644000175000017500000001045211033112257025112 0ustar eugeneeugenepackage net.sf.saxon.om; import java.util.List; import java.util.Iterator; import java.util.ArrayList; /** * An implementation of NamespaceDeclarations that contains all the inscope namespaces * made available by a NamespaceResolver. */ public class NamespaceResolverAsDeclarations implements NamespaceDeclarations { private NamePool pool; private NamespaceResolver resolver; private List prefixes; public NamespaceResolverAsDeclarations(NamePool pool, NamespaceResolver resolver) { this.pool = pool; this.resolver = resolver; prefixes = new ArrayList(10); Iterator iter = resolver.iteratePrefixes(); while (iter.hasNext()) { prefixes.add(iter.next()); } } /** * Get the number of declarations (and undeclarations) in this list. */ public int getNumberOfNamespaces() { return prefixes.size(); } /** * Get the prefix of the n'th declaration (or undeclaration) in the list, * counting from zero. * * @param index the index identifying which declaration is required. * @return the namespace prefix. For a declaration or undeclaration of the * default namespace, this is the zero-length string. * @throws IndexOutOfBoundsException if the index is out of range. */ public String getPrefix(int index) { return (String)prefixes.get(index); } /** * Get the namespace URI of the n'th declaration (or undeclaration) in the list, * counting from zero. * * @param index the index identifying which declaration is required. * @return the namespace URI. For a namespace undeclaration, this is the * zero-length string. * @throws IndexOutOfBoundsException if the index is out of range. */ public String getURI(int index) { return resolver.getURIForPrefix((String)prefixes.get(index), true); } /** * Get the n'th declaration in the list in the form of a namespace code. Namespace * codes can be translated into a prefix and URI by means of methods in the * NamePool * * @param index the index identifying which declaration is required. * @return the namespace code. This is an integer whose upper half indicates * the prefix (0 represents the default namespace), and whose lower half indicates * the URI (0 represents an undeclaration). * @throws IndexOutOfBoundsException if the index is out of range. * @see NamePool#getPrefixFromNamespaceCode(int) * @see NamePool#getURIFromNamespaceCode(int) */ public int getNamespaceCode(int index) { String prefix = getPrefix(index); String uri = getURI(index); return pool.allocateNamespaceCode(prefix, uri); } /** * Get all the namespace codes, as an array. * * @param buffer a sacrificial array that the method is free to use to contain the result. * May be null. * @return an integer array containing namespace codes. The array may be filled completely * with namespace codes, or it may be incompletely filled, in which case a -1 integer acts * as a terminator. */ public int[] getNamespaceCodes(int[] buffer) { if (buffer.length < getNumberOfNamespaces()) { buffer = new int[getNumberOfNamespaces()]; } for (int i=0; i currentEnd) { newEnd = currentEnd; } if (newEnd <= newStart) { return EmptyIterator.getInstance(); } return new ArrayIterator(items, newStart, newEnd); } /** * Test whether there are any more items * @return true if there are more items */ public boolean hasNext() { return index < end; } /** * Get the next item in the array * @return the next item in the array */ public Item next() { if (index >= end) { index = end+1; current = null; return null; } current = items[index++]; return current; } /** * Get the current item in the array * * @return the item returned by the most recent call of next() */ public Item current() { return current; } /** * Get the position of the current item in the array * * @return the current position (starting at 1 for the first item) */ public int position() { if (index > end) { return -1; } return index - start; } /** * Get the number of items in the part of the array being processed * * @return the number of items; equivalently, the position of the last * item */ public int getLastPosition() { return end - start; } public void close() { } /** * Get another iterator over the same items * * @return a new ArrayIterator */ public SequenceIterator getAnother() { return new ArrayIterator(items, start, end); } /** * Get an iterator that processes the same items in reverse order * * @return a new ArrayIterator */ public SequenceIterator getReverseIterator() { return new ReverseArrayIterator(items, start, end); } /** * Indicate that any nodes returned in the sequence will be atomized. This * means that if it wishes to do so, the implementation can return the typed * values of the nodes rather than the nodes themselves. The implementation * is free to ignore this hint. * @param atomizing true if the caller of this iterator will atomize any * nodes that are returned, and is therefore willing to accept the typed * value of the nodes instead of the nodes themselves. */ //public void setIsAtomizing(boolean atomizing) {} /** * Get the underlying array * * @return the underlying array being processed by the iterator */ public Item[] getArray() { return items; } /** * Get the initial start position * * @return the start position of the iterator in the array (zero-based) */ public int getStartPosition() { return start; } /** * Get the end position in the array * * @return the position in the array (zero-based) of the first item not included * in the iteration */ public int getEndPosition() { return end; } /** * Return a SequenceValue containing all the items in the sequence returned by this * SequenceIterator * * @return the corresponding SequenceValue */ public GroundedValue materialize() { if (start==0 && end == items.length) { return new SequenceExtent(items); } else { SequenceExtent e = new SequenceExtent(items); return new SequenceExtent(e, start, end-start); } } /** * Get properties of this iterator, as a bit-significant integer. * * @return the properties of this iterator. This will be some combination of * properties such as {@link #GROUNDED}, {@link #LAST_POSITION_FINDER}, * and {@link #LOOKAHEAD}. It is always * acceptable to return the value zero, indicating that there are no known special properties. * It is acceptable for the properties of the iterator to change depending on its state. */ public int getProperties() { return GROUNDED | LAST_POSITION_FINDER | LOOKAHEAD; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/om/StandardNames.java0000644000175000017500000010513111033112257021402 0ustar eugeneeugenepackage net.sf.saxon.om; import java.util.HashMap; /** * Well-known names used in XSLT processing. These names must all have * fingerprints in the range 0-1023, to avoid clashing with codes allocated * in a NamePool. We use the top three bits for the namespace, and the bottom * seven bits for the local name. *

    *

    Codes in the range 0-100 are used for standard node kinds such as ELEMENT, * DOCUMENT, etc, and for built-in types such as ITEM and EMPTY.

    */ public abstract class StandardNames { private static final int DFLT_NS = 0; private static final int XSL_NS = 1; private static final int SAXON_NS = 2; private static final int XML_NS = 3; private static final int XS_NS = 4; private static final int XSI_NS = 5; private static final int SCM_NS = 6; public static final int DFLT = 0; // 0 public static final int XSL = 128; // 128 public static final int SAXON = 128 * 2; // 256 public static final int XML = 128 * 3; // 384 public static final int XS = 128 * 4; // 512 public static final int XSI = 128 * 5; // 640 public static final int SCM = 128 * 6; // 768 public static final int XSL_ANALYZE_STRING = XSL; public static final int XSL_APPLY_IMPORTS = XSL + 1; public static final int XSL_APPLY_TEMPLATES = XSL + 2; public static final int XSL_ATTRIBUTE = XSL + 3; public static final int XSL_ATTRIBUTE_SET = XSL + 4; public static final int XSL_CALL_TEMPLATE = XSL + 5; public static final int XSL_CHARACTER_MAP = XSL + 6; public static final int XSL_CHOOSE = XSL + 7; public static final int XSL_COMMENT = XSL + 10; public static final int XSL_COPY = XSL + 11; public static final int XSL_COPY_OF = XSL + 12; public static final int XSL_DECIMAL_FORMAT = XSL + 13; public static final int XSL_DOCUMENT = XSL + 14; public static final int XSL_ELEMENT = XSL + 15; public static final int XSL_FALLBACK = XSL + 16; public static final int XSL_FOR_EACH = XSL + 17; public static final int XSL_FOR_EACH_GROUP = XSL + 20; public static final int XSL_FUNCTION = XSL + 21; public static final int XSL_IF = XSL + 22; public static final int XSL_IMPORT = XSL + 23; public static final int XSL_IMPORT_SCHEMA = XSL + 24; public static final int XSL_INCLUDE = XSL + 25; public static final int XSL_KEY = XSL + 26; public static final int XSL_MATCHING_SUBSTRING = XSL + 27; public static final int XSL_MESSAGE = XSL + 30; public static final int XSL_NEXT_MATCH = XSL + 31; public static final int XSL_NUMBER = XSL + 32; public static final int XSL_NAMESPACE = XSL + 33; public static final int XSL_NAMESPACE_ALIAS = XSL + 34; public static final int XSL_NON_MATCHING_SUBSTRING = XSL + 35; public static final int XSL_OTHERWISE = XSL + 36; public static final int XSL_OUTPUT = XSL + 37; public static final int XSL_OUTPUT_CHARACTER = XSL + 41; public static final int XSL_PARAM = XSL + 42; public static final int XSL_PERFORM_SORT = XSL + 43; public static final int XSL_PRESERVE_SPACE = XSL + 44; public static final int XSL_PROCESSING_INSTRUCTION = XSL + 45; public static final int XSL_RESULT_DOCUMENT = XSL + 46; public static final int XSL_SEQUENCE = XSL + 47; public static final int XSL_SORT = XSL + 50; public static final int XSL_STRIP_SPACE = XSL + 51; public static final int XSL_STYLESHEET = XSL + 52; public static final int XSL_TEMPLATE = XSL + 53; public static final int XSL_TEXT = XSL + 54; public static final int XSL_TRANSFORM = XSL + 55; public static final int XSL_VALUE_OF = XSL + 56; public static final int XSL_VARIABLE = XSL + 57; public static final int XSL_WITH_PARAM = XSL + 60; public static final int XSL_WHEN = XSL + 61; public static final int XSL_DEFAULT_COLLATION = XSL + 100; public static final int XSL_EXCLUDE_RESULT_PREFIXES = XSL + 101; public static final int XSL_EXTENSION_ELEMENT_PREFIXES = XSL + 102; public static final int XSL_INHERIT_NAMESPACES = XSL + 103; public static final int XSL_TYPE = XSL + 104; public static final int XSL_USE_ATTRIBUTE_SETS = XSL + 105; public static final int XSL_USE_WHEN = XSL + 106; public static final int XSL_VALIDATION = XSL + 107; public static final int XSL_VERSION = XSL + 108; public static final int XSL_XPATH_DEFAULT_NAMESPACE = XSL + 109; private static final String XSL_B = '{' + NamespaceConstant.XSLT + '}'; public static final String XSL_DEFAULT_COLLATION_CLARK = XSL_B + "default-collation"; public static final String XSL_INHERIT_NAMESPACES_CLARK = XSL_B + "inherit-namespaces"; public static final String XSL_VERSION_CLARK = XSL_B + "version"; public static final String XSL_XPATH_DEFAULT_NAMESPACE_CLARK = XSL_B + "xpath-default-namespace"; public static final String XSL_EXTENSION_ELEMENT_PREFIXES_CLARK = XSL_B + "extension-element-prefixes"; public static final String XSL_EXCLUDE_RESULT_PREFIXES_CLARK = XSL_B + "exclude-result-prefixes"; public static final int SAXON_ASSIGN = SAXON + 1; public static final int SAXON_BREAK = SAXON + 2; public static final int SAXON_CALL_TEMPLATE = SAXON + 3; public static final int SAXON_COLLATION = SAXON + 4; public static final int SAXON_CONTINUE = SAXON + 5; public static final int SAXON_DOCTYPE = SAXON + 6; public static final int SAXON_ENTITY_REF = SAXON + 7; public static final int SAXON_FINALLY = SAXON + 8; public static final int SAXON_IMPORT_QUERY = SAXON + 9; public static final int SAXON_ITERATE = SAXON + 10; public static final int SAXON_SCRIPT = SAXON + 11; public static final int SAXON_WHILE = SAXON + 12; private static final String SAXON_B = '{' + NamespaceConstant.SAXON + '}'; public static final String SAXON_ALLOW_ALL_BUILT_IN_TYPES = SAXON_B + "allow-all-built-in-types"; public static final String SAXON_ASSIGNABLE = SAXON_B + "assignable"; public static final String SAXON_CHARACTER_REPRESENTATION = SAXON_B + "character-representation"; public static final String SAXON_DOUBLE_SPACE = SAXON_B + "double-space"; public static final String SAXON_EXPLAIN = SAXON_B + "explain"; public static final String SAXON_READ_ONCE = SAXON_B + "read-once"; public static final String SAXON_INDENT_SPACES = SAXON_B + "indent-spaces"; public static final String SAXON_NEXT_IN_CHAIN = SAXON_B + "next-in-chain"; public static final String SAXON_REQUIRE_WELL_FORMED = SAXON_B + "require-well-formed"; public static final String SAXON_SUPPRESS_INDENTATION = SAXON_B + "suppress-indentation"; public static final String SAXON_MEMO_FUNCTION = SAXON_B + "memo-function"; // Not sure about this one... public static final int SAXON_JAVA_LANG_OBJECT = SAXON + 29; public static final int XML_BASE = XML + 1; public static final int XML_SPACE = XML + 2; public static final int XML_LANG = XML + 3; public static final int XML_ID = XML + 4; public static final String ALPHANUMERIC = "alphanumeric"; public static final String ARCHIVE = "archive"; public static final String AS = "as"; public static final String BYTE_ORDER_MARK = "byte-order-mark"; public static final String CASE_ORDER = "case-order"; public static final String CDATA_SECTION_ELEMENTS = "cdata-section-elements"; public static final String CHARACTER = "character"; public static final String CLASS = "class"; public static final String COLLATION = "collation"; public static final String COPY_NAMESPACES = "copy-namespaces"; public static final String COUNT = "count"; public static final String DATA_TYPE = "data-type"; public static final String DECIMAL_SEPARATOR = "decimal-separator"; public static final String DECOMPOSITION = "decomposition"; public static final String DEFAULT = "default"; public static final String DEFAULT_COLLATION = "default-collation"; public static final String DEFAULT_VALIDATION = "default-validation"; public static final String DIGIT = "digit"; public static final String DISABLE_OUTPUT_ESCAPING = "disable-output-escaping"; public static final String DOCTYPE_PUBLIC = "doctype-public"; public static final String DOCTYPE_SYSTEM = "doctype-system"; public static final String ELEMENTS = "elements"; public static final String ESCAPE_URI_ATTRIBUTES = "escape-uri-attributes"; public static final String ENCODING = "encoding"; public static final String EXCLUDE_RESULT_PREFIXES = "exclude-result-prefixes"; public static final String EXTENSION_ELEMENT_PREFIXES = "extension-element-prefixes"; public static final String FLAGS = "flags"; public static final String FORMAT = "format"; public static final String FROM = "from"; public static final String GROUP_ADJACENT = "group-adjacent"; public static final String GROUP_BY = "group-by"; public static final String GROUP_ENDING_WITH = "group-ending-with"; public static final String GROUP_STARTING_WITH = "group-starting-with"; public static final String GROUPING_SEPARATOR = "grouping-separator"; public static final String GROUPING_SIZE = "grouping-size"; public static final String HREF = "href"; public static final String ID = "id"; public static final String IGNORE_CASE = "ignore-case"; public static final String IGNORE_MODIFIERS = "ignore-modifiers"; public static final String IGNORE_SYMBOLS = "ignore-symbols"; public static final String IGNORE_WIDTH = "ignore-width"; public static final String IMPLEMENTS_PREFIX = "implements-prefix"; public static final String INCLUDE_CONTENT_TYPE = "include-content-type"; public static final String INDENT = "indent"; public static final String INFINITY = "infinity"; public static final String INHERIT_NAMESPACES = "inherit-namespaces"; public static final String INPUT_TYPE_ANNOTATIONS = "input-type-annotations"; public static final String LANG = "lang"; public static final String LANGUAGE = "language"; public static final String LETTER_VALUE = "letter-value"; public static final String LEVEL = "level"; public static final String MATCH = "match"; public static final String MEDIA_TYPE = "media-type"; public static final String METHOD = "method"; public static final String MINUS_SIGN = "minus-sign"; public static final String MODE = "mode"; public static final String NAME = "name"; public static final String NAMESPACE = "namespace"; public static final String NAN = "NaN"; public static final String NORMALIZATION_FORM = "normalization-form"; public static final String OMIT_XML_DECLARATION = "omit-xml-declaration"; public static final String ORDER = "order"; public static final String ORDINAL = "ordinal"; public static final String OUTPUT_VERSION = "output-version"; public static final String OVERRIDE = "override"; public static final String PATTERN_SEPARATOR = "pattern-separator"; public static final String PERCENT = "percent"; public static final String PER_MILLE = "per-mille"; public static final String PRIORITY = "priority"; public static final String REGEX = "regex"; public static final String REQUIRED = "required"; public static final String RESULT_PREFIX = "result-prefix"; public static final String RULES = "rules"; public static final String SCHEMA_LOCATION = "schema-location"; public static final String SELECT = "select"; public static final String SEPARATOR = "separator"; public static final String SRC = "src"; public static final String STABLE = "stable"; public static final String STANDALONE = "standalone"; public static final String STRENGTH = "strength"; public static final String STRING = "string"; public static final String STYLESHEET_PREFIX = "stylesheet-prefix"; public static final String TERMINATE = "terminate"; public static final String TEST = "test"; public static final String TUNNEL = "tunnel"; public static final String TYPE = "type"; public static final String UNDECLARE_PREFIXES = "undeclare-prefixes"; public static final String USE = "use"; public static final String USE_ATTRIBUTE_SETS = "use-attribute-sets"; public static final String USE_CHARACTER_MAPS = "use-character-maps"; public static final String USE_WHEN = "use-when"; public static final String VALIDATION = "validation"; public static final String VALUE = "value"; public static final String VERSION = "version"; public static final String XPATH_DEFAULT_NAMESPACE = "xpath-default-namespace"; public static final String ZERO_DIGIT = "zero-digit"; public static final int XS_STRING = XS + 1; public static final int XS_BOOLEAN = XS + 2; public static final int XS_DECIMAL = XS + 3; public static final int XS_FLOAT = XS + 4; public static final int XS_DOUBLE = XS + 5; public static final int XS_DURATION = XS + 6; public static final int XS_DATE_TIME = XS + 7; public static final int XS_TIME = XS + 8; public static final int XS_DATE = XS + 9; public static final int XS_G_YEAR_MONTH = XS + 10; public static final int XS_G_YEAR = XS + 11; public static final int XS_G_MONTH_DAY = XS + 12; public static final int XS_G_DAY = XS + 13; public static final int XS_G_MONTH = XS + 14; public static final int XS_HEX_BINARY = XS + 15; public static final int XS_BASE64_BINARY = XS + 16; public static final int XS_ANY_URI = XS + 17; public static final int XS_QNAME = XS + 18; public static final int XS_NOTATION = XS + 19; public static final int XS_INTEGER = XS + 20; // Note that any type code <= XS_INTEGER is considered to represent a // primitive type: see Type.isPrimitiveType() public static final int XS_NON_POSITIVE_INTEGER = XS + 21; public static final int XS_NEGATIVE_INTEGER = XS + 22; public static final int XS_LONG = XS + 23; public static final int XS_INT = XS + 24; public static final int XS_SHORT = XS + 25; public static final int XS_BYTE = XS + 26; public static final int XS_NON_NEGATIVE_INTEGER = XS + 27; public static final int XS_POSITIVE_INTEGER = XS + 28; public static final int XS_UNSIGNED_LONG = XS + 29; public static final int XS_UNSIGNED_INT = XS + 30; public static final int XS_UNSIGNED_SHORT = XS + 31; public static final int XS_UNSIGNED_BYTE = XS + 32; public static final int XS_NORMALIZED_STRING = XS + 41; public static final int XS_TOKEN = XS + 42; public static final int XS_LANGUAGE = XS + 43; public static final int XS_NMTOKEN = XS + 44; public static final int XS_NMTOKENS = XS + 45; // NB: list type public static final int XS_NAME = XS + 46; public static final int XS_NCNAME = XS + 47; public static final int XS_ID = XS + 48; public static final int XS_IDREF = XS + 49; public static final int XS_IDREFS = XS + 50; // NB: list type public static final int XS_ENTITY = XS + 51; public static final int XS_ENTITIES = XS + 52; // NB: list type public static final int XS_ANY_TYPE = XS + 60; public static final int XS_ANY_SIMPLE_TYPE = XS + 61; public static final int XS_INVALID_NAME = XS + 62; public static final int XS_ALL = XS + 70; public static final int XS_ANNOTATION = XS + 71; public static final int XS_ANY = XS + 72; public static final int XS_ANY_ATTRIBUTE = XS + 73; public static final int XS_APPINFO = XS + 74; public static final int XS_ATTRIBUTE = XS + 75; public static final int XS_ATTRIBUTE_GROUP = XS + 76; public static final int XS_CHOICE = XS + 77; public static final int XS_COMPLEX_CONTENT = XS + 80; public static final int XS_COMPLEX_TYPE = XS + 81; public static final int XS_DOCUMENTATION = XS + 82; public static final int XS_ELEMENT = XS + 83; public static final int XS_ENUMERATION = XS + 84; public static final int XS_EXTENSION = XS + 85; public static final int XS_FIELD = XS + 86; public static final int XS_FRACTION_DIGITS = XS + 87; public static final int XS_GROUP = XS + 88; public static final int XS_IMPORT = XS + 90; public static final int XS_INCLUDE = XS + 91; public static final int XS_KEY = XS + 92; public static final int XS_KEYREF = XS + 93; public static final int XS_LENGTH = XS + 94; public static final int XS_LIST = XS + 95; public static final int XS_MAX_EXCLUSIVE = XS + 96; public static final int XS_MAX_INCLUSIVE = XS + 97; public static final int XS_MAX_LENGTH = XS + 100; public static final int XS_MIN_EXCLUSIVE = XS + 101; public static final int XS_MIN_INCLUSIVE = XS + 102; public static final int XS_MIN_LENGTH = XS + 103; public static final int XS_notation = XS + 104; public static final int XS_PATTERN = XS + 105; public static final int XS_REDEFINE = XS + 106; public static final int XS_RESTRICTION = XS + 107; public static final int XS_SCHEMA = XS + 108; public static final int XS_SELECTOR = XS + 110; public static final int XS_SEQUENCE = XS + 111; public static final int XS_SIMPLE_CONTENT = XS + 112; public static final int XS_SIMPLE_TYPE = XS + 113; public static final int XS_TOTAL_DIGITS = XS + 114; public static final int XS_UNION = XS + 115; public static final int XS_UNIQUE = XS + 116; public static final int XS_WHITE_SPACE = XS + 117; public static final int XS_UNTYPED = XS + 118; public static final int XS_UNTYPED_ATOMIC = XS + 119; public static final int XS_ANY_ATOMIC_TYPE = XS + 120; public static final int XS_YEAR_MONTH_DURATION = XS + 121; public static final int XS_DAY_TIME_DURATION = XS + 122; public static final int XS_NUMERIC = XS + 123; public static final int XS_ASSERT = XS + 124; public static final int XS_ALTERNATIVE = XS + 125; public static final int XSI_TYPE = XSI + 1; public static final int XSI_NIL = XSI + 2; public static final int XSI_SCHEMA_LOCATION = XSI + 3; public static final int XSI_NO_NAMESPACE_SCHEMA_LOCATION = XSI + 4; public static final int XSI_SCHEMA_LOCATION_TYPE = XSI + 5; public static final int SCM_SCHEMA = SCM + 1; public static final int SCM_ELEMENT_DECLARATION = SCM + 2; public static final int SCM_ATTRIBUTE_DECLARATION = SCM + 3; public static final int SCM_COMPLEX_TYPE_DEFINITION = SCM + 4; public static final int SCM_SIMPLE_TYPE_DEFINITION = SCM + 5; public static final int SCM_ATTRIBUTE_GROUP_DECLARATION = SCM + 6; public static final int SCM_MODEL_GROUP_DECLARATION = SCM + 7; public static final int SCM_NOTATION_DECLARATION = SCM + 2; public static final int SCM_ANNOTATION = SCM + 2; public static final int SCM_NAME = SCM + 2; public static final int SCM_TARGET_NAMESPACE = SCM + 2; private static String[] localNames = new String[1023]; private static HashMap lookup = new HashMap(1023); // key is an expanded QName in Clark notation // value is a fingerprint, as a java.lang.Integer private StandardNames() { //pool = namePool; } private static void bindXSLTName(int constant, String localName) { localNames[constant] = localName; lookup.put('{' + NamespaceConstant.XSLT + '}' + localName, new Integer(constant)); } private static void bindSaxonName(int constant, String localName) { localNames[constant] = localName; lookup.put('{' + NamespaceConstant.SAXON + '}' + localName, new Integer(constant)); } private static void bindXMLName(int constant, String localName) { localNames[constant] = localName; lookup.put('{' + NamespaceConstant.XML + '}' + localName, new Integer(constant)); } private static void bindXSName(int constant, String localName) { localNames[constant] = localName; lookup.put('{' + NamespaceConstant.SCHEMA + '}' + localName, new Integer(constant)); } private static void bindXSIName(int constant, String localName) { localNames[constant] = localName; lookup.put('{' + NamespaceConstant.SCHEMA_INSTANCE + '}' + localName, new Integer(constant)); } static { bindXSLTName(XSL_ANALYZE_STRING, "analyze-string"); bindXSLTName(XSL_APPLY_IMPORTS, "apply-imports"); bindXSLTName(XSL_APPLY_TEMPLATES, "apply-templates"); bindXSLTName(XSL_ATTRIBUTE, "attribute"); bindXSLTName(XSL_ATTRIBUTE_SET, "attribute-set"); bindXSLTName(XSL_CALL_TEMPLATE, "call-template"); bindXSLTName(XSL_CHARACTER_MAP, "character-map"); bindXSLTName(XSL_CHOOSE, "choose"); bindXSLTName(XSL_COMMENT, "comment"); bindXSLTName(XSL_COPY, "copy"); bindXSLTName(XSL_COPY_OF, "copy-of"); bindXSLTName(XSL_DECIMAL_FORMAT, "decimal-format"); bindXSLTName(XSL_DOCUMENT, "document"); bindXSLTName(XSL_ELEMENT, "element"); bindXSLTName(XSL_FALLBACK, "fallback"); bindXSLTName(XSL_FOR_EACH, "for-each"); bindXSLTName(XSL_FOR_EACH_GROUP, "for-each-group"); bindXSLTName(XSL_FUNCTION, "function"); bindXSLTName(XSL_IF, "if"); bindXSLTName(XSL_IMPORT, "import"); bindXSLTName(XSL_IMPORT_SCHEMA, "import-schema"); bindXSLTName(XSL_INCLUDE, "include"); bindXSLTName(XSL_KEY, "key"); bindXSLTName(XSL_MATCHING_SUBSTRING, "matching-substring"); bindXSLTName(XSL_MESSAGE, "message"); bindXSLTName(XSL_NEXT_MATCH, "next-match"); bindXSLTName(XSL_NUMBER, "number"); bindXSLTName(XSL_NAMESPACE, "namespace"); bindXSLTName(XSL_NAMESPACE_ALIAS, "namespace-alias"); bindXSLTName(XSL_NON_MATCHING_SUBSTRING, "non-matching-substring"); bindXSLTName(XSL_OTHERWISE, "otherwise"); bindXSLTName(XSL_OUTPUT, "output"); bindXSLTName(XSL_OUTPUT_CHARACTER, "output-character"); bindXSLTName(XSL_PARAM, "param"); bindXSLTName(XSL_PERFORM_SORT, "perform-sort"); bindXSLTName(XSL_PRESERVE_SPACE, "preserve-space"); bindXSLTName(XSL_PROCESSING_INSTRUCTION, "processing-instruction"); bindXSLTName(XSL_RESULT_DOCUMENT, "result-document"); bindXSLTName(XSL_SEQUENCE, "sequence"); bindXSLTName(XSL_SORT, "sort"); bindXSLTName(XSL_STRIP_SPACE, "strip-space"); bindXSLTName(XSL_STYLESHEET, "stylesheet"); bindXSLTName(XSL_TEMPLATE, "template"); bindXSLTName(XSL_TEXT, "text"); bindXSLTName(XSL_TRANSFORM, "transform"); bindXSLTName(XSL_VALUE_OF, "value-of"); bindXSLTName(XSL_VARIABLE, "variable"); bindXSLTName(XSL_WITH_PARAM, "with-param"); bindXSLTName(XSL_WHEN, "when"); bindXSLTName(XSL_DEFAULT_COLLATION, "default-collation"); bindXSLTName(XSL_XPATH_DEFAULT_NAMESPACE, "xpath-default-namespace"); bindXSLTName(XSL_EXCLUDE_RESULT_PREFIXES, "exclude-result-prefixes"); bindXSLTName(XSL_EXTENSION_ELEMENT_PREFIXES, "extension-element-prefixes"); bindXSLTName(XSL_INHERIT_NAMESPACES, "inherit-namespaces"); bindXSLTName(XSL_TYPE, "type"); bindXSLTName(XSL_USE_ATTRIBUTE_SETS, "use-attribute-sets"); bindXSLTName(XSL_USE_WHEN, "use-when"); bindXSLTName(XSL_VALIDATION, "validation"); bindXSLTName(XSL_VERSION, "version"); bindSaxonName(SAXON_ASSIGN, "assign"); bindSaxonName(SAXON_BREAK, "break"); bindSaxonName(SAXON_CALL_TEMPLATE, "call-template"); bindSaxonName(SAXON_COLLATION, "collation"); bindSaxonName(SAXON_CONTINUE, "continue"); bindSaxonName(SAXON_DOCTYPE, "doctype"); bindSaxonName(SAXON_ENTITY_REF, "entity-ref"); bindSaxonName(SAXON_FINALLY, "finally"); bindSaxonName(SAXON_IMPORT_QUERY, "import-query"); bindSaxonName(SAXON_ITERATE, "iterate"); bindSaxonName(SAXON_SCRIPT, "script"); bindSaxonName(SAXON_WHILE, "while"); bindXMLName(XML_BASE, "base"); bindXMLName(XML_SPACE, "space"); bindXMLName(XML_LANG, "lang"); bindXMLName(XML_ID, "id"); bindXSName(XS_STRING, "string"); bindXSName(XS_BOOLEAN, "boolean"); bindXSName(XS_DECIMAL, "decimal"); bindXSName(XS_FLOAT, "float"); bindXSName(XS_DOUBLE, "double"); bindXSName(XS_DURATION, "duration"); bindXSName(XS_DATE_TIME, "dateTime"); bindXSName(XS_TIME, "time"); bindXSName(XS_DATE, "date"); bindXSName(XS_G_YEAR_MONTH, "gYearMonth"); bindXSName(XS_G_YEAR, "gYear"); bindXSName(XS_G_MONTH_DAY, "gMonthDay"); bindXSName(XS_G_DAY, "gDay"); bindXSName(XS_G_MONTH, "gMonth"); bindXSName(XS_HEX_BINARY, "hexBinary"); bindXSName(XS_BASE64_BINARY, "base64Binary"); bindXSName(XS_ANY_URI, "anyURI"); bindXSName(XS_QNAME, "QName"); bindXSName(XS_NOTATION, "NOTATION"); bindXSName(XS_INTEGER, "integer"); bindXSName(XS_NON_POSITIVE_INTEGER, "nonPositiveInteger"); bindXSName(XS_NEGATIVE_INTEGER, "negativeInteger"); bindXSName(XS_LONG, "long"); bindXSName(XS_INT, "int"); bindXSName(XS_SHORT, "short"); bindXSName(XS_BYTE, "byte"); bindXSName(XS_NON_NEGATIVE_INTEGER, "nonNegativeInteger"); bindXSName(XS_POSITIVE_INTEGER, "positiveInteger"); bindXSName(XS_UNSIGNED_LONG, "unsignedLong"); bindXSName(XS_UNSIGNED_INT, "unsignedInt"); bindXSName(XS_UNSIGNED_SHORT, "unsignedShort"); bindXSName(XS_UNSIGNED_BYTE, "unsignedByte"); bindXSName(XS_NORMALIZED_STRING, "normalizedString"); bindXSName(XS_TOKEN, "token"); bindXSName(XS_LANGUAGE, "language"); bindXSName(XS_NMTOKEN, "NMTOKEN"); bindXSName(XS_NMTOKENS, "NMTOKENS"); // NB: list type bindXSName(XS_NAME, "Name"); bindXSName(XS_NCNAME, "NCName"); bindXSName(XS_ID, "ID"); bindXSName(XS_IDREF, "IDREF"); bindXSName(XS_IDREFS, "IDREFS"); // NB: list type bindXSName(XS_ENTITY, "ENTITY"); bindXSName(XS_ENTITIES, "ENTITIES"); // NB: list type bindXSName(XS_ANY_TYPE, "anyType"); bindXSName(XS_ANY_SIMPLE_TYPE, "anySimpleType"); bindXSName(XS_INVALID_NAME, "invalidName"); bindXSName(XS_ALL, "all"); bindXSName(XS_ALTERNATIVE, "alternative"); bindXSName(XS_ANNOTATION, "annotation"); bindXSName(XS_ANY, "any"); bindXSName(XS_ANY_ATTRIBUTE, "anyAttribute"); bindXSName(XS_APPINFO, "appinfo"); bindXSName(XS_ASSERT, "assert"); bindXSName(XS_ATTRIBUTE, "attribute"); bindXSName(XS_ATTRIBUTE_GROUP, "attributeGroup"); bindXSName(XS_CHOICE, "choice"); bindXSName(XS_COMPLEX_CONTENT, "complexContent"); bindXSName(XS_COMPLEX_TYPE, "complexType"); bindXSName(XS_DOCUMENTATION, "documentation"); bindXSName(XS_ELEMENT, "element"); bindXSName(XS_ENUMERATION, "enumeration"); bindXSName(XS_EXTENSION, "extension"); bindXSName(XS_FIELD, "field"); bindXSName(XS_FRACTION_DIGITS, "fractionDigits"); bindXSName(XS_GROUP, "group"); bindXSName(XS_IMPORT, "import"); bindXSName(XS_INCLUDE, "include"); bindXSName(XS_KEY, "key"); bindXSName(XS_KEYREF, "keyref"); bindXSName(XS_LENGTH, "length"); bindXSName(XS_LIST, "list"); bindXSName(XS_MAX_EXCLUSIVE, "maxExclusive"); bindXSName(XS_MAX_INCLUSIVE, "maxInclusive"); bindXSName(XS_MAX_LENGTH, "maxLength"); bindXSName(XS_MIN_EXCLUSIVE, "minExclusive"); bindXSName(XS_MIN_INCLUSIVE, "minInclusive"); bindXSName(XS_MIN_LENGTH, "minLength"); bindXSName(XS_notation, "notation"); bindXSName(XS_PATTERN, "pattern"); bindXSName(XS_REDEFINE, "redefine"); //bindXSName(XS_REPORT, "report"); bindXSName(XS_RESTRICTION, "restriction"); bindXSName(XS_SCHEMA, "schema"); bindXSName(XS_SELECTOR, "selector"); bindXSName(XS_SEQUENCE, "sequence"); bindXSName(XS_SIMPLE_CONTENT, "simpleContent"); bindXSName(XS_SIMPLE_TYPE, "simpleType"); bindXSName(XS_TOTAL_DIGITS, "totalDigits"); bindXSName(XS_UNION, "union"); bindXSName(XS_UNIQUE, "unique"); bindXSName(XS_WHITE_SPACE, "whiteSpace"); bindXSName(XS_UNTYPED, "untyped"); bindXSName(XS_UNTYPED_ATOMIC, "untypedAtomic"); bindXSName(XS_ANY_ATOMIC_TYPE, "anyAtomicType"); bindXSName(XS_YEAR_MONTH_DURATION, "yearMonthDuration"); bindXSName(XS_DAY_TIME_DURATION, "dayTimeDuration"); bindXSName(XS_NUMERIC, "_numeric_"); bindXSIName(XSI_TYPE, "type"); bindXSIName(XSI_NIL, "nil"); bindXSIName(XSI_SCHEMA_LOCATION, "schemaLocation"); bindXSIName(XSI_NO_NAMESPACE_SCHEMA_LOCATION, "noNamespaceSchemaLocation"); bindXSIName(XSI_SCHEMA_LOCATION_TYPE, "anonymous_schemaLocationType"); } /** * Get the fingerprint of a system-defined name, from its URI and local name * * @param uri the namespace URI * @param localName the local part of the name * @return the standard fingerprint, or -1 if this is not a built-in name */ public static int getFingerprint(String uri, String localName) { Integer fp = (Integer)lookup.get('{' + uri + '}' + localName); if (fp == null) { return -1; } else { return fp.intValue(); } } /** * Get the local part of a system-defined name * @param fingerprint the fingerprint of the name * @return the local part of the name */ public static String getLocalName(int fingerprint) { return localNames[fingerprint]; } /** * Get the namespace URI part of a system-defined name * @param fingerprint the fingerprint of the name * @return the namespace URI part of the name */ public static String getURI(int fingerprint) { int c = fingerprint >> 7; switch (c) { case DFLT_NS: return ""; case XSL_NS: return NamespaceConstant.XSLT; case SAXON_NS: return NamespaceConstant.SAXON; case XML_NS: return NamespaceConstant.XML; case XS_NS: return NamespaceConstant.SCHEMA; case XSI_NS: return NamespaceConstant.SCHEMA_INSTANCE; case SCM_NS: return NamespaceConstant.SCM; default: return null; } } /** * Get the namespace URI part of a system-defined name as a URI code * @param fingerprint the fingerprint of the name * @return the namespace URI part of the name, as a URI code */ public static short getURICode(int fingerprint) { int c = fingerprint >> 7; switch (c) { case DFLT_NS: return 0; case XSL_NS: return NamespaceConstant.XSLT_CODE; case SAXON_NS: return NamespaceConstant.SAXON_CODE; case XML_NS: return NamespaceConstant.XML_CODE; case XS_NS: return NamespaceConstant.SCHEMA_CODE; case XSI_NS: return NamespaceConstant.XSI_CODE; default: return -1; } } /** * Get the Clark form of a system-defined name, given its name code or fingerprint * @param fingerprint the fingerprint of the name * @return the local name if the name is in the null namespace, or "{uri}local" * otherwise. The name is always interned. */ public static String getClarkName(int fingerprint) { String uri = getURI(fingerprint); if (uri.length() == 0) { return getLocalName(fingerprint); } else { return '{' + uri + '}' + getLocalName(fingerprint); } } /** * Get the conventional prefix of a system-defined name * @param fingerprint the fingerprint of the name * @return the conventional prefix of the name */ public static String getPrefix(int fingerprint) { int c = fingerprint >> 7; switch (c) { case DFLT_NS: return ""; case XSL_NS: return "xsl"; case SAXON_NS: return "saxon"; case XML_NS: return "xml"; case XS_NS: return "xs"; case XSI_NS: return "xsi"; default: return null; } } /** * Get the lexical display form of a system-defined name * @param fingerprint the fingerprint of the name * @return the lexical display form of the name, using a conventional prefix */ public static String getDisplayName(int fingerprint) { if (fingerprint == -1) { return "(anonymous type)"; } if (fingerprint > 1023) { return "(" + fingerprint + ')'; } if ((fingerprint >> 7) == DFLT) { return getLocalName(fingerprint); } return getPrefix(fingerprint) + ':' + getLocalName(fingerprint); } /** * Get a StructuredQName representing a system-defined name * @param fingerprint the fingerprint of the name * @return a StructuredQName representing the system-defined name */ public static StructuredQName getStructuredQName(int fingerprint) { return new StructuredQName(getPrefix(fingerprint), getURI(fingerprint), getLocalName(fingerprint)); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none //saxonb-9.1.0.8/bj/net/sf/saxon/om/MutableNodeInfo.java0000644000175000017500000002024711033112257021675 0ustar eugeneeugenepackage net.sf.saxon.om; import net.sf.saxon.event.Builder; /** * An extension of the NodeInfo interface defining a node that can be updated. The updating methods are * closely modelled on the updating functions defined in the XQuery Update specification. */ public interface MutableNodeInfo extends NodeInfo { /** * Set the type annotation on a node. This must only be called when the caller has verified (by validation) * that the node is a valid instance of the specified type. The call is ignored if the node is not an element * or attribute node. * @param typeCode the type annotation (possibly including high bits set to indicate the isID, isIDREF, and * isNilled properties) */ public void setTypeAnnotation(int typeCode); /** * Insert copies of a sequence of nodes as children of this node. * *

    This method takes no action unless the target node is a document node or element node. It also * takes no action in respect of any supplied nodes that are not elements, text nodes, comments, or * processing instructions.

    * *

    The supplied nodes will be copied to form the new children. Adjacent text nodes will be merged, and * zero-length text nodes removed.

    * @param source the nodes to be inserted * @param atStart true if the new nodes are to be inserted before existing children; false if they are * @param inherit true if the insert nodes are to inherit the namespaces of their new parent; false * if such namespaces are to be undeclared */ public void insertChildren(NodeInfo[] source, boolean atStart, boolean inherit); /** * Insert copies of a sequence of nodes as siblings of this node. * *

    This method takes no action unless the target node is an element, text node, comment, or * processing instruction, and one that has a parent node. It also * takes no action in respect of any supplied nodes that are not elements, text nodes, comments, or * processing instructions.

    * *

    The supplied nodes must use the same data model implementation as the tree into which they * will be inserted.

    * @param source the nodes to be inserted * @param before true if the new nodes are to be inserted before the target node; false if they are * @param inherit true if the insert nodes are to inherit the namespaces of their new parent; false * if such namespaces are to be undeclared */ public void insertSiblings(NodeInfo[] source, boolean before, boolean inherit); /** * Remove an attribute from this element node * *

    If this node is not an element, or if it has no attribute with the specified name, * this method takes no action.

    * *

    The attribute node itself is not modified in any way.

    * * @param nameCode the name of the attribute to be removed */ public void removeAttribute(int nameCode); /** * Add an attribute to this element node. * *

    If this node is not an element, or if the supplied node is not an attribute, the method * takes no action. If the element already has an attribute with this name, the existing attribute * is replaced.

    * * @param nameCode the name of the new attribute * @param typeCode the type annotation of the new attribute * @param value the string value of the new attribute * @param properties properties including IS_ID and IS_IDREF properties */ public void putAttribute(int nameCode, int typeCode, CharSequence value, int properties); /** * Delete this node (that is, detach it from its parent). *

    If this node has preceding and following siblings that are both text nodes, * the two text nodes will be joined into a single text node (the identity of this node * with respect to its predecessors is undefined).

    */ public void delete(); /** * Replace this node with a given sequence of nodes * @param replacement the replacement nodes * @param inherit true if the replacement nodes are to inherit the namespaces of their new parent; false * if such namespaces are to be undeclared * @throws IllegalArgumentException if any of the replacement nodes is of the wrong kind. When replacing * a child node, the replacement nodes must all be elements, text, comment, or PI nodes; when replacing * an attribute, the replacement nodes must all be attributes. */ public void replace(NodeInfo[] replacement, boolean inherit); /** * Replace the string-value of this node. If applied to an element or document node, this * causes all existing children to be deleted, and replaced with a new text node * whose string value is the value supplied. The caller is responsible for checking * that the value is valid, for example that comments do not contain a double hyphen; the * implementation is not required to check for such conditions. * @param stringValue the new string value */ public void replaceStringValue(CharSequence stringValue); /** * Rename this node. *

    This call has no effect if applied to a nameless node, such as a text node or comment.

    *

    If necessary, a new namespace binding will be added to the target element, or to the element * parent of the target attribute

    * @param newNameCode the namecode of the new name in the name pool * @throws IllegalArgumentException if the new name code is not present in the name pool, or if * it has a (prefix, uri) pair in which the * prefix is the same as that of an existing in-scope namespace binding and the uri is different from that * namespace binding. */ public void rename(int newNameCode); /** * Add a namespace binding (that is, a namespace node) to this element. This call has no effect if applied * to a node other than an element. * @param nscode The namespace code representing the (prefix, uri) pair of the namespace binding to be * added. If the target element already has a namespace binding with this (prefix, uri) pair, the call has * no effect. If the target element currently has a namespace binding with this prefix and a different URI, an * exception is raised. * @param inherit If true, the new namespace binding will be inherited by any children of the target element * that do not already have a namespace binding for the specified prefix, recursively. * If false, the new namespace binding will not be inherited. * @throws IllegalArgumentException if the namespace code is not present in the namepool, or if the target * element already has a namespace binding for this prefix */ public void addNamespace(int nscode, boolean inherit); /** * Remove type information from this node (and its ancestors, recursively). * This method implements the upd:removeType() primitive defined in the XQuery Update specification. * (Note: the caller is responsible for updating the set of nodes marked for revalidation) */ public void removeTypeAnnotation(); /** * Get a Builder suitable for building nodes that can be attached to this document. * @return a new Builder that constructs nodes using the same object model implementation * as this one, suitable for attachment to this tree */ public Builder newBuilder(); } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/om/NodeInfo.java0000644000175000017500000006020311033112257020357 0ustar eugeneeugenepackage net.sf.saxon.om; import net.sf.saxon.Configuration; import net.sf.saxon.event.Receiver; import net.sf.saxon.pattern.NodeTest; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.Value; import javax.xml.transform.Source; /** * The NodeInfo interface represents a node in Saxon's implementation of the XPath 2.0 data model. *

    * Note that several NodeInfo objects may represent the same node. To test node identity, the * method {@link #isSameNodeInfo(NodeInfo)} should be used. An exception to this rule applies for * document nodes, where the correspondence between document nodes and DocumentInfo objects is one to * one. NodeInfo objects are never reused: a given NodeInfo object represents the same node for its entire * lifetime. *

    * This is the primary interface for accessing trees in Saxon, and it forms part of the public * Saxon API. The only subclass of NodeInfo that applications should normally use is {@link DocumentInfo}, * which represents a document node. Methods that form part of the public API are (since Saxon 8.4) * labelled with a JavaDoc "since" tag: classes and methods that have no such label should not be * regarded as stable interfaces. *

    * The interface represented by this class is at a slightly higher level than the abstraction described * in the W3C data model specification, in that it includes support for the XPath axes, rather than exposing * the lower-level properties (such as "parent" and "children") directly. All navigation within trees, * except for a few convenience methods, is done by following the axes using the {@link #iterateAxis} method. * This allows different implementations of the XPath tree model to implement axis navigation in different ways. * Some implementations may choose to use the helper methods provided in class {@link Navigator}. *

    * Note that the stability of this interface applies to classes that use the interface, * not to classes that implement it. The interface may be extended in future to add new methods. *

    * New implementations of NodeInfo are advised also to implement the methods in interface * ExtendedNodeInfo, which will be moved into this interface at some time in the future. * * @author Michael H. Kay * @since 8.4. Extended with three extra methods, previously in ExtendedNodeInfo, in 9.1 */ public interface NodeInfo extends Source, Item, ValueRepresentation { final static int[] EMPTY_NAMESPACE_LIST = new int[0]; /** * Get the kind of node. This will be a value such as {@link net.sf.saxon.type.Type#ELEMENT} * or {@link net.sf.saxon.type.Type#ATTRIBUTE}. There are seven kinds of node: documents, elements, attributes, * text, comments, processing-instructions, and namespaces. * * @return an integer identifying the kind of node. These integer values are the * same as those used in the DOM * @see net.sf.saxon.type.Type * @since 8.4 */ public int getNodeKind(); /** * Determine whether this is the same node as another node. *

    * Note that two different NodeInfo instances can represent the same conceptual node. * Therefore the "==" operator should not be used to test node identity. The equals() * method should give the same result as isSameNodeInfo(), but since this rule was introduced * late it might not apply to all implementations. *

    * Note: a.isSameNodeInfo(b) if and only if generateId(a)==generateId(b). *

    * This method has the same semantics as isSameNode() in DOM Level 3, but * works on Saxon NodeInfo objects rather than DOM Node objects. * * @param other the node to be compared with this node * @return true if this NodeInfo object and the supplied NodeInfo object represent * the same node in the tree. */ public boolean isSameNodeInfo(NodeInfo other); /** * The equals() method compares nodes for identity. It is defined to give the same result * as isSameNodeInfo(). * @param other the node to be compared with this node * @return true if this NodeInfo object and the supplied NodeInfo object represent * the same node in the tree. * @since 8.7 Previously, the effect of the equals() method was not defined. Callers * should therefore be aware that third party implementations of the NodeInfo interface may * not implement the correct semantics. It is safer to use isSameNodeInfo() for this reason. * The equals() method has been defined because it is useful in contexts such as a Java Set or HashMap. */ public boolean equals(Object other); /** * The hashCode() method obeys the contract for hashCode(): that is, if two objects are equal * (represent the same node) then they must have the same hashCode() * @since 8.7 Previously, the effect of the equals() and hashCode() methods was not defined. Callers * should therefore be aware that third party implementations of the NodeInfo interface may * not implement the correct semantics. */ public int hashCode(); /** * Get the System ID for the node. Note this is not the * same as the base URI: the base URI can be modified by xml:base, but * the system ID cannot. The base URI is used primarily for resolving * relative URIs within the content of the document. The system ID is * used primarily in conjunction with a line number, for identifying the * location of elements within the source XML, in particular when errors * are found. For a document node, the System ID represents the value of * the document-uri property as defined in the XDM data model. * * @return the System Identifier of the entity in the source document * containing the node, or null if not known or not applicable. * @since 8.4 */ public String getSystemId(); /** * Get the Base URI for the node, that is, the URI used for resolving a relative URI contained * in the node. This will be the same as the System ID unless xml:base has been used. Where the * node does not have a base URI of its own, the base URI of its parent node is returned. * * @return the base URI of the node. This may be null if the base URI is unknown. * @since 8.4 */ public String getBaseURI(); /** * Get line number. Line numbers are not maintained by default, except for * stylesheets and schema documents. Line numbering can be requested using the * -l option on the command line, or by setting options on the TransformerFactory * or the Configuration before the source document is built. *

    * The granularity of line numbering is normally the element level: for other nodes * such as text nodes and attributes, the line number of the parent element will normally be returned. *

    * In the case of a tree constructed by taking input from a SAX parser, the line number will reflect the * SAX rules: that is, the line number of an element is the line number where the start tag ends. This * may be a little confusing where elements have many attributes spread over multiple lines, or where * single attributes (as can easily happen with XSLT 2.0 stylesheets) occupy several lines. *

    * In the case of a tree constructed by a stylesheet or query, the line number may reflect the line in * the stylesheet or query that caused the node to be constructed. *

    * The line number can be read from within an XPath expression using the Saxon extension function * saxon:line-number() * * @return the line number of the node in its original source document; or * -1 if not available * @since 8.4 */ public int getLineNumber(); /** * Get column number. Column numbers are not maintained by default. Column numbering * can be requested in the same way as line numbering; but a tree implementation can ignore * the request. *

    * The granularity of column numbering is normally the element level: for other nodes * such as text nodes and attributes, the line number of the parent element will normally be returned. *

    * In the case of a tree constructed by taking input from a SAX parser, the column number will reflect the * SAX rules: that is, the column number of an element is the column number where the start tag ends. This * may be a little confusing where elements have many attributes spread over multiple lines, or where * single attributes (as can easily happen with XSLT 2.0 stylesheets) occupy several lines. *

    * In the case of a tree constructed by a stylesheet or query, the column number may reflect the line in * the stylesheet or query that caused the node to be constructed. *

    * The column number can be read from within an XPath expression using the Saxon extension function * saxon:column-number() * * @return the column number of the node in its original source document; or * -1 if not available * @since 9.1 */ public int getColumnNumber(); /** * Determine the relative position of this node and another node, in document order. *

    * The other node must always be in the same tree; the effect of calling this method * when the two nodes are in different trees is undefined. To obtain a global ordering * of nodes, the application should first compare the result of getDocumentNumber(), * and only if the document number is the same should compareOrder() be called. * * @param other The other node, whose position is to be compared with this * node * @return -1 if this node precedes the other node, +1 if it follows the * other node, or 0 if they are the same node. (In this case, * isSameNode() will always return true, and the two nodes will * produce the same result for generateId()) * @since 8.4 */ public int compareOrder(NodeInfo other); /** * Return the string value of the node as defined in the XPath data model. *

    * The interpretation of this depends on the type * of node. For an element it is the accumulated character content of the element, * including descendant elements. *

    * This method returns the string value as if the node were untyped. Unlike the string value * accessor in the XPath 2.0 data model, it does not report an error if the element has a complex * type, instead it returns the concatenation of the descendant text nodes as it would if the element * were untyped. * * @return the string value of the node * @since 8.4 */ public String getStringValue(); /** * Get name code. The name code is a coded form of the node name: two nodes * with the same name code have the same namespace URI, the same local name, * and the same prefix. By masking the name code with {@link NamePool#FP_MASK}, you get a * fingerprint: two nodes with the same fingerprint have the same local name * and namespace URI. * * @return an integer name code, which may be used to obtain the actual node * name from the name pool. For unnamed nodes (text nodes, comments, document nodes, * and namespace nodes for the default namespace), returns -1. * @see net.sf.saxon.om.NamePool#allocate allocate * @see net.sf.saxon.om.NamePool#getFingerprint getFingerprint * @since 8.4 */ public int getNameCode(); /** * Get fingerprint. The fingerprint is a coded form of the expanded name * of the node: two nodes * with the same name code have the same namespace URI and the same local name. * The fingerprint contains no information about the namespace prefix. For a name * in the null namespace, the fingerprint is the same as the name code. * * @return an integer fingerprint; two nodes with the same fingerprint have * the same expanded QName. For unnamed nodes (text nodes, comments, document nodes, * and namespace nodes for the default namespace), returns -1. * @since 8.4 */ public int getFingerprint(); /** * Get the local part of the name of this node. This is the name after the ":" if any. * * @return the local part of the name. For an unnamed node, returns "". Unlike the DOM * interface, this returns the full name in the case of a non-namespaced name. * @since 8.4 */ public String getLocalPart(); /** * Get the URI part of the name of this node. This is the URI corresponding to the * prefix, or the URI of the default namespace if appropriate. * * @return The URI of the namespace of this node. For an unnamed node, * or for an element or attribute that is not in a namespace, or for a processing * instruction, returns an empty string. * @since 8.4 */ public String getURI(); /** * Get the display name of this node, in the form of a lexical QName. * For elements and attributes this is [prefix:]localname. * For unnamed nodes, it is an empty string. * * @return The display name of this node. For a node with no name, returns * an empty string. * @since 8.4 */ public String getDisplayName(); /** * Get the prefix of the name of the node. This is defined only for elements and attributes. * If the node has no prefix, or for other kinds of node, returns a zero-length string. * @return The prefix of the name of the node. * @since 8.4 */ public String getPrefix(); /** * Get the configuration used to build the tree containing this node. * @return the Configuration * @since 8.4 */ public Configuration getConfiguration(); /** * Get the NamePool that holds the namecode for this node * @return the namepool * @since 8.4 */ public NamePool getNamePool(); /** * Get the type annotation of this node, if any. The type annotation is represented as an integer; * this is the fingerprint of the name of the type, as defined in the name pool. Anonymous types * are given a system-defined name. The value of the type annotation can be used to retrieve the * actual schema type definition using the method {@link Configuration#getSchemaType}. *

    * The bit IS_DTD_TYPE (1<<30) will be set in the case of an attribute node if the type annotation * is one of ID, IDREF, or IDREFS and this is derived from DTD rather than schema validation. * * @return the type annotation of the node, under the mask NamePool.FP_MASK, and optionally the * bit setting IS_DTD_TYPE in the case of a DTD-derived ID or IDREF/S type (which is treated * as untypedAtomic for the purposes of obtaining the typed value). * *

    The result is undefined for nodes other than elements and attributes.

    * @since 8.4 */ public int getTypeAnnotation(); /** * Bit setting in the returned type annotation indicating a DTD_derived type on an attribute node */ public static int IS_DTD_TYPE = 1<<30; /** * Bit setting for use alongside a type annotation indicating that the is-nilled property is set */ public static int IS_NILLED = 1<<29; /** * Get the typed value. The result of this method will always be consistent with the method * {@link Item#getTypedValue()}. However, this method is often more convenient and may be * more efficient, especially in the common case where the value is expected to be a singleton. * @return the typed value. This will either be a single AtomicValue or a Value whose items are * atomic values. * @since 8.5 */ public Value atomize() throws XPathException; /** * Get the NodeInfo object representing the parent of this node * * @return the parent of this node; null if this node has no parent * @since 8.4 */ public NodeInfo getParent(); /** * Return an iteration over all the nodes reached by the given axis from this node * * @exception UnsupportedOperationException if the namespace axis is * requested and this axis is not supported for this implementation. * @param axisNumber an integer identifying the axis; one of the constants * defined in class {@link net.sf.saxon.om.Axis} * @return an AxisIterator that delivers the nodes reached by the axis in * turn. The nodes are returned in axis order (document order for a forwards * axis, reverse document order for a reverse axis). * @see net.sf.saxon.om.Axis * @since 8.4 */ public AxisIterator iterateAxis(byte axisNumber); /** * Return an iteration over all the nodes reached by the given axis from this node * that match a given NodeTest * * @exception UnsupportedOperationException if the namespace axis is * requested and this axis is not supported for this implementation. * @param axisNumber an integer identifying the axis; one of the constants * defined in class {@link net.sf.saxon.om.Axis} * @param nodeTest A condition to be satisfied by the returned nodes; nodes * that do not satisfy this condition are not included in the result * @return an AxisIterator that delivers the nodes reached by the axis in * turn. The nodes are returned in axis order (document order for a forwards * axis, reverse document order for a reverse axis). * @see net.sf.saxon.om.Axis * @since 8.4 */ public AxisIterator iterateAxis(byte axisNumber, NodeTest nodeTest); /** * Get the string value of a given attribute of this node * * @param fingerprint The fingerprint of the attribute name * @return the attribute value if it exists, or null if it does not exist. Always returns null * if this node is not an element. * @since 8.4 */ public String getAttributeValue(int fingerprint); /** * Get the root node of the tree containing this node * * @return the NodeInfo representing the top-level ancestor of this node. * This will not necessarily be a document node. If this node has no parent, * then the method returns this node. * @since 8.4 */ public NodeInfo getRoot(); /** * Get the root node, if it is a document node. * * @return the DocumentInfo representing the containing document. If this * node is part of a tree that does not have a document node as its * root, returns null. * @since 8.4 */ public DocumentInfo getDocumentRoot(); /** * Determine whether the node has any children. *

    * Note: the result is equivalent to
    * iterateAxis(Axis.CHILD).next() != null * * @return True if the node has one or more children * @since 8.4 */ public boolean hasChildNodes(); /** * Construct a character string that uniquely identifies this node. * Note: a.isSameNode(b) if and only if generateId(a)==generateId(b) * * @param buffer a buffer which will be updated to hold a string * that uniquely identifies this node, across all documents. * @since 8.7 *

    Changed in Saxon 8.7 to generate the ID value in a client-supplied buffer

    */ public void generateId(FastStringBuffer buffer); /** * Get the document number of the document containing this node. For a free-standing * orphan node, just return the hashcode. * @return the document number of the document containing this node * @since 8.4 */ public int getDocumentNumber(); /** * Copy this node to a given Receiver. *

    * This method is primarily for internal use. It should not be considered a stable * part of the Saxon API. * * @exception XPathException * @param out the Receiver to which the node should be copied. It is the caller's * responsibility to ensure that this Receiver is open before the method is called * (or that it is self-opening), and that it is closed after use. * @param whichNamespaces in the case of an element, controls * which namespace nodes should be copied. Values are {@link #NO_NAMESPACES}, * {@link #LOCAL_NAMESPACES}, {@link #ALL_NAMESPACES} * @param copyAnnotations indicates whether the type annotations * of element and attribute nodes should be copied * @param locationId If non-zero, identifies the location of the instruction * that requested this copy. If zero, indicates that the location information * for the original node is to be copied; in this case the Receiver must be * a LocationCopier */ public void copy(Receiver out, int whichNamespaces, boolean copyAnnotations, int locationId) throws XPathException; /** * Don't copy any namespace nodes. */ int NO_NAMESPACES = 0; /** * Copy namespaces declared (or undeclared) on this element, but not namespaces inherited from a parent element */ int LOCAL_NAMESPACES = 1; /** * Copy all in-scope namespaces */ int ALL_NAMESPACES = 2; /** * Get all namespace declarations and undeclarations defined on this element. *

    * This method is intended primarily for internal use. User applications needing * information about the namespace context of a node should use iterateAxis(Axis.NAMESPACE). * (However, not all implementations support the namespace axis, whereas all implementations are * required to support this method.) * * @param buffer If this is non-null, and the result array fits in this buffer, then the result * may overwrite the contents of this array, to avoid the cost of allocating a new array on the heap. * @return An array of integers representing the namespace declarations and undeclarations present on * this element. For a node other than an element, return null. Otherwise, the returned array is a * sequence of namespace codes, whose meaning may be interpreted by reference to the name pool. The * top half word of each namespace code represents the prefix, the bottom half represents the URI. * If the bottom half is zero, then this is a namespace undeclaration rather than a declaration. * The XML namespace is never included in the list. If the supplied array is larger than required, * then the first unused entry will be set to -1. *

    * For a node other than an element, the method returns null.

    */ public int[] getDeclaredNamespaces(int[] buffer); /** * Determine whether this node has the is-id property * @return true if the node is an ID */ public boolean isId(); /** * Determine whether this node has the is-idref property * @return true if the node is an IDREF or IDREFS element or attribute */ public boolean isIdref(); /** * Determine whether the node has the is-nilled property * @return true if the node has the is-nilled property */ public boolean isNilled(); } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/om/Axis.java0000644000175000017500000003066211033112257017570 0ustar eugeneeugenepackage net.sf.saxon.om; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.Type; /** * An axis, that is a direction of navigation in the document structure. */ public final class Axis { /** * Constant representing the ancestor axis */ public static final byte ANCESTOR = 0; /** Constant representing the ancestor-or-self axis */ public static final byte ANCESTOR_OR_SELF = 1; /** Constant representing the attribute axis */ public static final byte ATTRIBUTE = 2; /** Constant representing the child axis */ public static final byte CHILD = 3; /** Constant representing the descendant axis */ public static final byte DESCENDANT = 4; /** Constant representing the descendant-or-self axis */ public static final byte DESCENDANT_OR_SELF = 5; /** Constant representing the following axis */ public static final byte FOLLOWING = 6; /** Constant representing the following-sibling axis */ public static final byte FOLLOWING_SIBLING = 7; /** Constant representing the namespace axis */ public static final byte NAMESPACE = 8; /** Constant representing the parent axis */ public static final byte PARENT = 9; /** Constant representing the preceding axis */ public static final byte PRECEDING = 10; /** Constant representing the preceding-sibling axis */ public static final byte PRECEDING_SIBLING = 11; /** Constant representing the self axis */ public static final byte SELF = 12; // preceding-or-ancestor axis gives all preceding nodes including ancestors, // in reverse document order /** Constant representing the preceding-or-ancestor axis. This axis is used internally by the xsl:number implementation, it returns the union of the preceding axis and the ancestor axis. */ public static final byte PRECEDING_OR_ANCESTOR = 13; /** * Table indicating the principal node type of each axis */ public static final short[] principalNodeType = { Type.ELEMENT, // ANCESTOR Type.ELEMENT, // ANCESTOR_OR_SELF; Type.ATTRIBUTE, // ATTRIBUTE; Type.ELEMENT, // CHILD; Type.ELEMENT, // DESCENDANT; Type.ELEMENT, // DESCENDANT_OR_SELF; Type.ELEMENT, // FOLLOWING; Type.ELEMENT, // FOLLOWING_SIBLING; Type.NAMESPACE, // NAMESPACE; Type.ELEMENT, // PARENT; Type.ELEMENT, // PRECEDING; Type.ELEMENT, // PRECEDING_SIBLING; Type.ELEMENT, // SELF; Type.ELEMENT, // PRECEDING_OR_ANCESTOR; }; /** * Table indicating for each axis whether it is in forwards document order */ public static final boolean[] isForwards = { false, // ANCESTOR false, // ANCESTOR_OR_SELF; true, // ATTRIBUTE; true, // CHILD; true, // DESCENDANT; true, // DESCENDANT_OR_SELF; true, // FOLLOWING; true, // FOLLOWING_SIBLING; true, // NAMESPACE; true, // PARENT; false, // PRECEDING; false, // PRECEDING_SIBLING; true, // SELF; false, // PRECEDING_OR_ANCESTOR; }; /** * Table indicating for each axis whether it is in reverse document order */ // public static final boolean[] isReverse = // { // true, // ANCESTOR // true, // ANCESTOR_OR_SELF; // false, // ATTRIBUTE; // false, // CHILD; // false, // DESCENDANT; // false, // DESCENDANT_OR_SELF; // false, // FOLLOWING; // false, // FOLLOWING_SIBLING; // false, // NAMESPACE; // true, // PARENT; // true, // PRECEDING; // true, // PRECEDING_SIBLING; // true, // SELF; // true, // PRECEDING_OR_ANCESTOR; // }; /** * Table indicating for each axis whether it is a peer axis. An axis is a peer * axis if no node on the axis is an ancestor of another node on the axis. */ public static final boolean[] isPeerAxis = { false, // ANCESTOR false, // ANCESTOR_OR_SELF; true, // ATTRIBUTE; true, // CHILD; false, // DESCENDANT; false, // DESCENDANT_OR_SELF; false, // FOLLOWING; true, // FOLLOWING_SIBLING; true, // NAMESPACE; true, // PARENT; false, // PRECEDING; true, // PRECEDING_SIBLING; true, // SELF; false, // PRECEDING_OR_ANCESTOR; }; /** * Table indicating for each axis whether it is contained within the subtree * rooted at the origin node. */ public static final boolean[] isSubtreeAxis = { false, // ANCESTOR false, // ANCESTOR_OR_SELF; true, // ATTRIBUTE; true, // CHILD; true, // DESCENDANT; true, // DESCENDANT_OR_SELF; false, // FOLLOWING; false, // FOLLOWING_SIBLING; true, // NAMESPACE; false, // PARENT; false, // PRECEDING; false, // PRECEDING_SIBLING; true, // SELF; false, // PRECEDING_OR_ANCESTOR; }; /** * Table giving the name each axis */ public static final String[] axisName = { "ancestor", // ANCESTOR "ancestor-or-self", // ANCESTOR_OR_SELF; "attribute", // ATTRIBUTE; "child", // CHILD; "descendant", // DESCENDANT; "descendant-or-self", // DESCENDANT_OR_SELF; "following", // FOLLOWING; "following-sibling", // FOLLOWING_SIBLING; "namespace", // NAMESPACE; "parent", // PARENT; "preceding", // PRECEDING; "preceding-sibling", // PRECEDING_SIBLING; "self", // SELF; "preceding-or-ancestor",// PRECEDING_OR_ANCESTOR; }; /** * Table giving the name each axis */ public static final String[] axisJavaName = { "ANCESTOR", // ANCESTOR "ANCESTOR_OR_SELF", // ANCESTOR_OR_SELF; "ATTRIBUTE", // ATTRIBUTE; "CHILD", // CHILD; "DESCENDANT", // DESCENDANT; "DESCENDANT_OR_SELF", // DESCENDANT_OR_SELF; "FOLLOWING", // FOLLOWING; "FOLLOWING_SIBLING", // FOLLOWING_SIBLING; "NAMESPACE", // NAMESPACE; "PARENT", // PARENT; "PRECEDING", // PRECEDING; "PRECEDING_SIBLING", // PRECEDING_SIBLING; "SELF", // SELF; "PRECEDING_OR_ANCESTOR",// PRECEDING_OR_ANCESTOR; }; /** * The class is never instantiated */ private Axis() { } /** * Resolve an axis name into a symbolic constant representing the axis * * @param name * @throws XPathException * @return integer value representing the named axis */ public static byte getAxisNumber(String name) throws XPathException { if (name.equals("ancestor")) return ANCESTOR; if (name.equals("ancestor-or-self")) return ANCESTOR_OR_SELF; if (name.equals("attribute")) return ATTRIBUTE; if (name.equals("child")) return CHILD; if (name.equals("descendant")) return DESCENDANT; if (name.equals("descendant-or-self")) return DESCENDANT_OR_SELF; if (name.equals("following")) return FOLLOWING; if (name.equals("following-sibling")) return FOLLOWING_SIBLING; if (name.equals("namespace")) return NAMESPACE; if (name.equals("parent")) return PARENT; if (name.equals("preceding")) return PRECEDING; if (name.equals("preceding-sibling")) return PRECEDING_SIBLING; if (name.equals("self")) return SELF; // preceding-or-ancestor cannot be used in an XPath expression throw new XPathException("Unknown axis name: " + name); } /** * The following table indicates the combinations of axis and node-kind that always * return an empty result. */ private static final int DOC = 1< 0) { memo += i; controller.setRememberedNumber(node, memo); return memo; } i++; } context.getController().setRememberedNumber(node, i); return i; } /** * Get simple node number. This is defined as one plus the number of previous siblings of the * same node type and name. It is not accessible directly in XSL. This version doesn't require * the controller, and therefore doesn't remember previous results. It is used only by getPath(). * * @param node the node whose number is required * @return the node number, as defined above */ private static int getNumberSimple(NodeInfo node) { int fingerprint = node.getFingerprint(); NodeTest same; if (fingerprint == -1) { same = NodeKindTest.makeNodeKindTest(node.getNodeKind()); } else { same = new NameTest(node); } AxisIterator preceding = node.iterateAxis(Axis.PRECEDING_SIBLING, same); int i = 1; while (preceding.next() != null) { i++; } return i; } /** * Get node number (level="single"). If the current node matches the supplied pattern, the returned * number is one plus the number of previous siblings that match the pattern. Otherwise, * return the element number of the nearest ancestor that matches the supplied pattern. * * @param node the current node, the one whose node number is required * @param count Pattern that identifies which nodes should be * counted. Default (null) is the element name if the current node is * an element, or "node()" otherwise. * @param from Pattern that specifies where counting starts from. * Default (null) is the root node. (This parameter does not seem * useful but is included for the sake of XSLT conformance.) * @param context the dynamic context of the transformation, used if * the patterns reference context values (e.g. variables) * @return the node number established as follows: go to the nearest * ancestor-or-self that matches the 'count' pattern and that is a * descendant of the nearest ancestor that matches the 'from' pattern. * Return one plus the nunber of preceding siblings of that ancestor * that match the 'count' pattern. If there is no such ancestor, * return 0. * @throws XPathException when any error occurs in processing */ public static int getNumberSingle(NodeInfo node, Pattern count, Pattern from, XPathContext context) throws XPathException { if (count == null && from == null) { return getNumberSimple(node, context); } boolean knownToMatch = false; if (count == null) { if (node.getFingerprint() == -1) { // unnamed node count = new NodeTestPattern(NodeKindTest.makeNodeKindTest(node.getNodeKind())); } else { count = new NodeTestPattern(new NameTest(node)); } knownToMatch = true; } NodeInfo target = node; while (!(knownToMatch || count.matches(target, context))) { target = target.getParent(); if (target == null) { return 0; } if (from != null && from.matches(target, context)) { return 0; } } // we've found the ancestor to count from SequenceIterator preceding = target.iterateAxis(Axis.PRECEDING_SIBLING, count.getNodeTest()); // pass the filter condition down to the axis enumeration where possible boolean alreadyChecked = (count instanceof NodeTestPattern); int i = 1; while (true) { NodeInfo p = (NodeInfo)preceding.next(); if (p == null) { return i; } if (alreadyChecked || count.matches(p, context)) { i++; } } } /** * Get node number (level="any"). * Return one plus the number of previous nodes in the * document that match the supplied pattern * * @param inst Identifies the xsl:number expression; this is relevant * when the function is memoised to support repeated use of the same * instruction to number multiple nodes * @param node The node being numbered * @param count Pattern that identifies which nodes should be * counted. Default (null) is the element name if the current node is * an element, or "node()" otherwise. * @param from Pattern that specifies where counting starts from. * Default (null) is the root node. Only nodes after the first (most * recent) node that matches the 'from' pattern are counted. * @param context The dynamic context for the transformation * @param hasVariablesInPatterns if the count or from patterns * contain variables, then it's not safe to get the answer by adding * one to the number of the most recent node that matches * @return one plus the number of nodes that precede the current node, * that match the count pattern, and that follow the first node that * matches the from pattern if specified. * @throws net.sf.saxon.trans.XPathException * */ public static int getNumberAny(Expression inst, NodeInfo node, Pattern count, Pattern from, XPathContext context, boolean hasVariablesInPatterns) throws XPathException { NodeInfo memoNode = null; int memoNumber = 0; Controller controller = context.getController(); boolean memoise = (!hasVariablesInPatterns) && from==null; if (memoise) { Object[] memo = (Object[])controller.getUserData(inst, "xsl:number"); if (memo != null) { memoNode = (NodeInfo)memo[0]; memoNumber = ((Integer)memo[1]).intValue(); } } int num = 0; if (count == null) { if (node.getFingerprint() == -1) { // unnamed node count = new NodeTestPattern(NodeKindTest.makeNodeKindTest(node.getNodeKind())); } else { count = new NodeTestPattern(new NameTest(node)); } num = 1; } else if (count.matches(node, context)) { num = 1; } // We use a special axis invented for the purpose: the union of the preceding and // ancestor axes, but in reverse document order // Pass part of the filtering down to the axis iterator if possible NodeTest filter; if (from == null) { filter = count.getNodeTest(); } else if (from.getNodeKind() == Type.ELEMENT && count.getNodeKind() == Type.ELEMENT) { filter = NodeKindTest.ELEMENT; } else { filter = AnyNodeTest.getInstance(); } SequenceIterator preceding = node.iterateAxis(Axis.PRECEDING_OR_ANCESTOR, filter); boolean found = false; while (true) { NodeInfo prev = (NodeInfo)preceding.next(); if (prev == null) { break; } if (count.matches(prev, context)) { if (num == 1 && memoNode != null && prev.isSameNodeInfo(memoNode)) { num = memoNumber + 1; found = true; break; } num++; } if (from != null && from.matches(prev, context)) { found = true; break; } } if (!found && from != null) { // we've got to the end without matching the from pattern - result is () return 0; } if (memoise) { Object[] memo = new Object[2]; memo[0] = node; memo[1] = new Integer(num); controller.setUserData(inst, "xsl:number", memo); } return num; } /** * Get node number (level="multiple"). * Return a vector giving the hierarchic position of this node. See the XSLT spec for details. * * @param node The node to be numbered * @param count Pattern that identifies which nodes (ancestors and * their previous siblings) should be counted. Default (null) is the * element name if the current node is an element, or "node()" * otherwise. * @param from Pattern that specifies where counting starts from. * Default (null) is the root node. Only nodes below the first (most * recent) node that matches the 'from' pattern are counted. * @param context The dynamic context for the transformation * @return a vector containing for each ancestor-or-self that matches the * count pattern and that is below the nearest node that matches the * from pattern, an Integer which is one greater than the number of * previous siblings that match the count pattern. * @throws XPathException */ public static List getNumberMulti(NodeInfo node, Pattern count, Pattern from, XPathContext context) throws XPathException { //checkNumberable(node); ArrayList v = new ArrayList(5); if (count == null) { if (node.getFingerprint() == -1) { // unnamed node count = new NodeTestPattern(NodeKindTest.makeNodeKindTest(node.getNodeKind())); } else { count = new NodeTestPattern(new NameTest(node)); } } NodeInfo curr = node; while (true) { if (count.matches(curr, context)) { int num = getNumberSingle(curr, count, null, context); v.add(0, new Long(num)); } curr = curr.getParent(); if (curr == null) { break; } if (from != null && from.matches(curr, context)) { break; } } return v; } /** * Generic (model-independent) implementation of deep copy algorithm for nodes. * This is available for use by any node implementations that choose to use it. * * @param node The node to be copied * @param out The receiver to which events will be sent * @param namePool Namepool holding the name codes (used only to resolve namespace * codes) * @param whichNamespaces Indicates which namespace nodes for an element should * be copied. Values are {@link NodeInfo#NO_NAMESPACES}, * {@link NodeInfo#LOCAL_NAMESPACES}, {@link NodeInfo#ALL_NAMESPACES} * @param copyAnnotations Indicates whether type annotations should be copied * @param locationId The location of the instruction invoking the copy * @throws XPathException on any failure reported by the Receiver */ public static void copy(NodeInfo node, Receiver out, NamePool namePool, int whichNamespaces, boolean copyAnnotations, int locationId) throws XPathException { switch (node.getNodeKind()) { case Type.DOCUMENT: { out.startDocument(0); AxisIterator children0 = node.iterateAxis(Axis.CHILD, AnyNodeTest.getInstance()); while (true) { NodeInfo child = (NodeInfo)children0.next(); if (child == null) { break; } child.copy(out, whichNamespaces, copyAnnotations, locationId); } out.endDocument(); break; } case Type.ELEMENT: { out.startElement(node.getNameCode(), copyAnnotations ? node.getTypeAnnotation() : StandardNames.XS_UNTYPED, 0, 0); // output the namespaces switch (whichNamespaces) { case NodeInfo.NO_NAMESPACES: break; case NodeInfo.LOCAL_NAMESPACES: int[] localNamespaces = node.getDeclaredNamespaces(null); for (int i=0; i depth2) { p1 = p1.getParent(); if (p1.isSameNodeInfo(second)) { return +1; } depth1--; } p2 = second; while (depth2 > depth1) { p2 = p2.getParent(); if (p2.isSameNodeInfo(first)) { return -1; } depth2--; } // now move up both branches in sync until we find a common parent while (true) { NodeInfo par1 = p1.getParent(); NodeInfo par2 = p2.getParent(); if (par1 == null || par2 == null) { throw new NullPointerException("Node order comparison - internal error"); } if (par1.isSameNodeInfo(par2)) { if (p1.getNodeKind() == Type.ATTRIBUTE && p2.getNodeKind() != Type.ATTRIBUTE) { return -1; // attributes first } if (p1.getNodeKind() != Type.ATTRIBUTE && p2.getNodeKind() == Type.ATTRIBUTE) { return +1; // attributes first } return ((SiblingCountingNode)p1).getSiblingPosition() - ((SiblingCountingNode)p2).getSiblingPosition(); } p1 = par1; p2 = par2; } } /** * Classify node kinds into categories for sorting into document order: * 0 = document, 1 = namespace, 2 = attribute, 3 = (element, text, comment, pi) */ private static int[] nodeCategories = { -1, //0 = not used 3, //1 = element 2, //2 = attribute 3, //3 = text -1, -1, -1, //4,5,6 = not used 3, //7 = processing-instruction 3, //8 = comment 0, //9 = document -1, -1, -1, //10,11,12 = not used 1 //13 = namespace }; /** * Get a character string that uniquely identifies this node and that collates nodes * into document order * @param node the node whose unique identifier is reuqired * @param sb a buffer to which the unique identifier will be appended * @param addDocNr true if a unique document number is to be included in the information */ public static void appendSequentialKey(SiblingCountingNode node, FastStringBuffer sb, boolean addDocNr) { if (addDocNr) { sb.append('w'); sb.append(Integer.toString(node.getDocumentNumber())); } if (node.getNodeKind() != Type.DOCUMENT) { NodeInfo parent = node.getParent(); if (parent != null) { appendSequentialKey(((SiblingCountingNode)parent), sb, false); } } sb.append(alphaKey(node.getSiblingPosition())); } /** * Construct an alphabetic key from an positive integer; the key collates in the same sequence * as the integer * * @param value The positive integer key value (negative values are treated as zero). * @return the alphabetic key value */ public static String alphaKey(int value) { if (value < 1) { return "a"; } if (value < 10) { return "b" + value; } if (value < 100) { return "c" + value; } if (value < 1000) { return "d" + value; } if (value < 10000) { return "e" + value; } if (value < 100000) { return "f" + value; } if (value < 1000000) { return "g" + value; } if (value < 10000000) { return "h" + value; } if (value < 100000000) { return "i" + value; } if (value < 1000000000) { return "j" + value; } return "k" + value; } /** * Determine if a string is all-whitespace * * @param content the string to be tested * @return true if the supplied string contains no non-whitespace * characters * @deprecated since Saxon 8.5: use {@link Whitespace#isWhite} */ public static boolean isWhite(CharSequence content) { return Whitespace.isWhite(content); } /** * Test if one node is an ancestor-or-self of another * * @param a the putative ancestor-or-self node * @param d the putative descendant node * @return true if a is an ancestor-or-self of d */ public static boolean isAncestorOrSelf(NodeInfo a, NodeInfo d) { // Fast path for the TinyTree implementation if (a instanceof TinyNodeImpl) { if (d instanceof TinyNodeImpl) { return ((TinyNodeImpl)a).isAncestorOrSelf((TinyNodeImpl)d); } else if (d.getNodeKind() == Type.NAMESPACE) { // fall through } else { return false; } } // Generic implementation NodeInfo p = d; while (p != null) { if (a.isSameNodeInfo(p)) { return true; } p = p.getParent(); } return false; } /////////////////////////////////////////////////////////////////////////////// // Helper classes to support axis iteration /////////////////////////////////////////////////////////////////////////////// /** * Create an iterator over a singleton node, if it exists and matches a nodetest; * otherwise return an empty iterator * @param node the singleton node, or null if the node does not exist * @param nodeTest the test to be applied * @return an iterator over the node if it exists and matches the test. */ public static AxisIterator filteredSingleton(NodeInfo node, NodeTest nodeTest) { if (node != null && nodeTest.matches(node)) { return SingleNodeIterator.makeIterator(node); } else { return EmptyIterator.getInstance(); } } /** * AxisFilter is an iterator that applies a NodeTest filter to * the nodes returned by an underlying AxisIterator. */ public static class AxisFilter extends AxisIteratorImpl { private AxisIterator base; private NodeTest nodeTest; //private int last = -1; /** * S * Construct a AxisFilter * * @param base the underlying iterator that returns all the nodes on * a required axis. This must not be an atomizing iterator! * @param test a NodeTest that is applied to each node returned by the * underlying AxisIterator; only those nodes that pass the NodeTest are * returned by the AxisFilter */ public AxisFilter(AxisIterator base, NodeTest test) { this.base = base; nodeTest = test; position = 0; } public Item next() { while (true) { current = (NodeInfo)base.next(); if (current == null) { position = -1; return null; } if (nodeTest.matches(current)) { position++; return current; } } } public SequenceIterator getAnother() { return new AxisFilter((AxisIterator)base.getAnother(), nodeTest); } } /** * BaseEnumeration is an abstract implementation of an AxisIterator, it * simplifies the implementation of the underlying AxisIterator by requiring * it to provide only two methods: advance(), and getAnother(). *

    * NOTA BENE: BaseEnumeration does not maintain the value of the position variable. * It must therefore either (a) be wrapped in an AxisFilter, which does maintain * position, or (b) be subclassed by a class that maintains position itself. */ public static abstract class BaseEnumeration extends AxisIteratorImpl { public final Item next() { advance(); return current; } /** * The advance() method must be provided in each concrete implementation. * It must leave the variable current set to the next node to be returned in the * iteration, or to null if there are no more nodes to be returned. */ public abstract void advance(); public abstract SequenceIterator getAnother(); } /** * General-purpose implementation of the ancestor and ancestor-or-self axes */ public static final class AncestorEnumeration extends BaseEnumeration { private boolean includeSelf; private boolean atStart; private NodeInfo start; /** * Create an iterator over the ancestor or ancestor-or-self axis * @param start the initial context node * @param includeSelf true if the "self" node is to be included */ public AncestorEnumeration(NodeInfo start, boolean includeSelf) { this.start = start; this.includeSelf = includeSelf; current = start; atStart = true; } public void advance() { if (atStart) { atStart = false; if (includeSelf) { return; } } current = (current == null ? null : current.getParent()); } public SequenceIterator getAnother() { return new AncestorEnumeration(start, includeSelf); } } // end of class AncestorEnumeration /** * General-purpose implementation of the descendant and descendant-or-self axes, * in terms of the child axis. * But it also has the option to return the descendants in reverse document order; * this is used when evaluating the preceding axis. Note that the includeSelf option * should not be used when scanning in reverse order, as the self node will always be * returned first. */ public static final class DescendantEnumeration extends BaseEnumeration { private AxisIterator children = null; private AxisIterator descendants = null; private NodeInfo start; private boolean includeSelf; private boolean forwards; private boolean atEnd = false; /** * Create an iterator over the descendant or descendant-or-self axis * @param start the initial context node * @param includeSelf true if the "self" node is to be included * @param forwards true for a forwards iteration, false for reverse order */ public DescendantEnumeration(NodeInfo start, boolean includeSelf, boolean forwards) { this.start = start; this.includeSelf = includeSelf; this.forwards = forwards; } public void advance() { if (descendants != null) { NodeInfo nextd = (NodeInfo)descendants.next(); if (nextd != null) { current = nextd; return; } else { descendants = null; } } if (children != null) { NodeInfo n = (NodeInfo)children.next(); if (n != null) { if (n.hasChildNodes()) { if (forwards) { descendants = new DescendantEnumeration(n, false, forwards); current = n; } else { descendants = new DescendantEnumeration(n, true, forwards); advance(); } } else { current = n; } } else { if (forwards || !includeSelf) { current = null; } else { atEnd = true; children = null; current = start; } } } else if (atEnd) { // we're just finishing a backwards scan current = null; } else { // we're just starting... if (start.hasChildNodes()) { //children = new NodeWrapper.ChildEnumeration(start, true, forwards); children = start.iterateAxis(Axis.CHILD); if (!forwards) { if (children instanceof net.sf.saxon.expr.ReversibleIterator) { children = (AxisIterator)((net.sf.saxon.expr.ReversibleIterator)children).getReverseIterator(); } else { try { List list = new ArrayList(20); SequenceIterator forwards = start.iterateAxis(Axis.CHILD); while (true) { Item n = forwards.next(); if (n == null) { break; } list.add(n); } NodeInfo[] nodes = new NodeInfo[list.size()]; nodes = (NodeInfo[])list.toArray(nodes); children = new ReverseNodeArrayIterator(nodes, 0, nodes.length); } catch (XPathException e) { throw new AssertionError("Internal error in Navigator#descendantEnumeration: " + e.getMessage()); // shouldn't happen. } } } } else { children = EmptyIterator.getInstance(); } if (forwards && includeSelf) { current = start; } else { advance(); } } } public SequenceIterator getAnother() { return new DescendantEnumeration(start, includeSelf, forwards); } } // end of class DescendantEnumeration /** * General purpose implementation of the following axis, in terms of the * ancestor, child, and following-sibling axes */ public static final class FollowingEnumeration extends BaseEnumeration { private NodeInfo start; private AxisIterator ancestorEnum = null; private AxisIterator siblingEnum = null; private AxisIterator descendEnum = null; /** * Create an iterator over the "following" axis * @param start the initial context node */ public FollowingEnumeration(NodeInfo start) { this.start = start; ancestorEnum = new AncestorEnumeration(start, false); switch (start.getNodeKind()) { case Type.ELEMENT: case Type.TEXT: case Type.COMMENT: case Type.PROCESSING_INSTRUCTION: //siblingEnum = new NodeWrapper.ChildEnumeration(start, false, true); // gets following siblings siblingEnum = start.iterateAxis(Axis.FOLLOWING_SIBLING); break; case Type.ATTRIBUTE: case Type.NAMESPACE: //siblingEnum = new NodeWrapper.ChildEnumeration((NodeWrapper)start.getParent(), true, true); // gets children of the attribute's parent node NodeInfo parent = start.getParent(); if (parent == null) { siblingEnum = EmptyIterator.getInstance(); } else { siblingEnum = parent.iterateAxis(Axis.CHILD); } break; default: siblingEnum = EmptyIterator.getInstance(); } //advance(); } public void advance() { if (descendEnum != null) { NodeInfo nextd = (NodeInfo)descendEnum.next(); if (nextd != null) { current = nextd; return; } else { descendEnum = null; } } if (siblingEnum != null) { NodeInfo nexts = (NodeInfo)siblingEnum.next(); if (nexts != null) { current = nexts; NodeInfo n = current; if (n.hasChildNodes()) { descendEnum = new DescendantEnumeration(n, false, true); } else { descendEnum = null; } return; } else { descendEnum = null; siblingEnum = null; } } NodeInfo nexta = (NodeInfo)ancestorEnum.next(); if (nexta != null) { current = nexta; NodeInfo n = current; if (n.getNodeKind() == Type.DOCUMENT) { siblingEnum = EmptyIterator.getInstance(); } else { //siblingEnum = new NodeWrapper.ChildEnumeration(next, false, true); siblingEnum = n.iterateAxis(Axis.FOLLOWING_SIBLING); } advance(); } else { current = null; } } public SequenceIterator getAnother() { return new FollowingEnumeration(start); } } // end of class FollowingEnumeration /** * Helper method to iterate over the preceding axis, or Saxon's internal * preceding-or-ancestor axis, by making use of the ancestor, descendant, and * preceding-sibling axes. */ public static final class PrecedingEnumeration extends BaseEnumeration { private NodeInfo start; private AxisIterator ancestorEnum = null; private AxisIterator siblingEnum = null; private AxisIterator descendEnum = null; private boolean includeAncestors; /** * Create an iterator for the preceding or "preceding-or-ancestor" axis (the latter being * used internall to support xsl:number) * @param start the initial context node * @param includeAncestors true if ancestors of the initial context node are to be included * in the result */ public PrecedingEnumeration(NodeInfo start, boolean includeAncestors) { this.start = start; this.includeAncestors = includeAncestors; ancestorEnum = new AncestorEnumeration(start, false); switch (start.getNodeKind()) { case Type.ELEMENT: case Type.TEXT: case Type.COMMENT: case Type.PROCESSING_INSTRUCTION: // get preceding-sibling enumeration siblingEnum = start.iterateAxis(Axis.PRECEDING_SIBLING); break; default: siblingEnum = EmptyIterator.getInstance(); } } public void advance() { if (descendEnum != null) { NodeInfo nextd = (NodeInfo)descendEnum.next(); if (nextd != null) { current = nextd; return; } else { descendEnum = null; } } if (siblingEnum != null) { NodeInfo nexts = (NodeInfo)siblingEnum.next(); if (nexts != null) { if (nexts.hasChildNodes()) { descendEnum = new DescendantEnumeration(nexts, true, false); advance(); } else { descendEnum = null; current = nexts; } return; } else { descendEnum = null; siblingEnum = null; } } NodeInfo nexta = (NodeInfo)ancestorEnum.next(); if (nexta != null) { current = nexta; NodeInfo n = current; if (n.getNodeKind() == Type.DOCUMENT) { siblingEnum = EmptyIterator.getInstance(); } else { siblingEnum = n.iterateAxis(Axis.PRECEDING_SIBLING); } if (!includeAncestors) { advance(); } } else { current = null; } } public SequenceIterator getAnother() { return new PrecedingEnumeration(start, includeAncestors); } } // end of class PrecedingEnumeration } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/om/NamePool.java0000644000175000017500000012400511033112257020371 0ustar eugeneeugenepackage net.sf.saxon.om; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.Whitespace; import java.io.Serializable; import java.util.Arrays; import java.util.HashMap; /** * A NamePool holds a collection of expanded names, each containing a namespace URI, * a namespace prefix, and a local name; plus a collection of namespaces, each * consisting of a prefix/URI pair. * *

    Each expanded name is allocated a unique integer namecode. The namecode enables * all three parts of the expanded name to be determined, that is, the prefix, the * URI, and the local name.

    * *

    The equivalence betweem names depends only on the URI and the local name. * The namecode is designed so that if two namecodes represent names with the same * URI and local name, the two namecodes are the same in the bottom 20 bits. It is * therefore possible to compare two names for equivalence by performing an integer * comparison of these 20 bits. The bottom 20 bits of a namecode are referred to as * a fingerprint.

    * *

    The NamePool eliminates duplicate names if they have the same prefix, uri, * and local part. It retains duplicates if they have different prefixes

    * *

    Internally the NamePool is organized as a fixed number of hash chains. The selection * of a hash chain is based on hashing the local name, because it is unusual to have many * names that share the same local name but use different URIs. There are 1024 hash chains * and the identifier of the hash chain forms the bottom ten bits of the namecode. The * next ten bits represent the sequential position of an entry within the hash chain. The * upper bits represent the selection of prefix, from among the list of prefixes that have * been used with a given URI. A prefix part of zero means no prefix; if the two prefixes * used with a particular namespace are "xs" and "xsd", say, then these will be prefix * codes 1 and 2.

    * *

    Fingerprints in the range 0 to 1023 are reserved for system use, and are allocated as constants * mainly to names in the XSLT and XML Schema namespaces: constants representing these names * are found in {@link StandardNames}. * *

    Operations that update the NamePool, or that have the potential to update it, are * synchronized. Read-only operations are done without synchronization. Although technically * unsafe, this has not led to any problems in practice. Performance problems due to excessive * contention on the NamePool have occasionally been observed: if this happens, the best strategy * is to consider splitting the workload to use multiple Configurations each with a separate * NamePool.

    * *

    Internal organization of the NamePool

    * *

    The NamePool holds two kinds of entry: name entries, representing * expanded names (local name + prefix + URI), identified by a name code, * and namespace entries (prefix + URI) identified by a namespace code.

    * *

    The data structure of the name table is as follows.

    * *

    There is a fixed size hash table; names are allocated to slots in this * table by hashing on the local name. Each entry in the table is the head of * a chain of NameEntry objects representing names that have the same hash code.

    * *

    Each NameEntry represents a distinct name (same URI and local name). It contains * the local name as a string, plus a short integer representing the URI (as an * offset into the array uris[] - this is known as the URIcode).

    * *

    The fingerprint of a name consists of the hash slot number (in the bottom 10 bits) * concatenated with the depth of the entry down the chain of hash synonyms (in the * next 10 bits). Fingerprints with depth 0 (i.e., in the range 0-1023) are reserved * for predefined names (names of XSLT elements and attributes, and of built-in types). * These names are not stored in the name pool, but are accessible as if they were.

    * *

    A nameCode contains the fingerprint in the bottom 20 bits. It also contains * a 10-bit prefix index. This distinguishes the prefix used, among all the * prefixes that have been used with this namespace URI. If the prefix index is * zero, the prefix is null. Otherwise, it indexes an array of * prefix Strings associated with the namespace URI. Note that the data structures * and algorithms are optimized for the case where URIs usually use the same prefix.

    * *

    The nameCode -1 is reserved to mean "not known" or inapplicable. The fingerprint -1 * has the same meaning. Note that masking the nameCode -1 to extract its bottom 20 bits is * incorrect, and will lead to errors.

    * * @author Michael H. Kay */ public class NamePool implements Serializable { /** * FP_MASK is a mask used to obtain a fingerprint from a nameCode. Given a * nameCode nc, the fingerprint is nc & NamePool.FP_MASK. * (In practice, Saxon code often uses the literal constant 0xfffff, * to extract the bottom 20 bits). * *

    The difference between a fingerprint and a nameCode is that * a nameCode contains information * about the prefix of a name, the fingerprint depends only on the namespace * URI and local name. Note that the "null" nameCode (-1) does not produce * the "null" fingerprint (also -1) when this mask is applied.

    */ public static final int FP_MASK = 0xfffff; // Since fingerprints in the range 0-1023 belong to predefined names, user-defined names // will always have a fingerprint above this range, which can be tested by a mask. public static final int USER_DEFINED_MASK = 0xffc00; // Limit: maximum number of prefixes allowed for one URI public static final int MAX_PREFIXES_PER_URI = 1023; // The default singular instance, used unless the user deliberately wants to // manage name pools himself private static NamePool defaultNamePool = null; /** * Get the singular static NamePool. Until Saxon 8.9, all Configurations shared the same * NamePool unless users explicitly allocated a different one. This is no longer the case * (each Configuration now has its own NamePool), but the singular static NamePool remains * available. * @return a singular NamePool, shared by all users of this Java VM instance. */ public static synchronized NamePool getDefaultNamePool() { if (defaultNamePool == null) { defaultNamePool = new NamePool(); } return defaultNamePool; } /** * Set the default NamePool. NOTE: although a "default" namepool still exists, it is actually * no longer used by default. Since Saxon 8.9, when you create a new Configuration, a new NamePool * specific to that configuration is created. The so-called "default" namepool is only used if you * specifically ask for it. * @param pool the NamePool to be returned by calls of {@link #getDefaultNamePool()} */ public static void setDefaultNamePool(NamePool pool) { defaultNamePool = pool; } /** * Internal structure of a NameEntry, the entry on the hash chain of names. */ private static class NameEntry implements Serializable { String localName; short uriCode; NameEntry nextEntry; // link to next NameEntry with the same hashcode public NameEntry(short uriCode, String localName) { this.uriCode = uriCode; this.localName = localName.intern(); nextEntry = null; } } NameEntry[] hashslots = new NameEntry[1024]; String[] prefixes = new String[100]; short prefixesUsed = 0; String[] uris = new String[100]; String[][] prefixesForUri = new String[100][0]; short urisUsed = 0; // General purpose cache for data held by clients of the namePool private HashMap clientData; /** * Create a NamePool */ public NamePool() { prefixes[NamespaceConstant.NULL_CODE] = ""; uris[NamespaceConstant.NULL_CODE] = NamespaceConstant.NULL; String[] nullp = {""}; prefixesForUri[NamespaceConstant.NULL_CODE] = nullp; prefixes[NamespaceConstant.XML_CODE] = "xml"; uris[NamespaceConstant.XML_CODE] = NamespaceConstant.XML; String[] xmlp = {"xml"}; prefixesForUri[NamespaceConstant.XML_CODE] = xmlp; prefixes[NamespaceConstant.XSLT_CODE] = "xsl"; uris[NamespaceConstant.XSLT_CODE] = NamespaceConstant.XSLT; String[] xsltp = {"xslt"}; prefixesForUri[NamespaceConstant.XSLT_CODE] = xsltp; prefixes[NamespaceConstant.SAXON_CODE] = "saxon"; uris[NamespaceConstant.SAXON_CODE] = NamespaceConstant.SAXON; String[] saxonp = {"saxon"}; prefixesForUri[NamespaceConstant.SAXON_CODE] = saxonp; prefixes[NamespaceConstant.SCHEMA_CODE] = "xs"; uris[NamespaceConstant.SCHEMA_CODE] = NamespaceConstant.SCHEMA; String[] schemap = {"xs"}; prefixesForUri[NamespaceConstant.SCHEMA_CODE] = schemap; // prefixes[NamespaceConstant.XDT_CODE] = "xdt"; // uris[NamespaceConstant.XDT_CODE] = NamespaceConstant.XDT; // String[] xdtp = {"xdt"}; // prefixesForUri[NamespaceConstant.XDT_CODE] = xdtp; prefixes[NamespaceConstant.XSI_CODE] = "xsi"; uris[NamespaceConstant.XSI_CODE] = NamespaceConstant.SCHEMA_INSTANCE; String[] xsip = {"xsi"}; prefixesForUri[NamespaceConstant.XSI_CODE] = xsip; prefixesUsed = 6; urisUsed = 6; } /** * Get a name entry corresponding to a given name code * @param nameCode the integer name code * @return the NameEntry for this name code, or null if there is none. */ private NameEntry getNameEntry(int nameCode) { int hash = nameCode & 0x3ff; int depth = (nameCode >> 10) & 0x3ff; NameEntry entry = hashslots[hash]; for (int i = 1; i < depth; i++) { if (entry == null) { return null; } entry = entry.nextEntry; } return entry; } /** * Allocate the namespace code for a namespace prefix/URI pair. * Create it if not already present * * @param prefix the namespace prefix * @param uri the namespace URI * @return an integer code identifying the namespace. The namespace code * identifies both the prefix and the URI. */ public synchronized int allocateNamespaceCode(String prefix, String uri) { // System.err.println("allocate nscode for " + prefix + " = " + uri); int prefixCode = allocateCodeForPrefix(prefix); int uriCode = allocateCodeForURI(uri); if (prefixCode != 0) { // ensure the prefix is in the list of prefixes used with this URI final String[] prefixes = prefixesForUri[uriCode]; if (prefixes.length == 0 || (!prefixes[0].equals(prefix) && Arrays.asList(prefixes).indexOf(prefix) < 0)) { if (prefixes.length == MAX_PREFIXES_PER_URI) { throw new NamePoolLimitException("NamePool limit exceeded: max " + MAX_PREFIXES_PER_URI + " prefixes per URI"); } String[] p2 = new String[prefixes.length + 1]; System.arraycopy(prefixes, 0, p2, 0, prefixes.length); p2[prefixes.length] = prefix; prefixesForUri[uriCode] = p2; } } return (prefixCode << 16) + uriCode; } /** * Get the existing namespace code for a namespace prefix/URI pair. * @param prefix the namespace prefix. May be "" for the default namespace * @param uri the namespace URI. May be "" for the "null namespace" * @return the integer namespace code that identifies this namespace binding; * or -1 if this binding is not present in the name pool */ public int getNamespaceCode(String prefix, String uri) { //System.err.println("get nscode for " + prefix + " = " + uri); int prefixCode = getCodeForPrefix(prefix); if (prefixCode < 0) { return -1; } int uriCode = getCodeForURI(uri); if (uriCode < 0) { return -1; } if (prefixCode != 0) { // ensure the prefix is in the list of prefixes used with this URI final String[] prefixes = prefixesForUri[uriCode]; if (prefixes.length == 0 || (!prefixes[0].equals(prefix) && Arrays.asList(prefixes).indexOf(prefix) < 0)) { return -1; } } return (prefixCode << 16) + uriCode; } /** * Allocate a namespace code for a given namecode * * @param namecode a code identifying an expanded QName, e.g. of an element or attribute * @return a code identifying the namespace used in the given name. The namespace code * identifies both the prefix and the URI. Return -1 if no namespace code has been allocated * (in this case the caller should call allocateNamespaceCode() to get one). */ public int getNamespaceCode(int namecode) { short uriCode; int fp = namecode & FP_MASK; if ((fp & USER_DEFINED_MASK) == 0) { uriCode = StandardNames.getURICode(fp); } else { NameEntry entry = getNameEntry(namecode); if (entry == null) { return -1; } else { uriCode = entry.uriCode; } } int prefixIndex = getPrefixIndex(namecode); String prefix = getPrefixWithIndex(uriCode, prefixIndex); if (prefix == null) { return -1; } int prefixCode = getCodeForPrefix(prefix); if (prefixCode == -1) { return -1; } return (prefixCode << 16) + uriCode; } /** * Get the prefix index from a namecode * @param nameCode the name code * @return the prefix index. A value of zero means the name is unprefixed (which in the case of an * attribute, means that it is in the null namespace) */ public static int getPrefixIndex(int nameCode) { return (nameCode >> 20) & 0x3ff; } /** * Allocate the uri code for a given URI; create one if not found * @param uri The namespace URI. Supply "" or null for the "null namespace" * @return an integer code that uniquely identifies this URI within the namepool. */ public synchronized short allocateCodeForURI(String uri) { if (uri == null) { return NamespaceConstant.NULL_CODE; } for (short j = 0; j < urisUsed; j++) { if (uris[j].equals(uri)) { return j; } } if (urisUsed >= uris.length) { if (urisUsed > 32000) { throw new NamePoolLimitException("Too many namespace URIs"); } String[][] p = new String[urisUsed * 2][0]; String[] u = new String[urisUsed * 2]; System.arraycopy(prefixesForUri, 0, p, 0, urisUsed); System.arraycopy(uris, 0, u, 0, urisUsed); prefixesForUri = p; uris = u; } uris[urisUsed] = uri; return urisUsed++; } /** * Get the uri code for a given URI * @param uri the URI whose code is required * @return the associated integer URI code, or -1 if not present in the name pool */ public short getCodeForURI(String uri) { for (short j = 0; j < urisUsed; j++) { if (uris[j].equals(uri)) { return j; } } return -1; } /** * Allocate the prefix code for a given Prefix; create one if not found * * @param prefix the namespace prefix whose code is to be allocated or returned * @return the numeric code for this prefix */ private short allocateCodeForPrefix(String prefix) { // Not synchronized, because it's always called from a synchronized method // exploit knowledge of the standard prefixes to shorten the search short start = 1; if (prefix.length() == 0) { return NamespaceConstant.NULL_CODE; } if (prefix.charAt(0) != 'x') { if (prefix.equals("saxon")) { return NamespaceConstant.SAXON_CODE; } start = NamespaceConstant.XSI_CODE + 1; } for (short i=start; i < prefixesUsed; i++) { if (prefixes[i].equals(prefix)) { return i; } } if (prefixesUsed >= prefixes.length) { if (prefixesUsed > 32000) { throw new NamePoolLimitException("Too many namespace prefixes"); } String[] p = new String[prefixesUsed * 2]; System.arraycopy(prefixes, 0, p, 0, prefixesUsed); prefixes = p; } prefixes[prefixesUsed] = prefix; return prefixesUsed++; } /** * Get the prefix code for a given Prefix * @param prefix the prefix. Supply "" for the null prefix representing the default namespace. * @return a code uniquely identifying this prefix within the name pool, or -1 if not found */ public short getCodeForPrefix(String prefix) { for (short i = 0; i < prefixesUsed; i++) { if (prefixes[i].equals(prefix)) { return i; } } return -1; } /** * Suggest a prefix for a given URI. If there are several, it's undefined which one is returned. * If there are no prefixes registered for this URI, return null. * @param URI the namespace URI * @return a prefix that has previously been associated with this URI, if available; otherwise null */ public String suggestPrefixForURI(String URI) { if (URI.equals(NamespaceConstant.XML)) { return "xml"; } short uriCode = getCodeForURI(URI); if (uriCode == -1) { return null; } if (prefixesForUri[uriCode].length >= 1) { return prefixesForUri[uriCode][0]; } return null; } /** * Get a prefix among all the prefixes used with a given URI, given its index * @param uriCode the integer code identifying the URI * @param index indicates which of the prefixes associated with this URI is required * @return the prefix with the given index. If the index is 0, the prefix is always "". */ private String getPrefixWithIndex(short uriCode, int index) { if (index == 0) { return ""; } return prefixesForUri[uriCode][index-1]; } /** * Allocate a name from the pool, or a new Name if there is not a matching one there * * @param prefix the namespace prefix. Use "" for the null prefix, representing the absent namespace * @param uri the namespace URI. Use "" or null for the non-namespace. * @param localName the local part of the name * @return an integer (the "namecode") identifying the name within the namepool. * The Name itself may be retrieved using the getName(int) method */ public synchronized int allocate(String prefix, String uri, String localName) { if (NamespaceConstant.isReserved(uri) || NamespaceConstant.SAXON.equals(uri)) { int fp = StandardNames.getFingerprint(uri, localName); if (fp != -1) { short uriCode = StandardNames.getURICode(fp); int pindex; if (prefix.length() == 0) { pindex = 0; } else { final String[] prefixes = prefixesForUri[uriCode]; int prefixPosition = Arrays.asList(prefixes).indexOf(prefix); if (prefixPosition < 0) { if (prefixes.length == MAX_PREFIXES_PER_URI) { throw new NamePoolLimitException("NamePool limit exceeded: max " + MAX_PREFIXES_PER_URI + " prefixes per URI"); } String[] p2 = new String[prefixes.length + 1]; System.arraycopy(prefixes, 0, p2, 0, prefixes.length); p2[prefixes.length] = prefix; prefixesForUri[uriCode] = p2; prefixPosition = prefixes.length; } pindex = prefixPosition + 1; } return (pindex << 20) + fp; } } // otherwise register the name in this NamePool short uriCode = allocateCodeForURI(uri); return allocateInternal(prefix, uriCode, localName); } /** * Allocate a name from the pool, or a new Name if there is not a matching one there * * @param prefix - the namespace prefix * @param uriCode - the code of the URI * @param localName - the local part of the QName * @return an integer (the "namecode") identifying the name within the namepool. */ public synchronized int allocate(String prefix, short uriCode, String localName) { // System.err.println("Allocate " + prefix + " : " + uriCode + " : " + localName); if (NamespaceConstant.isSpecialURICode(uriCode)) { return allocate(prefix, getURIFromURICode(uriCode), localName); } else { return allocateInternal(prefix, uriCode, localName); } } private int allocateInternal(String prefix, short uriCode, String localName) { int hash = (localName.hashCode() & 0x7fffffff) % 1023; int depth = 1; final String[] prefixes = prefixesForUri[uriCode]; int prefixIndex; if (prefix.length() == 0) { prefixIndex = 0; } else { int prefixPosition = Arrays.asList(prefixes).indexOf(prefix); if (prefixPosition < 0) { if (prefixes.length == MAX_PREFIXES_PER_URI) { throw new NamePoolLimitException("NamePool limit exceeded: max " + MAX_PREFIXES_PER_URI + " prefixes per URI"); } String[] p2 = new String[prefixes.length + 1]; System.arraycopy(prefixes, 0, p2, 0, prefixes.length); p2[prefixes.length] = prefix; prefixesForUri[uriCode] = p2; prefixPosition = prefixes.length; } prefixIndex = prefixPosition + 1; } NameEntry entry; if (hashslots[hash] == null) { entry = new NameEntry(uriCode, localName); hashslots[hash] = entry; } else { entry = hashslots[hash]; while (true) { boolean sameLocalName = (entry.localName.equals(localName)); boolean sameURI = (entry.uriCode == uriCode); if (sameLocalName && sameURI) { // may need to add a new prefix to the entry break; } else { NameEntry next = entry.nextEntry; depth++; if (depth >= 1024) { throw new NamePoolLimitException("Saxon name pool is full"); } if (next == null) { entry.nextEntry = new NameEntry(uriCode, localName); break; } else { entry = next; } } } } // System.err.println("name code = " + prefixIndex + "/" + depth + "/" + hash); return ((prefixIndex << 20) + (depth << 10) + hash); } /** * Allocate a namespace code for the prefix/URI of a given namecode * * @param namecode a code identifying an expanded QName, e.g. of an element or attribute * @return a code identifying the namespace used in the given name. The namespace code * identifies both the prefix and the URI. */ public synchronized int allocateNamespaceCode(int namecode) { short uriCode; int fp = namecode & FP_MASK; if ((fp & USER_DEFINED_MASK) == 0) { uriCode = StandardNames.getURICode(fp); } else { NameEntry entry = getNameEntry(namecode); if (entry == null) { unknownNameCode(namecode); return -1; // to keep the compiler happy } else { uriCode = entry.uriCode; } } int prefixIndex = getPrefixIndex(namecode); String prefix = getPrefixWithIndex(uriCode, prefixIndex); int prefixCode = allocateCodeForPrefix(prefix); return (prefixCode << 16) + uriCode; } /** * Get the namespace-URI of a name, given its name code or fingerprint * @param nameCode the name code or fingerprint of a name * @return the namespace URI corresponding to this name code. Returns "" for the * null namespace. * @throws IllegalArgumentException if the nameCode is not known to the NamePool. */ public String getURI(int nameCode) { if ((nameCode & USER_DEFINED_MASK) == 0) { return StandardNames.getURI(nameCode & FP_MASK); } NameEntry entry = getNameEntry(nameCode); if (entry == null) { unknownNameCode(nameCode); return null; // to keep the compiler happy } return uris[entry.uriCode]; } /** * Get the URI code of a name, given its name code or fingerprint * @param nameCode the name code or fingerprint of a name in the name pool * @return the integer code identifying the namespace URI part of the name */ public short getURICode(int nameCode) { if ((nameCode & USER_DEFINED_MASK) == 0) { return StandardNames.getURICode(nameCode & FP_MASK); } NameEntry entry = getNameEntry(nameCode); if (entry == null) { unknownNameCode(nameCode); return -1; } return entry.uriCode; } /** * Get the local part of a name, given its name code or fingerprint * @param nameCode the integer name code or fingerprint of the name * @return the local part of the name represented by this name code or fingerprint */ public String getLocalName(int nameCode) { if ((nameCode & USER_DEFINED_MASK) == 0) { return StandardNames.getLocalName(nameCode & FP_MASK); } NameEntry entry = getNameEntry(nameCode); if (entry == null) { unknownNameCode(nameCode); return null; } return entry.localName; } /** * Get the prefix part of a name, given its name code * @param nameCode the integer name code of a name in the name pool * @return the prefix of this name. Note that if a fingerprint rather than a full name code is supplied * the returned prefix will be "" */ public String getPrefix(int nameCode) { if ((nameCode & USER_DEFINED_MASK) == 0) { return StandardNames.getPrefix(nameCode & FP_MASK); } short uriCode = getURICode(nameCode); int prefixIndex = getPrefixIndex(nameCode); return getPrefixWithIndex(uriCode, prefixIndex); } /** * Get the display form of a name (the QName), given its name code or fingerprint * @param nameCode the integer name code or fingerprint of a name in the name pool * @return the corresponding lexical QName (if a fingerprint was supplied, this will * simply be the local name) */ public String getDisplayName(int nameCode) { if ((nameCode & USER_DEFINED_MASK) == 0) { // This indicates a standard name known to the system (but it might have a non-standard prefix) int prefixIndex = getPrefixIndex(nameCode); short uriCode = getURICode(nameCode); String prefix; if (uriCode == NamespaceConstant.XML_CODE) { return "xml:" + StandardNames.getLocalName(nameCode & FP_MASK); } else { prefix = getPrefixWithIndex(uriCode, prefixIndex); if (prefix.length() == 0) { return StandardNames.getLocalName(nameCode & FP_MASK); } else { return prefix + ':' + StandardNames.getLocalName(nameCode & FP_MASK); } } } NameEntry entry = getNameEntry(nameCode); if (entry == null) { unknownNameCode(nameCode); return null; } int prefixIndex = getPrefixIndex(nameCode); String prefix = getPrefixWithIndex(entry.uriCode, prefixIndex); if (prefix == null || prefix.length() == 0) { return entry.localName; } else { return prefix + ':' + entry.localName; } } /** * Get the Clark form of a name, given its name code or fingerprint * @param nameCode the integer name code or fingerprint of a name in the name pool * @return the local name if the name is in the null namespace, or "{uri}local" * otherwise. The name is always interned. */ public String getClarkName(int nameCode) { if ((nameCode & USER_DEFINED_MASK) == 0) { return StandardNames.getClarkName(nameCode & FP_MASK); } NameEntry entry = getNameEntry(nameCode); if (entry == null) { unknownNameCode(nameCode); return null; } if (entry.uriCode == 0) { return entry.localName; } else { String n = '{' + getURIFromURICode(entry.uriCode) + '}' + entry.localName; return n.intern(); } } /** * Allocate a fingerprint given a Clark Name * @param expandedName the name in Clark notation, that is "localname" or "{uri}localName" * @return the fingerprint of the name, which need not previously exist in the name pool */ public int allocateClarkName(String expandedName) { String namespace; String localName; if (expandedName.charAt(0) == '{') { int closeBrace = expandedName.indexOf('}'); if (closeBrace < 0) { throw new IllegalArgumentException("No closing '}' in Clark name"); } namespace = expandedName.substring(1, closeBrace); if (closeBrace == expandedName.length()) { throw new IllegalArgumentException("Missing local part in Clark name"); } localName = expandedName.substring(closeBrace + 1); } else { namespace = ""; localName = expandedName; } return allocate("", namespace, localName); } /** * Parse a Clark-format expanded name, returning the URI and local name * @param expandedName the name in Clark notation, that is "localname" or "{uri}localName" * @return an array of two strings, the URI and the local name respectively */ public static String[] parseClarkName(String expandedName) { String namespace; String localName; if (expandedName.charAt(0) == '{') { int closeBrace = expandedName.indexOf('}'); if (closeBrace < 0) { throw new IllegalArgumentException("No closing '}' in Clark name"); } namespace = expandedName.substring(1, closeBrace); if (closeBrace == expandedName.length()) { throw new IllegalArgumentException("Missing local part in Clark name"); } localName = expandedName.substring(closeBrace + 1); } else { namespace = ""; localName = expandedName; } return new String[] {namespace, localName}; } /** * Internal error: name not found in namepool * (Usual cause is allocating a name code from one name pool and trying to * find it in another) * @param nameCode the absent name code */ private void unknownNameCode(int nameCode) { //System.err.println("Unknown name code " + nameCode); //diagnosticDump(); //(new IllegalArgumentException("Unknown name")).printStackTrace(); throw new IllegalArgumentException("Unknown name code " + nameCode); } /** * Get a fingerprint for the name with a given uri and local name. * These must be present in the NamePool. * The fingerprint has the property that if two fingerprint are the same, the names * are the same (ie. same local name and same URI). * @param uri the namespace URI of the required QName * @param localName the local part of the required QName * @return the integer fingerprint, or -1 if this is not found in the name pool */ public int getFingerprint(String uri, String localName) { // A read-only version of allocate() short uriCode; if (uri.length() == 0) { uriCode = 0; } else { if (NamespaceConstant.isReserved(uri) || uri.equals(NamespaceConstant.SAXON)) { int fp = StandardNames.getFingerprint(uri, localName); if (fp != -1) { return fp; // otherwise, look for the name in this namepool } } uriCode = -1; for (short j = 0; j < urisUsed; j++) { if (uris[j].equals(uri)) { uriCode = j; break; } } if (uriCode == -1) { return -1; } } int hash = (localName.hashCode() & 0x7fffffff) % 1023; int depth = 1; NameEntry entry; if (hashslots[hash] == null) { return -1; } entry = hashslots[hash]; while (true) { if (entry.uriCode == uriCode && entry.localName.equals(localName)) { break; } else { NameEntry next = entry.nextEntry; depth++; if (next == null) { return -1; } else { entry = next; } } } return (depth << 10) + hash; } /** * Get the namespace URI from a namespace code. * @param code a namespace code, representing the binding of a prefix to a namespace URI * @return the namespace URI represented by this namespace binding */ public String getURIFromNamespaceCode(int code) { return uris[code & 0xffff]; } /** * Get the namespace URI from a URI code. * @param code a code that identifies the URI within the name pool * @return the URI represented by this code */ public String getURIFromURICode(short code) { return uris[code]; } /** * Get the namespace prefix from a namespace code. * @param code a namespace code representing the binding of a prefix to a URI) * @return the prefix represented by this namespace binding */ public String getPrefixFromNamespaceCode(int code) { // System.err.println("get prefix for " + code); return prefixes[code >> 16]; } /** * Get the nameCode for a lexical QName, given a namespace resolver. * @param qname the lexical QName (with leading and trailing whitespace allowed). * @param useDefault if true, an absent prefix is resolved by the NamespaceResolver * to the namespace URI assigned to the prefix "". If false, an absent prefix is * interpreted as meaning the name is in no namespace. * @param resolver NamespaceResolver used to resolve the namespace prefix to a namespace URI * @param checker NameChecker used to check names against the XML 1.0 or 1.1 specification * @return the corresponding nameCode * @throws net.sf.saxon.trans.XPathException if the string is not a valid lexical QName or * if the namespace prefix has not been declared */ public int allocateLexicalQName(CharSequence qname, boolean useDefault, NamespaceResolver resolver, NameChecker checker) throws XPathException { try { String[] parts = checker.getQNameParts(Whitespace.trimWhitespace(qname)); String uri = resolver.getURIForPrefix(parts[0], useDefault); if (uri == null) { throw new XPathException("Namespace prefix '" + parts[0] + "' has not been declared"); } return allocate(parts[0], uri, parts[1]); } catch (QNameException e) { throw new XPathException(e.getMessage()); } } /** * Get fingerprint for expanded name supplied in Clark format: {uri}local * @param expandedName the QName in Clark notation * @return a fingerprint identifying this name in the name pool */ // public int getFingerprintForExpandedName(String expandedName) { // // String localName; // String namespace; // // if (expandedName.charAt(0) == '{') { // int closeBrace = expandedName.indexOf('}'); // if (closeBrace < 0) { // throw new IllegalArgumentException("No closing '}' in parameter name"); // } // namespace = expandedName.substring(1, closeBrace); // if (closeBrace == expandedName.length()) { // throw new IllegalArgumentException("Missing local part in parameter name"); // } // localName = expandedName.substring(closeBrace + 1); // } else { // namespace = ""; // localName = expandedName; // } // // return allocate("", namespace, localName); // } /** * Save client data on behalf of a user of the namepool * @param key the class that is maintaining private data in the name pool * @param value the private data maintained in the name pool on behalf of this class */ public void setClientData(Class key, Object value) { if (clientData == null) { clientData = new HashMap(10); } clientData.put(key, value); } /** * Retrieve client data on behalf of a user of the namepool * @param key the class that is maintaining private data in the name pool * @return the private data maintained in the name pool on behalf of this class */ public Object getClientData(Class key) { if (clientData == null) { return null; } return clientData.get(key); } /** * Diagnostic print of the namepool contents. */ public synchronized void diagnosticDump() { System.err.println("Contents of NamePool " + this); for (int i = 0; i < 1024; i++) { NameEntry entry = hashslots[i]; int depth = 0; while (entry != null) { System.err.println("Fingerprint " + depth + '/' + i); System.err.println(" local name = " + entry.localName + " uri code = " + entry.uriCode); entry = entry.nextEntry; depth++; } } for (int p = 0; p < prefixesUsed; p++) { System.err.println("Prefix " + p + " = " + prefixes[p]); } for (int u = 0; u < urisUsed; u++) { System.err.println("URI " + u + " = " + uris[u]); FastStringBuffer fsb = new FastStringBuffer(100); for (int p=0; p * @return the next Item. If there are no more nodes, return null. */ public Item next(); /** * Get the current item in the sequence. * * @return the current item, that is, the item most recently returned by * next() */ public Item current(); /** * Get the current position * * @return the position of the current item (the item most recently * returned by next()), starting at 1 for the first node */ public int position(); /** * Get another iterator over the same sequence of items, positioned at the * start of the sequence. It must be possible to call this method at any time, whether * none, some, or all of the items in the original iterator have been read. The method * is non-destructive: it does not change the state of the original iterator. * @return a new iterator over the same sequence */ public SequenceIterator getAnother(); } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/om/ListIterator.java0000644000175000017500000000657111033112257021313 0ustar eugeneeugenepackage net.sf.saxon.om; import net.sf.saxon.expr.LastPositionFinder; import net.sf.saxon.value.SequenceExtent; import java.util.List; /** * Class ListIterator, iterates over a sequence of items held in a Java ArrayList, * or indeed in any other kind of List */ public class ListIterator implements UnfailingIterator, LastPositionFinder, LookaheadIterator, GroundedIterator { int index=0; int length; Item current = null; List list = null; /** * Create a ListIterator over a given List * @param list the list: all objects in the list must be instances of {@link Item} */ public ListIterator(List list) { index = 0; this.list = list; this.length = list.size(); } /** * Create a ListIterator over the leading part of a given List * @param list the list: all objects in the list must be instances of {@link Item} * @param length the number of items to be included */ public ListIterator(List list, int length) { index = 0; this.list = list; this.length = length; } public boolean hasNext() { return index= length) { current = null; index = -1; length = -1; return null; } current = (Item)list.get(index++); return current; } public Item current() { return current; } public int position() { return index; } public void close() { } public int getLastPosition() { return length; } public SequenceIterator getAnother() { return new ListIterator(list); } /** * Get properties of this iterator, as a bit-significant integer. * * @return the properties of this iterator. This will be some combination of * properties such as {@link #GROUNDED}, {@link #LAST_POSITION_FINDER}, * and {@link #LOOKAHEAD}. It is always * acceptable to return the value zero, indicating that there are no known special properties. * It is acceptable for the properties of the iterator to change depending on its state. */ public int getProperties() { return GROUNDED | LAST_POSITION_FINDER | LOOKAHEAD; } /** * Return a SequenceValue containing all the items in the sequence returned by this * SequenceIterator * * @return the corresponding SequenceValue */ public GroundedValue materialize() { return new SequenceExtent(list); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/om/StructuredQName.java0000644000175000017500000002437511033112257021756 0ustar eugeneeugenepackage net.sf.saxon.om; import net.sf.saxon.Configuration; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.Whitespace; import java.io.Serializable; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; /** * This class provides an economical representation of a QName triple (prefix, URI, and localname). * The value is stored internally as a character array containing the concatenation of URI, localname, * and prefix (in that order) with two integers giving the start positions of the localname and prefix. * *

    Instances of this class are immutable.

    */ public class StructuredQName implements Serializable { private final static String EMPTY_STRING = ""; private char[] content; private int localNameStart; private int prefixStart; /** * Construct a StructuredQName from a prefix, URI, and local name. This method performs no validation. * @param prefix The prefix. Use an empty string to represent the null prefix. * @param uri The namespace URI. Use an empty string or null to represent the no-namespace * @param localName The local part of the name */ public StructuredQName(String prefix, String uri, String localName) { if (uri == null) { uri = ""; } int plen = prefix.length(); int ulen = uri.length(); int llen = localName.length(); localNameStart = ulen; prefixStart = ulen + llen; content = new char[ulen + llen + plen]; uri.getChars(0, ulen, content, 0); localName.getChars(0, llen, content, ulen); prefix.getChars(0, plen, content, ulen+llen); } /** * Make a structuredQName from a Namepool nameCode * @param pool the NamePool * @param nameCode a name code that has been registered in the NamePool */ public StructuredQName(NamePool pool, int nameCode) { this(pool.getPrefix(nameCode), pool.getURI(nameCode), pool.getLocalName(nameCode)); } /** * Make a structuredQName from a Clark name * @param expandedName the name in Clark notation "{uri}local" if in a namespace, or "local" otherwise. * The format "{}local" is also accepted for a name in no namespace. * @return the constructed StructuredQName * @throws IllegalArgumentException if the Clark name is malformed */ public static StructuredQName fromClarkName(String expandedName) { String namespace; String localName; if (expandedName.charAt(0) == '{') { int closeBrace = expandedName.indexOf('}'); if (closeBrace < 0) { throw new IllegalArgumentException("No closing '}' in Clark name"); } namespace = expandedName.substring(1, closeBrace); if (closeBrace == expandedName.length()) { throw new IllegalArgumentException("Missing local part in Clark name"); } localName = expandedName.substring(closeBrace + 1); } else { namespace = ""; localName = expandedName; } return new StructuredQName("", namespace, localName); } /** * Make a structured QName from a lexical QName, using a supplied NamespaceResolver to * resolve the prefix * @param lexicalName the QName as a lexical name (prefix:local) * @param useDefault set to true if an absent prefix implies use of the default namespace; * set to false if an absent prefix implies no namespace * @param checker NameChecker to be used to check conformance against XML 1.0 or 1.1 lexical rules * @param resolver NamespaceResolver used to look up a URI for the prefix * @return the StructuredQName object corresponding to this lexical QName * @throws XPathException if the namespace prefix is not in scope or if the value is lexically * invalid. Error code FONS0004 is set if the namespace prefix has not been declared; error * code FOCA0002 is set if the name is lexically invalid. */ public static StructuredQName fromLexicalQName(CharSequence lexicalName, boolean useDefault, NameChecker checker, NamespaceResolver resolver) throws XPathException { try { String[] parts = checker.getQNameParts(Whitespace.trimWhitespace(lexicalName)); String uri = resolver.getURIForPrefix(parts[0], useDefault); if (uri == null) { XPathException de = new XPathException("Namespace prefix '" + parts[0] + "' has not been declared"); de.setErrorCode("FONS0004"); throw de; } return new StructuredQName(parts[0], uri, parts[1]); } catch (QNameException e) { XPathException de = new XPathException(e.getMessage()); de.setErrorCode("FOCA0002"); throw de; } } /** * Get the prefix of the QName. * @return the prefix. Returns the empty string if the name is unprefixed. */ public String getPrefix() { return new String(content, prefixStart, content.length - prefixStart); } /** * Get the namespace URI of the QName. * @return the URI. Returns the empty string to represent the no-namespace */ public String getNamespaceURI() { if (localNameStart == 0) { return EMPTY_STRING; } return new String(content, 0, localNameStart); } /** * Get the local part of the QName * @return the local part of the QName */ public String getLocalName() { return new String(content, localNameStart, prefixStart - localNameStart); } /** * Get the display name, that is the lexical QName in the form [prefix:]local-part * @return the lexical QName */ public String getDisplayName() { if (prefixStart == content.length) { return getLocalName(); } else { FastStringBuffer buff = new FastStringBuffer(content.length - localNameStart + 1); buff.append(content, prefixStart, content.length - prefixStart); buff.append(':'); buff.append(content, localNameStart, prefixStart - localNameStart); return buff.toString(); } } /** * Get the expanded QName in Clark format, that is "{uri}local" if it is in a namespace, or just "local" * otherwise. * @return the QName in Clark notation */ public String getClarkName() { FastStringBuffer buff = new FastStringBuffer(content.length - prefixStart + 2); if (localNameStart > 0) { buff.append('{'); buff.append(content, 0, localNameStart); buff.append('}'); } buff.append(content, localNameStart, prefixStart - localNameStart); return buff.toString(); } /** * The toString() method displays the QName as a lexical QName, that is prefix:local * @return the lexical QName */ public String toString() { return getDisplayName(); } /** * Compare two StructuredQName values for equality. This compares the URI and local name parts, * excluding any prefix */ public boolean equals(Object other) { if (other instanceof StructuredQName) { StructuredQName sq2 = (StructuredQName)other; if (localNameStart != sq2.localNameStart || prefixStart != sq2.prefixStart) { return false; } for (int i=prefixStart-1; i>=0; i--) { // compare from the end of the local name to maximize chance of finding a difference quickly if (content[i] != sq2.content[i]) { return false; } } return true; } else { return false; } } /** * Get a hashcode to reflect the equals() method * @return a hashcode based on the URI and local part only, ignoring the prefix. */ public int hashCode() { int h = 0x8004a00b; h ^= prefixStart; h ^= localNameStart; for (int i=prefixStart-1; i>=0; i--) { h ^= (content[i] << (i&0x1f)); } return h; } /** * Temporary method to construct a javax.xml.namespace.QName without actually mentioning it * by name (because the class is not available in JDK 1.4) * @param config the Saxon configuration * @return an object of class javax.xml.namespace.QName representing this qualified name, or null * if the object cannot be constructed (typically because the class javax.xml.namespace.QName is * not available) */ public Object makeQName(Configuration config) { try { Class qnameClass = config.getClass("javax.xml.namespace.QName", false, null); Class[] argTypes = {String.class, String.class, String.class}; Constructor constructor = qnameClass.getConstructor(argTypes); String[] argValues = {getNamespaceURI(), getLocalName(), getPrefix()}; return constructor.newInstance((Object[])argValues); } catch (XPathException e) { return null; } catch (NoSuchMethodException e) { return null; } catch (InstantiationException e) { return null; } catch (IllegalAccessException e) { return null; } catch (InvocationTargetException e) { return null; } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/om/DocumentPool.java0000644000175000017500000000706711033112257021277 0ustar eugeneeugenepackage net.sf.saxon.om; import java.util.HashMap; import java.util.Iterator; import java.io.Serializable; /** * An object representing the collection of documents handled during * a single transformation. * *

    The function of allocating document numbers is performed * by the DocumentNumberAllocator in the Configuration, not by the DocumentPool. This has a * number of effects: in particular it allows operations involving multiple * documents (such as generateId() and document()) to occur in a free-standing * XPath environment.

    */ public final class DocumentPool implements Serializable { // The document pool ensures that the document() // function, when called twice with the same URI, returns the same document // each time. For this purpose we use a hashtable from // URI to DocumentInfo object. private HashMap documentNameMap = new HashMap(10); /** * Add a document to the pool * @param doc The DocumentInfo for the document in question * @param uri The document-uri property of the document. */ public void add(DocumentInfo doc, String uri) { if (uri!=null) { documentNameMap.put(uri, doc); } } /** * Get the document with a given document-uri * @param uri The document-uri property of the document. * @return the DocumentInfo with the given document-uri property if it exists, * or null if it is not found. */ public DocumentInfo find(String uri) { return (DocumentInfo)documentNameMap.get(uri); } /** * Get the URI for a given document node, if it is present in the pool. This supports the * document-uri() function. * @param doc The document node * @return The uri of the document node, if present in the pool, or the systemId of the document node otherwise */ public String getDocumentURI(NodeInfo doc) { Iterator iter = documentNameMap.keySet().iterator(); while (iter.hasNext()) { String uri = (String)iter.next(); if (find(uri).isSameNodeInfo(doc)) { return uri; } } return null; } /** * Release a document from the document pool. This means that if the same document is * loaded again later, the source will need to be re-parsed, and nodes will get new identities. * @param doc the document to be discarded from the pool * @return the document supplied in the doc parameter */ public DocumentInfo discard(DocumentInfo doc) { Iterator iter = documentNameMap.keySet().iterator(); while (iter.hasNext()) { Object name = iter.next(); DocumentInfo entry = (DocumentInfo) documentNameMap.get(name); if (entry == doc) { documentNameMap.remove(name); return doc; } } return doc; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/om/LookaheadIterator.java0000644000175000017500000000310711033112257022257 0ustar eugeneeugenepackage net.sf.saxon.om; /** * A SequenceIterator is used to iterate over a sequence. A LookaheadIterator * is one that supports a hasNext() method to determine if there are more nodes * after the current node. */ public interface LookaheadIterator extends SequenceIterator { /** * Determine whether there are more items to come. Note that this operation * is stateless and it is not necessary (or usual) to call it before calling * next(). It is used only when there is an explicit need to tell if we * are at the last element. *

    * This method must not be called unless the result of getProperties() on the iterator * includes the bit setting {@link SequenceIterator#LOOKAHEAD} * * @return true if there are more items in the sequence */ public boolean hasNext(); } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/om/FingerprintedNode.java0000644000175000017500000000227611033112257022272 0ustar eugeneeugenepackage net.sf.saxon.om; /** * This is a marker interface used to identify nodes that contain a namepool fingerprint. Although all nodes * are capable of returning a fingerprint, some (notably DOM, XOM, and JDOM nodes) need to calculate it on demand. * A node that implements this interface indicates that obtaining the fingerprint for use in name comparisons * is more efficient than using the URI and local name. */ public interface FingerprintedNode {} // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/om/PrefixNormalizer.java0000644000175000017500000000611111033112257022154 0ustar eugeneeugenepackage net.sf.saxon.om; import org.xml.sax.helpers.XMLFilterImpl; import org.xml.sax.SAXException; import org.xml.sax.Attributes; import java.util.HashMap; import java.util.Stack; /** * */ public class PrefixNormalizer extends XMLFilterImpl { private HashMap uriToPrefix = new HashMap(); // contains the preferred prefix for each URI private Stack prefixes = new Stack(); private Stack uris = new Stack(); /** * Filter a start Namespace prefix mapping event. * * @param prefix The Namespace prefix. * @param uri The Namespace URI. * @throws org.xml.sax.SAXException The client may throw * an exception during processing. */ public void startPrefixMapping(String prefix, String uri) throws SAXException { super.startPrefixMapping(prefix, uri); prefixes.push(prefix); uris.push(uri); if (uriToPrefix.get(uri) == null) { uriToPrefix.put(uri, prefix); } } /** * Filter a start element event. * * @param uri The element's Namespace URI, or the empty string. * @param localName The element's local name, or the empty string. * @param qName The element's qualified (prefixed) name, or the empty * string. * @param atts The element's attributes. * @throws org.xml.sax.SAXException The client may throw * an exception during processing. */ public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException { String newQName = qName; if (uri.length() != 0) { String preferredPrefix = (String)uriToPrefix.get(uri); if (!qName.startsWith(preferredPrefix)) { newQName = preferredPrefix + ':' + localName; } } int alen = atts.getLength(); for (int a=0; a 0xffff) { append(UTF16.highSurrogate(ch)); append(UTF16.lowSurrogate(ch)); } else { append((char)ch); } } /** * Prepend a wide character to the buffer (as a surrogate pair if necessary) * @param ch the character, as a 32-bit Unicode codepoint */ public void prependWideChar(int ch) { if (ch > 0xffff) { prepend(UTF16.lowSurrogate(ch)); prepend(UTF16.highSurrogate(ch)); } else { prepend((char)ch); } } /** * Returns the length of this character sequence. The length is the number * of 16-bit chars in the sequence.

    * * @return the number of chars in this sequence */ public int length() { return used; } /** * Returns the char value at the specified index. An index ranges from zero * to length() - 1. The first char value of the sequence is at * index zero, the next at index one, and so on, as for array * indexing.

    *

    *

    If the char value specified by the index is a * surrogate, the surrogate * value is returned. * * @param index the index of the char value to be returned * @return the specified char value * @throws IndexOutOfBoundsException if the index argument is negative or not less than * length() */ public char charAt(int index) { if (index >= used) { throw new IndexOutOfBoundsException("" + index); } return array[index]; } /** * Returns a new CharSequence that is a subsequence of this sequence. * The subsequence starts with the char value at the specified index and * ends with the char value at index end - 1. The length * (in chars) of the * returned sequence is end - start, so if start == end * then an empty sequence is returned.

    * * @param start the start index, inclusive * @param end the end index, exclusive * @return the specified subsequence * @throws IndexOutOfBoundsException if start or end are negative, * if end is greater than length(), * or if start is greater than end */ public CharSequence subSequence(int start, int end) { return new CharSlice(array, start, end - start); } /** * Copies characters from this FastStringBuffer into the destination character * array. *

    * The first character to be copied is at index srcBegin; * the last character to be copied is at index srcEnd-1 * (thus the total number of characters to be copied is * srcEnd-srcBegin). The characters are copied into the * subarray of dst starting at index dstBegin * and ending at index: *

         *     dstbegin + (srcEnd-srcBegin) - 1
         * 
    * * @param srcBegin index of the first character in the string * to copy. * @param srcEnd index after the last character in the string * to copy. * @param dst the destination array. * @param dstBegin the start offset in the destination array. * @exception IndexOutOfBoundsException If any of the following * is true: *
    • srcBegin is negative. *
    • srcBegin is greater than srcEnd *
    • srcEnd is greater than the length of this * string *
    • dstBegin is negative *
    • dstBegin+(srcEnd-srcBegin) is larger than * dst.length
    */ public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) { if (srcBegin < 0) { throw new StringIndexOutOfBoundsException(srcBegin); } if (srcEnd > used) { throw new StringIndexOutOfBoundsException(srcEnd); } if (srcBegin > srcEnd) { throw new StringIndexOutOfBoundsException(srcEnd - srcBegin); } System.arraycopy(array, srcBegin, dst, dstBegin, srcEnd - srcBegin); } /** * Get the index of the first character equal to a given value * @param ch the character to search for * @return the position of the first occurrence, or -1 if not found */ public int indexOf(char ch) { for (int i=0; i=length() */ public void setCharAt(int index, char ch) { if (index<0 || index>used) { throw new IndexOutOfBoundsException(""+index); } array[index] = ch; } /** * Insert a character at a particular offset * @param index the index of the character to be set * @param ch the new character to insert at that location * @throws IndexOutOfBoundsException if int<0 or int>=length() */ public void insertCharAt(int index, char ch) { if (index<0 || index>used) { throw new IndexOutOfBoundsException(""+index); } ensureCapacity(1); for (int i=used; i>index; i--) { array[i] = array[i-1]; } used++; array[index] = ch; } /** * Remove a character at a particular offset * @param index the index of the character to be set * @throws IndexOutOfBoundsException if int<0 or int>=length() */ public void removeCharAt(int index) { if (index<0 || index>used) { throw new IndexOutOfBoundsException(""+index); } used--; System.arraycopy(array, index + 1, array, index, used - index); } /** * Insert a given character at the start of the buffer * @param ch the character to insert */ public void prepend(char ch) { char[] a2 = new char[array.length + 1]; System.arraycopy(array, 0, a2, 1, used); a2[0] = ch; used += 1; array = a2; } /** * Insert a given character N times at the start of the buffer * @param ch the character to insert * @param repeat the number of occurrences required. Supplying 0 or a negative number is OK, * and is treated as a no-op. */ public void prependRepeated(char ch, int repeat) { if (repeat > 0) { char[] a2 = new char[array.length + repeat]; System.arraycopy(array, 0, a2, repeat, used); Arrays.fill(a2, 0, repeat, ch); used += repeat; array = a2; } } /** * Set the length. If this exceeds the current length, this method is a no-op. * If this is less than the current length, characters beyond the specified point * are deleted. * @param length the new length */ public void setLength(int length) { if (length < 0 || length > used) { return; } used = length; } /** * Expand the character array if necessary to ensure capacity for appended data * @param extra the amount of additional capacity needed, in characters */ public void ensureCapacity(int extra) { if (used + extra > array.length) { int newlen = array.length * 2; if (newlen < used + extra) { newlen = used + extra*2; } char[] array2 = new char[newlen]; System.arraycopy(array, 0, array2, 0, used); array = array2; } } /** * Remove surplus space from the array. This doesn't reduce the array to the minimum * possible size; it only reclaims space if it seems worth doing. Specifically, it * contracts the array if the amount of wasted space is more than 256 characters, or * more than half the allocated size and more than 20 chars. * @return the buffer after removing unused space */ public CharSequence condense() { if (array.length - used > 256 || (array.length > used * 2 && array.length - used > 20)) { char[] array2 = new char[used]; System.arraycopy(array, 0, array2, 0, used); array = array2; } return this; } /** * Write the value to a writer * @param writer the writer to which the content is to be written */ public void write(Writer writer) throws java.io.IOException { writer.write(array, 0, used); } /** * Diagnostic print of the contents of a CharSequence. Ordinary printable ASCII characters * are displayed as themselves; anything else is displayed as a \\uNNNN escape sequence * @param in the CharSequence whose contents are to be displayed. * @return the diagnostic output */ public static String diagnosticPrint(CharSequence in) { FastStringBuffer buff = new FastStringBuffer(in.length()*2); for (int i=0; i 32 && c < 127) { buff.append(c); } else { buff.append("\\u"); for (int d=12; d>=0; d-=4) { buff.append("0123456789ABCDEF".charAt((c>>d)&0xf)); } } } return buff.toString(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none // saxonb-9.1.0.8/bj/net/sf/saxon/om/VirtualUntypedCopy.java0000644000175000017500000001353611033112257022517 0ustar eugeneeugenepackage net.sf.saxon.om; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.Type; import net.sf.saxon.value.UntypedAtomicValue; import net.sf.saxon.value.Value; import net.sf.saxon.event.Receiver; /** * This class represents a virtual copy of a node with type annotations stripped */ public class VirtualUntypedCopy extends VirtualCopy { // TODO: need a VirtualUntypedDocumentCopy for the document node?? /** * Public factory method: create an untyped virtual copy of a node * @param original the node to be copied * @param root the root of the tree * @return the virtual copy. */ public static VirtualCopy makeVirtualUntypedCopy(NodeInfo original, NodeInfo root) { VirtualCopy vc; // Don't allow copies of copies of copies: define the new copy in terms of the original while (original instanceof VirtualUntypedCopy) { original = ((VirtualUntypedCopy)original).original; } while (root instanceof VirtualUntypedCopy) { root = ((VirtualUntypedCopy)root).original; } if (original.getNodeKind() == Type.DOCUMENT) { vc = new VirtualDocumentCopy((DocumentInfo)original); } else { vc = new VirtualUntypedCopy(original); } vc.root = root; return vc; } /** * Protected constructor: create a virtual copy of a node * * @param base the node to be copied */ protected VirtualUntypedCopy(NodeInfo base) { super(base); } /** * Get the type annotation of this node, if any. * * @return the type annotation of the node. * @see net.sf.saxon.type.Type */ public int getTypeAnnotation() { switch (getNodeKind()) { case Type.ELEMENT: return StandardNames.XS_UNTYPED; case Type.ATTRIBUTE: return StandardNames.XS_UNTYPED_ATOMIC; default: return super.getTypeAnnotation(); } } /** * Get the typed value. The result of this method will always be consistent with the method * {@link net.sf.saxon.om.Item#getTypedValue()}. However, this method is often more convenient and may be * more efficient, especially in the common case where the value is expected to be a singleton. * * @return the typed value. If requireSingleton is set to true, the result will always be an * AtomicValue. In other cases it may be a Value representing a sequence whose items are atomic * values. * @since 8.5 */ public Value atomize() throws XPathException { switch (getNodeKind()) { case Type.ELEMENT: case Type.ATTRIBUTE: return new UntypedAtomicValue(getStringValueCS()); default: return super.atomize(); } } /** * Get the typed value of the item * * @return the typed value of the item. In general this will be a sequence * @throws net.sf.saxon.trans.XPathException * where no typed value is available, e.g. for * an element with complex content */ public SequenceIterator getTypedValue() throws XPathException { switch (getNodeKind()) { case Type.ELEMENT: case Type.ATTRIBUTE: return SingletonIterator.makeIterator(new UntypedAtomicValue(getStringValueCS())); default: return super.getTypedValue(); } } public void copy(Receiver out, int whichNamespaces, boolean copyAnnotations, int locationId) throws XPathException { super.copy(out, whichNamespaces, false, locationId); } /** * Create an iterator that makes and returns virtual copies of nodes on the original tree * * @param axis the axis to be navigated * @param newParent the parent of the nodes in the new virtual tree (may be null) * @param root the root of the virtual tree */ protected VirtualCopy.VirtualCopier makeCopier(AxisIterator axis, VirtualCopy newParent, NodeInfo root) { return new VirtualUntypedCopier(axis, newParent, root); } protected class VirtualUntypedCopier extends VirtualCopy.VirtualCopier { public VirtualUntypedCopier(AxisIterator base, VirtualCopy parent, NodeInfo subtreeRoot) { super(base, parent, subtreeRoot); } /** * Method to create the virtual copy of a node encountered when navigating. This method * is separated out so that it can be overridden in a subclass. */ protected VirtualCopy createCopy(NodeInfo node, NodeInfo root) { return VirtualUntypedCopy.makeVirtualUntypedCopy(node, root); } /** * Get another iterator over the same sequence of items, positioned at the * start of the sequence * * @return a new iterator over the same sequence */ public SequenceIterator getAnother() { return new VirtualUntypedCopier((AxisIterator)base.getAnother(), parent, subtreeRoot); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/om/VirtualNode.java0000644000175000017500000000315311033112257021113 0ustar eugeneeugenepackage net.sf.saxon.om; /** * This interface is implemented by NodeInfo implementations that act as wrappers * on some underlying tree. It provides a method to access the real node underlying * the virtual node, for use by applications that need to drill down to the * underlying data. */ public interface VirtualNode extends NodeInfo { /** * Get the real node undelying this virtual node. Note that this may itself be * a VirtualNode; you may have to drill down through several layers of * wrapping. *

    * In some cases a single VirtualNode may represent an XPath text node that maps to a sequence * of adjacent nodes (for example text nodes and CDATA nodes) in the underlying tree. In this case * the first node in this sequence is returned. * @return The underlying node. */ public Object getUnderlyingNode(); } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none //saxonb-9.1.0.8/bj/net/sf/saxon/om/PrependIterator.java0000644000175000017500000001111111033112257021757 0ustar eugeneeugenepackage net.sf.saxon.om; import net.sf.saxon.pattern.NodeTest; import net.sf.saxon.value.Value; import net.sf.saxon.trans.XPathException; /** * An iterator over nodes, that prepends a given node to the nodes * returned by another iterator. Used to modify an iterator over axis A * to one that iterates over A-OR-SELF. */ public class PrependIterator implements AxisIterator { NodeInfo start; AxisIterator base; int position = 0; public PrependIterator(NodeInfo start, AxisIterator base) { this.start = start; this.base = base; } /** * Move to the next node, without returning it. Returns true if there is * a next node, false if the end of the sequence has been reached. After * calling this method, the current node may be retrieved using the * current() function. */ public boolean moveNext() { return (next() != null); } /** * Get the next item in the sequence.
    * * @return the next Item. If there are no more nodes, return null. */ public Item next() { if (position == 0) { position = 1; return start; } Item n = base.next(); if (n == null) { position = -1; } else { position++; } return n; } /** * Get the current item in the sequence. * * @return the current item, that is, the item most recently returned by * next() */ public Item current() { if (position() == 1) { return start; } else if (position < 1) { return null; } else { return base.current(); } } /** * Get the current position * * @return the position of the current item (the item most recently * returned by next()), starting at 1 for the first node */ public int position() { return position; } public void close() { base.close(); } /** * Return an iterator over an axis, starting at the current node. * * @param axis the axis to iterate over, using a constant such as * {@link Axis#CHILD} * @param test a predicate to apply to the nodes before returning them. * @throws NullPointerException if there is no current node */ public AxisIterator iterateAxis(byte axis, NodeTest test) { return ((NodeInfo)current()).iterateAxis(axis, test); } /** * Return the atomized value of the current node. * * @return the atomized value. * @throws NullPointerException if there is no current node */ public Value atomize() throws XPathException { return ((NodeInfo)current()).atomize(); } /** * Return the string value of the current node. * * @return the string value, as an instance of CharSequence. * @throws NullPointerException if there is no current node */ public CharSequence getStringValue() { return ((NodeInfo)current()).getStringValueCS(); } /** * Get another iterator over the same sequence of items, positioned at the * start of the sequence * * @return a new iterator over the same sequence */ public SequenceIterator getAnother() { return new PrependIterator(start, base); } /** * Get properties of this iterator, as a bit-significant integer. * * @return the properties of this iterator. This will be some combination of * properties such as {@link #GROUNDED}, {@link #LAST_POSITION_FINDER}, * and {@link #LOOKAHEAD}. It is always * acceptable to return the value zero, indicating that there are no known special properties. * It is acceptable for the properties of the iterator to change depending on its state. */ public int getProperties() { return 0; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. //saxonb-9.1.0.8/bj/net/sf/saxon/om/VirtualDocumentCopy.java0000644000175000017500000000567111033112257022646 0ustar eugeneeugenepackage net.sf.saxon.om; import net.sf.saxon.Configuration; import java.util.Iterator; /** * A virtual copy of a document node * */ public class VirtualDocumentCopy extends VirtualCopy implements DocumentInfo { public VirtualDocumentCopy(DocumentInfo base) { super(base); } /** * Set the configuration, which defines the name pool used for all names in this document. * This is always called after a new document has been created. * * @param config The configuration to be used */ public void setConfiguration(Configuration config) { // } /** * Get the element with a given ID, if any * * @param id the required ID value * @return the element with the given ID, or null if there is no such ID * present (or if the parser has not notified attributes as being of * type ID) */ public NodeInfo selectID(String id) { NodeInfo n = ((DocumentInfo)original).selectID(id); if (n == null) { return null; } VirtualCopy vc = VirtualCopy.makeVirtualCopy(n, original); vc.documentNumber = documentNumber; return vc; } /** * Get the list of unparsed entities defined in this document * @return an Iterator, whose items are of type String, containing the names of all * unparsed entities defined in this document. If there are no unparsed entities or if the * information is not available then an empty iterator is returned */ public Iterator getUnparsedEntityNames() { return ((DocumentInfo)original).getUnparsedEntityNames(); } /** * Get the unparsed entity with a given name * * @param name the name of the entity * @return if the entity exists, return an array of two Strings, the first * holding the system ID of the entity, the second holding the public * ID if there is one, or null if not. If the entity does not exist, * return null. */ public String[] getUnparsedEntity(String name) { return ((DocumentInfo)original).getUnparsedEntity(name); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/om/Name11Checker.java0000644000175000017500000000470011033112257021165 0ustar eugeneeugenepackage net.sf.saxon.om; import net.sf.saxon.charcode.XMLCharacterData; /** * The class checks names against the rules of the XML 1.1 and XML Namespaces 1.1 specification */ public final class Name11Checker extends NameChecker { public static final Name11Checker theInstance = new Name11Checker(); /** * Get the singular instance of this class * @return the singular instance of this class */ public static Name11Checker getInstance() { return theInstance; } /** * Test whether a character is a valid XML character * * @param ch the character to be tested * @return true if this is a valid character in the selected version of XML */ public boolean isValidChar(int ch) { //return XMLChar.isValid(ch); return XMLCharacterData.isValid11(ch); } /** * Test whether a character can appear in an NCName * * @param ch the character to be tested * @return true if this is a valid character in an NCName the selected version of XML */ public boolean isNCNameChar(int ch) { return XMLCharacterData.isNCName11(ch); } /** * Test whether a character can appear at the start of an NCName * * @param ch the character to be tested * @return true if this is a valid character at the start of an NCName the selected version of XML */ public boolean isNCNameStartChar(int ch) { return XMLCharacterData.isNCNameStart11(ch); } /** * Return the XML version supported by this NameChecker * * @return "1.1" as a string */ public String getXMLVersion() { return "1.1"; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/om/EmptyIterator.java0000644000175000017500000001506111033112257021470 0ustar eugeneeugenepackage net.sf.saxon.om; import net.sf.saxon.expr.LastPositionFinder; import net.sf.saxon.value.EmptySequence; import net.sf.saxon.value.Value; import net.sf.saxon.pattern.NodeTest; import net.sf.saxon.trans.XPathException; /** * EmptyIterator: an iterator over an empty sequence. Since such an iterator has no state, * only one instance is required; therefore a singleton instance is available via the static * getInstance() method. */ public class EmptyIterator implements AxisIterator, net.sf.saxon.expr.ReversibleIterator, LastPositionFinder, GroundedIterator, LookaheadIterator { private static EmptyIterator theInstance = new EmptyIterator(); /** * Get an EmptyIterator, an iterator over an empty sequence. * @return an EmptyIterator (in practice, this always returns the same * one) */ public static EmptyIterator getInstance() { return theInstance; } /** * private constructor */ private EmptyIterator() {} /** * Move to the next node, without returning it. Returns true if there is * a next node, false if the end of the sequence has been reached. After * calling this method, the current node may be retrieved using the * current() function. */ public boolean moveNext() { return false; } /** * Get the next item. * @return the next item. For the EmptyIterator this is always null. */ public Item next() { return null; } /** * Get the current item, that is, the item returned by the most recent call of next(). * @return the current item. For the EmptyIterator this is always null. */ public Item current() { return null; } /** * Get the position of the current item. * @return the position of the current item. For the EmptyIterator this is always zero * (whether or not the next() method has been called). */ public int position() { return 0; } /** * Get the position of the last item in the sequence. * @return the position of the last item in the sequence, always zero in * this implementation */ public int getLastPosition() { return 0; } public void close() { } /** * Return an iterator over an axis, starting at the current node. * * @param axis the axis to iterate over, using a constant such as * {@link Axis#CHILD} * @param test a predicate to apply to the nodes before returning them. * @throws NullPointerException if there is no current node */ public AxisIterator iterateAxis(byte axis, NodeTest test) { throw new NullPointerException(); } /** * Return the atomized value of the current node. * * @return the atomized value. * @throws NullPointerException if there is no current node */ public Value atomize() throws XPathException { throw new NullPointerException(); } /** * Return the string value of the current node. * * @return the string value, as an instance of CharSequence. * @throws NullPointerException if there is no current node */ public CharSequence getStringValue() { throw new NullPointerException(); } /** * Get another iterator over the same items, positioned at the start. * @return another iterator over an empty sequence (in practice, it * returns the same iterator each time) */ public SequenceIterator getAnother() { return theInstance; } /** * Indicate that any nodes returned in the sequence will be atomized. This * means that if it wishes to do so, the implementation can return the typed * values of the nodes rather than the nodes themselves. The implementation * is free to ignore this hint. * @param atomizing true if the caller of this iterator will atomize any * nodes that are returned, and is therefore willing to accept the typed * value of the nodes instead of the nodes themselves. */ //public void setIsAtomizing(boolean atomizing) {} /** * Get another iterator over the same items, in reverse order. * @return a reverse iterator over an empty sequence (in practice, it * returns the same iterator each time) */ public SequenceIterator getReverseIterator() { return theInstance; } /** * Get properties of this iterator, as a bit-significant integer. * * @return the properties of this iterator. This will be some combination of * properties such as {@link #GROUNDED}, {@link #LAST_POSITION_FINDER}, * and {@link #LOOKAHEAD}. It is always * acceptable to return the value zero, indicating that there are no known special properties. * It is acceptable for the properties of the iterator to change depending on its state. */ public int getProperties() { return GROUNDED | LAST_POSITION_FINDER | LOOKAHEAD; } /** * Return a Value containing all the items in the sequence returned by this * SequenceIterator. This should be an "in-memory" value, not a Closure. * * @return the corresponding Value */ public GroundedValue materialize() { return EmptySequence.getInstance(); } /** * Determine whether there are more items to come. Note that this operation * is stateless and it is not necessary (or usual) to call it before calling * next(). It is used only when there is an explicit need to tell if we * are at the last element. * * @return true if there are more nodes */ public boolean hasNext() { return false; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/om/EmptyNamespaceDeclarationList.java0000644000175000017500000000750311033112257024577 0ustar eugeneeugenepackage net.sf.saxon.om; /** * A class representing an empty set of namespace declarations */ public class EmptyNamespaceDeclarationList implements NamespaceDeclarations { private static final int[] emptyArray = new int[0]; private static EmptyNamespaceDeclarationList THE_INSTANCE = new EmptyNamespaceDeclarationList(); private EmptyNamespaceDeclarationList(){}; /** * Get the singular instance of this class * @return the singular instance of this class */ public static EmptyNamespaceDeclarationList getInstance() { return THE_INSTANCE; } /** * Get the n'th declaration in the list in the form of a namespace code. Namespace * codes can be translated into a prefix and URI by means of methods in the * NamePool * * @param index the index identifying which declaration is required. * @return the namespace code. This is an integer whose upper half indicates * the prefix (0 represents the default namespace), and whose lower half indicates * the URI (0 represents an undeclaration). * @throws IndexOutOfBoundsException if the index is out of range. * @see NamePool#getPrefixFromNamespaceCode(int) * @see NamePool#getURIFromNamespaceCode(int) */ public int getNamespaceCode(int index) { throw new IndexOutOfBoundsException(index+""); } /** * Get all the namespace codes, as an array. * * @param buffer a sacrificial array that the method is free to use to contain the result. * May be null. * @return an integer array containing namespace codes. The array may be filled completely * with namespace codes, or it may be incompletely filled, in which case a -1 integer acts * as a terminator. */ public int[] getNamespaceCodes(int[] buffer) { return emptyArray; } /** * Get the number of declarations (and undeclarations) in this list. */ public int getNumberOfNamespaces() { return 0; } /** * Get the prefix of the n'th declaration (or undeclaration) in the list, * counting from zero. * * @param index the index identifying which declaration is required. * @return the namespace prefix. For a declaration or undeclaration of the * default namespace, this is the zero-length string. * @throws IndexOutOfBoundsException if the index is out of range. */ public String getPrefix(int index) { throw new IndexOutOfBoundsException(index+""); } /** * Get the namespace URI of the n'th declaration (or undeclaration) in the list, * counting from zero. * * @param index the index identifying which declaration is required. * @return the namespace URI. For a namespace undeclaration, this is the * zero-length string. * @throws IndexOutOfBoundsException if the index is out of range. */ public String getURI(int index) { throw new IndexOutOfBoundsException(index+""); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/om/SingletonIterator.java0000644000175000017500000001460211033112257022334 0ustar eugeneeugenepackage net.sf.saxon.om; import net.sf.saxon.expr.LastPositionFinder; import net.sf.saxon.value.AtomicValue; import net.sf.saxon.value.SingletonNode; /** * SingletonIterator: an iterator over a sequence of zero or one values */ public class SingletonIterator implements UnfailingIterator, net.sf.saxon.expr.ReversibleIterator, LastPositionFinder, GroundedIterator, LookaheadIterator { private Item item; private int position = 0; /** * Private constructor: external classes should use the factory method * @param value the item to iterate over */ private SingletonIterator(Item value) { this.item = value; } /** * Factory method. * @param item the item to iterate over * @return a SingletonIterator over the supplied item, or an EmptyIterator * if the supplied item is null. */ public static UnfailingIterator makeIterator(Item item) { if (item==null) { return EmptyIterator.getInstance(); } else { return new SingletonIterator(item); } } /** * Determine whether there are more items to come. Note that this operation * is stateless and it is not necessary (or usual) to call it before calling * next(). It is used only when there is an explicit need to tell if we * are at the last element. * * @return true if there are more items */ public boolean hasNext() { return position == 0; } public Item next() { if (position == 0) { position = 1; return item; } else if (position == 1) { position = -1; return null; } else { return null; } } public Item current() { if (position == 1) { return item; } else { return null; } } /** * Return the current position in the sequence. * @return 0 before the first call on next(); 1 before the second call on next(); -1 after the second * call on next(). */ public int position() { return position; } public int getLastPosition() { return 1; } public void close() { } public SequenceIterator getAnother() { return new SingletonIterator(item); } public SequenceIterator getReverseIterator() { return new SingletonIterator(item); } public Item getValue() { return item; } /** * Return a Value containing all the items in the sequence returned by this * SequenceIterator * * @return the corresponding Value. If the value is a closure or a function call package, it will be * evaluated and expanded. */ public GroundedValue materialize() { if (item instanceof AtomicValue) { return (AtomicValue)item; } else { return new SingletonNode((NodeInfo)item); } } /** * Indicate that any nodes returned in the sequence will be atomized. This * means that if it wishes to do so, the implementation can return the typed * values of the nodes rather than the nodes themselves. The implementation * is free to ignore this hint. *

    * This implementation attempts atomization of a singleton node if it is untyped. * This avoids adding an iterator to iterate over the value in the common case where * the typed value of the node is a single atomic value. * * @param atomizing true if the caller of this iterator will atomize any * nodes that are returned, and is therefore willing to accept the typed * value of the nodes instead of the nodes themselves. */ // public void setIsAtomizing(boolean atomizing) { // if (atomizing && (item instanceof NodeInfo)) { // NodeInfo node = (NodeInfo)item; // switch (node.getNodeKind()) { // case Type.DOCUMENT: // case Type.TEXT: // item = new UntypedAtomicValue(node.getStringValueCS()); // return; // // case Type.ELEMENT: // case Type.ATTRIBUTE: // int t = ((NodeInfo)item).getTypeAnnotation(); // if (t == -1 || t == StandardNames.XDT_UNTYPED || t == StandardNames.XDT_UNTYPED_ATOMIC) { // item = new UntypedAtomicValue(node.getStringValueCS()); // return; // } else { // // do nothing: don't attempt to atomize the node here // return; // } // // case Type.COMMENT: // case Type.PROCESSING_INSTRUCTION: // case Type.NAMESPACE: // item = new StringValue(node.getStringValueCS()); // return; // default: // return; // } // } // } /** * Get properties of this iterator, as a bit-significant integer. * * @return the properties of this iterator. This will be some combination of * properties such as {@link #GROUNDED}, {@link #LAST_POSITION_FINDER}, * and {@link #LOOKAHEAD}. It is always * acceptable to return the value zero, indicating that there are no known special properties. * It is acceptable for the properties of the iterator to change depending on its state. */ public int getProperties() { return GROUNDED | LAST_POSITION_FINDER | LOOKAHEAD; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/om/SingleNodeIterator.java0000644000175000017500000001371211033112257022422 0ustar eugeneeugenepackage net.sf.saxon.om; import net.sf.saxon.expr.LastPositionFinder; import net.sf.saxon.pattern.NodeTest; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.SingletonNode; import net.sf.saxon.value.Value; /** * SingletonIterator: an iterator over a sequence of zero or one values */ public class SingleNodeIterator implements AxisIterator, UnfailingIterator, net.sf.saxon.expr.ReversibleIterator, LastPositionFinder, GroundedIterator, LookaheadIterator { private NodeInfo item; private int position = 0; /** * Private constructor: external classes should use the factory method * @param value the item to iterate over */ private SingleNodeIterator(NodeInfo value) { this.item = value; } /** * Factory method. * @param item the item to iterate over * @return a SingletonIterator over the supplied item, or an EmptyIterator * if the supplied item is null. */ public static AxisIterator makeIterator(NodeInfo item) { if (item==null) { return EmptyIterator.getInstance(); } else { return new SingleNodeIterator(item); } } /** * Determine whether there are more items to come. Note that this operation * is stateless and it is not necessary (or usual) to call it before calling * next(). It is used only when there is an explicit need to tell if we * are at the last element. * * @return true if there are more items */ public boolean hasNext() { return position == 0; } /** * Move to the next node, without returning it. Returns true if there is * a next node, false if the end of the sequence has been reached. After * calling this method, the current node may be retrieved using the * current() function. */ public boolean moveNext() { return next() != null; } public Item next() { if (position == 0) { position = 1; return item; } else if (position == 1) { position = -1; return null; } else { return null; } } public Item current() { if (position == 1) { return item; } else { return null; } } /** * Return the current position in the sequence. * @return 0 before the first call on next(); 1 before the second call on next(); -1 after the second * call on next(). */ public int position() { return position; } public int getLastPosition() { return 1; } public void close() { } /** * Return an iterator over an axis, starting at the current node. * * @param axis the axis to iterate over, using a constant such as * {@link Axis#CHILD} * @param test a predicate to apply to the nodes before returning them. */ public AxisIterator iterateAxis(byte axis, NodeTest test) { if (position == 1) { return item.iterateAxis(axis, test); } else { throw new NullPointerException(); } } /** * Return the atomized value of the current node. * * @return the atomized value. * @throws NullPointerException if there is no current node */ public Value atomize() throws XPathException { if (position == 1) { return item.atomize(); } else { throw new NullPointerException(); } } /** * Return the string value of the current node. * * @return the string value, as an instance of CharSequence. * @throws NullPointerException if there is no current node */ public CharSequence getStringValue() { if (position == 1) { return item.getStringValueCS(); } else { throw new NullPointerException(); } } public SequenceIterator getAnother() { return new SingleNodeIterator(item); } public SequenceIterator getReverseIterator() { return new SingleNodeIterator(item); } public Item getValue() { return item; } /** * Return a Value containing all the items in the sequence returned by this * SequenceIterator * * @return the corresponding Value. If the value is a closure or a function call package, it will be * evaluated and expanded. */ public GroundedValue materialize() { return new SingletonNode(item); } /** * Get properties of this iterator, as a bit-significant integer. * * @return the properties of this iterator. This will be some combination of * properties such as {@link #GROUNDED}, {@link #LAST_POSITION_FINDER}, * and {@link #LOOKAHEAD}. It is always * acceptable to return the value zero, indicating that there are no known special properties. * It is acceptable for the properties of the iterator to change depending on its state. */ public int getProperties() { return GROUNDED | LAST_POSITION_FINDER | LOOKAHEAD; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/om/DocumentInfo.java0000644000175000017500000000617211033112257021255 0ustar eugeneeugenepackage net.sf.saxon.om; import java.util.Iterator; /** * This interface represents a document node as defined in the XPath 2.0 data model. * It extends NodeInfo, which is used to represent any node. Every document node must * be an instance of DocumentInfo. *

    * The interface supports two methods in addition to those for NodeInfo: one to find * elements given their ID value, and one to locate unparsed entities. In addition, * document nodes have an important property that is not true of nodes in general: * two distinct Java DocumentInfo objects never represent the same document node. * So the Java "==" operator returns the same result as the {@link NodeInfo#isSameNodeInfo} * method. *

    * This interface is part of the Saxon public API, and as such (from Saxon8.4 onwards) * those methods that form part of the stable public API are labelled with a JavaDoc "since" tag * to indicate when they were added to the product. * * @author Michael H. Kay * @since 8.4 */ public interface DocumentInfo extends NodeInfo { /** * Get the element with a given ID, if any * * @param id the required ID value * @return the element with the given ID, or null if there is no such ID * present (or if the parser has not notified attributes as being of * type ID) * @since 8.4 */ public NodeInfo selectID(String id); /** * Get the list of unparsed entities defined in this document * @return an Iterator, whose items are of type String, containing the names of all * unparsed entities defined in this document. If there are no unparsed entities or if the * information is not available then an empty iterator is returned */ public Iterator getUnparsedEntityNames(); /** * Get the unparsed entity with a given name * * @param name the name of the entity * @return if the entity exists, return an array of two Strings, the first * holding the system ID of the entity, the second holding the public * ID if there is one, or null if not. If the entity does not exist, * the method returns null. Applications should be written on the * assumption that this array may be extended in the future to provide * additional information. * @since 8.4 */ public String[] getUnparsedEntity(String name); } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/om/NameChecker.java0000644000175000017500000001743311033112257021032 0ustar eugeneeugenepackage net.sf.saxon.om; import net.sf.saxon.trans.Err; import net.sf.saxon.trans.XPathException; /** * A NameChecker performs validation and analysis of XML names. There are two implementations * of this interface, one for XML 1.0 names and one for XML 1.1 names. The class also handles * validation of characters against the XML 1.0 or XML 1.1 rules. */ public abstract class NameChecker { /** * Validate whether a given string constitutes a valid QName, as defined in XML Namespaces. * Note that this does not test whether the prefix is actually declared. * * @param name the name to be tested * @return true if the name is a lexically-valid QName */ public final boolean isQName(String name) { int colon = name.indexOf(':'); if (colon < 0) { return isValidNCName(name); } return colon != 0 && colon != name.length() - 1 && isValidNCName(name.substring(0, colon)) && isValidNCName(name.substring(colon + 1)); } /** * Validate whether a given string constitutes a valid NCName, as defined in XML Namespaces. * * @param name the name to be tested * @return true if the name is a lexically-valid QName */ //public abstract boolean isValidNCName(CharSequence name); /** * Extract the prefix from a QName. Note, the QName is assumed to be valid. * * @param qname The lexical QName whose prefix is required * @return the prefix, that is the part before the colon. Returns an empty * string if there is no prefix */ public static String getPrefix(String qname) { int colon = qname.indexOf(':'); if (colon < 0) { return ""; } return qname.substring(0, colon); } /** * Validate a QName, and return the prefix and local name. The local name is checked * to ensure it is a valid NCName. The prefix is not checked, on the theory that the caller * will look up the prefix to find a URI, and if the prefix is invalid, then no URI will * be found. * * @param qname the lexical QName whose parts are required. Note that leading and trailing * whitespace is not permitted * @return an array of two strings, the prefix and the local name. The first * item is a zero-length string if there is no prefix. * @throws QNameException if not a valid QName. */ public final String[] getQNameParts(CharSequence qname) throws QNameException { String[] parts = new String[2]; int colon = -1; int len = qname.length(); for (int i = 0; i < len; i++) { if (qname.charAt(i) == ':') { colon = i; break; } } if (colon < 0) { parts[0] = ""; parts[1] = qname.toString(); if (!isValidNCName(parts[1])) { throw new QNameException("Invalid QName " + Err.wrap(qname)); } } else { if (colon == 0) { throw new QNameException("QName cannot start with colon: " + Err.wrap(qname)); } if (colon == len - 1) { throw new QNameException("QName cannot end with colon: " + Err.wrap(qname)); } parts[0] = qname.subSequence(0, colon).toString(); parts[1] = qname.subSequence(colon + 1, len).toString(); if (!isValidNCName(parts[1])) { throw new QNameException("Invalid QName local part " + Err.wrap(parts[1])); } } return parts; } /** * Validate a QName, and return the prefix and local name. Both parts are checked * to ensure they are valid NCNames. *

    *

    Used from compiled code

    * * @param qname the lexical QName whose parts are required. Note that leading and trailing * whitespace is not permitted * @return an array of two strings, the prefix and the local name. The first * item is a zero-length string if there is no prefix. * @throws XPathException if not a valid QName. */ public final String[] checkQNameParts(CharSequence qname) throws XPathException { try { String[] parts = getQNameParts(qname); if (parts[0].length() > 0 && !isValidNCName(parts[0])) { throw new XPathException("Invalid QName prefix " + Err.wrap(parts[0])); } return parts; } catch (QNameException e) { XPathException err = new XPathException(e.getMessage()); err.setErrorCode("FORG0001"); throw err; } } /** * Validate whether a given string constitutes a valid NCName, as defined in XML Namespaces. * * @param ncName the name to be tested * @return true if the name is a lexically-valid QName */ public final boolean isValidNCName(CharSequence ncName) { if (ncName.length() == 0) { return false; } char ch = ncName.charAt(0); if (!isNCNameStartChar(ch)) { return false; } for (int i = 1; i < ncName.length(); i++) { ch = ncName.charAt(i); if (!isNCNameChar(ch)) { return false; } } return true; } /** * Check to see if a string is a valid Nmtoken according to [7] * in the XML 1.0 Recommendation * * @param nmtoken string to check * @return true if nmtoken is a valid Nmtoken */ public final boolean isValidNmtoken(CharSequence nmtoken) { if (nmtoken.length() == 0) { return false; } for (int i = 0; i < nmtoken.length(); i++) { char ch = nmtoken.charAt(i); if (ch != ':' && !isNCNameChar(ch)) { return false; } } return true; } /** * Test whether a character is a valid XML character * * @param ch the character to be tested * @return true if this is a valid character in the selected version of XML */ public abstract boolean isValidChar(int ch); /** * Test whether a character can appear in an NCName * * @param ch the character to be tested * @return true if this is a valid character in an NCName the selected version of XML */ public abstract boolean isNCNameChar(int ch); /** * Test whether a character can appear at the start of an NCName * * @param ch the character to be tested * @return true if this is a valid character at the start of an NCName the selected version of XML */ public abstract boolean isNCNameStartChar(int ch); /** * Return the XML version supported by this NameChecker * * @return "1.0" or "1.1" as a string */ public abstract String getXMLVersion(); } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/om/ValueRepresentation.java0000644000175000017500000000532011033112257022654 0ustar eugeneeugenepackage net.sf.saxon.om; import net.sf.saxon.trans.XPathException; /** * A ValueRepresentation is a representation of a Value. This is a marker interface * used to represent the union of two classes: Value, and NodeInfo. * Either of these two classes can be used to represent a value. The class is used primarily * to represent the value of a variable. *

    * This class is intended primarily for internal use, and should not be considered part * of the Saxon public API. */ public interface ValueRepresentation { /** * An empty array of ValueRepresentation objects */ public static final ValueRepresentation[] EMPTY_VALUE_ARRAY = new ValueRepresentation[0]; /** * Convert the value to a string, using the serialization rules. * For atomic values this is the same as a cast; for sequence values * it gives a space-separated list. For nodes, it returns the string value of the * node as defined in XDM. * @throws XPathException The method can fail if evaluation of the value * has been deferred, and if a failure occurs during the deferred evaluation. * No failure is possible in the case of an AtomicValue or a Node. */ public String getStringValue() throws XPathException; /** * Convert the value to a string, using the serialization rules, * and returning the result as a CharSequence. In some cases this may be more * efficient than obtaining the result as a string. * For atomic values the result is the same as a cast; for sequence values * it gives a space-separated list. For nodes, it returns the string value of the * node as defined in XDM. * @throws XPathException The method can fail if evaluation of the value * has been deferred, and if a failure occurs during the deferred evaluation. * No failure is possible in the case of an AtomicValue or a Node. */ public CharSequence getStringValueCS() throws XPathException; } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/om/GroundedValue.java0000644000175000017500000000343511033112257021426 0ustar eugeneeugenepackage net.sf.saxon.om; /** * A value that exists in memory and that can be directly addressed */ public interface GroundedValue extends ValueRepresentation { /** * Get the n'th item in the value, counting from 0 * @param n the index of the required item, with 0 representing the first item in the sequence * @return the n'th item if it exists, or null otherwise */ public Item itemAt(int n); /** * Get a subsequence of the value * @param start the index of the first item to be included in the result, counting from zero. * A negative value is taken as zero. If the value is beyond the end of the sequence, an empty * sequence is returned * @param length the number of items to be included in the result. Specify Integer.MAX_VALUE to * get the subsequence up to the end of the base sequence. If the value is negative, an empty sequence * is returned. If the value goes off the end of the sequence, the result returns items up to the end * of the sequence * @return the required subsequence. If min is */ public GroundedValue subsequence(int start, int length); } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/om/AllElementStripper.java0000644000175000017500000000411211033112257022426 0ustar eugeneeugenepackage net.sf.saxon.om; import net.sf.saxon.event.Stripper; /** * The AllElementStripper refines the Stripper class to do stripping of * all whitespace nodes in a document * @author Michael H. Kay */ public class AllElementStripper extends Stripper { private static AllElementStripper theInstance = new AllElementStripper(); public static AllElementStripper getInstance() { return theInstance; } public AllElementStripper() {} public Stripper getAnother() { return theInstance; } /** * Decide whether an element is in the set of white-space preserving element types * @param nameCode identifies the element being tested * @return STRIP_DEFAULT: strip spaces unless xml:space tells you not to. */ public byte isSpacePreserving(int nameCode) { return STRIP_DEFAULT; } /** * Decide whether an element is in the set of white-space preserving element types. * This version of the method is useful in cases where getting the namecode of the * element is potentially expensive, e.g. with DOM nodes. * @param element Identifies the element whose whitespace is possibly to * be preserved */ public byte isSpacePreserving(NodeInfo element) { return STRIP_DEFAULT; } } // end of class AllElementStripper // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/om/ExternalObjectModel.java0000644000175000017500000002332611033112257022555 0ustar eugeneeugenepackage net.sf.saxon.om; import net.sf.saxon.Configuration; import net.sf.saxon.event.PipelineConfiguration; import net.sf.saxon.event.Receiver; import net.sf.saxon.expr.JPConverter; import net.sf.saxon.expr.PJConverter; import net.sf.saxon.trans.XPathException; import javax.xml.transform.Result; import javax.xml.transform.Source; /** * This interface must be implemented by any third-party object model that can * be wrapped with a wrapper that implements the Saxon Object Model (the NodeInfo interface). *

    * This interface is designed to enable advanced applications to implement and register * new object model implementations that Saxon can then use without change. Although it is intended * for external use, it cannot at this stage be considered part of the stable Saxon Public API. * In particular, it is likely that the interface will grow by the addition of new methods. */ public interface ExternalObjectModel { /** * Get the URI of the external object model as used in the JAXP factory interfaces for obtaining * an XPath implementation */ public String getIdentifyingURI(); /** * Get a converter from XPath values to values in the external object model * @param targetClass the required class of the result of the conversion. If this class represents * a node or list of nodes in the external object model, the method should return a converter that takes * a native node or sequence of nodes as input and returns a node or sequence of nodes in the * external object model representation. Otherwise, it should return null. * @return a converter, if the targetClass is recognized as belonging to this object model; * otherwise null */ public PJConverter getPJConverter(Class targetClass); /** * Get a converter from a sequence of nodes to the object used in this object model to represent * a sequence of nodes. * @param node: an example of an object used to represent a node. If this external object model * does not recognize this object */ /** * Get a converter from XPath values to values in the external object model * @param targetClass the required class of the result of the conversion. If this class represents * a node or list of nodes in the external object model, the method should return a converter that takes * an object of this class as input and returns a node or sequence of nodes in the * native Saxon representation. Otherwise, it should return null. * @return a converter, if the targetClass is recognized as belonging to this object model; * otherwise null */ public JPConverter getJPConverter(Class targetClass); /** * Get a converter that converts a sequence of XPath nodes to this model's representation * of a node list. * @param node an example of the kind of node used in this model * @return if the model does not recognize this node as one of its own, return null. Otherwise * return a PJConverter that takes a list of XPath nodes (represented as NodeInfo objects) and * returns a collection of nodes in this object model */ public PJConverter getNodeListCreator(Object node); /** * Test whether this object model recognizes a given node as one of its own. This method * will generally be called at run time. * @param object An object that possibly represents a node * @return true if the object is a representation of a node in this object model */ //public boolean isRecognizedNode(Object object); /** * Test whether this object model recognizes a given class as representing a * node in that object model. This method will generally be called at compile time. * @param nodeClass A class that possibly represents nodes * @return true if the class is used to represent nodes in this object model */ //public boolean isRecognizedNodeClass(Class nodeClass); /** * Test whether this object model recognizes a given class as representing a * list of nodes in that object model. This method will generally be called at compile time. * @param nodeClass A class that possibly represents nodes * @return true if the class is used to represent nodes in this object model */ //public boolean isRecognizedNodeListClass(Class nodeClass); /** * Test whether this object model recognizes a particular kind of JAXP Result object, * and if it does, return a Receiver that builds an instance of this data model from * a sequence of events. If the Result is not recognised, return null. * @param result a JAXP result object * @return a Receiver that writes to that result, if available; or null otherwise */ public Receiver getDocumentBuilder(Result result) throws XPathException; /** * Test whether this object model recognizes a particular kind of JAXP Source object, * and if it does, send the contents of the document to a supplied Receiver, and return true. * Otherwise, return false. * @param source a JAXP Source object * @param receiver the Receiver that is to receive the data from the Source * @param pipe configuration information * @return true if the data from the Source has been sent to the Receiver, false otherwise */ public boolean sendSource(Source source, Receiver receiver, PipelineConfiguration pipe) throws XPathException; /** * Wrap or unwrap a node using this object model to return the corresponding Saxon node. If the supplied * source does not belong to this object model, return null * @param source a JAXP Source object * @param config the Saxon configuration * @return a NodeInfo corresponding to the Source, if this can be constructed; otherwise null */ public NodeInfo unravel(Source source, Configuration config); /** * Convert a Java object to an XPath value. If the supplied object is recognized as a representation * of a value using this object model, the object model should convert the value to an XPath value * and return this as the result. If not, it should return null. If the object is recognized but cannot * be converted, an exception should be thrown * @param object the object to be converted * @param config the Saxon configuration * @return the result of the conversion if the object can be converted, or null otherwise */ //public Value convertObjectToXPathValue(Object object, Configuration config) throws XPathException; /** * Convert an XPath value to an object in this object model. If the supplied value can be converted * to an object in this model, of the specified class, then the conversion should be done and the * resulting object returned. If the value cannot be converted, the method should return null. Note * that the supplied class might be a List, in which case the method should inspect the contents of the * Value to see whether they belong to this object model. * @param value the value to be converted * @param targetClass the required class of the result of the conversion. (This is a Class object when calling * a Java method, a Type object when calling .NET) * @param context the XPath dynamic evaluation context * @return the result of the conversion; always an instance of targetClass, or null if the value * cannot be converted. * @throws XPathException if the target class is explicitly associated with this object model, but the * supplied value cannot be converted to the appropriate class */ // public Object convertXPathValueToObject(Value value, Object targetClass, XPathContext context) throws XPathException; /** * Wrap a document node in the external object model in a document wrapper that implements * the Saxon DocumentInfo interface * @param node a node (any node) in the third party document * @param baseURI the base URI of the node (supply "" if unknown) * @param config the Saxon configuration (which among other things provides access to the NamePool) * @return the wrapper, which must implement DocumentInfo */ //public DocumentInfo wrapDocument(Object node, String baseURI, Configuration config); /** * Wrap a node within the external object model in a node wrapper that implements the Saxon * VirtualNode interface (which is an extension of NodeInfo) * @param document the document wrapper, as a DocumentInfo object * @param node the node to be wrapped. This must be a node within the document wrapped by the * DocumentInfo provided in the first argument * @return the wrapper for the node, as an instance of VirtualNode */ // public NodeInfo wrapNode(DocumentInfo document, Object node); } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): Gunther Schadow (changes to allow access to public fields; also wrapping // of extensions and mapping of null to empty sequence). // saxonb-9.1.0.8/bj/net/sf/saxon/om/ProcInstParser.java0000644000175000017500000001323011033112257021572 0ustar eugeneeugenepackage net.sf.saxon.om; /** * ProcInstParser is used to parse pseudo-attributes within Processing Instructions * @author Michael H. Kay * @version 10 July 2000 */ public class ProcInstParser { /** * Class is never instantiated */ private ProcInstParser() { } /** * Get a pseudo-attribute. This is useful only if the processing instruction data part * uses pseudo-attribute syntax, which it does not have to. This syntax is as described * in the W3C Recommendation "Associating Style Sheets with XML Documents". * @return the value of the pseudo-attribute if present, or null if not */ public static String getPseudoAttribute(String content, String name) { int pos = 0; while (pos <= content.length()-4) { // minimum length of x="" int nextQuote = -1; for (int q=pos; q'); i+=3; } else if (value.substring(i+1).startsWith("amp;")) { sb.append('&'); i+=4; } else if (value.substring(i+1).startsWith("quot;")) { sb.append('"'); i+=5; } else if (value.substring(i+1).startsWith("apos;")) { sb.append('\''); i+=5; } else { return null; } } else { sb.append(c); } } return sb.toString(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/om/NodeArrayIterator.java0000644000175000017500000000614311033112257022257 0ustar eugeneeugenepackage net.sf.saxon.om; import net.sf.saxon.pattern.NodeTest; import net.sf.saxon.value.Value; import net.sf.saxon.trans.XPathException; /** * An iterator over an array of nodes. This is the same as * {@link ArrayIterator}, except that the iterator is an {@link AxisIterator} */ public class NodeArrayIterator extends ArrayIterator implements AxisIterator { public NodeArrayIterator(NodeInfo[] nodes) { super(nodes); } public NodeArrayIterator(NodeInfo[] nodes, int start, int end) { super(nodes, start, end); } /** * Move to the next node, without returning it. Returns true if there is * a next node, false if the end of the sequence has been reached. After * calling this method, the current node may be retrieved using the * current() function. */ public boolean moveNext() { return (next() != null); } /** * Return an iterator over an axis, starting at the current node. * * @param axis the axis to iterate over, using a constant such as * {@link Axis#CHILD} * @param test a predicate to apply to the nodes before returning them. * @throws NullPointerException if there is no current node */ public AxisIterator iterateAxis(byte axis, NodeTest test) { return ((NodeInfo)current()).iterateAxis(axis, test); } /** * Return the atomized value of the current node. * * @return the atomized value. * @throws NullPointerException if there is no current node */ public Value atomize() throws XPathException { return ((NodeInfo)current()).atomize(); } /** * Return the string value of the current node. * * @return the string value, as an instance of CharSequence. * @throws NullPointerException if there is no current node */ public CharSequence getStringValue() { return ((NodeInfo)current()).getStringValueCS(); } /** * Get another iterator over the same items * * @return a new ArrayIterator */ public SequenceIterator getAnother() { return new NodeArrayIterator((NodeInfo[])items, start, end); } /** * Get an iterator that processes the same items in reverse order * * @return a new ArrayIterator */ public SequenceIterator getReverseIterator() { return new ReverseNodeArrayIterator((NodeInfo[])items, start, end); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/om/AxisIteratorImpl.java0000644000175000017500000000745611033112257022131 0ustar eugeneeugenepackage net.sf.saxon.om; import net.sf.saxon.pattern.NodeTest; import net.sf.saxon.value.Value; import net.sf.saxon.trans.XPathException; /** * A SequenceIterator is used to iterate over a sequence. An AxisIterator * is a SequenceIterator that always iterates over a set of nodes, and that * throws no exceptions; it also supports the ability * to find the last() position, again with no exceptions. * This class is an abstract implementation of AxisIterator that is used * as a base class for many concrete implementations. The main functionality * that it provides is maintaining the current position. */ public abstract class AxisIteratorImpl implements AxisIterator { protected int position = 0; protected NodeInfo current; /** * Move to the next node, without returning it. Returns true if there is * a next node, false if the end of the sequence has been reached. After * calling this method, the current node may be retrieved using the * current() function. */ public boolean moveNext() { return (next() != null); } /** * Get the current node in the sequence. * @return the node returned by the most recent call on next() */ public Item current() { return current; } /** * Get the current position * @return the position of the most recent node returned by next() */ public final int position() { return position; } public void close() { } /** * Return an iterator over an axis, starting at the current node. * * @param axis the axis to iterate over, using a constant such as * {@link Axis#CHILD} * @param test a predicate to apply to the nodes before returning them. */ public AxisIterator iterateAxis(byte axis, NodeTest test) { return current.iterateAxis(axis, test); } /** * Return the atomized value of the current node. * * @return the atomized value. * @throws NullPointerException if there is no current node */ public Value atomize() throws XPathException { return current.atomize(); } /** * Return the string value of the current node. * * @return the string value, as an instance of CharSequence. * @throws NullPointerException if there is no current node */ public CharSequence getStringValue() { return current.getStringValueCS(); } /** * Get properties of this iterator, as a bit-significant integer. * * @return the properties of this iterator. This will be some combination of * properties such as {@link #GROUNDED}, {@link #LAST_POSITION_FINDER}, * and {@link #LOOKAHEAD}. It is always * acceptable to return the value zero, indicating that there are no known special properties. * It is acceptable for the properties of the iterator to change depending on its state. */ public int getProperties() { return 0; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/om/NodeListIterator.java0000644000175000017500000000515511033112257022116 0ustar eugeneeugenepackage net.sf.saxon.om; import net.sf.saxon.pattern.NodeTest; import net.sf.saxon.value.Value; import net.sf.saxon.trans.XPathException; import java.util.List; /** * Specialization of ListIterator for use when the items in the list are all nodes */ public class NodeListIterator extends ListIterator implements AxisIterator { /** * Create a NodeListIterator. * @param list the list, all of whose members must be instances of NodeInfo (this is not checked) */ public NodeListIterator(List list) { super(list); } /** * Move to the next node, without returning it. Returns true if there is * a next node, false if the end of the sequence has been reached. After * calling this method, the current node may be retrieved using the * current() function. */ public boolean moveNext() { return (next() != null); } /** * Return an iterator over an axis, starting at the current node. * * @param axis the axis to iterate over, using a constant such as * {@link Axis#CHILD} * @param test a predicate to apply to the nodes before returning them. * @throws NullPointerException if there is no current node */ public AxisIterator iterateAxis(byte axis, NodeTest test) { return ((NodeInfo)current()).iterateAxis(axis, test); } /** * Return the atomized value of the current node. * * @return the atomized value. * @throws NullPointerException if there is no current node */ public Value atomize() throws XPathException { return((NodeInfo)current()).atomize(); } /** * Return the string value of the current node. * * @return the string value, as an instance of CharSequence. * @throws NullPointerException if there is no current node */ public CharSequence getStringValue() { return ((NodeInfo)current()).getStringValue(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/om/NamespaceResolverForElements.java0000644000175000017500000000521711033112257024444 0ustar eugeneeugenepackage net.sf.saxon.om; import java.util.Iterator; /** * This class is a NamespaceResolver that modifies an underyling NamespaceResolver * by changing the mapping of the null prefix to be a specified namespace, rather than * the one used by the underlying namespace resolver. */ public class NamespaceResolverForElements implements NamespaceResolver{ private NamespaceResolver baseResolver; private String defaultNamespace; public NamespaceResolverForElements(NamespaceResolver base, String defaultNamespace) { this.baseResolver = base; this.defaultNamespace = defaultNamespace; } /** * Get the namespace URI corresponding to a given prefix. Return null * if the prefix is not in scope. * @param prefix the namespace prefix. May be the zero-length string, indicating * that there is no prefix. This indicates either the default namespace or the * null namespace, depending on the value of useDefault. * @param useDefault true if the default namespace is to be used when the * prefix is "". If false, the method returns "" when the prefix is "". * @return the uri for the namespace, or null if the prefix is not in scope. * The "null namespace" is represented by the pseudo-URI "". */ public String getURIForPrefix(String prefix, boolean useDefault) { if (useDefault && prefix.length()==0) { return defaultNamespace; } else { return baseResolver.getURIForPrefix(prefix, useDefault); } } /** * Get an iterator over all the prefixes declared in this namespace context. This will include * the default namespace (prefix="") and the XML namespace where appropriate */ public Iterator iteratePrefixes() { return baseResolver.iteratePrefixes(); } } // // The contents of this file are subject to the Mozilla Public License Version // 1.0 (the "License"); // you may not use this file except in compliance with the License. You may // obtain a copy of the License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations // under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael Kay, // // Portions created by (your name) are Copyright (C) (your legal entity). All // Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/om/VirtualCopy.java0000644000175000017500000007155111033112257021147 0ustar eugeneeugenepackage net.sf.saxon.om; import net.sf.saxon.Configuration; import net.sf.saxon.event.Receiver; import net.sf.saxon.pattern.AnyNodeTest; import net.sf.saxon.pattern.NodeTest; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.Type; import net.sf.saxon.value.Value; import javax.xml.transform.SourceLocator; /** * This class represents a node that is a virtual copy of another node: that is, it behaves as a node that's the * same as another node, but has different identity. Moreover, this class can create a virtual copy of a subtree, * so that the parent of the virtual copy is null rather than being a virtual copy of the parent of the original. * This means that none of the axes when applied to the virtual copy is allowed to stray outside the subtree. * The virtual copy is implemented by means of a reference to the node of which * it is a copy, but methods that are sensitive to node identity return a different result. */ public class VirtualCopy implements NodeInfo, SourceLocator { protected String systemId; protected int documentNumber; protected NodeInfo original; protected VirtualCopy parent; protected NodeInfo root; // the node forming the root of the subtree that was copied /** * Protected constructor: create a virtual copy of a node * @param base the node to be copied */ protected VirtualCopy(NodeInfo base) { original = base; systemId = base.getBaseURI(); } /** * Public factory method: create a virtual copy of a node * @param original the node to be copied * @param root the root of the tree containing the node to be copied * @return the virtual copy. If the original was already a virtual copy, this will be a virtual copy * of the real underlying node. */ public static VirtualCopy makeVirtualCopy(NodeInfo original, NodeInfo root) { VirtualCopy vc; // Don't allow copies of copies of copies: define the new copy in terms of the original while (original instanceof VirtualCopy) { original = ((VirtualCopy)original).original; } while (root instanceof VirtualCopy) { root = ((VirtualCopy)root).original; } if (original.getNodeKind() == Type.DOCUMENT) { vc = new VirtualDocumentCopy((DocumentInfo)original); } else { vc = new VirtualCopy(original); } vc.root = root; return vc; } /** * Wrap a node in a VirtualCopy. * This method is designed for subclassing * @param node the node to be wrapped */ protected VirtualCopy wrap(NodeInfo node) { return new VirtualCopy(node); } /** * Set the unique document number of the virtual document. This method must be called to ensure * that nodes in the virtual copy have unique node identifiers * @param documentNumber the document number to be allocated. This can be obtained from the * {@link net.sf.saxon.om.DocumentNumberAllocator} which is accessible from the Configuration using * {@link net.sf.saxon.Configuration#getDocumentNumberAllocator()} */ public void setDocumentNumber(int documentNumber) { this.documentNumber = documentNumber; } /** * Get the kind of node. This will be a value such as Type.ELEMENT or Type.ATTRIBUTE * * @return an integer identifying the kind of node. These integer values are the * same as those used in the DOM * @see net.sf.saxon.type.Type */ public int getNodeKind() { return original.getNodeKind(); } /** * Determine whether this is the same node as another node. * Note: a.isSameNodeInfo(b) if and only if generateId(a)==generateId(b). * This method has the same semantics as isSameNode() in DOM Level 3, but * works on Saxon NodeInfo objects rather than DOM Node objects. * * @param other the node to be compared with this node * @return true if this NodeInfo object and the supplied NodeInfo object represent * the same node in the tree. */ public boolean isSameNodeInfo(NodeInfo other) { return other instanceof VirtualCopy && documentNumber == other.getDocumentNumber() && original.isSameNodeInfo(((VirtualCopy)other).original); } /** * The equals() method compares nodes for identity. It is defined to give the same result * as isSameNodeInfo(). * @param other the node to be compared with this node * @return true if this NodeInfo object and the supplied NodeInfo object represent * the same node in the tree. * @since 8.7 Previously, the effect of the equals() method was not defined. Callers * should therefore be aware that third party implementations of the NodeInfo interface may * not implement the correct semantics. It is safer to use isSameNodeInfo() for this reason. * The equals() method has been defined because it is useful in contexts such as a Java Set or HashMap. */ public boolean equals(Object other) { return other instanceof NodeInfo && isSameNodeInfo((NodeInfo)other); } /** * The hashCode() method obeys the contract for hashCode(): that is, if two objects are equal * (represent the same node) then they must have the same hashCode() * @since 8.7 Previously, the effect of the equals() and hashCode() methods was not defined. Callers * should therefore be aware that third party implementations of the NodeInfo interface may * not implement the correct semantics. */ public int hashCode() { return original.hashCode() ^ (documentNumber << 19); } /** * Get the System ID for the node. * * @return the System Identifier of the entity in the source document * containing the node, or null if not known. Note this is not the * same as the base URI: the base URI can be modified by xml:base, but * the system ID cannot. */ public String getSystemId() { return systemId; } /** * Get the Base URI for the node, that is, the URI used for resolving a relative URI contained * in the node. This will be the same as the System ID unless xml:base has been used. * * @return the base URI of the node */ public String getBaseURI() { return Navigator.getBaseURI(this); } /** * Get line number * * @return the line number of the node in its original source document; or * -1 if not available */ public int getLineNumber() { return original.getLineNumber(); } /** * Get column number * @return the column number of the node in its original source document; or -1 if not available */ public int getColumnNumber() { return original.getColumnNumber(); } /** * Determine the relative position of this node and another node, in document order. * The other node will always be in the same document. * * @param other The other node, whose position is to be compared with this * node * @return -1 if this node precedes the other node, +1 if it follows the * other node, or 0 if they are the same node. (In this case, * isSameNode() will always return true, and the two nodes will * produce the same result for generateId()) */ public int compareOrder(NodeInfo other) { return original.compareOrder(((VirtualCopy)other).original); } /** * Return the string value of the node. The interpretation of this depends on the type * of node. For an element it is the accumulated character content of the element, * including descendant elements. * * @return the string value of the node */ public String getStringValue() { return original.getStringValue(); } /** * Get the value of the item as a CharSequence. This is in some cases more efficient than * the version of the method that returns a String. */ public CharSequence getStringValueCS() { return original.getStringValueCS(); } /** * Get name code. The name code is a coded form of the node name: two nodes * with the same name code have the same namespace URI, the same local name, * and the same prefix. By masking the name code with &0xfffff, you get a * fingerprint: two nodes with the same fingerprint have the same local name * and namespace URI. * * @return an integer name code, which may be used to obtain the actual node * name from the name pool * @see NamePool#allocate allocate * @see NamePool#getFingerprint getFingerprint */ public int getNameCode() { return original.getNameCode(); } /** * Get fingerprint. The fingerprint is a coded form of the expanded name * of the node: two nodes * with the same name code have the same namespace URI and the same local name. * A fingerprint of -1 should be returned for a node with no name. * * @return an integer fingerprint; two nodes with the same fingerprint have * the same expanded QName */ public int getFingerprint() { return original.getFingerprint(); } /** * Get the local part of the name of this node. This is the name after the ":" if any. * * @return the local part of the name. For an unnamed node, returns "". Unlike the DOM * interface, this returns the full name in the case of a non-namespaced name. */ public String getLocalPart() { return original.getLocalPart(); } /** * Get the URI part of the name of this node. This is the URI corresponding to the * prefix, or the URI of the default namespace if appropriate. * * @return The URI of the namespace of this node. For an unnamed node, * or for a node with an empty prefix, return an empty * string. */ public String getURI() { return original.getURI(); } /** * Get the prefix of the name of the node. This is defined only for elements and attributes. * If the node has no prefix, or for other kinds of node, return a zero-length string. * * @return The prefix of the name of the node. */ public String getPrefix() { return original.getPrefix(); } /** * Get the display name of this node. For elements and attributes this is [prefix:]localname. * For unnamed nodes, it is an empty string. * * @return The display name of this node. For a node with no name, return * an empty string. */ public String getDisplayName() { return original.getDisplayName(); } /** * Get the configuration */ public Configuration getConfiguration() { return original.getConfiguration(); } /** * Get the NamePool that holds the namecode for this node * * @return the namepool */ public NamePool getNamePool() { return original.getNamePool(); } /** * Get the type annotation of this node, if any. * * @return the type annotation of the node. * @see net.sf.saxon.type.Type */ public int getTypeAnnotation() { return original.getTypeAnnotation(); } /** * Get the NodeInfo object representing the parent of this node * * @return the parent of this node; null if this node has no parent */ public NodeInfo getParent() { if (original.isSameNodeInfo(root)) { return null; } if (parent == null) { NodeInfo basep = original.getParent(); if (basep == null) { return null; } parent = wrap(basep); parent.setDocumentNumber(documentNumber); } return parent; } /** * Return an iteration over all the nodes reached by the given axis from this node * * @param axisNumber an integer identifying the axis; one of the constants * defined in class net.sf.saxon.om.Axis * @return an AxisIterator that scans the nodes reached by the axis in * turn. * @throws UnsupportedOperationException if the namespace axis is * requested and this axis is not supported for this implementation. * @see Axis */ public AxisIterator iterateAxis(byte axisNumber) { return iterateAxis(axisNumber, AnyNodeTest.getInstance()); } /** * Return an iteration over all the nodes reached by the given axis from this node * that match a given NodeTest * * @param axisNumber an integer identifying the axis; one of the constants * defined in class net.sf.saxon.om.Axis * @param nodeTest A pattern to be matched by the returned nodes; nodes * that do not match this pattern are not included in the result * @return an AxisIterator that scans the nodes reached by the axis in * turn. * @throws UnsupportedOperationException if the namespace axis is * requested and this axis is not supported for this implementation. * @see Axis */ public AxisIterator iterateAxis(byte axisNumber, NodeTest nodeTest) { VirtualCopy newParent = null; if (axisNumber == Axis.CHILD || axisNumber == Axis.ATTRIBUTE || axisNumber == Axis.NAMESPACE) { newParent = this; } else if (axisNumber == Axis.SELF || axisNumber == Axis.PRECEDING_SIBLING || axisNumber == Axis.FOLLOWING_SIBLING) { newParent = parent; } NodeInfo root; if (Axis.isSubtreeAxis[axisNumber]) { root = null; } else { root = this.root; } return makeCopier(original.iterateAxis(axisNumber, nodeTest), newParent, root); } /** * Get the value of a given attribute of this node * * @param fingerprint The fingerprint of the attribute name * @return the attribute value if it exists or null if not */ public String getAttributeValue(int fingerprint) { return original.getAttributeValue(fingerprint); } /** * Get the root node of the tree containing this node * * @return the NodeInfo representing the top-level ancestor of this node. * This will not necessarily be a document node */ public NodeInfo getRoot() { NodeInfo n = this; while (true) { NodeInfo p = n.getParent(); if (p == null) { return n; } n = p; } } /** * Get the root node, if it is a document node. * * @return the DocumentInfo representing the containing document. If this * node is part of a tree that does not have a document node as its * root, return null. */ public DocumentInfo getDocumentRoot() { NodeInfo root = getRoot(); if (root.getNodeKind() == Type.DOCUMENT) { return (DocumentInfo)root; } return null; } /** * Determine whether the node has any children.
    * Note: the result is equivalent to
    * getEnumeration(Axis.CHILD, AnyNodeTest.getInstance()).hasNext() * * @return True if the node has one or more children */ public boolean hasChildNodes() { return original.hasChildNodes(); } /** * Get a character string that uniquely identifies this node. * Note: a.isSameNode(b) if and only if generateId(a)==generateId(b) * * @param buffer a buffer, to which will be appended * a string that uniquely identifies this node, across all * documents. */ public void generateId(FastStringBuffer buffer) { buffer.append("d"); buffer.append(Integer.toString(documentNumber)); original.generateId(buffer); } /** * Get the document number of the document containing this node. For a free-standing * orphan node, just return the hashcode. */ public int getDocumentNumber() { return documentNumber; } /** * Copy this node to a given outputter * * @param out the Receiver to which the node should be copied * @param whichNamespaces in the case of an element, controls * which namespace nodes should be copied. Values are NO_NAMESPACES, * LOCAL_NAMESPACES, ALL_NAMESPACES * @param copyAnnotations indicates whether the type annotations * of element and attribute nodes should be copied * @param locationId Identifies the location of the instruction * that requested this copy. Pass zero if no other information is available * @throws net.sf.saxon.trans.XPathException * */ public void copy(Receiver out, int whichNamespaces, boolean copyAnnotations, int locationId) throws XPathException { original.copy(out, whichNamespaces, copyAnnotations, locationId); } /** * Get all namespace undeclarations and undeclarations defined on this element. * * @param buffer If this is non-null, and the result array fits in this buffer, then the result * may overwrite the contents of this array, to avoid the cost of allocating a new array on the heap. * @return An array of integers representing the namespace declarations and undeclarations present on * this element. For a node other than an element, return null. Otherwise, the returned array is a * sequence of namespace codes, whose meaning may be interpreted by reference to the name pool. The * top half word of each namespace code represents the prefix, the bottom half represents the URI. * If the bottom half is zero, then this is a namespace undeclaration rather than a declaration. * The XML namespace is never included in the list. If the supplied array is larger than required, * then the first unused entry will be set to -1. *

    *

    For a node other than an element, the method returns null.

    */ public int[] getDeclaredNamespaces(int[] buffer) { return original.getDeclaredNamespaces(buffer); } /** * Set the system identifier for this Source. *

    *

    The system identifier is optional if the source does not * get its data from a URL, but it may still be useful to provide one. * The application can use a system identifier, for example, to resolve * relative URIs and to include in error messages and warnings.

    * * @param systemId The system identifier as a URL string. */ public void setSystemId(String systemId) { this.systemId = systemId; } /** * Get the typed value of the item * * @return the typed value of the item. In general this will be a sequence * @throws net.sf.saxon.trans.XPathException * where no typed value is available, e.g. for * an element with complex content */ public SequenceIterator getTypedValue() throws XPathException { return original.getTypedValue(); } /** * Get the typed value. The result of this method will always be consistent with the method * {@link Item#getTypedValue()}. However, this method is often more convenient and may be * more efficient, especially in the common case where the value is expected to be a singleton. * * @return the typed value. If requireSingleton is set to true, the result will always be an * AtomicValue. In other cases it may be a Value representing a sequence whose items are atomic * values. * @since 8.5 */ public Value atomize() throws XPathException { return original.atomize(); } /** * Determine whether this node has the is-id property * * @return true if the node is an ID */ public boolean isId() { return original.isId(); } /** * Determine whether this node has the is-idref property * * @return true if the node is an IDREF or IDREFS element or attribute */ public boolean isIdref() { return original.isIdref(); } /** * Determine whether the node has the is-nilled property * * @return true if the node has the is-nilled property */ public boolean isNilled() { return original.isNilled(); } /** * Return the public identifier for the current document event. *

    *

    The return value is the public identifier of the document * entity or of the external parsed entity in which the markup that * triggered the event appears.

    * @return A string containing the public identifier, or * null if none is available. * @see #getSystemId */ public String getPublicId() { return (original instanceof SourceLocator ? ((SourceLocator)original).getPublicId() : null); } /** * Create an iterator that makes and returns virtual copies of nodes on the original tree * @param axis the axis to be navigated * @param newParent the parent of the nodes in the new virtual tree (may be null) * @param root the root of the virtual tree * @return the iterator that does the copying */ protected VirtualCopier makeCopier(AxisIterator axis, VirtualCopy newParent, NodeInfo root) { return new VirtualCopier(axis, newParent, root); } /** * VirtualCopier implements the XPath axes as applied to a VirtualCopy node. It works by * applying the requested axis to the node of which this is a copy. There are two * complications: firstly, all nodes encountered must themselves be (virtually) copied * to give them a new identity. Secondly, axes that stray outside the subtree rooted at * the original copied node must be truncated. */ protected class VirtualCopier implements AxisIterator { protected AxisIterator base; private VirtualCopy parent; protected NodeInfo subtreeRoot; private NodeInfo current; public VirtualCopier(AxisIterator base, VirtualCopy parent, NodeInfo subtreeRoot) { this.base = base; this.parent = parent; this.subtreeRoot = subtreeRoot; } /** * Move to the next node, without returning it. Returns true if there is * a next node, false if the end of the sequence has been reached. After * calling this method, the current node may be retrieved using the * current() function. */ public boolean moveNext() { return (next() != null); } /** * Get the next item in the sequence.
    * * @return the next Item. If there are no more nodes, return null. */ public Item next() { NodeInfo next = (NodeInfo)base.next(); if (next != null) { if (subtreeRoot != null) { // we're only interested in nodes within the subtree that was copied. // Assert: once we find a node outside this subtree, all further nodes will also be outside // the subtree. if (!isAncestorOrSelf(subtreeRoot, next)) { return null; } } VirtualCopy vc = createCopy(next, root); vc.parent = parent; vc.systemId = systemId; vc.documentNumber = documentNumber; next = vc; } current = next; return next; } /** * Get the current item in the sequence. * * @return the current item, that is, the item most recently returned by * next() */ public Item current() { return current; } /** * Get the current position * * @return the position of the current item (the item most recently * returned by next()), starting at 1 for the first node */ public int position() { return base.position(); } public void close() { base.close(); } /** * Return an iterator over an axis, starting at the current node. * * @param axis the axis to iterate over, using a constant such as * {@link Axis#CHILD} * @param test a predicate to apply to the nodes before returning them. * @throws NullPointerException if there is no current node */ public AxisIterator iterateAxis(byte axis, NodeTest test) { return current.iterateAxis(axis, test); } /** * Return the atomized value of the current node. * * @return the atomized value. * @throws NullPointerException if there is no current node */ public Value atomize() throws XPathException { return current.atomize(); } /** * Return the string value of the current node. * * @return the string value, as an instance of CharSequence. * @throws NullPointerException if there is no current node */ public CharSequence getStringValue() { return current.getStringValueCS(); } /** * Get another iterator over the same sequence of items, positioned at the * start of the sequence * * @return a new iterator over the same sequence */ public SequenceIterator getAnother() { return new VirtualCopier((AxisIterator)base.getAnother(), parent, subtreeRoot); } /** * Get properties of this iterator, as a bit-significant integer. * * @return the properties of this iterator. This will be some combination of * properties such as {@link #GROUNDED}, {@link #LAST_POSITION_FINDER}, * and {@link #LOOKAHEAD}. It is always * acceptable to return the value zero, indicating that there are no known special properties. * It is acceptable for the properties of the iterator to change depending on its state. */ public int getProperties() { return 0; } /** * Test whether a node is an ancestor-or-self of another * @param a the putative ancestor * @param d the putative descendant * @return true if a is an ancestor of d */ private boolean isAncestorOrSelf(NodeInfo a, NodeInfo d) { while (true) { if (a.isSameNodeInfo(d)) { return true; } d = d.getParent(); if (d == null) { return false; } } } /** * Method to create the virtual copy of a node encountered when navigating. This method * is separated out so that it can be overridden in a subclass. * @param node the node to be copied * @param root the root of the tree * @return the virtual copy */ protected VirtualCopy createCopy(NodeInfo node, NodeInfo root) { return VirtualCopy.makeVirtualCopy(node, root); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/om/ReverseNodeArrayIterator.java0000644000175000017500000000705211033112257023613 0ustar eugeneeugenepackage net.sf.saxon.om; import net.sf.saxon.pattern.NodeTest; import net.sf.saxon.value.Value; import net.sf.saxon.trans.XPathException; /** * Iterator over an array of nodes in reverse order */ public class ReverseNodeArrayIterator extends ReverseArrayIterator implements AxisIterator { /** * Create a reverse iterator over a slice of an array * @param items The array of items * @param start The first item in the array to be be used (this will be the last * one in the resulting iteration). Zero-based. * @param end The item after the last one in the array to be used (this will be the * first one to be returned by the iterator). Zero-based. */ public ReverseNodeArrayIterator(Item[] items, int start, int end) { super(items, start, end); } /** * Move to the next node, without returning it. Returns true if there is * a next node, false if the end of the sequence has been reached. After * calling this method, the current node may be retrieved using the * current() function. */ public boolean moveNext() { return (next() != null); } /** * Return an iterator over an axis, starting at the current node. * * @param axis the axis to iterate over, using a constant such as * {@link Axis#CHILD} * @param test a predicate to apply to the nodes before returning them. * @throws NullPointerException if there is no current node */ public AxisIterator iterateAxis(byte axis, NodeTest test) { return ((NodeInfo)current()).iterateAxis(axis, test); } /** * Return the atomized value of the current node. * * @return the atomized value. * @throws NullPointerException if there is no current node */ public Value atomize() throws XPathException { return ((NodeInfo)current()).atomize(); } /** * Return the string value of the current node. * * @return the string value, as an instance of CharSequence. * @throws NullPointerException if there is no current node */ public CharSequence getStringValue() { return ((NodeInfo)current()).getStringValueCS(); } /** * Get another iterator over the same items * @return another iterator over the same items, positioned at the start of the sequence */ public SequenceIterator getAnother() { return new ReverseNodeArrayIterator((NodeInfo[])items, start, end); } /** * Get an iterator that processes the same items in reverse order. * Since this iterator is processing the items backwards, this method * returns an ArrayIterator that processes them forwards. * * @return a new ArrayIterator */ public SequenceIterator getReverseIterator() { return new NodeArrayIterator((NodeInfo[])items, start, end); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/om/InscopeNamespaceResolver.java0000644000175000017500000000753111033112257023622 0ustar eugeneeugenepackage net.sf.saxon.om; import net.sf.saxon.sort.IntIterator; import net.sf.saxon.type.Type; import java.util.Iterator; /** * A NamespaceResolver that resolves namespace prefixes by reference to a node in a document for which * those namespaces are in-scope. */ public class InscopeNamespaceResolver implements NamespaceResolver { private NodeInfo node; /** * Create a NamespaceResolver that resolves according to the in-scope namespaces * of a given node * @param node the given node */ public InscopeNamespaceResolver(NodeInfo node) { if (node.getNodeKind() == Type.ELEMENT) { this.node = node; } else { this.node = node.getParent(); } } /** * Get the namespace URI corresponding to a given prefix. Return null * if the prefix is not in scope. * * @param prefix the namespace prefix * @param useDefault true if the default namespace is to be used when the * prefix is "" * @return the uri for the namespace, or null if the prefix is not in scope * Return "" for the no-namespace. */ public String getURIForPrefix(String prefix, boolean useDefault) { if ("".equals(prefix) && !useDefault) { return ""; } AxisIterator iter = node.iterateAxis(Axis.NAMESPACE); while (true) { NodeInfo node = (NodeInfo)iter.next(); if (node == null) { break; } if (node.getLocalPart().equals(prefix)) { return node.getStringValue(); } } if ("".equals(prefix)) { return ""; } else { return null; } } /** * Get an iterator over all the prefixes declared in this namespace context. This will include * the default namespace (prefix="") and the XML namespace where appropriate */ public Iterator iteratePrefixes() { final NamePool pool = node.getNamePool(); return new Iterator() { int phase = 0; IntIterator iter = NamespaceCodeIterator.iterateNamespaces(node); public boolean hasNext() { if (iter.hasNext()) { return true; } else if (phase == 0) { phase = 1; return true; } else { return false; } } public Object next() { if (phase == 1) { phase = 2; return "xml"; } else { return pool.getPrefixFromNamespaceCode(iter.next()); } } public void remove() { throw new UnsupportedOperationException("remove"); } }; } /** * Get the node on which this namespace resolver is based * @return the node on which this namespace resolver is based */ public NodeInfo getNode() { return node; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none //saxonb-9.1.0.8/bj/net/sf/saxon/om/NamespaceCodeIterator.java0000644000175000017500000001415611033112257023065 0ustar eugeneeugenepackage net.sf.saxon.om; import net.sf.saxon.event.Receiver; import net.sf.saxon.sort.EmptyIntIterator; import net.sf.saxon.sort.IntHashSet; import net.sf.saxon.sort.IntIterator; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.Type; /** * This class provides an iterator over the namespace codes representing the in-scope namespaces * of any node. It relies on nodes to implement the method * {@link net.sf.saxon.om.NodeInfo#getDeclaredNamespaces(int[])}. * *

    The result does not include the XML namespace.

    */ public class NamespaceCodeIterator implements IntIterator { private NodeInfo element; private int index; private int next; private int[] localDeclarations; //IntHashSet declared; IntHashSet undeclared; /** * Factory method: create an iterator over the in-scope namespace codes for an element * @param element the element (or other node) whose in-scope namespaces are required. If this * is not an element, the result will be an empty iterator * @return an iterator over the namespace codes. A namespace code is an integer that represents * a prefix-uri binding; the prefix and URI can be obtained by reference to the name pool. This * iterator will represent all the in-scope namespaces, without duplicates, and respecting namespace * undeclarations. It does not include the XML namespace. */ public static IntIterator iterateNamespaces(NodeInfo element) { if (element.getNodeKind() == Type.ELEMENT) { return new NamespaceCodeIterator(element); } else { return EmptyIntIterator.getInstance(); } } /** * Send all the in-scope namespaces for a node to a specified receiver * @param element the element in question (the method does nothing if this is not an element) * @param receiver the receiver to which the namespaces are notified */ public static void sendNamespaces(NodeInfo element, Receiver receiver) throws XPathException { if (element.getNodeKind() == Type.ELEMENT) { int[] undeclared = new int[8]; int undeclaredSize = 0; int[] localDeclarations = element.getDeclaredNamespaces(null); while (true) { for (int i=0; i> 16); boolean isnew = true; for (int j=0; j= localDeclarations.length; int nsCode = 0; if (!ascend) { nsCode = localDeclarations[index++]; ascend = nsCode == -1; } if (ascend) { element = element.getParent(); if (element != null && element.getNodeKind() == Type.ELEMENT) { localDeclarations = element.getDeclaredNamespaces(localDeclarations); index = 0; continue; } else { next = -1; return; } } short uriCode = (short)(nsCode & 0xffff); short prefixCode = (short)(nsCode >> 16); if (uriCode == 0) { // this is an undeclaration undeclared.add(prefixCode); } else { if (undeclared.add(prefixCode)) { // it was added, so it's new, so return it next = nsCode; return; } // else it wasn't added, so we've already seen it } } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/om/Validation.java0000644000175000017500000000425211033112257020752 0ustar eugeneeugenepackage net.sf.saxon.om; /** * This class contains constants and static methods to manipulate the validation * property of a type. */ public final class Validation { public static final int INVALID = -1; public static final int STRICT = 1; public static final int LAX = 2; public static final int PRESERVE = 3; public static final int STRIP = 4; public static final int SKIP = 4; // synonym provided for the XQuery API public static final int DEFAULT = 0; public static final int BY_TYPE = 8; public static final int VALIDATION_MODE_MASK = 0xff; public static final int VALIDATE_OUTPUT = 0x10000; /** * This class is never instantiated */ private Validation() { } public static int getCode(String value) { if (value.equals("strict")) { return STRICT; } else if (value.equals("lax")) { return LAX; } else if (value.equals("preserve")) { return PRESERVE; } else if (value.equals("strip")) { return STRIP; } else { return INVALID; } } public static String toString(int value) { switch(value & VALIDATION_MODE_MASK) { case STRICT: return "strict"; case LAX: return "lax"; case PRESERVE: return "preserve"; case STRIP: return "skip"; // for XQuery case BY_TYPE: return "by type"; default: return "invalid"; } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/om/NamespaceIterator.java0000644000175000017500000010120411156423042022264 0ustar eugeneeugenepackage net.sf.saxon.om; import net.sf.saxon.Configuration; import net.sf.saxon.event.Receiver; import net.sf.saxon.event.ReceiverOptions; import net.sf.saxon.pattern.AnyNodeTest; import net.sf.saxon.pattern.NodeTest; import net.sf.saxon.pattern.NodeKindTest; import net.sf.saxon.sort.IntIterator; import net.sf.saxon.sort.IntHashSet; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.Type; import net.sf.saxon.value.StringValue; import net.sf.saxon.value.Value; /** * This class provides an implementation of the namespace axis over any implementation * of the data model. It relies on element nodes to implement the method * {@link NodeInfo#getDeclaredNamespaces(int[])} */ public class NamespaceIterator implements AxisIterator { private NodeInfo element; private NodeTest test; private int index; private int position; private NamespaceNodeImpl next; private NamespaceNodeImpl current; private IntIterator nsIterator; /** * Factory method to create an iterator over the in-scope namespace nodes * @param element the node whose namespaces are required * @param test used to filter the returned nodes * @return an iterator over the namespace nodes that satisfy the test */ public static AxisIterator makeIterator(NodeInfo element, NodeTest test) { boolean first = true; if (test instanceof AnyNodeTest || test == NodeKindTest.NAMESPACE) { test = null; } AxisIterator result = null; IntHashSet declared = null; IntHashSet undeclared = null; int[] buffer = new int[8]; NodeInfo node = element; while (node != null && node.getNodeKind() == Type.ELEMENT) { int[] nslist = node.getDeclaredNamespaces(buffer); if (nslist != null) { for (int i=0; i> 16); if (uriCode == 0) { // this is an undeclaration undeclared.add(prefixCode); } else { if (!undeclared.contains(prefixCode)) { declared.add(nslist[i]); undeclared.add(prefixCode); } } } } node = node.getParent(); } if (result == null) { NodeInfo ns = new NamespaceNodeImpl(element, NamespaceConstant.XML_NAMESPACE_CODE, 0); if (test == null) { return SingleNodeIterator.makeIterator(ns); } else { return Navigator.filteredSingleton(ns, test); } } else { ((NamespaceIterator)result).nsIterator = declared.iterator(); return result; } } private NamespaceIterator() { } /** * Get the next item in the sequence. */ public void advance() { while (nsIterator.hasNext()) { int nscode = nsIterator.next(); next = new NamespaceNodeImpl(element, nscode, ++index); if (test == null || test.matches(next)) { return; } } next = null; } /** * Move to the next node, without returning it. Returns true if there is * a next node, false if the end of the sequence has been reached. After * calling this method, the current node may be retrieved using the * current() function. */ public boolean moveNext() { return (next() != null); } /** * Get the next item in the sequence.
    * * @return the next Item. If there are no more nodes, return null. */ public Item next() { if (index == -1) { advance(); index = 0; } current = next; if (current == null) { position = -1; return null; } advance(); position++; return current; } /** * Get the current item in the sequence. * * @return the current item, that is, the item most recently returned by * next() */ public Item current() { return current; } /** * Get the current position * * @return the position of the current item (the item most recently * returned by next()), starting at 1 for the first node */ public int position() { return position; } public void close() { } /** * Return an iterator over an axis, starting at the current node. * * @param axis the axis to iterate over, using a constant such as * {@link Axis#CHILD} * @param test a predicate to apply to the nodes before returning them. * @throws NullPointerException if there is no current node */ public AxisIterator iterateAxis(byte axis, NodeTest test) { return current.iterateAxis(axis, test); } /** * Return the atomized value of the current node. * * @return the atomized value. * @throws NullPointerException if there is no current node */ public Value atomize() throws XPathException { return current.atomize(); } /** * Return the string value of the current node. * * @return the string value, as an instance of CharSequence. * @throws NullPointerException if there is no current node */ public CharSequence getStringValue() { return current.getStringValueCS(); } /** * Get another iterator over the same sequence of items, positioned at the * start of the sequence * * @return a new iterator over the same sequence */ public SequenceIterator getAnother() { return makeIterator(element, test); } /** * Get properties of this iterator, as a bit-significant integer. * * @return the properties of this iterator. This will be some combination of * properties such as {@link #GROUNDED}, {@link #LAST_POSITION_FINDER}, * and {@link #LOOKAHEAD}. It is always * acceptable to return the value zero, indicating that there are no known special properties. * It is acceptable for the properties of the iterator to change depending on its state. */ public int getProperties() { return 0; } /** * Get a list of in-scope namespace codes. If an array of namespace codes is needed, without * actually constructing the namespace nodes, this factory method can be used directly. * The result is an array of integers, each containing a prefix code in the top * half and a uri code in the bottom half. Note that calling this method is destructive: the * iterator is consumed and cannot be used again. * @param element the element whose nodes are required * @return the list of in scope namespaces */ public static int[] getInScopeNamespaceCodes(NodeInfo element) { boolean first = true; IntHashSet declared = null; IntHashSet undeclared = null; int[] buffer = new int[8]; NodeInfo node = element; while (node != null && node.getNodeKind() == Type.ELEMENT) { int[] nslist = node.getDeclaredNamespaces(buffer); if (nslist != null) { for (int i=0; i> 16); if (uriCode == 0) { // this is an undeclaration undeclared.add(prefixCode); } else { if (!undeclared.contains(prefixCode)) { declared.add(nslist[i]); undeclared.add(prefixCode); } } } } node = node.getParent(); } if (first) { return XML_NAMESPACE_CODE_ARRAY; } else { try { int[] codes = new int[declared.size()]; int i = 0; IntIterator ii = declared.iterator(); while (ii.hasNext()) { codes[i++] = ii.next(); } return codes; } catch (ArrayIndexOutOfBoundsException e) { // Diagnostic patch for a rarely-occurring problem, observed in both 8.6 and 9.1 System.err.println("*** Internal error in NamespaceIterator ***"); declared.diagnosticDump(); throw e; } } } private static int[] XML_NAMESPACE_CODE_ARRAY = {NamespaceConstant.XML_NAMESPACE_CODE}; /** * Inner class: a model-independent representation of a namespace node */ public static class NamespaceNodeImpl implements NodeInfo, FingerprintedNode { NodeInfo element; int nscode; int position; int namecode; /** * Create a namespace node * @param element the parent element of the namespace node * @param nscode the namespace code, representing the prefix and URI of the namespace binding * @param position maintains document order among namespace nodes for the same element */ public NamespaceNodeImpl(NodeInfo element, int nscode, int position) { this.element = element; this.nscode = nscode; this.position = position; NamePool pool = element.getNamePool(); String prefix = pool.getPrefixFromNamespaceCode(nscode); if ("".equals(prefix)) { namecode = -1; } else { namecode = pool.allocate("", "", prefix); } } /** * Get the kind of node. This will be a value such as Type.ELEMENT or Type.ATTRIBUTE * * @return an integer identifying the kind of node. These integer values are the * same as those used in the DOM * @see net.sf.saxon.type.Type */ public int getNodeKind() { return Type.NAMESPACE; } /** * Determine whether this is the same node as another node. * Note: a.isSameNodeInfo(b) if and only if generateId(a)==generateId(b). * This method has the same semantics as isSameNode() in DOM Level 3, but * works on Saxon NodeInfo objects rather than DOM Node objects. * * @param other the node to be compared with this node * @return true if this NodeInfo object and the supplied NodeInfo object represent * the same node in the tree. */ public boolean isSameNodeInfo(NodeInfo other) { return other instanceof NamespaceNodeImpl && element.isSameNodeInfo(((NamespaceNodeImpl)other).element) && nscode == ((NamespaceNodeImpl)other).nscode; } /** * The equals() method compares nodes for identity. It is defined to give the same result * as isSameNodeInfo(). * @param other the node to be compared with this node * @return true if this NodeInfo object and the supplied NodeInfo object represent * the same node in the tree. * @since 8.7 Previously, the effect of the equals() method was not defined. Callers * should therefore be aware that third party implementations of the NodeInfo interface may * not implement the correct semantics. It is safer to use isSameNodeInfo() for this reason. * The equals() method has been defined because it is useful in contexts such as a Java Set or HashMap. */ public boolean equals(Object other) { return other instanceof NodeInfo && isSameNodeInfo((NodeInfo)other); } /** * The hashCode() method obeys the contract for hashCode(): that is, if two objects are equal * (represent the same node) then they must have the same hashCode() * @since 8.7 Previously, the effect of the equals() and hashCode() methods was not defined. Callers * should therefore be aware that third party implementations of the NodeInfo interface may * not implement the correct semantics. */ public int hashCode() { return element.hashCode() ^ (position<<13); } /** * Get the System ID for the node. * * @return the System Identifier of the entity in the source document * containing the node, or null if not known. Note this is not the * same as the base URI: the base URI can be modified by xml:base, but * the system ID cannot. */ public String getSystemId() { return element.getSystemId(); } /** * Get the Base URI for the node, that is, the URI used for resolving a relative URI contained * in the node. This will be the same as the System ID unless xml:base has been used. * * @return the base URI of the node */ public String getBaseURI() { return null; // the base URI of a namespace node is the empty sequence } /** * Get line number * * @return the line number of the node in its original source document; or * -1 if not available */ public int getLineNumber() { return element.getLineNumber(); } /** * Get column number * * @return the column number of the node in its original source document; or * -1 if not available */ public int getColumnNumber() { return element.getColumnNumber(); } /** * Determine the relative position of this node and another node, in document order. * The other node will always be in the same document. * * @param other The other node, whose position is to be compared with this * node * @return -1 if this node precedes the other node, +1 if it follows the * other node, or 0 if they are the same node. (In this case, * isSameNode() will always return true, and the two nodes will * produce the same result for generateId()) */ public int compareOrder(NodeInfo other) { if (other instanceof NamespaceNodeImpl && element.isSameNodeInfo(((NamespaceNodeImpl)other).element)) { // JDK 1.5: return Integer.signum(position - ((NamespaceNodeI)other).position); int c = position - ((NamespaceNodeImpl)other).position; if (c == 0) return 0; if (c < 0) return -1; return +1; } else if (element.isSameNodeInfo(other)) { return +1; } else { return element.compareOrder(other); } } /** * Return the string value of the node. The interpretation of this depends on the type * of node. For a namespace node, it is the namespace URI. * * @return the string value of the node */ public String getStringValue() { return element.getNamePool().getURIFromURICode((short)(nscode & 0xffff)); } /** * Get the value of the item as a CharSequence. This is in some cases more efficient than * the version of the method that returns a String. */ public CharSequence getStringValueCS() { return getStringValue(); } /** * Get name code. The name code is a coded form of the node name: two nodes * with the same name code have the same namespace URI, the same local name, * and the same prefix. By masking the name code with &0xfffff, you get a * fingerprint: two nodes with the same fingerprint have the same local name * and namespace URI. * * @return an integer name code, which may be used to obtain the actual node * name from the name pool * @see NamePool#allocate allocate * @see NamePool#getFingerprint getFingerprint */ public int getNameCode() { return namecode; } /** * Get fingerprint. The fingerprint is a coded form of the expanded name * of the node: two nodes * with the same name code have the same namespace URI and the same local name. * A fingerprint of -1 should be returned for a node with no name. * * @return an integer fingerprint; two nodes with the same fingerprint have * the same expanded QName */ public int getFingerprint() { if (namecode == -1) { return -1; } return namecode & NamePool.FP_MASK; } /** * Get the local part of the name of this node. This is the name after the ":" if any. * * @return the local part of the name. For an unnamed node, returns "". Unlike the DOM * interface, this returns the full name in the case of a non-namespaced name. */ public String getLocalPart() { if (namecode == -1) { return ""; } else { return element.getNamePool().getLocalName(namecode); } } /** * Get the URI part of the name of this node. This is the URI corresponding to the * prefix, or the URI of the default namespace if appropriate. * * @return The URI of the namespace of this node. Since the name of a namespace * node is always an NCName (the namespace prefix), this method always returns "". */ public String getURI() { return ""; } /** * Get the display name of this node. For elements and attributes this is [prefix:]localname. * For unnamed nodes, it is an empty string. * * @return The display name of this node. For a node with no name, return * an empty string. */ public String getDisplayName() { return getLocalPart(); } /** * Get the prefix of the name of the node. This is defined only for elements and attributes. * If the node has no prefix, or for other kinds of node, return a zero-length string. * * @return The prefix of the name of the node. */ public String getPrefix() { return ""; } /** * Get the configuration */ public Configuration getConfiguration() { return element.getConfiguration(); } /** * Get the NamePool that holds the namecode for this node * * @return the namepool */ public NamePool getNamePool() { return element.getNamePool(); } /** * Get the type annotation of this node, if any. * Returns -1 for kinds of nodes that have no annotation, and for elements annotated as * untyped, and attributes annotated as untypedAtomic. * * @return the type annotation of the node. * @see net.sf.saxon.type.Type */ public int getTypeAnnotation() { return -1; } /** * Get the NodeInfo object representing the parent of this node * * @return the parent of this node; null if this node has no parent */ public NodeInfo getParent() { return element; } /** * Return an iteration over all the nodes reached by the given axis from this node * * @param axisNumber an integer identifying the axis; one of the constants * defined in class net.sf.saxon.om.Axis * @return an AxisIterator that scans the nodes reached by the axis in * turn. * @throws UnsupportedOperationException if the namespace axis is * requested and this axis is not supported for this implementation. * @see Axis */ public AxisIterator iterateAxis(byte axisNumber) { return iterateAxis(axisNumber, AnyNodeTest.getInstance()); } /** * Return an iteration over all the nodes reached by the given axis from this node * that match a given NodeTest * * @param axisNumber an integer identifying the axis; one of the constants * defined in class net.sf.saxon.om.Axis * @param nodeTest A pattern to be matched by the returned nodes; nodes * that do not match this pattern are not included in the result * @return a NodeEnumeration that scans the nodes reached by the axis in * turn. * @throws UnsupportedOperationException if the namespace axis is * requested and this axis is not supported for this implementation. * @see Axis */ public AxisIterator iterateAxis(byte axisNumber, NodeTest nodeTest) { switch (axisNumber) { case Axis.ANCESTOR: return element.iterateAxis(Axis.ANCESTOR_OR_SELF, nodeTest); case Axis.ANCESTOR_OR_SELF: if (nodeTest.matches(this)) { return new PrependIterator(this, element.iterateAxis(Axis.ANCESTOR_OR_SELF, nodeTest)); } else { return element.iterateAxis(Axis.ANCESTOR_OR_SELF, nodeTest); } case Axis.ATTRIBUTE: case Axis.CHILD: case Axis.DESCENDANT: case Axis.DESCENDANT_OR_SELF: case Axis.FOLLOWING_SIBLING: case Axis.NAMESPACE: case Axis.PRECEDING_SIBLING: return EmptyIterator.getInstance(); case Axis.FOLLOWING: return new Navigator.AxisFilter( new Navigator.FollowingEnumeration(this), nodeTest); case Axis.PARENT: return Navigator.filteredSingleton(element, nodeTest); case Axis.PRECEDING: return new Navigator.AxisFilter( new Navigator.PrecedingEnumeration(this, false), nodeTest); case Axis.SELF: return Navigator.filteredSingleton(this, nodeTest); case Axis.PRECEDING_OR_ANCESTOR: return new Navigator.AxisFilter( new Navigator.PrecedingEnumeration(this, true), nodeTest); default: throw new IllegalArgumentException("Unknown axis number " + axisNumber); } } /** * Get the value of a given attribute of this node * * @param fingerprint The fingerprint of the attribute name * @return the attribute value if it exists or null if not */ public String getAttributeValue(int fingerprint) { return null; } /** * Get the root node of the tree containing this node * * @return the NodeInfo representing the top-level ancestor of this node. * This will not necessarily be a document node */ public NodeInfo getRoot() { return element.getRoot(); } /** * Get the root node, if it is a document node. * * @return the DocumentInfo representing the containing document. If this * node is part of a tree that does not have a document node as its * root, return null. */ public DocumentInfo getDocumentRoot() { return element.getDocumentRoot(); } /** * Determine whether the node has any children.
    * Note: the result is equivalent to
    * getEnumeration(Axis.CHILD, AnyNodeTest.getInstance()).hasNext() * * @return True if the node has one or more children */ public boolean hasChildNodes() { return false; } /** * Get a character string that uniquely identifies this node. * Note: a.isSameNode(b) if and only if generateId(a)==generateId(b) * * @param buffer buffer to hold a string that uniquely identifies this node, across all * documents. */ public void generateId(FastStringBuffer buffer) { element.generateId(buffer); buffer.append("n"); buffer.append(Integer.toString(position)); } /** * Get the document number of the document containing this node. For a free-standing * orphan node, just return the hashcode. */ public int getDocumentNumber() { return element.getDocumentNumber(); } /** * Copy this node to a given outputter * * @param out the Receiver to which the node should be copied * @param whichNamespaces in the case of an element, controls * which namespace nodes should be copied. Values are {@link #NO_NAMESPACES}, * {@link #LOCAL_NAMESPACES}, {@link #ALL_NAMESPACES} * @param copyAnnotations indicates whether the type annotations * of element and attribute nodes should be copied * @param locationId If non-zero, identifies the location of the instruction * that requested this copy. If zero, indicates that the location information * for the original node is to be copied; in this case the Receiver must be * a LocationCopier * @throws net.sf.saxon.trans.XPathException * */ public void copy(Receiver out, int whichNamespaces, boolean copyAnnotations, int locationId) throws XPathException { out.namespace(nscode, ReceiverOptions.REJECT_DUPLICATES); } /** * Get all namespace undeclarations and undeclarations defined on this element. * * @param buffer If this is non-null, and the result array fits in this buffer, then the result * may overwrite the contents of this array, to avoid the cost of allocating a new array on the heap. * @return An array of integers representing the namespace declarations and undeclarations present on * this element. For a node other than an element, return null. Otherwise, the returned array is a * sequence of namespace codes, whose meaning may be interpreted by reference to the name pool. The * top half word of each namespace code represents the prefix, the bottom half represents the URI. * If the bottom half is zero, then this is a namespace undeclaration rather than a declaration. * The XML namespace is never included in the list. If the supplied array is larger than required, * then the first unused entry will be set to -1. *

    *

    For a node other than an element, the method returns null.

    */ public int[] getDeclaredNamespaces(int[] buffer) { return null; } /** * Set the system identifier for this Source. *

    *

    The system identifier is optional if the source does not * get its data from a URL, but it may still be useful to provide one. * The application can use a system identifier, for example, to resolve * relative URIs and to include in error messages and warnings.

    * * @param systemId The system identifier as a URL string. */ public void setSystemId(String systemId) { // no action: namespace nodes have the same base URI as their parent } /** * Get the typed value of the item * * @return the typed value of the item. In general this will be a sequence * @throws net.sf.saxon.trans.XPathException * where no typed value is available, e.g. for * an element with complex content */ public SequenceIterator getTypedValue() throws XPathException { return SingletonIterator.makeIterator(new StringValue(getStringValueCS())); } /** * Get the typed value. The result of this method will always be consistent with the method * {@link Item#getTypedValue()}. However, this method is often more convenient and may be * more efficient, especially in the common case where the value is expected to be a singleton. * * @return the typed value. If requireSingleton is set to true, the result will always be an * AtomicValue. In other cases it may be a Value representing a sequence whose items are atomic * values. * @since 8.5 */ public Value atomize() throws XPathException { return new StringValue(getStringValueCS()); } /** * Determine whether this node has the is-id property * * @return true if the node is an ID */ public boolean isId() { return false; } /** * Determine whether this node has the is-idref property * * @return true if the node is an IDREF or IDREFS element or attribute */ public boolean isIdref() { return false; } /** * Determine whether the node has the is-nilled property * * @return true if the node has the is-nilled property */ public boolean isNilled() { return false; } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/om/NamespaceConstant.java0000644000175000017500000002451511033112257022272 0ustar eugeneeugenepackage net.sf.saxon.om; /** * This class is not instantiated, it exists to hold a set of constants representing known * namespaces. For each of these, there is a constant for the namespace URI and for many of * them, there is a numeric constant used as the code for this namespace in the name pool. * *

    This class also defines constant URIs for some objects other than namespaces - * for example, URIs that identify the various object models used in the JAXP XPath API, * and the Unicode codepoint collation URI.

    * * @author Michael H. Kay */ public class NamespaceConstant { /** * A URI representing the null namespace (actually, an empty string) */ public static final String NULL = ""; /** * The numeric URI code representing the null namespace (actually, zero) */ public static final short NULL_CODE = 0; /** * The namespace code for the null namespace */ public static final int NULL_NAMESPACE_CODE = 0; /** * Fixed namespace name for XML: "http://www.w3.org/XML/1998/namespace". */ public static final String XML = "http://www.w3.org/XML/1998/namespace"; /** * Numeric code representing the XML namespace */ public static final short XML_CODE = 1; /** * The namespace code for the XML namespace */ public static final int XML_NAMESPACE_CODE = 0x00010001; /** * Fixed namespace name for XSLT: "http://www.w3.org/1999/XSL/Transform" */ public static final String XSLT = "http://www.w3.org/1999/XSL/Transform"; /** * Numeric code representing the XSLT namespace */ public static final short XSLT_CODE = 2; /** * Fixed namespace name for SAXON: "http://saxon.sf.net/" */ public static final String SAXON = "http://saxon.sf.net/"; /** * Numeric code representing the SAXON namespace */ public static final short SAXON_CODE = 3; /** * Namespace name for XML Schema: "http://www.w3.org/2001/XMLSchema" */ public static final String SCHEMA = "http://www.w3.org/2001/XMLSchema"; /** * Numeric code representing the schema namespace */ public static final short SCHEMA_CODE = 4; /** * XML-schema-defined namespace for use in instance documents ("xsi") */ public static final String SCHEMA_INSTANCE = "http://www.w3.org/2001/XMLSchema-instance"; public static final short XSI_CODE = 5; /** * Fixed namespace name for EXSLT/Common: "http://exslt.org/common" */ public static final String EXSLT_COMMON = "http://exslt.org/common"; /** * Fixed namespace name for EXSLT/math: "http://exslt.org/math" */ public static final String EXSLT_MATH = "http://exslt.org/math"; /** * Fixed namespace name for EXSLT/sets: "http://exslt.org/sets" */ public static final String EXSLT_SETS = "http://exslt.org/sets"; /** * Fixed namespace name for EXSLT/date: "http://exslt.org/dates-and-times" */ public static final String EXSLT_DATES_AND_TIMES = "http://exslt.org/dates-and-times"; /** * Fixed namespace name for EXSLT/random: "http://exslt.org/random" */ public static final String EXSLT_RANDOM = "http://exslt.org/random"; /** * The standard namespace for functions and operators */ public static final String FN = "http://www.w3.org/2005/xpath-functions"; /** * The standard namespace for system error codes */ public static final String ERR = "http://www.w3.org/2005/xqt-errors"; /** * Predefined XQuery namespace for local functions */ public static final String LOCAL = "http://www.w3.org/2005/xquery-local-functions"; /** * Recognize the Microsoft namespace so we can give a suitably sarcastic error message */ public static final String MICROSOFT_XSL = "http://www.w3.org/TR/WD-xsl"; /** * The XHTML namespace http://www.w3.org/1999/xhtml */ public static final String XHTML = "http://www.w3.org/1999/xhtml"; /** * The XMLNS namespace (used in DOM) */ public static final String XMLNS = "http://www.w3.org/2000/xmlns/"; /** * Namespace for types representing external Java objects */ public static final String JAVA_TYPE = "http://saxon.sf.net/java-type"; /** * Namespace for types representing external .NET objects */ public static final String DOT_NET_TYPE = "http://saxon.sf.net/clitype"; /** * Namespace for names allocated to anonymous types. This exists so that * a name fingerprint can be allocated for use as a type annotation. */ public static final String ANONYMOUS = "http://ns.saxonica.com/anonymous-type"; /** * Namespace for the Saxon serialization of the schema component model */ public static final String SCM = "http://ns.saxonica.com/schema-component-model"; /** * URI identifying the Saxon object model for use in the JAXP 1.3 XPath API */ public static final String OBJECT_MODEL_SAXON = "http://saxon.sf.net/jaxp/xpath/om"; /** * URI identifying the XOM object model for use in the JAXP 1.3 XPath API */ public static final String OBJECT_MODEL_XOM = "http://www.xom.nu/jaxp/xpath/xom"; /** * URI identifying the JDOM object model for use in the JAXP 1.3 XPath API */ public static final String OBJECT_MODEL_JDOM = "http://jdom.org/jaxp/xpath/jdom"; /** * URI identifying the DOM4J object model for use in the JAXP 1.3 XPath API */ public static final String OBJECT_MODEL_DOM4J = "http://www.dom4j.org/jaxp/xpath/dom4j"; /** * URI identifying the .NET DOM object model (not used, but needed for consistency) */ public static final String OBJECT_MODEL_DOT_NET_DOM = "http://saxon.sf.net/object-model/dotnet/dom"; /** * URI identifying the Unicode codepoint collation */ public static final String CODEPOINT_COLLATION_URI = "http://www.w3.org/2005/xpath-functions/collation/codepoint"; /** * Private constructor: class is never instantiated */ private NamespaceConstant() { } /** * Determine whether a namespace is a reserved namespace */ public static final boolean isReserved(String uri) { if (uri == null) { return false; } return uri.equals(XSLT) || uri.equals(FN) || uri.equals(XML) || uri.equals(SCHEMA)|| uri.equals(SCHEMA_INSTANCE); } /** * Determine whether a namespace is a reserved namespace */ public static final boolean isSpecialURICode(short uriCode) { return uriCode <= 6; } /** * Determine whether a namespace is a reserved namespace */ public static final boolean isReservedInQuery(String uri) { return uri.equals(FN) || uri.equals(XML) || uri.equals(SCHEMA) || //uri.equals(XDT) || uri.equals(SCHEMA_INSTANCE); } /** * Find a similar namespace to one that is a possible mis-spelling * @param candidate the possibly mis-spelt namespace * @return the correct spelling of the namespace */ public static String findSimilarNamespace(String candidate) { return null; // Suppressed as caused crashes late in the 9.1 build validation // if (isSimilar(candidate, XML)) { // return XML; // } else if (isSimilar(candidate, SCHEMA)) { // return SCHEMA; // } else if (isSimilar(candidate, XSLT)) { // return XSLT; // } else if (isSimilar(candidate, SCHEMA_INSTANCE)) { // return SCHEMA_INSTANCE; // } else if (isSimilar(candidate, FN)) { // return FN; // } else if (isSimilar(candidate, SAXON)) { // return SAXON; // } else if (isSimilar(candidate, EXSLT_COMMON)) { // return EXSLT_COMMON; // } else if (isSimilar(candidate, EXSLT_MATH)) { // return EXSLT_MATH; // } else if (isSimilar(candidate, EXSLT_DATES_AND_TIMES)) { // return EXSLT_DATES_AND_TIMES; // } else if (isSimilar(candidate, EXSLT_RANDOM)) { // return EXSLT_RANDOM; // } else if (isSimilar(candidate, XHTML)) { // return XHTML; // } else if (isSimilar(candidate, ERR)) { // return ERR; // } else if (isSimilar(candidate, JAVA_TYPE)) { // return JAVA_TYPE; // } else if (isSimilar(candidate, DOT_NET_TYPE)) { // return DOT_NET_TYPE; // } else { // return null; // } } // private static boolean isSimilar(String s1, String s2) { // if (s1.equalsIgnoreCase(s2)) { // return true; // } else if (s1.startsWith(s2) && s1.length() - s2.length() < 3) { // return true; // } else if (s2.startsWith(s1) && s2.length() - s1.length() < 3) { // return true; // } else { // int diff = 0; // for (int i=0; i 0 && i < s2.length()-1 && c1 == s2.charAt(i-1)) // || (i < s2.length()+1 && c1 == s2.charAt(i+1)))) { // diff++; // } // } // return diff < 3; // } // } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/om/SequenceIterator.java0000644000175000017500000001640311033112257022143 0ustar eugeneeugenepackage net.sf.saxon.om; import net.sf.saxon.trans.XPathException; /** * A SequenceIterator is used to iterate over any XPath 2 sequence (of values or nodes). * To get the next item in a sequence, call next(); if this returns null, you've * reached the end of the sequence. *

    * A SequenceIterator keeps track of the current Item and the current position. * The objects returned by the SequenceIterator will always be either nodes * (class NodeInfo) or singleton values (class AtomicValue): these are represented * collectively by the interface Item. *

    * This interface forms part of the public Saxon API. The JavaDoc "since" flag is used from * release 8.4 onwards to indicate methods that are considered to be a stable part * of the API. Methods without a "since" flag should not be regarded as a stable part * of the API. *

    * Note that the stability of this interface applies to classes that use the interface, * not to classes that implement it. The interface may be extended in future to add new methods. * * @author Michael H. Kay * @since 8.4 */ public interface SequenceIterator { /** * Get the next item in the sequence. This method changes the state of the * iterator, in particular it affects the result of subsequent calls of * position() and current(). * @throws XPathException if an error occurs retrieving the next item * @return the next item, or null if there are no more items. Once a call * on next() has returned null, no further calls should be made. The preferred * action for an iterator if subsequent calls on next() are made is to return * null again, and all implementations within Saxon follow this rule. * @since 8.4 */ public Item next() throws XPathException; /** * Get the current value in the sequence (the one returned by the * most recent call on next()). This will be null before the first * call of next(). This method does not change the state of the iterator. * * @return the current item, the one most recently returned by a call on * next(). Returns null if next() has not been called, or if the end * of the sequence has been reached. * @since 8.4 */ public Item current(); /** * Get the current position. This will usually be zero before the first call * on next(), otherwise it will be the number of times that next() has * been called. Once next() has returned null, the preferred action is * for subsequent calls on position() to return -1, but not all existing * implementations follow this practice. (In particular, the EmptyIterator * is stateless, and always returns 0 as the value of position(), whether * or not next() has been called.) *

    * This method does not change the state of the iterator. * * @return the current position, the position of the item returned by the * most recent call of next(). This is 1 after next() has been successfully * called once, 2 after it has been called twice, and so on. If next() has * never been called, the method returns zero. If the end of the sequence * has been reached, the value returned will always be <= 0; the preferred * value is -1. * * @since 8.4 */ public int position(); /** * Close the iterator. This indicates to the supplier of the data that the client * does not require any more items to be delivered by the iterator. This may enable the * supplier to release resources. After calling close(), no further calls on the * iterator should be made; if further calls are made, the effect of such calls is undefined. * *

    (Currently, closing an iterator is important only when the data is being "pushed" in * another thread. Closing the iterator terminates that thread and means that it needs to do * no additional work. Indeed, failing to close the iterator may cause the push thread to hang * waiting for the buffer to be emptied.)

    */ public void close(); /** * Get another SequenceIterator that iterates over the same items as the original, * but which is repositioned at the start of the sequence. *

    * This method allows access to all the items in the sequence without disturbing the * current position of the iterator. Internally, its main use is in evaluating the last() * function. *

    * This method does not change the state of the iterator. * * @exception XPathException if any error occurs * @return a SequenceIterator that iterates over the same items, * positioned before the first item * @since 8.4 */ public SequenceIterator getAnother() throws XPathException; /** * Get properties of this iterator, as a bit-significant integer. * @return the properties of this iterator. This will be some combination of * properties such as {@link #GROUNDED}, {@link #LAST_POSITION_FINDER}, * and {@link #LOOKAHEAD}. It is always * acceptable to return the value zero, indicating that there are no known special properties. * It is acceptable for the properties of the iterator to change depending on its state. * @since 8.6 */ public int getProperties(); /** * Property value: the iterator is "grounded". This means that (a) the * iterator must be an instance of {@link GroundedIterator}, and (b) the * implementation of the materialize() method must be efficient (in particular, * it should not involve the creation of new objects) */ public static final int GROUNDED = 1; /** * Property value: the iterator knows the number of items that it will deliver. * This means that (a) the iterator must be an instance of {@link net.sf.saxon.expr.LastPositionFinder}, * and (b) the implementation of the getLastPosition() method must be efficient (in particular, * it should take constant time, rather than time proportional to the length of the sequence) */ public static final int LAST_POSITION_FINDER = 1<<1; /** * Property value: the iterator knows whether there are more items still to come. This means * that (a) the iterator must be an instance of {@link LookaheadIterator}, and (b) the * implementation of the hasNext() method must be efficient (more efficient than the client doing * it) */ public static final int LOOKAHEAD = 1<<2; } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/om/AttributeCollection.java0000644000175000017500000001536011033112257022641 0ustar eugeneeugenepackage net.sf.saxon.om; /** * AttributeCollection represents the collection of attributes available on a particular element * node. It is modelled on the SAX2 Attributes interface, but is extended firstly to work with * Saxon NamePools, and secondly to provide type information as required by the XPath 2.0 data model. */ public interface AttributeCollection { /** * Return the number of attributes in the list. * * @return The number of attributes in the list. */ int getLength(); /** * Get the namecode of an attribute (by position). * * @param index The position of the attribute in the list. * @return The name code of the attribute, or -1 if there is no attribute at that position. */ int getNameCode(int index); /** * Get the type annotation of an attribute (by position). * * @param index The position of the attribute in the list. * @return The type annotation, as the fingerprint of the type name. * The bit {@link net.sf.saxon.om.NodeInfo#IS_DTD_TYPE} represents a DTD-derived type. */ int getTypeAnnotation(int index); /** * Get the locationID of an attribute (by position) * @param index The position of the attribute in the list. * @return The location identifier of the attribute. This can be supplied * to a {@link net.sf.saxon.event.LocationProvider} in order to obtain the * actual system identifier and line number of the relevant location */ int getLocationId(int index); /** * Get the systemId part of the location of an attribute, at a given index. * *

    Attribute location information is not available from a SAX parser, so this method * is not useful for getting the location of an attribute in a source document. However, * in a Saxon result document, the location information represents the location in the * stylesheet of the instruction used to generate this attribute, which is useful for * debugging.

    * @param index the required attribute * @return the systemId of the location of the attribute */ String getSystemId(int index); /** * Get the line number part of the location of an attribute, at a given index. * *

    Attribute location information is not available from a SAX parser, so this method * is not useful for getting the location of an attribute in a source document. However, * in a Saxon result document, the location information represents the location in the * stylesheet of the instruction used to generate this attribute, which is useful for * debugging.

    * @param index the required attribute * @return the line number of the location of the attribute */ int getLineNumber(int index); /** * Get the properties of an attribute (by position) * @param index The position of the attribute in the list. * @return The properties of the attribute. This is a set * of bit-settings defined in class {@link net.sf.saxon.event.ReceiverOptions}. The * most interesting of these is {{@link net.sf.saxon.event.ReceiverOptions#DEFAULTED_ATTRIBUTE}, * which indicates an attribute that was added to an element as a result of schema validation. */ int getProperties(int index); /** * Get the prefix of the name of an attribute (by position). * * @param index The position of the attribute in the list. * @return The prefix of the attribute name as a string, or null if there * is no attribute at that position. Returns "" for an attribute that * has no prefix. */ String getPrefix(int index); /** * Get the lexical QName of an attribute (by position). * * @param index The position of the attribute in the list. * @return The lexical QName of the attribute as a string, or null if there * is no attribute at that position. */ String getQName(int index); /** * Get the local name of an attribute (by position). * * @param index The position of the attribute in the list. * @return The local name of the attribute as a string, or null if there * is no attribute at that position. */ String getLocalName(int index); /** * Get the namespace URI of an attribute (by position). * * @param index The position of the attribute in the list. * @return The local name of the attribute as a string, or null if there * is no attribute at that position. */ String getURI(int index); /** * Get the index of an attribute (by name). * * @param uri The namespace uri of the attribute. * @param localname The local name of the attribute. * @return The index position of the attribute */ int getIndex(String uri, String localname); /** * Get the index, given the fingerprint */ int getIndexByFingerprint(int fingerprint); /** * Get the attribute value using its fingerprint */ String getValueByFingerprint(int fingerprint); /** * Get the value of an attribute (by name). * * @param uri The namespace uri of the attribute. * @param localname The local name of the attribute. * @return The value of the attribute */ public String getValue(String uri, String localname); /** * Get the value of an attribute (by position). * * @param index The position of the attribute in the list. * @return The attribute value as a string, or null if * there is no attribute at that position. */ String getValue(int index); /** * Determine whether a given attribute has the is-ID property set */ boolean isId(int index); /** * Determine whether a given attribute has the is-idref property set */ boolean isIdref(int index); } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/om/ReverseArrayIterator.java0000644000175000017500000000772711033112257023016 0ustar eugeneeugenepackage net.sf.saxon.om; import net.sf.saxon.expr.LastPositionFinder; /** * ReverseArrayIterator is used to enumerate items held in an array in reverse order. * @author Michael H. Kay */ public class ReverseArrayIterator implements UnfailingIterator, net.sf.saxon.expr.ReversibleIterator, LookaheadIterator, LastPositionFinder { Item[] items; int index = 0; int start; int end; // item after the last to be output Item current = null; /** * Create an iterator a slice of an array * @param items The array of items * @param start The first item in the array to be be used (this will be the last * one in the resulting iteration). Zero-based. * @param end The item after the last one in the array to be used (this will be the * first one to be returned by the iterator). Zero-based. */ public ReverseArrayIterator(Item[] items, int start, int end) { this.items = items; this.end = end; this.start = start; index = end - 1; } /** * Determine whether there are more items to come. Note that this operation * is stateless and it is not necessary (or usual) to call it before calling * next(). It is used only when there is an explicit need to tell if we * are at the last element. * * @return true if there are more items in the sequence */ public boolean hasNext() { return index >= start; } public Item next() { if (index >= start) { current = items[index--]; return current; } else { current = null; return null; } } public Item current() { return current; } public int position() { if (index < start-1) { return -1; // position() returns -1 after next() returns null } return end - 1 - index; } public int getLastPosition() { return end - start; } public void close() { } public SequenceIterator getAnother() { return new ReverseArrayIterator(items, start, end); } /** * Get properties of this iterator, as a bit-significant integer. * * @return the properties of this iterator. This will be some combination of * properties such as {@link #GROUNDED}, {@link #LAST_POSITION_FINDER}, * and {@link #LOOKAHEAD}. It is always * acceptable to return the value zero, indicating that there are no known special properties. * It is acceptable for the properties of the iterator to change depending on its state. */ public int getProperties() { return LAST_POSITION_FINDER; } /** * Get an iterator that processes the same items in reverse order. * Since this iterator is processing the items backwards, this method * returns an ArrayIterator that processes them forwards. * @return a new ArrayIterator */ public SequenceIterator getReverseIterator() { return new ArrayIterator(items, start, end); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/om/package.html0000644000175000017500000000374711033112257020306 0ustar eugeneeugene Package overview for net.sf.saxon.om

    This package defines the interface to the Saxon tree structure. This structure is used to represent both the source document and the stylesheet. Essentially, this class represents Saxon's realization of the XPath data model.

    The classes in the package are rather a miscellany. What they have in common is that they describe the way the Saxon tree structure is accessed, in a way that it independent of the two tree implementations (in packages net.sf.saxon.tree and net.sf.saxon.tinytree).

    Broadly speaking, the classes fall into four categories:

    • Interface classes: DocumentInfo, NodeInfo, Item, ValueRepresentation. These describe the interface offered by the object model to the rest of the system, including the application.
    • Iterator classes: SequenceIterator, AxisIterator, ArrayIterator, EmptyIterator, SingletonIterator, and others. These classes provide mechanisms for iterating over sequences. The most general, and the one which applications are most likely to use, is the SequenceIterator interface itself. AxisIterator is a specialization of this interface whose main difference is that it cannot throw exceptions. The other classes are implementations of SequenceIterator for use in particular circumstances.
    • Shared implementation classes: DocumentPool, NamePool, Navigator, XMLChar. These contain functionality that is shared between the various tree implementations. (However, there is also some shared functionality in the net.sf.saxon.tree package). These classes are not generally needed by applications, with the exception of NamePool, which complex applications may need to manipulate.
    • Information classes: Axis, NamespaceConstant. These contain constants.

    Michael H. Kay
    Saxonica Limited
    9 February 2005

    saxonb-9.1.0.8/bj/net/sf/saxon/style/0000755000175000017500000000000012216261750016546 5ustar eugeneeugenesaxonb-9.1.0.8/bj/net/sf/saxon/style/ExtensionInstruction.java0000644000175000017500000000266511033112257023631 0ustar eugeneeugenepackage net.sf.saxon.style; import net.sf.saxon.trans.XPathException; /** * Abstract class representing an extension instruction */ public abstract class ExtensionInstruction extends StyleElement { /** * Determine whether this node is an instruction. * @return true - it is an instruction */ public final boolean isInstruction() { return true; } /** * Determine whether this type of element is allowed to contain an xsl:fallback * instruction */ public final boolean mayContainFallback() { return true; } public void validate() throws XPathException { // } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Additional Contributor(s): Rick Bonnett [rbonnett@acadia.net] // saxonb-9.1.0.8/bj/net/sf/saxon/style/XSLWithParam.java0000644000175000017500000000450711033112257021673 0ustar eugeneeugenepackage net.sf.saxon.style; import net.sf.saxon.expr.Expression; import net.sf.saxon.instruct.Executable; import net.sf.saxon.instruct.WithParam; import net.sf.saxon.om.Axis; import net.sf.saxon.om.AxisIterator; import net.sf.saxon.om.Item; import net.sf.saxon.trans.XPathException; /** * An xsl:with-param element in the stylesheet.
    * The xsl:with-param element has mandatory attribute name and optional attribute select */ public class XSLWithParam extends XSLGeneralVariable { protected boolean allowsAsAttribute() { return true; } protected boolean allowsTunnelAttribute() { return true; } public void validate() throws XPathException { super.validate(); // Check for duplicate parameter names AxisIterator iter = iterateAxis(Axis.PRECEDING_SIBLING); while (true) { Item prev = iter.next(); if (prev == null) { break; } if (prev instanceof XSLWithParam) { if (this.getVariableQName().equals(((XSLWithParam)prev).getVariableQName())) { compileError("Duplicate parameter name", "XTSE0670"); } } } } public Expression compile(Executable exec) throws XPathException { WithParam inst = new WithParam(); inst.adoptChildExpression(select); inst.setParameterId( getPrincipalStylesheet().allocateUniqueParameterNumber(getVariableQName())); initializeInstruction(exec, inst); return inst; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/style/XSLPerformSort.java0000644000175000017500000001154311033112257022257 0ustar eugeneeugenepackage net.sf.saxon.style; import net.sf.saxon.expr.Expression; import net.sf.saxon.expr.Literal; import net.sf.saxon.instruct.Executable; import net.sf.saxon.om.*; import net.sf.saxon.sort.SortExpression; import net.sf.saxon.sort.SortKeyDefinition; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.Type; import net.sf.saxon.type.TypeHierarchy; import net.sf.saxon.value.Whitespace; /** * Handler for xsl:perform-sort elements in stylesheet (XSLT 2.0).
    */ public class XSLPerformSort extends StyleElement { Expression select = null; /** * Determine whether this node is an instruction. * @return true - it is an instruction */ public boolean isInstruction() { return true; } /** * Determine the type of item returned by this instruction (only relevant if * it is an instruction). * @return the item type returned */ protected ItemType getReturnedItemType() { if (select==null) { return getCommonChildItemType(); } else { final TypeHierarchy th = getConfiguration().getTypeHierarchy(); return select.getItemType(th); } } /** * Determine whether this type of element is allowed to contain a template-body * @return true: yes, it may contain a template-body */ public boolean mayContainSequenceConstructor() { return true; } /** * Specify that xsl:sort is a permitted child */ protected boolean isPermittedChild(StyleElement child) { return (child instanceof XSLSort); } public void prepareAttributes() throws XPathException { AttributeCollection atts = getAttributeList(); String selectAtt = null; for (int a=0; a= 0) { return ALWAYS_STRIP; } return STRIP_DEFAULT; } /** * Decide whether an element is in the set of white-space preserving element types. * This version of the method is useful in cases where getting the namecode of the * element is potentially expensive, e.g. with DOM nodes. * @param element Identifies the element whose whitespace is possibly to * be preserved * @return true if the element is in the set of white-space preserving element types */ public byte isSpacePreserving(NodeInfo element) throws XPathException { return isSpacePreserving(element.getNameCode()); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/style/XSLTStaticContext.java0000644000175000017500000000244111033112257022712 0ustar eugeneeugenepackage net.sf.saxon.style; import net.sf.saxon.expr.StaticContext; import net.sf.saxon.trans.XPathException; /** * Extends the standard XPath static context with information that is available for * XPath expressions invoked from XSLT */ public interface XSLTStaticContext extends StaticContext { /** * Determine if an extension element is available * @throws net.sf.saxon.trans.XPathException if the name is invalid or the prefix is not declared */ public boolean isElementAvailable(String qname) throws XPathException; } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/style/XSLGeneralVariable.java0000644000175000017500000004217111157411303023022 0ustar eugeneeugenepackage net.sf.saxon.style; import net.sf.saxon.expr.*; import net.sf.saxon.instruct.*; import net.sf.saxon.om.*; import net.sf.saxon.pattern.NodeKindTest; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.Type; import net.sf.saxon.value.Cardinality; import net.sf.saxon.value.SequenceType; import net.sf.saxon.value.StringValue; import net.sf.saxon.value.Whitespace; /** * This class defines common behaviour across xsl:variable, xsl:param, and xsl:with-param */ public abstract class XSLGeneralVariable extends StyleElement { protected Expression select = null; protected SequenceType requiredType = null; protected String constantText = null; protected boolean global; protected SlotManager slotManager = null; // used only for global variable declarations protected boolean assignable = false; protected boolean redundant = false; protected boolean requiredParam = false; protected boolean implicitlyRequiredParam = false; protected boolean tunnel = false; private boolean textonly; /** * Determine the type of item returned by this instruction (only relevant if * it is an instruction). * @return the item type returned. This is null for a variable: we are not * interested in the type of the variable, but in what the xsl:variable constributes * to the result of the sequence constructor it is part of. */ protected ItemType getReturnedItemType() { return null; } /** * Determine whether this type of element is allowed to contain a template-body * @return true: yes, it may contain a template-body */ public boolean mayContainSequenceConstructor() { return true; } protected boolean allowsAsAttribute() { return true; } protected boolean allowsTunnelAttribute() { return false; } protected boolean allowsValue() { return true; } protected boolean allowsRequired() { return false; } /** * Test whether it is permitted to assign to the variable using the saxon:assign * extension element. * @return true if the extra attribute saxon:assignable="yes" * is present. */ public boolean isAssignable() { return assignable; } /** * Test whether this is a tunnel parameter (tunnel="yes") * @return true if this is a tunnel parameter */ public boolean isTunnelParam() { return tunnel; } /** * Test whether this is a required parameter (required="yes") * @return true if this is a required parameter */ public boolean isRequiredParam() { return requiredParam; } /** * Test whether this is a global variable or parameter * @return true if this is global */ public boolean isGlobal() { return isTopLevel(); // might be called before the "global" field is initialized } /** * Get the display name of the variable. * @return the lexical QName */ public String getVariableDisplayName() { return getAttributeValue(StandardNames.NAME); } /** * Mark this global variable as redundant. This is done before prepareAttributes is called. */ public void setRedundant() { redundant = true; } /** * Get the QName of the variable * @return the name as a structured QName, or a dummy name if the variable has no name attribute * or has an invalid name attribute */ public StructuredQName getVariableQName() { // if an expression has a forwards reference to this variable, getVariableQName() can be // called before prepareAttributes() is called. We need to allow for this. But we'll // deal with any errors when we come round to processing this attribute, to avoid // duplicate error messages if (getObjectName() == null) { String nameAttribute = getAttributeValue(StandardNames.NAME); if (nameAttribute == null) { return new StructuredQName("saxon", NamespaceConstant.SAXON, "error-variable-name"); } try { setObjectName(makeQName(nameAttribute)); } catch (NamespaceException err) { setObjectName(new StructuredQName("saxon", NamespaceConstant.SAXON, "error-variable-name")); } catch (XPathException err) { setObjectName(new StructuredQName("saxon", NamespaceConstant.SAXON, "error-variable-name")); } } return getObjectName(); } public void prepareAttributes() throws XPathException { getVariableQName(); AttributeCollection atts = getAttributeList(); String selectAtt = null; String assignAtt = null; String nameAtt = null; String asAtt = null; String requiredAtt = null; String tunnelAtt = null; for (int a=0; a 0) { gvar.setContainsLocals(slotManager); } exec.registerGlobalVariable(gvar); setReferenceCount(gvar); if (exp2 != select) { gvar.setSelectExpression(exp2); } } } protected void setReferenceCount(GeneralVariable var) { // overridden in subclass } /** * Get the type of construct. This will be a constant in * class {@link net.sf.saxon.trace.Location}. This method is part of the * {@link net.sf.saxon.trace.InstructionInfo} interface */ public int getConstructType() { return StandardNames.XSL_VARIABLE; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/style/XSLStylesheet.java0000644000175000017500000013566111033112257022136 0ustar eugeneeugenepackage net.sf.saxon.style; import net.sf.saxon.Configuration; import net.sf.saxon.PreparedStylesheet; import net.sf.saxon.event.SaxonOutputKeys; import net.sf.saxon.expr.CollationMap; import net.sf.saxon.expr.Expression; import net.sf.saxon.functions.*; import net.sf.saxon.instruct.Executable; import net.sf.saxon.instruct.LocationMap; import net.sf.saxon.om.*; import net.sf.saxon.query.XQueryFunction; import net.sf.saxon.query.XQueryFunctionLibrary; import net.sf.saxon.sort.*; import net.sf.saxon.trans.*; import net.sf.saxon.type.SchemaException; import net.sf.saxon.type.Type; import net.sf.saxon.value.Whitespace; import java.util.*; /** * An xsl:stylesheet or xsl:transform element in the stylesheet.
    * Note this element represents a stylesheet module, not necessarily * the whole stylesheet. However, much of the functionality (and the fields) * are relevant only to the top-level module. */ public class XSLStylesheet extends StyleElement { Executable exec; // the Location Map keeps track of modules and line numbers of expressions and instructions private LocationMap locationMap = new LocationMap(); // index of global variables and parameters, by StructuredQName // (overridden variables are excluded). // Used at compile-time only, except for debugging private HashMap globalVariableIndex = new HashMap(20); // the name pool used for names that will be needed at run-time, notably // the names used in XPath expressions and patterns, but also key names, parameter names, etc //private NamePool targetNamePool; // true if this stylesheet was included by xsl:include, false if it is the // principal stylesheet or if it was imported private boolean wasIncluded = false; // the import precedence for top-level elements in this stylesheet private int precedence = 0; // the lowest precedence of any stylesheet imported by this one private int minImportPrecedence = 0; // the StyleSheet that included or imported this one; null for the principal stylesheet private XSLStylesheet importer = null; // the PreparedStylesheet object used to load this stylesheet private PreparedStylesheet stylesheet; // the top-level elements in this logical stylesheet (after include/import) private List topLevel; // table of named templates. Key is the integer fingerprint of the template name; // value is the XSLTemplate object in the source stylesheet. private HashMap templateIndex = new HashMap(20); // the value of the inputTypeAnnotations attribute on this module, combined with the values // on all imported/included modules. This is a combination of the bit-significant values // ANNOTATION_STRIP and ANNOTATION_PRESERVE. private int inputAnnotations = 0; public static final int ANNOTATION_STRIP = 1; public static final int ANNOTATION_PRESERVE = 2; // table of imported schemas. The members of this set are strings holding the target namespace. private HashSet schemaIndex = new HashSet(10); // table of functions imported from XQuery library modules private XQueryFunctionLibrary queryFunctions; // function library for external Java functions private FunctionLibrary javaFunctions; // media type (MIME type) of principal output //private String mediaType; // namespace aliases. This information is needed at compile-time only private int numberOfAliases = 0; private ArrayList namespaceAliasList = new ArrayList(5); private short[] aliasSCodes; private int[] aliasNCodes; // count of the maximum number of local variables in xsl:template match patterns private int largestPatternStackFrame = 0; // default validation private int defaultValidation = Validation.STRIP; // library of functions that are in-scope for XPath expressions in this stylesheet private FunctionLibraryList functionLibrary; // flag: true if there's an xsl:result-document that uses a dynamic format private boolean needsDynamicOutputProperties = false; // flag: saxon:allow-all-built-in-types is set to true private boolean allowsAllBuiltInTypes = false; // map for allocating unique numbers to local parameter names. Key is a // StructuredQName; value is a boxed int. Use only on the principal module. private HashMap localParameterNumbers = null; /** * Create link to the owning PreparedStylesheet object * @param sheet the PreparedStylesheet */ public void setPreparedStylesheet(PreparedStylesheet sheet) { Configuration config = sheet.getConfiguration(); stylesheet = sheet; //targetNamePool = sheet.getTargetNamePool(); exec = new Executable(config); exec.setConfiguration(config); exec.setRuleManager(new RuleManager()); exec.setLocationMap(locationMap); exec.setHostLanguage(Configuration.XSLT); functionLibrary = new FunctionLibraryList(); functionLibrary.addFunctionLibrary( SystemFunctionLibrary.getSystemFunctionLibrary(SystemFunctionLibrary.FULL_XSLT)); functionLibrary.addFunctionLibrary(new StylesheetFunctionLibrary(this, true)); functionLibrary.addFunctionLibrary(config.getVendorFunctionLibrary()); functionLibrary.addFunctionLibrary(new ConstructorFunctionLibrary(config)); queryFunctions = new XQueryFunctionLibrary(config); functionLibrary.addFunctionLibrary(queryFunctions); if (config.isAllowExternalFunctions()) { javaFunctions = config.getExtensionBinder("java"); Configuration.getPlatform().addFunctionLibraries(functionLibrary, config, Configuration.XSLT); } functionLibrary.addFunctionLibrary(new StylesheetFunctionLibrary(this, false)); } /** * Get the owning PreparedStylesheet object */ public PreparedStylesheet getPreparedStylesheet() { if (importer != null) { return importer.getPreparedStylesheet(); } return stylesheet; } /** * Get the run-time Executable object */ public Executable getExecutable() { return exec; } protected boolean mayContainParam() { return true; } /** * Get the function library. Available only on the principal stylesheet module * @return the function library */ public FunctionLibrary getFunctionLibrary() { return functionLibrary; } /** * Get the locationMap object * @return the LocationMap */ public LocationMap getLocationMap() { return locationMap; } /** * Get the RuleManager which handles template rules * @return the template rule manager */ public RuleManager getRuleManager() { return exec.getRuleManager(); } /** * Get the rules determining which nodes are to be stripped from the tree * @return the Mode object holding the whitespace stripping rules. The stripping * rules defined in xsl:strip-space are managed in the same way as template rules, * hence the use of a special Mode object */ protected Mode getStripperRules() { if (exec.getStripperRules() == null) { exec.setStripperRules(new Mode(Mode.STRIPPER_MODE, Mode.DEFAULT_MODE_NAME)); } return exec.getStripperRules(); } /** * Determine whether this stylesheet does any whitespace stripping * @return true if this stylesheet strips whitespace from source documents */ public boolean stripsWhitespace() { for (int i = 0; i < topLevel.size(); i++) { NodeInfo s = (NodeInfo) topLevel.get(i); if (s.getFingerprint() == StandardNames.XSL_STRIP_SPACE) { return true; } } return false; } /** * Get the KeyManager which handles key definitions * @return the key manager */ public KeyManager getKeyManager() { if (exec.getKeyManager() == null) { exec.setKeyManager(new KeyManager(getConfiguration())); } return exec.getKeyManager(); } /** * Get the DecimalFormatManager which handles decimal-format definitions * @return the DecimalFormatManager for this stylesheet */ public DecimalFormatManager getDecimalFormatManager() { if (exec.getDecimalFormatManager() == null) { exec.setDecimalFormatManager(new DecimalFormatManager()); } return exec.getDecimalFormatManager(); } /** * Get the collation map * @return the CollationMap */ public CollationMap getCollationMap() { return exec.getCollationTable(); } /** * Register a named collation (actually a StringCollator) * @param name the name of the collation * @param collation the StringCollator that implements this collation */ public void setCollation(String name, StringCollator collation) { if (exec.getCollationTable() == null) { exec.setCollationTable(new CollationMap(getConfiguration())); } exec.getCollationTable().setNamedCollation(name, collation); } /** * Find a named collation. Note this method should only be used at compile-time, before declarations * have been pre-processed. After that time, use getCollation(). * @param name identifies the name of the collation required; null indicates that the default * collation is required * @return null if the collation is not found */ protected StringCollator findCollation(String name) { if (name == null) { name = exec.getDefaultCollationName(); } if (name.equals(NamespaceConstant.CODEPOINT_COLLATION_URI)) { return CodepointCollator.getInstance(); } // First try to find it in the table StringCollator c = null; if (exec.getCollationTable() != null) { c = exec.getCollationTable().getNamedCollation(name); } if (c != null) return c; // At compile-time, the collation might not yet be in the table. So search for it XSLStylesheet stylesheet = getPrincipalStylesheet(); List toplevel = stylesheet.getTopLevel(); // search for a matching collation name, starting at the end in case of duplicates. // this also ensures we get the one with highest import precedence. for (int i = toplevel.size() - 1; i >= 0; i--) { if (toplevel.get(i) instanceof SaxonCollation) { SaxonCollation t = (SaxonCollation) toplevel.get(i); if (t.getCollationName().equals(name)) { return t.getCollator(); } } } Configuration config = getConfiguration(); return config.getCollationURIResolver().resolve(name, getBaseURI(), config); } /** * Get the name of the default collation */ public String getDefaultCollationName() { return exec.getDefaultCollationName(); } /** * Get a character map, identified by the fingerprint of its name. * Search backwards through the stylesheet. * @param name The character map name being sought * @return the identified character map, or null if not found */ public XSLCharacterMap getCharacterMap(StructuredQName name) { for (int i = topLevel.size() - 1; i >= 0; i--) { if (topLevel.get(i) instanceof XSLCharacterMap) { XSLCharacterMap t = (XSLCharacterMap) topLevel.get(i); if (t.getCharacterMapName().equals(name)) { return t; } } } return null; } /** * Set the import precedence of this stylesheet * @param prec the import precedence. Higher numbers indicate higher precedence, but the actual * number has no significance */ public void setPrecedence(int prec) { precedence = prec; } /** * Get the import precedence of this stylesheet */ public int getPrecedence() { if (wasIncluded) return importer.getPrecedence(); return precedence; } /** * Get the minimum import precedence of this stylesheet, that is, the lowest precedence * of any stylesheet imported by this one * @return the minimum precedence of imported stylesheet modules */ public int getMinImportPrecedence() { return minImportPrecedence; } /** * Set the minimum import precedence of this stylesheet, that is, the lowest precedence * of any stylesheet imported by this one * @param precedence the precedence of the first stylesheet module that this one imports */ public void setMinImportPrecedence(int precedence) { minImportPrecedence = precedence; } /** * Set the StyleSheet that included or imported this one. * @param importer the stylesheet module that included or imported this module */ public void setImporter(XSLStylesheet importer) { this.importer = importer; } /** * Get the StyleSheet that included or imported this one. * @return null if this is the principal stylesheet */ public XSLStylesheet getImporter() { return importer; } /** * Indicate that this stylesheet was included (by its "importer") using an xsl:include * statement as distinct from xsl:import */ public void setWasIncluded() { wasIncluded = true; } /** * Get the top level elements in this stylesheet, after applying include/import * @return a list of top-level elements in this stylesheet module or in those * modules that it includes or imports */ public List getTopLevel() { return topLevel; } /** * Allocate a slot number for a global variable or parameter * @param qName the name of the variable or parameter * @return int the allocated slot number */ public int allocateGlobalSlot(StructuredQName qName) { return exec.getGlobalVariableMap().allocateSlotNumber(qName); } /** * Ensure there is enough space for local variables or parameters when evaluating the match pattern of * template rules * @param n the number of slots to be allocated */ public void allocatePatternSlots(int n) { if (n > largestPatternStackFrame) { largestPatternStackFrame = n; } } /** * Prepare the attributes on the stylesheet element */ public void prepareAttributes() throws XPathException { String inputTypeAnnotationsAtt = null; String allowAllBuiltInTypesAtt = null; AttributeCollection atts = getAttributeList(); for (int a = 0; a < atts.getLength(); a++) { int nc = atts.getNameCode(a); String f = getNamePool().getClarkName(nc); if (f.equals(StandardNames.VERSION)) { // already processed } else if (f.equals(StandardNames.ID)) { // } else if (f.equals(StandardNames.EXTENSION_ELEMENT_PREFIXES)) { // } else if (f.equals(StandardNames.EXCLUDE_RESULT_PREFIXES)) { // } else if (f.equals(StandardNames.DEFAULT_VALIDATION)) { defaultValidation = Validation.getCode(atts.getValue(a)); if (defaultValidation == Validation.INVALID) { compileError("Invalid value for default-validation attribute. " + "Permitted values are (strict, lax, preserve, strip)", "XTSE0020"); } else if (!getConfiguration().isSchemaAware(Configuration.XSLT) && defaultValidation != Validation.STRIP) { compileError("default-validation='" + atts.getValue(a) + "' requires a schema-aware processor", "XTSE1660"); } } else if (f.equals(StandardNames.INPUT_TYPE_ANNOTATIONS)) { inputTypeAnnotationsAtt = atts.getValue(a); } else if (f.equals(StandardNames.SAXON_ALLOW_ALL_BUILT_IN_TYPES)) { allowAllBuiltInTypesAtt = atts.getValue(a); } else { checkUnknownAttribute(nc); } } if (version == null) { reportAbsence("version"); } if (inputTypeAnnotationsAtt != null) { if (inputTypeAnnotationsAtt.equals("strip")) { setInputTypeAnnotations(ANNOTATION_STRIP); } else if (inputTypeAnnotationsAtt.equals("preserve")) { setInputTypeAnnotations(ANNOTATION_PRESERVE); } else if (inputTypeAnnotationsAtt.equals("unspecified")) { // } else { compileError("Invalid value for input-type-annotations attribute. " + "Permitted values are (strip, preserve, unspecified)", "XTSE0020"); } } if (allowAllBuiltInTypesAtt != null) { if (allowAllBuiltInTypesAtt.equals("yes")) { allowsAllBuiltInTypes = true; } else if (allowAllBuiltInTypesAtt.equals("no")) { // } else { compileWarning("Invalid value for saxon:allow-all-built-in-types attribute. " + "Permitted values are (yes, no)", SaxonErrorCode.SXWN9007); } } } /** * Get the value of the default validation attribute * @return the value of the default-validation attribute, as a constant such * as {@link Validation#STRIP} */ public int getDefaultValidation() { return defaultValidation; } /** * Get the value of the input-type-annotations attribute, for this module alone. * The value is an or-ed combination of the two bits * {@link #ANNOTATION_STRIP} and {@link #ANNOTATION_PRESERVE} * @return the value if the input-type-annotations attribute in this stylesheet module */ public int getInputTypeAnnotationsAttribute() throws XPathException { String inputTypeAnnotationsAtt = getAttributeValue(StandardNames.INPUT_TYPE_ANNOTATIONS); if (inputTypeAnnotationsAtt != null) { if (inputTypeAnnotationsAtt.equals("strip")) { setInputTypeAnnotations(ANNOTATION_STRIP); } else if (inputTypeAnnotationsAtt.equals("preserve")) { setInputTypeAnnotations(ANNOTATION_PRESERVE); } else if (inputTypeAnnotationsAtt.equals("unspecified")) { // } else { compileError("Invalid value for input-type-annotations attribute. " + "Permitted values are (strip, preserve, unspecified)", "XTSE0020"); } } return inputAnnotations; } /** * Get the value of the input-type-annotations attribute, for this module combined with that * of all included/imported modules. The value is an or-ed combination of the two bits * {@link #ANNOTATION_STRIP} and {@link #ANNOTATION_PRESERVE} * @return the value of the input-type-annotations attribute, for this module combined with that * of all included/imported modules */ public int getInputTypeAnnotations() { return inputAnnotations; } /** * Set the value of the input-type-annotations attribute, for this module combined with that * of all included/imported modules. The value is an or-ed combination of the two bits * {@link #ANNOTATION_STRIP} and {@link #ANNOTATION_PRESERVE} * @param annotations the value of the input-type-annotations attribute, for this module combined with that * of all included/imported modules. */ public void setInputTypeAnnotations(int annotations) throws XPathException { inputAnnotations |= annotations; if (inputAnnotations == (ANNOTATION_STRIP | ANNOTATION_PRESERVE)) { compileError("One stylesheet module specifies input-type-annotations='strip', " + "another specifies input-type-annotations='preserve'", "XTSE0265"); } } /** * Determine whether the use of non-primitive built-in types has been enabled for this stylesheet * (This is relevant only for Saxon-B: such types are always permitted in Saxon-SA) * @return true if all built-in types can be used */ public boolean allowsAllBuiltInTypes() { return allowsAllBuiltInTypes; } /** * Get the declared namespace alias for a given namespace URI code if there is one. * If there is more than one, we get the last. * @param uriCode The code of the uri used in the stylesheet. * @return The namespace code to be used (prefix in top half, uri in bottom half): return -1 * if no alias is defined */ protected int getNamespaceAlias(short uriCode) { // if there are several matches, the last in stylesheet takes priority; // but the list is in reverse stylesheet order for (int i = 0; i < numberOfAliases; i++) { if (uriCode == aliasSCodes[i]) { return aliasNCodes[i]; } } return uriCode; } /** * Determine if a namespace is included in the result-prefix of a namespace-alias * @param uriCode the namepool code of the URI * @return true if an xsl:namespace-alias has been defined for this namespace URI */ protected boolean isAliasResultNamespace(short uriCode) { for (int i = 0; i < numberOfAliases; i++) { if (uriCode == (aliasNCodes[i] & 0xffff)) { return true; } } return false; } /** * Validate this element */ public void validate() throws XPathException { if (validationError != null) { compileError(validationError); } if (getParent().getNodeKind() != Type.DOCUMENT) { compileError(getDisplayName() + " must be the outermost element", "XTSE0010"); } AxisIterator kids = iterateAxis(Axis.CHILD); while(true) { NodeInfo curr = (NodeInfo)kids.next(); if (curr == null) break; if (curr.getNodeKind() == Type.TEXT || curr instanceof XSLTemplate || curr instanceof XSLImport || curr instanceof XSLInclude || curr instanceof XSLAttributeSet || curr instanceof XSLCharacterMap || curr instanceof XSLDecimalFormat || curr instanceof XSLFunction || curr instanceof XSLImportSchema || curr instanceof XSLKey || curr instanceof XSLNamespaceAlias || curr instanceof XSLOutput || curr instanceof XSLParam || curr instanceof XSLPreserveSpace || curr instanceof XSLVariable || curr instanceof DataElement) { // all is well } else if (!NamespaceConstant.XSLT.equals(curr.getURI()) && !"".equals(curr.getURI())) { // elements in other namespaces are allowed and ignored } else if (curr instanceof AbsentExtensionElement && ((StyleElement)curr).forwardsCompatibleModeIsEnabled()) { // this is OK: an unknown XSLT element is allowed in forwards compatibility mode } else if (NamespaceConstant.XSLT.equals(curr.getURI())) { ((StyleElement)curr).compileError("Element " + curr.getDisplayName() + " must not appear directly within " + getDisplayName(), "XTSE0010"); } else { ((StyleElement)curr).compileError("Element " + curr.getDisplayName() + " must not appear directly within " + getDisplayName() + " because it is not in a namespace", "XTSE0130"); } } } /** * Preprocess does all the processing possible before the source document is available. * It is done once per stylesheet, so the stylesheet can be reused for multiple source * documents. The method is called only on the XSLStylesheet element representing the * principal stylesheet module */ public void preprocess() throws XPathException { // process any xsl:include and xsl:import elements spliceIncludes(); // build indexes for selected top-level elements buildIndexes(); // process the attributes of every node in the tree processAllAttributes(); // collect any namespace aliases collectNamespaceAliases(); // fix up references from XPath expressions to variables and functions, for static typing for (int i = 0; i < topLevel.size(); i++) { Object node = topLevel.get(i); if (node instanceof StyleElement) { ((StyleElement) node).fixupReferences(); } } // Validate the whole logical style sheet (i.e. with included and imported sheets) validate(); for (int i = 0; i < topLevel.size(); i++) { Object node = topLevel.get(i); if (node instanceof StyleElement) { ((StyleElement) node).validateSubtree(); } } } /** * Process xsl:include and xsl:import elements. */ public void spliceIncludes() throws XPathException { boolean foundNonImport = false; topLevel = new ArrayList(50); minImportPrecedence = precedence; StyleElement previousElement = this; AxisIterator kids = iterateAxis(Axis.CHILD); while (true) { NodeInfo child = (NodeInfo) kids.next(); if (child == null) { break; } if (child.getNodeKind() == Type.TEXT) { // in an embedded stylesheet, white space nodes may still be there if (!Whitespace.isWhite(child.getStringValueCS())) { previousElement.compileError( "No character data is allowed between top-level elements", "XTSE0120"); } } else if (child instanceof DataElement) { foundNonImport = true; } else { previousElement = (StyleElement) child; if (child instanceof XSLGeneralIncorporate) { XSLGeneralIncorporate xslinc = (XSLGeneralIncorporate) child; xslinc.processAttributes(); if (xslinc.isImport()) { if (foundNonImport) { xslinc.compileError("xsl:import elements must come first", "XTSE0200"); } } else { foundNonImport = true; } // get the included stylesheet. This follows the URL, builds a tree, and splices // in any indirectly-included stylesheets. XSLStylesheet inc = xslinc.getIncludedStylesheet(this, precedence); if (inc == null) return; // error has been reported // after processing the imported stylesheet and any others it brought in, // adjust the import precedence of this stylesheet if necessary if (xslinc.isImport()) { precedence = inc.getPrecedence() + 1; } else { precedence = inc.getPrecedence(); inc.setMinImportPrecedence(minImportPrecedence); inc.setWasIncluded(); } // copy the top-level elements of the included stylesheet into the top level of this // stylesheet. Normally we add these elements at the end, in order, but if the precedence // of an element is less than the precedence of the previous element, we promote it. // This implements the requirement in the spec that when xsl:include is used to // include a stylesheet, any xsl:import elements in the included document are moved // up in the including document to after any xsl:import elements in the including // document. List incchildren = inc.topLevel; for (int j = 0; j < incchildren.size(); j++) { StyleElement elem = (StyleElement) incchildren.get(j); int last = topLevel.size() - 1; if (last < 0 || elem.getPrecedence() >= ((StyleElement) topLevel.get(last)).getPrecedence()) { topLevel.add(elem); } else { while (last >= 0 && elem.getPrecedence() < ((StyleElement) topLevel.get(last)).getPrecedence()) { last--; } topLevel.add(last + 1, elem); } } } else { foundNonImport = true; topLevel.add(child); } } } } /** * Build indexes for selected top-level declarations */ private void buildIndexes() throws XPathException { // Scan the declarations in reverse order for (int i = topLevel.size() - 1; i >= 0; i--) { Object node = topLevel.get(i); if (node instanceof XSLTemplate) { indexNamedTemplate((XSLTemplate) node); } else if (node instanceof XSLVariableDeclaration) { indexVariableDeclaration((XSLVariableDeclaration) node); } else if (node instanceof XSLNamespaceAlias) { namespaceAliasList.add(node); numberOfAliases++; } else if (node instanceof XSLImportSchema) { try { ((XSLImportSchema) node).readSchema(); } catch (SchemaException e) { throw XPathException.makeXPathException(e); } } else if (node instanceof XSLDecimalFormat) { ((XSLDecimalFormat) node).register(); } else if (node instanceof SaxonImportQuery) { ((SaxonImportQuery) node).importModule(); } else if (node instanceof XSLKey) { StructuredQName keyName = ((XSLKey)node).getKeyName(); if (keyName != null) { exec.getKeyManager().preRegisterKeyDefinition(keyName); } } } // Now seal all the schemas that have been imported to guarantee consistency with instance documents Configuration config = getConfiguration(); Iterator iter = schemaIndex.iterator(); while (iter.hasNext()) { String ns = (String)iter.next(); config.sealNamespace(ns); } } /** * Index a global xsl:variable or xsl:param element * @param var The XSLVariable or XSLParam element * @throws XPathException */ private void indexVariableDeclaration(XSLVariableDeclaration var) throws XPathException { StructuredQName qName = var.getVariableQName(); if (qName != null) { // see if there is already a global variable with this precedence XSLVariableDeclaration other = (XSLVariableDeclaration) globalVariableIndex.get(qName); if (other == null) { // this is the first globalVariableIndex.put(qName, var); } else { // check the precedences int thisPrecedence = var.getPrecedence(); int otherPrecedence = other.getPrecedence(); if (thisPrecedence == otherPrecedence) { var.compileError("Duplicate global variable declaration (see line " + other.getLineNumber() + " of " + other.getSystemId() + ')', "XTSE0630"); } else if (thisPrecedence < otherPrecedence) { var.setRedundant(); } else { // can't happen, but we'll play safe other.setRedundant(); globalVariableIndex.put(qName, var); } } } } /** * Add a named template to the index * @param template The Template object * @throws XPathException */ private void indexNamedTemplate(XSLTemplate template) throws XPathException { StructuredQName qName = template.getTemplateName(); if (qName != null) { // see if there is already a named template with this precedence XSLTemplate other = (XSLTemplate) templateIndex.get(qName); if (other == null) { // this is the first templateIndex.put(qName, template); exec.putNamedTemplate(qName, template.getCompiledTemplate()); } else { // check the precedences int thisPrecedence = template.getPrecedence(); int otherPrecedence = other.getPrecedence(); if (thisPrecedence == otherPrecedence) { template.compileError("Duplicate named template (see line " + other.getLineNumber() + " of " + other.getSystemId() + ')', "XTSE0660"); } else if (thisPrecedence < otherPrecedence) { //template.setRedundantNamedTemplate(); } else { // can't happen, but we'll play safe //other.setRedundantNamedTemplate(); templateIndex.put(qName, template); exec.putNamedTemplate(qName, template.getCompiledTemplate()); } } } } /** * Collect any namespace aliases */ private void collectNamespaceAliases() throws XPathException { aliasSCodes = new short[numberOfAliases]; aliasNCodes = new int[numberOfAliases]; int precedenceBoundary = 0; int currentPrecedence = -1; // Note that we are processing the list in reverse stylesheet order, // that is, highest precedence first. for (int i = 0; i < numberOfAliases; i++) { XSLNamespaceAlias xna = (XSLNamespaceAlias) namespaceAliasList.get(i); short scode = xna.getStylesheetURICode(); int ncode = xna.getResultNamespaceCode(); int prec = xna.getPrecedence(); // check that there isn't a conflict with another xsl:namespace-alias // at the same precedence if (currentPrecedence != prec) { currentPrecedence = prec; precedenceBoundary = i; } for (int j = precedenceBoundary; j < i; j++) { if (scode == aliasSCodes[j]) { if ((ncode & 0xffff) != (aliasNCodes[j] & 0xffff)) { xna.compileError("More than one alias is defined for the same namespace prefix", "XTSE0810"); } } } aliasSCodes[i] = scode; aliasNCodes[i] = ncode; } namespaceAliasList = null; // throw it in the garbage } protected boolean hasNamespaceAliases() { return numberOfAliases > 0; } /** * Process the attributes of every node in the stylesheet */ public void processAllAttributes() throws XPathException { processDefaultCollationAttribute(StandardNames.DEFAULT_COLLATION); prepareAttributes(); if (topLevel == null) return; // can happen if xsl:stylesheet appears in the wrong place for (int i = 0; i < topLevel.size(); i++) { Object s = topLevel.get(i); if (s instanceof StyleElement) { try { ((StyleElement) s).processAllAttributes(); } catch (XPathException err) { ((StyleElement) s).compileError(err); } } } } /** * Get the global variable or parameter with a given name (taking * precedence rules into account) * @param qName name of the global variable or parameter * @return the variable declaration */ public XSLVariableDeclaration getGlobalVariable(StructuredQName qName) { return (XSLVariableDeclaration) globalVariableIndex.get(qName); } /** * Set that this stylesheet needs dynamic output properties * @param b true if this stylesheet needs dynamic output properties */ public void setNeedsDynamicOutputProperties(boolean b) { needsDynamicOutputProperties = b; } /** * Create an output properties object representing the xsl:output elements in the stylesheet. * @param formatQName The name of the output format required. If set to null, gathers * information for the unnamed output format * @return the Properties object containing the details of the specified output format * @throws XPathException if a named output format does not exist in * the stylesheet */ public Properties gatherOutputProperties(StructuredQName formatQName) throws XPathException { boolean found = (formatQName == null); Properties details = new Properties(); HashMap precedences = new HashMap(10); for (int i = topLevel.size()-1; i >= 0; i--) { Object s = topLevel.get(i); if (s instanceof XSLOutput) { XSLOutput xo = (XSLOutput) s; if (formatQName == null ? xo.getFormatQName() == null : formatQName.equals(xo.getFormatQName())) { found = true; xo.gatherOutputProperties(details, precedences); } } } if (!found) { compileError("Requested output format " + formatQName.getDisplayName() + " has not been defined", "XTDE1460"); } return details; } /** * Declare an imported XQuery function * @param function the imported function */ protected void declareXQueryFunction(XQueryFunction function) throws XPathException { queryFunctions.declareFunction(function); } /** * Declare a URI that maps to a Java class containing extension functions * @param uri the namespace uri used in the function names * @param theClass the Java class containing methods accessible using this URI */ protected void declareJavaClass(String uri, Class theClass) { Configuration.getPlatform().declareJavaClass(javaFunctions, uri, theClass); } /** * Get an imported schema with a given namespace * @param targetNamespace The target namespace of the required schema. * Supply an empty string for the default namespace * @return the required Schema, or null if no such schema has been imported */ protected boolean isImportedSchema(String targetNamespace) { return schemaIndex.contains(targetNamespace); } protected void addImportedSchema(String targetNamespace) { schemaIndex.add(targetNamespace); } protected HashSet getImportedSchemaTable() { return schemaIndex; } /** * Compile the stylesheet to create an executable. * @return the Executable representing the compiled stylesheet */ public Executable compileStylesheet() throws XPathException { try { // If any XQuery functions were imported, fix up all function calls // registered against these functions. try { //queryFunctions.bindUnboundFunctionCalls(); Iterator qf = queryFunctions.getFunctionDefinitions(); while (qf.hasNext()) { XQueryFunction f = (XQueryFunction) qf.next(); f.fixupReferences(getStaticContext()); } } catch (XPathException e) { compileError(e); } // Call compile method for each top-level object in the stylesheet for (int i = 0; i < topLevel.size(); i++) { NodeInfo node = (NodeInfo) topLevel.get(i); if (node instanceof StyleElement) { StyleElement snode = (StyleElement) node; //int module = putModuleNumber(snode.getSystemId()); Expression inst = snode.compile(exec); if (inst != null) { inst.setLocationId(allocateLocationId(getSystemId(), snode.getLineNumber())); } } } // Fix up references to the default default decimal format if (exec.getDecimalFormatManager() != null) { try { exec.getDecimalFormatManager().fixupDefaultDefault(); } catch (XPathException err) { compileError(err.getMessage(), err.getErrorCodeLocalPart()); } } exec.setStripsWhitespace(stripsWhitespace()); Properties props = gatherOutputProperties(null); props.setProperty(SaxonOutputKeys.STYLESHEET_VERSION, getVersion().toString()); exec.setDefaultOutputProperties(props); // handle named output formats for use at run-time HashSet outputNames = new HashSet(5); for (int i=0; i 0) { // do nothing return exec; } else { // rethrow the exception throw err; } } } /** * Dummy compile() method to satisfy the interface */ public Expression compile(Executable exec) { return null; } /** * Allocate a unique number to a local parameter name. This should only be called on the principal * stylesheet module. * @param qName the local parameter name * @return an integer that uniquely identifies this parameter name within the stylesheet */ public int allocateUniqueParameterNumber(StructuredQName qName) { if (localParameterNumbers == null) { localParameterNumbers = new HashMap(50); } Integer x = (Integer)localParameterNumbers.get(qName); if (x == null) { x = new Integer(localParameterNumbers.size()); localParameterNumbers.put(qName, x); } return x.intValue(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/style/SaxonIterate.java0000644000175000017500000001001411033112257022004 0ustar eugeneeugenepackage net.sf.saxon.style; import net.sf.saxon.expr.Expression; import net.sf.saxon.expr.IterateInstr; import net.sf.saxon.expr.Literal; import net.sf.saxon.instruct.Executable; import net.sf.saxon.om.*; import net.sf.saxon.trans.SaxonErrorCode; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ItemType; import java.util.ArrayList; import java.util.List; /** * Handler for saxon:iterate elements in stylesheet.
    */ public class SaxonIterate extends StyleElement { Expression select = null; /** * Determine whether this node is an instruction. * @return true - it is an instruction */ public boolean isInstruction() { return true; } /** * Specify that xsl:sort is a permitted child */ protected boolean isPermittedChild(StyleElement child) { return (child instanceof XSLParam); } /** * Determine the type of item returned by this instruction (only relevant if * it is an instruction). * @return the item type returned */ protected ItemType getReturnedItemType() { return getCommonChildItemType(); } /** * Determine whether this type of element is allowed to contain a template-body * @return true: yes, it may contain a template-body */ public boolean mayContainSequenceConstructor() { return true; } protected boolean mayContainParam() { return true; } public void prepareAttributes() throws XPathException { AttributeCollection atts = getAttributeList(); String selectAtt = null; for (int a=0; a */ public class XSLPreserveSpace extends StyleElement { private String elements; public void prepareAttributes() throws XPathException { AttributeCollection atts = getAttributeList(); for (int a=0; a */ public abstract class XSLVariableDeclaration extends XSLGeneralVariable implements VariableDeclaration, StylesheetProcedure { // The slot number for the variable is allocated at this level (a) for global variables, and // (b) for local parameters. For local variables, slot numbers are allocated only after an entire // template or function has been compiled. private int slotNumber = -9876; // initial value designed solely to show up when debugging // List of VariableReference objects that reference this XSLVariableDeclaration protected List references = new ArrayList(10); /** * Get the SlotManager associated with this stylesheet construct. The SlotManager contains the * information needed to manage the local stack frames used by run-time instances of the code. * @return the associated SlotManager object */ public SlotManager getSlotManager() { return slotManager; } /** * Get the slot number allocated to this variable (its position in the stackframe) * @return the allocated slot number */ public int getSlotNumber() { return slotNumber; } /** * Allocate a slot number to this variable * @param slot the position of the variable on the local stack frame */ public void setSlotNumber(int slot) { slotNumber = slot; } /** * Get the static type of the variable. * @return the static type declared for the variable */ public abstract SequenceType getRequiredType(); /** * Method called by VariableReference to register the variable reference for * subsequent fixup */ public void registerReference(BindingReference ref) { references.add(ref); } /** * Determine whether this node is an instruction. * @return true - it is an instruction (well, it can be, anyway) */ public boolean isInstruction() { return true; } /** * Notify all references to this variable of the data type */ public void fixupReferences() throws XPathException { final SequenceType type = getRequiredType(); final TypeHierarchy th = getConfiguration().getTypeHierarchy(); final Iterator iter = references.iterator(); while (iter.hasNext()) { Value constantValue = null; int properties = 0; if (this instanceof XSLVariable && !isAssignable()) { if (select instanceof Literal) { // we can't rely on the constant value because it hasn't yet been type-checked, // which could change it (eg by numeric promotion). Rather than attempt all the type-checking // now, we do a quick check. See test bug64 int relation = th.relationship(select.getItemType(th), type.getPrimaryType()); if (relation == TypeHierarchy.SAME_TYPE || relation == TypeHierarchy.SUBSUMED_BY) { constantValue = ((Literal)select).getValue(); } } if (select != null) { properties = select.getSpecialProperties(); } } ((BindingReference)iter.next()).setStaticType(type, constantValue, properties); } super.fixupReferences(); } /** * Check that the variable is not already declared, and allocate a slot number */ public void validate() throws XPathException { super.validate(); if (global) { if (!redundant) { slotNumber = getPrincipalStylesheet().allocateGlobalSlot(getVariableQName()); } } } /** * Notify all variable references of the Binding instruction * @param binding the Binding that represents this variable declaration in the executable code tree */ protected void fixupBinding(Binding binding) { Iterator iter = references.iterator(); while (iter.hasNext()) { ((BindingReference)iter.next()).fixup(binding); } } /** * Set the number of references to this variable. This code is invoked only for a global variable, * and only if there is at least one reference. * @param var the variable */ protected void setReferenceCount(GeneralVariable var) { // int referenceCount = RangeVariable.getReferenceCount( // references, false); // if (referenceCount < 10) { // // allow for the fact that the references may be in functions that are executed repeatedly // referenceCount = 10; // } // var.setReferenceCount(referenceCount); var.setReferenceCount(10); // TODO: temporary } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/style/XSLImportSchema.java0000644000175000017500000001244511033112257022372 0ustar eugeneeugenepackage net.sf.saxon.style; import net.sf.saxon.Configuration; import net.sf.saxon.PreparedStylesheet; import net.sf.saxon.value.Whitespace; import net.sf.saxon.trans.XPathException; import net.sf.saxon.trans.SaxonErrorCode; import net.sf.saxon.event.PipelineConfiguration; import net.sf.saxon.expr.Expression; import net.sf.saxon.instruct.Executable; import net.sf.saxon.om.*; import net.sf.saxon.type.SchemaException; import javax.xml.transform.TransformerConfigurationException; /** * Compile-time representation of an xsl:import-schema declaration * in a stylesheet */ public class XSLImportSchema extends StyleElement { public void prepareAttributes() throws XPathException { AttributeCollection atts = getAttributeList(); String namespace = null; for (int a=0; a */ public class XSLImport extends XSLGeneralIncorporate { /** * isImport() returns true if this is an xsl:import statement rather than an xsl:include */ public boolean isImport() { return true; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/style/XSLParam.java0000644000175000017500000001504111033112257021032 0ustar eugeneeugenepackage net.sf.saxon.style; import net.sf.saxon.expr.*; import net.sf.saxon.instruct.*; import net.sf.saxon.om.Axis; import net.sf.saxon.om.AxisIterator; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.SequenceType; import net.sf.saxon.value.Whitespace; import net.sf.saxon.Configuration; /** * An xsl:param element in the stylesheet.
    * The xsl:param element has mandatory attribute name and optional attributes * select, required, as, ... */ public class XSLParam extends XSLVariableDeclaration { Expression conversion = null; protected boolean allowsValue() { return !(getParent() instanceof XSLFunction); // function parameters cannot take a default value } protected boolean allowsRequired() { return !(getParent() instanceof XSLFunction); // function parameters cannot take the "required" attribute } protected boolean allowsTunnelAttribute() { return true; } public void validate() throws XPathException { NodeInfo parent = getParent(); global = (parent instanceof XSLStylesheet); if (!((parent instanceof StyleElement) && ((StyleElement)parent).mayContainParam())) { compileError("xsl:param must be immediately within a template, function or stylesheet", "XTSE0010"); } if (!global) { AxisIterator preceding = iterateAxis(Axis.PRECEDING_SIBLING); while (true) { NodeInfo node = (NodeInfo)preceding.next(); if (node == null) { break; } if (node instanceof XSLParam) { if (this.getVariableQName().equals(((XSLParam)node).getVariableQName())) { compileError("The name of the parameter is not unique", "XTSE0580"); } } else if (node instanceof StyleElement) { compileError("xsl:param must be the first element within a template or function", "XTSE0010"); } else { // it must be a text node; allow it if all whitespace if (!Whitespace.isWhite(node.getStringValueCS())) { compileError("xsl:param must not be preceded by text", "XTSE0010"); } } } SlotManager p = getContainingSlotManager(); if (p==null) { compileError("Local variable must be declared within a template or function", "XTSE0010"); } else { setSlotNumber(p.allocateSlotNumber(getVariableQName())); } } if (requiredParam) { if (select != null) { // NB, we do this test before setting the default select attribute compileError("The select attribute should be omitted when required='yes'", "XTSE0010"); } if (hasChildNodes()) { compileError("A parameter specifying required='yes' must have empty content", "XTSE0010"); } } super.validate(); } /** * Compile: this ensures space is available for local variables declared within * this global variable */ public Expression compile(Executable exec) throws XPathException { if (redundant) { return null; } if (getParent() instanceof XSLFunction) { // Do nothing. We did everything necessary while compiling the XSLFunction element. return null; } else { int slot = getSlotNumber(); if (requiredType != null) { SuppliedParameterReference pref = new SuppliedParameterReference(slot); pref.setLocationId(staticContext.getLocationMap().allocateLocationId(getSystemId(), getLineNumber())); RoleLocator role = new RoleLocator(RoleLocator.PARAM, getVariableDisplayName(), 0); //role.setSourceLocator(new ExpressionLocation(this)); role.setErrorCode("XTTE0590"); conversion = TypeChecker.staticTypeCheck( pref, requiredType, false, role, makeExpressionVisitor()); } GeneralVariable inst; if (global) { inst = new GlobalParam(); ((GlobalParam)inst).setHostLanguage(Configuration.XSLT); ((GlobalParam)inst).setExecutable(getExecutable()); ((GlobalParam)inst).setContainer(((GlobalParam)inst)); if (isRequiredParam()) { getExecutable().addRequiredParam(getVariableQName()); } if (select != null) { select.setContainer(((GlobalVariable)inst)); } } else { inst = new LocalParam(); ((LocalParam)inst).setConversion(conversion); ((LocalParam)inst).setParameterId( getPrincipalStylesheet().allocateUniqueParameterNumber(getVariableQName())); } initializeInstruction(exec, inst); inst.setVariableQName(getVariableQName()); inst.setSlotNumber(slot); inst.setRequiredType(getRequiredType()); fixupBinding(inst); return inst; } } /** * Get the static type of the parameter. This is the declared type, because we cannot know * the actual value in advance. */ public SequenceType getRequiredType() { if (requiredType!=null) { return requiredType; } else { return SequenceType.ANY_SEQUENCE; } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/style/ExpressionContext.java0000644000175000017500000002762011033112257023115 0ustar eugeneeugenepackage net.sf.saxon.style; import net.sf.saxon.Configuration; import net.sf.saxon.trans.Err; import net.sf.saxon.expr.EarlyEvaluationContext; import net.sf.saxon.expr.VariableReference; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.expr.LocalVariableReference; import net.sf.saxon.functions.FunctionLibrary; import net.sf.saxon.instruct.Executable; import net.sf.saxon.instruct.LocationMap; import net.sf.saxon.om.*; import net.sf.saxon.sort.StringCollator; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.BuiltInAtomicType; import javax.xml.transform.SourceLocator; import java.util.Set; /** * An ExpressionContext represents the context for an XPath expression written * in the stylesheet. */ public class ExpressionContext implements XSLTStaticContext { private StyleElement element; private NamePool namePool; private NamespaceResolver namespaceResolver = null; /** * Create a static context for XPath expressions in an XSLT stylesheet * @param styleElement the element on which the XPath expression appears */ public ExpressionContext(StyleElement styleElement) { element = styleElement; namePool = styleElement.getNamePool(); } /** * Get the system configuration */ public Configuration getConfiguration() { return element.getConfiguration(); } /** * Get the executable * @return the executable */ public Executable getExecutable() { return element.getExecutable(); } /** * Construct a dynamic context for early evaluation of constant subexpressions */ public XPathContext makeEarlyEvaluationContext() { return new EarlyEvaluationContext(getConfiguration(), element.getPrincipalStylesheet().getCollationMap()); } /** * Get the location map */ public LocationMap getLocationMap() { return element.getPrincipalStylesheet().getLocationMap(); } /** * Issue a compile-time warning */ public void issueWarning(String s, SourceLocator locator) { element.issueWarning(s, locator); } /** * Get the NamePool used for compiling expressions */ public NamePool getNamePool() { return namePool; } /** * Get the System ID of the entity containing the expression (used for diagnostics) */ public String getSystemId() { return element.getSystemId(); } /** * Get the line number of the expression within its containing entity * Returns -1 if no line number is available */ public int getLineNumber() { return element.getLineNumber(); } /** * Get the Base URI of the element containing the expression, for resolving any * relative URI's used in the expression. * Used by the document() function. */ public String getBaseURI() { return element.getBaseURI(); } /** * Get the URI for a prefix, using this Element as the context for namespace resolution. * The default namespace will not be used when the prefix is empty. * @param prefix The prefix * @throws XPathException if the prefix is not declared */ public String getURIForPrefix(String prefix) throws XPathException { String uri = element.getURIForPrefix(prefix, false); if (uri == null) { XPathException err = new XPathException("Undeclared namespace prefix " + Err.wrap(prefix)); err.setErrorCode("XPST0081"); err.setIsStaticError(true); throw err; } return uri; } /** * Get a copy of the NamespaceResolver suitable for saving in the executable code * @return a NamespaceResolver */ public NamespaceResolver getNamespaceResolver() { if (namespaceResolver == null) { namespaceResolver = element.makeNamespaceContext(); } return namespaceResolver; } /** * Get a fingerprint for a name, using this as the context for namespace resolution * @param qname The name as written, in the form "[prefix:]localname" * @param useDefault Defines the action when there is no prefix. If true, use * the default namespace URI (as for element names). If false, use no namespace URI * (as for attribute names). * @return -1 if the name is not already present in the name pool */ public int getFingerprint(String qname, boolean useDefault) throws XPathException { String[] parts; try { parts = getConfiguration().getNameChecker().getQNameParts(qname); } catch (QNameException err) { throw new XPathException(err.getMessage()); } String prefix = parts[0]; if (prefix.length() == 0) { String uri = ""; if (useDefault) { uri = getURIForPrefix(prefix); } return namePool.getFingerprint(uri, qname); } else { String uri = getURIForPrefix(prefix); return namePool.getFingerprint(uri, parts[1]); } } /** * Get a StructuredQName for a name, using this as the context for namespace resolution * @param qname The name as written, in the form "[prefix:]localname" * @param useDefault Defines the action when there is no prefix. If true, use * the default namespace URI (as for element names). If false, use no namespace URI * (as for attribute names). * @return -1 if the name is not already present in the name pool */ public StructuredQName getStructuredQName(String qname, boolean useDefault) throws XPathException { String[] parts; try { parts = getConfiguration().getNameChecker().getQNameParts(qname); } catch (QNameException err) { throw new XPathException(err.getMessage()); } String prefix = parts[0]; if (prefix.length() == 0) { String uri = ""; if (useDefault) { uri = getURIForPrefix(prefix); } return new StructuredQName("", uri, qname); } else { String uri = getURIForPrefix(prefix); return new StructuredQName(prefix, uri, parts[1]); } } /** * Bind a variable to an object that can be used to refer to it * @param qName the name of the variable * @return a VariableDeclaration object that can be used to identify it in the Bindery * @throws XPathException if the variable has not been declared */ public VariableReference bindVariable(StructuredQName qName) throws XPathException { XSLVariableDeclaration xslVariableDeclaration = element.bindVariable(qName); VariableReference var = (xslVariableDeclaration.isGlobal() ? new VariableReference() : new LocalVariableReference()); xslVariableDeclaration.registerReference(var); return var; } /** * Get the function library containing all the in-scope functions available in this static * context */ public FunctionLibrary getFunctionLibrary() { return element.getPrincipalStylesheet().getFunctionLibrary(); } /** * Determine if an extension element is available * @throws XPathException if the name is invalid or the prefix is not declared */ public boolean isElementAvailable(String qname) throws XPathException { try { String[] parts = getConfiguration().getNameChecker().getQNameParts(qname); String uri; if (parts[0].length() == 0) { uri = getDefaultElementNamespace(); } else { uri = getURIForPrefix(parts[0]); } return element.getPreparedStylesheet(). getStyleNodeFactory().isElementAvailable(uri, parts[1]); } catch (QNameException e) { XPathException err = new XPathException("Invalid element name. " + e.getMessage()); err.setErrorCode("XTDE1440"); throw err; } } /** * Get a named collation. * @param name The name of the required collation. Supply null to get the default collation. * @return the collation; or null if the required collation is not found. */ public StringCollator getCollation(String name) { return element.getPrincipalStylesheet().findCollation(name); } /** * Get the default collation. Return null if no default collation has been defined */ public String getDefaultCollationName() { return element.getDefaultCollationName(); //return element.getPrincipalStylesheet().getDefaultCollationName(); } /** * Get the default XPath namespace for elements and types * Return NamespaceConstant.NULL for the non-namespace */ public String getDefaultElementNamespace() { return element.getDefaultXPathNamespace(); } /** * Get the default function namespace */ public String getDefaultFunctionNamespace() { return NamespaceConstant.FN; } /** * Determine whether Backwards Compatible Mode is used */ public boolean isInBackwardsCompatibleMode() { return element.backwardsCompatibleModeIsEnabled(); } /** * Test whether a schema has been imported for a given namespace * @param namespace the target namespace of the required schema * @return true if a schema for this namespace has been imported */ public boolean isImportedSchema(String namespace) { return getXSLStylesheet().isImportedSchema(namespace); } /** * Get the set of imported schemas * @return a Set, the set of URIs representing the names of imported schemas */ public Set getImportedSchemaNamespaces() { return getXSLStylesheet().getImportedSchemaTable(); } /** * Determine whether a built-in type is available in this context. This method caters for differences * between host languages as to which set of types are built in. * * @param type the supposedly built-in type. This will always be a type in the * XS or XDT namespace. * @return true if this type can be used in this static context */ public boolean isAllowedBuiltInType(BuiltInAtomicType type) { return getConfiguration().isSchemaAware(Configuration.XSLT) || type.isAllowedInBasicXSLT() || getXSLStylesheet().allowsAllBuiltInTypes(); } /** * Get the XSLStylesheet object * @return the XSLStylesheet object representing the outermost element of the stylesheet module */ public XSLStylesheet getXSLStylesheet() { return element.getPrincipalStylesheet(); } /** * Get the stylesheet element containing this XPath expression * @return the element in the tree representation of the source stylesheet */ public StyleElement getStyleElement() { return element; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/style/XSLCallTemplate.java0000644000175000017500000002507011033112257022344 0ustar eugeneeugenepackage net.sf.saxon.style; import net.sf.saxon.trans.Err; import net.sf.saxon.expr.Expression; import net.sf.saxon.instruct.CallTemplate; import net.sf.saxon.instruct.Executable; import net.sf.saxon.instruct.Template; import net.sf.saxon.om.*; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.AnyItemType; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.Type; import net.sf.saxon.value.SequenceType; import net.sf.saxon.value.Whitespace; import java.util.List; /** * An xsl:call-template element in the stylesheet */ public class XSLCallTemplate extends StyleElement { private StructuredQName calledTemplateName; // the name of the called template private XSLTemplate template = null; private boolean useTailRecursion = false; private Expression calledTemplateExpression; // allows name to be an AVT /** * Determine whether the called template can be specified as an AVT * @return true if the template name can be specified at run-time, that is, if this is a saxon:call-template * instruction */ protected boolean allowAVT() { return false; } /** * Determine whether this node is an instruction. * @return true - it is an instruction */ public boolean isInstruction() { return true; } /** * Determine the type of item returned by this instruction (only relevant if * it is an instruction). * @return the item type returned */ protected ItemType getReturnedItemType() { if (template==null) { return AnyItemType.getInstance(); } else { return template.getReturnedItemType(); } } public void prepareAttributes() throws XPathException { AttributeCollection atts = getAttributeList(); String nameAttribute = null; for (int a=0; a=0) { calledTemplateExpression = makeAttributeValueTemplate(nameAttribute); } else { try { calledTemplateName = makeQName(nameAttribute); } catch (NamespaceException err) { calledTemplateName = new StructuredQName("saxon", NamespaceConstant.SAXON, "error-template"); compileError(err.getMessage(), "XTSE0280"); } catch (XPathException err) { calledTemplateName = new StructuredQName("saxon", NamespaceConstant.SAXON, "error-template"); compileError(err.getMessage(), err.getErrorCodeLocalPart()); } } } public void validate() throws XPathException { AxisIterator kids = iterateAxis(Axis.CHILD); while (true) { NodeInfo child = (NodeInfo)kids.next(); if (child == null) { break; } if (child instanceof XSLWithParam) { // OK; } else if (child instanceof XSLFallback && mayContainFallback()) { // xsl:fallback is not allowed on xsl:call-template, but is allowed on saxon:call-template (cheat!) } else if (child.getNodeKind() == Type.TEXT) { // with xml:space=preserve, white space nodes may still be there if (!Whitespace.isWhite(child.getStringValueCS())) { compileError("No character data is allowed within xsl:call-template", "XTSE0010"); } } else { compileError("Child element " + Err.wrap(child.getDisplayName(), Err.ELEMENT) + " is not allowed within xsl:call-template", "XTSE0010"); } } if (calledTemplateExpression==null && !(calledTemplateName.getNamespaceURI().equals(NamespaceConstant.SAXON) && calledTemplateName.getLocalName().equals("error-template"))) { template = findTemplate(calledTemplateName); if (template==null) { return; } } calledTemplateExpression = typeCheck("name", calledTemplateExpression); } public void postValidate() throws XPathException { // check that a parameter is supplied for each required parameter // of the called template if (template != null) { AxisIterator declaredParams = template.iterateAxis(Axis.CHILD); while(true) { NodeInfo param = (NodeInfo)declaredParams.next(); if (param == null) { break; } if (param instanceof XSLParam && ((XSLParam)param).isRequiredParam() && !((XSLParam)param).isTunnelParam()) { AxisIterator actualParams = iterateAxis(Axis.CHILD); boolean ok = false; while(true) { NodeInfo withParam = (NodeInfo)actualParams.next(); if (withParam == null) { break; } if (withParam instanceof XSLWithParam && ((XSLWithParam)withParam).getVariableQName().equals( ((XSLParam)param).getVariableQName())) { ok = true; break; } } if (!ok) { compileError("No value supplied for required parameter " + Err.wrap(((XSLParam)param).getVariableDisplayName(), Err.VARIABLE), "XTSE0690"); } } } // check that every supplied parameter is declared in the called // template AxisIterator actualParams = iterateAxis(Axis.CHILD); while(true) { NodeInfo w = (NodeInfo)actualParams.next(); if (w == null) { break; } if (w instanceof XSLWithParam && !((XSLWithParam)w).isTunnelParam()) { XSLWithParam withParam = (XSLWithParam)w; AxisIterator formalParams = template.iterateAxis(Axis.CHILD); boolean ok = false; while(true) { NodeInfo param = (NodeInfo)formalParams.next(); if (param == null) { break; } if (param instanceof XSLParam && ((XSLParam)param).getVariableQName().equals(withParam.getVariableQName())) { ok = true; SequenceType required = ((XSLParam)param).getRequiredType(); withParam.checkAgainstRequiredType(required); break; } } if (!ok) { if (!backwardsCompatibleModeIsEnabled()) { compileError("Parameter " + withParam.getVariableDisplayName() + " is not declared in the called template", "XTSE0680"); } } } } } } private XSLTemplate findTemplate(StructuredQName templateName) throws XPathException { XSLStylesheet stylesheet = getPrincipalStylesheet(); List toplevel = stylesheet.getTopLevel(); // search for a matching template name, starting at the end in case of duplicates. // this also ensures we get the one with highest import precedence. for (int i=toplevel.size()-1; i>=0; i--) { if (toplevel.get(i) instanceof XSLTemplate) { XSLTemplate t = (XSLTemplate)toplevel.get(i); if (templateName.equals(t.getTemplateName())) { return t; } } } compileError("No template exists named " + calledTemplateName, "XTSE0650"); return null; } /** * Mark tail-recursive calls on templates and functions. * For most instructions, this does nothing. */ public boolean markTailCalls() { useTailRecursion = true; return true; } public Expression compile(Executable exec) throws XPathException { Template target = null; NamespaceResolver nsContext = null; if (calledTemplateExpression==null) { if (template==null) { return null; // error already reported } target = template.getCompiledTemplate(); } else { //getPrincipalStyleSheet().setRequireRuntimeTemplateMap(true); nsContext = makeNamespaceContext(); } CallTemplate call = new CallTemplate ( target, useTailRecursion, calledTemplateExpression, nsContext ); call.setActualParameters(getWithParamInstructions(exec, false, call), getWithParamInstructions(exec, true, call)); return call; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/style/XSLCharacterMap.java0000644000175000017500000002147511117541257022345 0ustar eugeneeugenepackage net.sf.saxon.style; import net.sf.saxon.trans.Err; import net.sf.saxon.value.Whitespace; import net.sf.saxon.sort.IntHashMap; import net.sf.saxon.expr.Expression; import net.sf.saxon.instruct.Executable; import net.sf.saxon.om.*; import net.sf.saxon.trans.XPathException; import java.util.*; /** * An xsl:character-map declaration in the stylesheet.
    */ public class XSLCharacterMap extends StyleElement { //int fingerprint; // the name of this character map String use; // the value of the use-character-maps attribute, as supplied List characterMapElements = null; // list of XSLCharacterMap objects referenced by this one boolean validated = false; // set to true once validate() has been called boolean redundant = false; // set to true if another character-map overrrides this one /** * Get the fingerprint of the name of this character map * @return the fingerprint value */ public StructuredQName getCharacterMapName() { StructuredQName name = getObjectName(); if (name == null) { try { return makeQName(getAttributeValue("name")); } catch (Exception err) { // the error will be reported later return new StructuredQName("", "", "unnamedCharacterMap_" + hashCode()); } } return name; } /** * Test whether this character map is redundant (because another with the * same name has higher import precedence). Note that a character map is not * considered redundant simply because it is not referenced in an xsl:output * declaration; we allow character-maps to be selected at run-time using the * setOutputProperty() API. * @return true if this character map is redundant */ public boolean isRedundant() { return redundant; } /** * Validate the attributes on this instruction * @throws XPathException */ public void prepareAttributes() throws XPathException { String name = null; use = null; AttributeCollection atts = getAttributeList(); for (int a=0; a */ public class SaxonEntityRef extends StyleElement { String nameAttribute; /** * Determine whether this node is an instruction. * @return true - it is an instruction */ public boolean isInstruction() { return true; } public void prepareAttributes() throws XPathException { AttributeCollection atts = getAttributeList(); for (int a=0; a */ public class XSLMatchingSubstring extends StyleElement { /** * Determine the type of item returned by this instruction (only relevant if * it is an instruction). * @return the item type returned */ protected ItemType getReturnedItemType() { return getCommonChildItemType(); } public void prepareAttributes() throws XPathException { AttributeCollection atts = getAttributeList(); for (int a=0; a * This instruction creates a document node in the result tree, optionally * validating it. */ public class XSLDocument extends StyleElement { private int validationAction = Validation.STRIP; private SchemaType schemaType = null; /** * Determine whether this node is an instruction. * @return true - it is an instruction */ public boolean isInstruction() { return true; } /** * Determine whether this type of element is allowed to contain a template-body * @return true: yes, it may contain a template-body */ public boolean mayContainSequenceConstructor() { return true; } public void prepareAttributes() throws XPathException { AttributeCollection atts = getAttributeList(); String validationAtt = null; String typeAtt = null; for (int a=0; a */ public final class XSLMessage extends StyleElement { private Expression terminate = null; private Expression select = null; /** * Determine whether this node is an instruction. * @return true - it is an instruction */ public boolean isInstruction() { return true; } /** * Determine whether this type of element is allowed to contain a template-body * @return true: yes, it may contain a template-body */ public boolean mayContainSequenceConstructor() { return true; } public void prepareAttributes() throws XPathException { String terminateAtt = null; String selectAtt = null; AttributeCollection atts = getAttributeList(); for (int a=0; a * It is also used to represent unknown top-level elements, which are ignored. */ public class LiteralResultElement extends StyleElement { private int resultNameCode; private int[] attributeNames; private Expression[] attributeValues; private int numberOfAttributes; private boolean toplevel; private int[] namespaceCodes; private AttributeSet[] attributeSets; private SchemaType schemaType = null; private int validation = Validation.STRIP; private boolean inheritNamespaces = true; /** * Determine whether this type of element is allowed to contain a sequence constructor * @return true: yes, it may contain a sequence constructor */ public boolean mayContainSequenceConstructor() { return true; } /** * Specify that this is an instruction */ public boolean isInstruction() { return true; } /** * Process the attribute list */ public void prepareAttributes() throws XPathException { // Process the values of all attributes. At this stage we deal with attribute // values (especially AVTs), but we do not apply namespace aliasing to the // attribute names. int num = getAttributeList().getLength(); if (num == 0) { numberOfAttributes = 0; } else { NamePool namePool = getNamePool(); attributeNames = new int[num]; attributeValues = new Expression[num]; numberOfAttributes = 0; for (int i=0; i 0) { for (int i=0; i 0) { for (int i=attributeNames.length - 1; i>=0; i--) { FixedAttribute att = new FixedAttribute( attributeNames[i], Validation.STRIP, null, StandardNames.XS_UNTYPED_ATOMIC); try { att.setSelect(attributeValues[i], exec.getConfiguration()); } catch (XPathException err) { compileError(err); } att.setLocationId(allocateLocationId(getSystemId(), getLineNumber())); Expression exp = att; if (getConfiguration().isCompileWithTracing()) { TraceExpression trace = new TraceExpression(exp); trace.setLineNumber(getLineNumber()); trace.setColumnNumber(-1); trace.setSystemId(getSystemId()); trace.setNamespaceResolver(getNamespaceResolver()); trace.setConstructType(Location.LITERAL_RESULT_ATTRIBUTE); trace.setLocationId(allocateLocationId(getSystemId(), getLineNumber())); trace.setObjectName(new StructuredQName(getNamePool(), attributeNames[i])); exp = trace; } if (content == null) { content = exp; } else { content = Block.makeBlock(exp, content); content.setLocationId(allocateLocationId(getSystemId(), getLineNumber())); } } } if (attributeSets != null) { UseAttributeSets use = new UseAttributeSets(attributeSets); if (content == null) { content = use; } else { content = Block.makeBlock(use, content); content.setLocationId(allocateLocationId(getSystemId(), getLineNumber())); } } if (content == null) { content = Literal.makeEmptySequence(); } inst.setContentExpression(content); return inst; } /** * Make a top-level literal result element into a stylesheet. This implements * the "Simplified Stylesheet" facility. * @param pss the PreparedStylesheet (the compiled stylesheet as provided) * @param nodeFactory the node factory used to construct the stylesheet tree * @return the reconstructed stylesheet with an xsl:stylesheet and xsl:template element added */ public DocumentImpl makeStylesheet(PreparedStylesheet pss, StyleNodeFactory nodeFactory) throws XPathException { // the implementation grafts the LRE node onto a containing xsl:template and // xsl:stylesheet NamePool pool = getNamePool(); String xslPrefix = getPrefixForURI(NamespaceConstant.XSLT); if (xslPrefix==null) { String message; if (getLocalPart().equals("stylesheet") || getLocalPart().equals("transform")) { if (getPrefixForURI(NamespaceConstant.MICROSOFT_XSL) != null) { message = "Saxon is not able to process Microsoft's WD-xsl dialect"; } else { message = "Namespace for stylesheet element should be " + NamespaceConstant.XSLT; } } else { message = "The supplied file does not appear to be a stylesheet"; } XPathException err = new XPathException(message); err.setLocator(this); err.setErrorCode("XTSE0150"); err.setIsStaticError(true); //noinspection EmptyCatchBlock try { pss.reportError(err); } catch (TransformerException err2) { } throw err; } // check there is an xsl:version attribute (it's mandatory), and copy // it to the new xsl:stylesheet element String version = getAttributeValue(StandardNames.XSL_VERSION); if (version==null) { XPathException err = new XPathException("Simplified stylesheet: xsl:version attribute is missing"); err.setErrorCode("XTSE0150"); err.setIsStaticError(true); err.setLocator(this); //noinspection EmptyCatchBlock try { pss.reportError(err); } catch (TransformerException err2) { } throw err; } try { DocumentImpl oldRoot = (DocumentImpl)getDocumentRoot(); TreeBuilder builder = new TreeBuilder(); builder.setPipelineConfiguration(pss.getConfiguration().makePipelineConfiguration()); builder.setNodeFactory(nodeFactory); builder.setSystemId(this.getSystemId()); builder.open(); builder.startDocument(0); int st = StandardNames.XSL_STYLESHEET; builder.startElement(st, StandardNames.XS_UNTYPED, 0, 0); builder.namespace(NamespaceConstant.XSLT_CODE, 0); builder.attribute(pool.allocate("", "", "version"), StandardNames.XS_UNTYPED_ATOMIC, version, 0, 0); builder.startContent(); int te = StandardNames.XSL_TEMPLATE; builder.startElement(te, StandardNames.XS_UNTYPED, 0, 0); builder.attribute(pool.allocate("", "", "match"), StandardNames.XS_UNTYPED_ATOMIC, "/", 0, 0); builder.startContent(); builder.graftElement(this); builder.endElement(); builder.endElement(); builder.endDocument(); builder.close(); DocumentImpl newRoot = (DocumentImpl)builder.getCurrentRoot(); newRoot.graftLocationMap(oldRoot); return newRoot; } catch (XPathException err) { //TransformerConfigurationException e = new TransformerConfigurationException(err); err.setLocator(this); throw err; } } /** * Get the type of construct. This will be a constant in * class {@link net.sf.saxon.trace.Location}. This method is part of the * {@link net.sf.saxon.trace.InstructionInfo} interface */ public int getConstructType() { return Location.LITERAL_RESULT_ELEMENT; } /** * Get a name identifying the object of the expression, for example a function name, template name, * variable name, key name, element name, etc. This is used only where the name is known statically. * If there is no name, the value will be -1. * @return the name of the literal result element */ public int getObjectNameCode() { return resultNameCode; } /** * Get the value of a particular property of the instruction. This is part of the * {@link net.sf.saxon.trace.InstructionInfo} interface for run-time tracing and debugging. The properties * available include all the attributes of the source instruction (named by the attribute name): * these are all provided as string values. * @param name The name of the required property * @return The value of the requested property, or null if the property is not available */ public Object getProperty(String name) { if (name.equals("name")) { return getDisplayName(); } return null; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/style/AttributeValueTemplate.java0000644000175000017500000001304711033112257024043 0ustar eugeneeugenepackage net.sf.saxon.style; import net.sf.saxon.expr.*; import net.sf.saxon.functions.Concat; import net.sf.saxon.functions.SystemFunction; import net.sf.saxon.instruct.SimpleContentConstructor; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.BuiltInAtomicType; import net.sf.saxon.type.TypeHierarchy; import net.sf.saxon.value.Cardinality; import net.sf.saxon.value.StringValue; import java.util.ArrayList; import java.util.List; /** * This class represents an attribute value template. The class allows an AVT to be parsed, and * can construct an Expression that returns the effective value of the AVT. * * This is an abstract class that is never instantiated, it contains static methods only. */ public abstract class AttributeValueTemplate { private AttributeValueTemplate() {} /** * Static factory method to create an AVT from an XSLT string representation. */ public static Expression make(String avt, int lineNumber, StaticContext env) throws XPathException { List components = new ArrayList(5); int i0, i1, i8, i9; int len = avt.length(); int last = 0; ExpressionVisitor visitor = ExpressionVisitor.make(env); while (last < len) { i0 = avt.indexOf("{", last); i1 = avt.indexOf("{{", last); i8 = avt.indexOf("}", last); i9 = avt.indexOf("}}", last); if ((i0 < 0 || len < i0) && (i8 < 0 || len < i8)) { // found end of string addStringComponent(components, avt, last, len); break; } else if (i8 >= 0 && (i0 < 0 || i8 < i0)) { // found a "}" if (i8 != i9) { // a "}" that isn't a "}}" XPathException err = new XPathException("Closing curly brace in attribute value template \"" + avt.substring(0, len) + "\" must be doubled"); err.setErrorCode("XTSE0370"); err.setIsStaticError(true); throw err; } addStringComponent(components, avt, last, i8 + 1); last = i8 + 2; } else if (i1 >= 0 && i1 == i0) { // found a doubled "{{" addStringComponent(components, avt, last, i1 + 1); last = i1 + 2; } else if (i0 >= 0) { // found a single "{" if (i0 > last) { addStringComponent(components, avt, last, i0); } Expression exp; ExpressionParser parser = new ExpressionParser(); exp = parser.parse(avt, i0 + 1, Token.RCURLY, lineNumber, env); exp = visitor.simplify(exp); last = parser.getTokenizer().currentTokenStartOffset + 1; if (env.isInBackwardsCompatibleMode()) { components.add(makeFirstItem(exp, env)); } else { components.add(visitor.simplify( new SimpleContentConstructor(exp, new StringLiteral(StringValue.SINGLE_SPACE)))); } } else { throw new IllegalStateException("Internal error parsing AVT"); } } // is it empty? if (components.size() == 0) { return new StringLiteral(StringValue.EMPTY_STRING); } // is it a single component? if (components.size() == 1) { return visitor.simplify((Expression) components.get(0)); } // otherwise, return an expression that concatenates the components Expression[] args = new Expression[components.size()]; components.toArray(args); Concat fn = (Concat) SystemFunction.makeSystemFunction("concat", args); fn.setLocationId(env.getLocationMap().allocateLocationId(env.getSystemId(), lineNumber)); return visitor.simplify(fn); } private static void addStringComponent(List components, String avt, int start, int end) { if (start < end) { components.add(new StringLiteral(avt.substring(start, end))); } } /** * Make an expression that extracts the first item of a sequence, after atomization */ public static Expression makeFirstItem(Expression exp, StaticContext env) { final TypeHierarchy th = env.getConfiguration().getTypeHierarchy(); if (!exp.getItemType(th).isAtomicType()) { exp = new Atomizer(exp, env.getConfiguration()); } if (Cardinality.allowsMany(exp.getCardinality())) { exp = new FirstItemExpression(exp); } if (!th.isSubType(exp.getItemType(th), BuiltInAtomicType.STRING)) { exp = new AtomicSequenceConverter(exp, BuiltInAtomicType.STRING); } return exp; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/style/SaxonScript.java0000644000175000017500000001420211033112257021656 0ustar eugeneeugenepackage net.sf.saxon.style; import net.sf.saxon.expr.Expression; import net.sf.saxon.instruct.Executable; import net.sf.saxon.om.AttributeCollection; import net.sf.saxon.om.StandardNames; import net.sf.saxon.trans.SaxonErrorCode; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.Whitespace; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.util.StringTokenizer; /** * A saxon:script element in the stylesheet. */ public class SaxonScript extends StyleElement { private Class javaClass = null; private String implementsURI = null; private String language = null; public void prepareAttributes() throws XPathException { String languageAtt = null; String implementsAtt = null; String srcAtt = null; String archiveAtt = null; AttributeCollection atts = getAttributeList(); for (int a=0; a1 ? "s" : "")); } catch (java.lang.NoClassDefFoundError err2) { compileError("Cannot use the archive attribute with this Java VM"); } } } else { // language != java compileError("The only language supported for Saxon extension functions is 'java'"); } getPrincipalStylesheet().declareJavaClass(implementsURI, javaClass); } public void validate() throws XPathException { checkTopLevel(null); } public Expression compile(Executable exec) throws XPathException { return null; } /** * Get the Java class, if this saxon:script element matches the specified URI. * Otherwise return null */ // private Class getJavaClass(String uri) { // if (language==null) { // // allow for forwards references, but don't bother reporting // // any errors; that will happen when the element is processed // // in its own right. // try { // prepareAttributes(); // } catch (TransformerConfigurationException e) { // return null; // } // } // if (language.equals("java") && implementsURI.equals(uri)) { // return javaClass; // } else { // return null; // } // } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/style/XSLVariable.java0000644000175000017500000001365511033112257021530 0ustar eugeneeugenepackage net.sf.saxon.style; import net.sf.saxon.Configuration; import net.sf.saxon.expr.Expression; import net.sf.saxon.expr.Literal; import net.sf.saxon.expr.StaticProperty; import net.sf.saxon.instruct.Executable; import net.sf.saxon.instruct.GeneralVariable; import net.sf.saxon.instruct.GlobalVariable; import net.sf.saxon.instruct.LocalVariable; import net.sf.saxon.pattern.NodeKindTest; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.TypeHierarchy; import net.sf.saxon.value.SequenceType; /** * Handler for xsl:variable elements in stylesheet.
    * The xsl:variable element has mandatory attribute name and optional attribute select */ public class XSLVariable extends XSLVariableDeclaration { private int state = 0; // 0 = before prepareAttributes() // 1 = during prepareAttributes() // 2 = after prepareAttributes() public void prepareAttributes() throws XPathException { if (state==2) return; if (state==1) { compileError("Circular reference to variable", "XTDE0640"); } state = 1; //System.err.println("Prepare attributes of $" + getVariableName()); super.prepareAttributes(); state = 2; } /** * Determine whether this node is an instruction. * @return true - it is an instruction (well, it can be, anyway) */ public boolean isInstruction() { return true; } /** * Get the static type of the variable. This is the declared type, unless the value * is statically known and constant, in which case it is the actual type of the value. */ public SequenceType getRequiredType() { // System.err.println("Get required type of $" + getVariableName()); final TypeHierarchy th = getConfiguration().getTypeHierarchy(); SequenceType defaultType = (requiredType==null ? SequenceType.ANY_SEQUENCE : requiredType); if (assignable) { return defaultType; } else if (requiredType != null) { return requiredType; } else if (select!=null) { if (Literal.isEmptySequence(select)) { // returning Type.EMPTY gives problems with static type checking return defaultType; } else { try { // try to infer the type from the select expression return SequenceType.makeSequenceType(select.getItemType(th), select.getCardinality()); } catch (Exception err) { // this may fail because the select expression references a variable or function // whose type is not yet known, because of forwards (perhaps recursive) references. return defaultType; } } } else if (hasChildNodes()) { return SequenceType.makeSequenceType(NodeKindTest.DOCUMENT, StaticProperty.EXACTLY_ONE); } else { // no select attribute or content: value is an empty string return SequenceType.SINGLE_STRING; } } /** * Compile: used only for global variables. * This method ensures space is available for local variables declared within * this global variable */ public Expression compile(Executable exec) throws XPathException { if (references.isEmpty() && !assignable) { redundant = true; } if (!redundant) { GeneralVariable inst; if (global) { inst = new GlobalVariable(); ((GlobalVariable)inst).setExecutable(getExecutable()); ((GlobalVariable)inst).setHostLanguage(Configuration.XSLT); if (select != null) { select.setContainer(((GlobalVariable)inst)); } initializeInstruction(exec, inst); inst.setVariableQName(getVariableQName()); inst.setSlotNumber(getSlotNumber()); inst.setRequiredType(getRequiredType()); fixupBinding(inst); inst.setContainer(((GlobalVariable)inst)); return inst; } else { throw new AssertionError("Local variable found when compiling a global variable"); } } return null; } public Expression compileLocalVariable(Executable exec) throws XPathException { if (references.isEmpty() && !assignable) { redundant = true; } if (!redundant) { GeneralVariable inst; if (global) { throw new AssertionError("Global variable found when compiling local variable"); } else { inst = new LocalVariable(); inst.setContainer(this); if (select != null) { select.setContainer(this); } initializeInstruction(exec, inst); inst.setVariableQName(getVariableQName()); inst.setRequiredType(getRequiredType()); return inst; } } return null; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/style/XSLChoose.java0000644000175000017500000001742211033112257021217 0ustar eugeneeugenepackage net.sf.saxon.style; import net.sf.saxon.expr.Expression; import net.sf.saxon.expr.Literal; import net.sf.saxon.instruct.Choose; import net.sf.saxon.instruct.Executable; import net.sf.saxon.instruct.TraceWrapper; import net.sf.saxon.om.AttributeCollection; import net.sf.saxon.om.Axis; import net.sf.saxon.om.AxisIterator; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ItemType; import net.sf.saxon.value.BooleanValue; /** * An xsl:choose elements in the stylesheet.
    */ public class XSLChoose extends StyleElement { private StyleElement otherwise; private int numberOfWhens = 0; /** * Determine whether this node is an instruction. * @return true - it is an instruction */ public boolean isInstruction() { return true; } /** * Determine the type of item returned by this instruction (only relevant if * it is an instruction). * @return the item type returned */ protected ItemType getReturnedItemType() { return getCommonChildItemType(); } public void prepareAttributes() throws XPathException { AttributeCollection atts = getAttributeList(); for (int a=0; a */ public final class XSLComment extends XSLStringConstructor { public void prepareAttributes() throws XPathException { String selectAtt = null; AttributeCollection atts = getAttributeList(); for (int a=0; a */ public class XSLInclude extends XSLGeneralIncorporate { /** * isImport() returns true if this is an xsl:import statement rather than an xsl:include */ public boolean isImport() { return false; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/style/ExtensionElementFactory.java0000644000175000017500000000253111033112257024221 0ustar eugeneeugenepackage net.sf.saxon.style; /** * Interface ExtensionElementFactory.
    * A "Factory" for user-defined nodes in the stylesheet tree.
    * (Actually, it's not strictly a factory: it doesn't create the nodes, * it merely identifies what class they should be. */ public interface ExtensionElementFactory { /** * Identify the class to be used for stylesheet elements with a given local name. * The returned class must extend net.sf.saxon.style.StyleElement * @return null if the local name is not a recognised element type in this * namespace. */ public Class getExtensionClass(String localname); } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/style/XSLNumber.java0000644000175000017500000002607111033112257021227 0ustar eugeneeugenepackage net.sf.saxon.style; import net.sf.saxon.expr.*; import net.sf.saxon.instruct.Executable; import net.sf.saxon.instruct.NumberInstruction; import net.sf.saxon.instruct.ValueOf; import net.sf.saxon.number.NumberFormatter; import net.sf.saxon.number.Numberer; import net.sf.saxon.number.Numberer_en; import net.sf.saxon.om.AttributeCollection; import net.sf.saxon.om.StandardNames; import net.sf.saxon.pattern.NodeKindTest; import net.sf.saxon.pattern.Pattern; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ItemType; import net.sf.saxon.value.SequenceType; import net.sf.saxon.value.Whitespace; /** * An xsl:number element in the stylesheet.
    */ public class XSLNumber extends StyleElement { private static final int SINGLE = 0; private static final int MULTI = 1; private static final int ANY = 2; private static final int SIMPLE = 3; private int level; private Pattern count = null; private Pattern from = null; private Expression select = null; private Expression value = null; private Expression format = null; private Expression groupSize = null; private Expression groupSeparator = null; private Expression letterValue = null; private Expression lang = null; private Expression ordinal = null; private NumberFormatter formatter = null; private Numberer numberer = null; private boolean hasVariablesInPatterns = false; private static Numberer defaultNumberer = new Numberer_en(); /** * Determine whether this node is an instruction. * @return true - it is an instruction */ public boolean isInstruction() { return true; } /** * Determine the type of item returned by this instruction (only relevant if * it is an instruction). * @return the item type returned */ protected ItemType getReturnedItemType() { return NodeKindTest.TEXT; } public void prepareAttributes() throws XPathException { AttributeCollection atts = getAttributeList(); String selectAtt = null; String valueAtt = null; String countAtt = null; String fromAtt = null; String levelAtt = null; String formatAtt = null; String gsizeAtt = null; String gsepAtt = null; String langAtt = null; String letterValueAtt = null; String ordinalAtt = null; for (int a=0; a=0) { hasVariablesInPatterns = true; } } if (fromAtt!=null) { from = makePattern(fromAtt); if (fromAtt.indexOf('$')>=0) { hasVariablesInPatterns = true; } } if (levelAtt==null) { level = SINGLE; } else if (levelAtt.equals("single")) { level = SINGLE; } else if (levelAtt.equals("multiple")) { level = MULTI; } else if (levelAtt.equals("any")) { level = ANY; } else { compileError("Invalid value for level attribute", "XTSE0020"); } if (level==SINGLE && from==null && count==null) { level=SIMPLE; } if (formatAtt != null) { format = makeAttributeValueTemplate(formatAtt); if (format instanceof StringLiteral) { formatter = new NumberFormatter(); formatter.prepare(((StringLiteral)format).getStringValue()); } // else we'll need to allocate the formatter at run-time } else { formatter = new NumberFormatter(); formatter.prepare("1"); } if (gsepAtt!=null && gsizeAtt!=null) { // the spec says that if only one is specified, it is ignored groupSize = makeAttributeValueTemplate(gsizeAtt); groupSeparator = makeAttributeValueTemplate(gsepAtt); } if (langAtt==null) { numberer = defaultNumberer; } else { lang = makeAttributeValueTemplate(langAtt); if (lang instanceof StringLiteral) { numberer = makeNumberer(((StringLiteral)lang).getStringValue()); } // else we allocate a numberer at run-time } if (letterValueAtt != null) { letterValue = makeAttributeValueTemplate(letterValueAtt); } if (ordinalAtt != null) { ordinal = makeAttributeValueTemplate(ordinalAtt); } } public void validate() throws XPathException { checkEmpty(); select = typeCheck("select", select); value = typeCheck("value", value); format = typeCheck("format", format); groupSize = typeCheck("group-size", groupSize); groupSeparator = typeCheck("group-separator", groupSeparator); letterValue = typeCheck("letter-value", letterValue); ordinal = typeCheck("ordinal", ordinal); lang = typeCheck("lang", lang); from = typeCheck("from", from); count = typeCheck("count", count); if (select != null) { try { RoleLocator role = new RoleLocator(RoleLocator.INSTRUCTION, "xsl:number/select", 0); //role.setSourceLocator(new ExpressionLocation(this)); role.setErrorCode("XTTE1000"); select = TypeChecker.staticTypeCheck(select, SequenceType.SINGLE_NODE, false, role, makeExpressionVisitor()); } catch (XPathException err) { compileError(err); } } } public Expression compile(Executable exec) throws XPathException { NumberInstruction expr = new NumberInstruction (exec.getConfiguration(), select, level, count, from, value, format, groupSize, groupSeparator, letterValue, ordinal, lang, formatter, numberer, hasVariablesInPatterns, backwardsCompatibleModeIsEnabled()); int loc = getStaticContext().getLocationMap().allocateLocationId(getSystemId(), getLineNumber()); expr.setLocationId(loc); ValueOf inst = new ValueOf(expr, false, false); inst.setLocationId(allocateLocationId(getSystemId(), getLineNumber())); inst.setIsNumberingInstruction(); return inst; } /** * Load a Numberer class for a given language and check it is OK. * @param language the identifier of the language, for example "en" or "de" * @return the Numberer to use for that language. If a class named "net.sf.saxon.number.Numberer_XX" exists, * this class is instantiated, otherwise the Numberer for the default language (English) is returned. */ protected Numberer makeNumberer (String language) { Numberer numberer; if (language.equals("en")) { numberer = defaultNumberer; } else { String langClassName = "net.sf.saxon.number.Numberer_"; for (int i=0; i */ public final class XSLCopyOf extends StyleElement { private Expression select; private boolean copyNamespaces; private int validation = Validation.PRESERVE; private SchemaType schemaType; private boolean readOnce = false; // extension attribute to enable serial processing /** * Determine whether this node is an instruction. * @return true - it is an instruction */ public boolean isInstruction() { return true; } public void prepareAttributes() throws XPathException { AttributeCollection atts = getAttributeList(); String selectAtt = null; String copyNamespacesAtt = null; String validationAtt = null; String typeAtt = null; String readOnceAtt = null; for (int a=0; a * A Factory for nodes in the stylesheet tree.
    * Currently only allows Element nodes to be user-constructed. * @author Michael H. Kay */ public class StyleNodeFactory implements NodeFactory { IntHashMap userStyles = new IntHashMap(4); Configuration config; NamePool namePool; boolean allowExtensions; ErrorListener errorListener; /** * Create the node factory for representing an XSLT stylesheet as a tree structure * @param config the Saxon configuration * @param errorListener used for reporting errors */ public StyleNodeFactory(Configuration config, ErrorListener errorListener) { this.config = config; namePool = config.getNamePool(); allowExtensions = config.isAllowExternalFunctions(); this.errorListener = errorListener; } /** * Create an Element node. Note, if there is an error detected while constructing * the Element, we add the element anyway, and return success, but flag the element * with a validation error. This allows us to report more than * one error from a single compilation. * @param nameCode The element name * @param typeCode * @param attlist the attribute list */ public ElementImpl makeElementNode( NodeInfo parent, int nameCode, int typeCode, AttributeCollectionImpl attlist, int[] namespaces, int namespacesUsed, LocationProvider locator, int locationId, int sequence) { boolean toplevel = (parent instanceof XSLStylesheet); String baseURI = null; int lineNumber = -1; int columnNumber = -1; if (locator!=null) { baseURI = locator.getSystemId(locationId); lineNumber = locator.getLineNumber(locationId); columnNumber = locator.getColumnNumber(locationId); } if (parent instanceof DataElement) { DataElement d = new DataElement(); d.setNamespaceDeclarations(namespaces, namespacesUsed); d.initialise(nameCode, typeCode, attlist, parent, sequence); d.setLocation(baseURI, lineNumber, columnNumber); return d; } int f = nameCode&0xfffff; // Try first to make an XSLT element StyleElement e = makeXSLElement(f); if (e != null) { // recognized as an XSLT element e.setNamespaceDeclarations(namespaces, namespacesUsed); e.initialise(nameCode, typeCode, attlist, parent, sequence); e.setLocation(baseURI, lineNumber, columnNumber); // We're not catching multiple errors in the following attributes, but catching each of the // exceptions helps to ensure we don't report spurious errors through not processing some // of the attributes when others are faulty. try { e.processExtensionElementAttribute(StandardNames.EXTENSION_ELEMENT_PREFIXES); } catch (TransformerException err) { e.setValidationError(err, StyleElement.REPORT_ALWAYS); } try { e.processExcludedNamespaces(StandardNames.EXCLUDE_RESULT_PREFIXES); } catch (TransformerException err) { e.setValidationError(err, StyleElement.REPORT_ALWAYS); } try { e.processVersionAttribute(StandardNames.VERSION); } catch (TransformerException err) { e.setValidationError(err, StyleElement.REPORT_ALWAYS); } e.processDefaultXPathNamespaceAttribute(StandardNames.XPATH_DEFAULT_NAMESPACE); return e; } else { // not recognized as an XSLT element short uriCode = namePool.getURICode(nameCode); String localname = namePool.getLocalName(nameCode); StyleElement temp = null; // Detect a misspelt XSLT declaration if (uriCode == NamespaceConstant.XSLT_CODE && (parent instanceof XSLStylesheet) && ((XSLStylesheet)parent).getVersion().compareTo(BigDecimal.valueOf('2')) <= 0 ) { temp = new AbsentExtensionElement(); temp.setValidationError(new XPathException("Unknown top-level XSLT declaration"), StyleElement.REPORT_UNLESS_FORWARDS_COMPATIBLE ); } Class assumedClass = LiteralResultElement.class; // We can't work out the final class of the node until we've examined its attributes // such as version and extension-element-prefixes; but we can have a good guess, and // change it later if need be. boolean assumedSaxonElement = false; // recognize Saxon extension elements if (temp==null) { if (uriCode == NamespaceConstant.SAXON_CODE) { temp = makeSaxonElement(f); if (temp!=null) { assumedClass = temp.getClass(); assumedSaxonElement = true; } } else if (toplevel && uriCode != 0) { DataElement d = new DataElement(); d.setNamespaceDeclarations(namespaces, namespacesUsed); d.initialise(nameCode, typeCode, attlist, parent, sequence); d.setLocation(baseURI, lineNumber, columnNumber); return d; } } if (temp==null) { temp = new LiteralResultElement(); } temp.setNamespaceDeclarations(namespaces, namespacesUsed); try { temp.initialise(nameCode, typeCode, attlist, parent, sequence); temp.setLocation(baseURI, lineNumber, columnNumber); temp.processDefaultCollationAttribute(StandardNames.XSL_DEFAULT_COLLATION_CLARK); temp.processExtensionElementAttribute(StandardNames.XSL_EXTENSION_ELEMENT_PREFIXES_CLARK); temp.processExcludedNamespaces(StandardNames.XSL_EXCLUDE_RESULT_PREFIXES_CLARK); temp.processVersionAttribute(StandardNames.XSL_VERSION_CLARK); temp.processDefaultXPathNamespaceAttribute(StandardNames.XSL_XPATH_DEFAULT_NAMESPACE_CLARK); } catch (XPathException err) { temp.setValidationError(err, StyleElement.REPORT_ALWAYS); } // Now we work out what class of element we really wanted, and change it if necessary TransformerException reason; Class actualClass; if (uriCode == NamespaceConstant.XSLT_CODE) { reason = new XPathException("Unknown XSLT element: " + localname); ((XPathException)reason).setErrorCode("XTSE0010"); ((XPathException)reason).setIsStaticError(true); actualClass = AbsentExtensionElement.class; temp.setValidationError(reason, StyleElement.REPORT_UNLESS_FALLBACK_AVAILABLE); } else if (uriCode == NamespaceConstant.SAXON_CODE) { if (toplevel || temp.isExtensionNamespace(uriCode)) { if (assumedSaxonElement) { // all is well actualClass = assumedClass; } else { actualClass = AbsentExtensionElement.class; reason = new XPathException( "Unknown Saxon extension instruction: " + localname); temp.setValidationError(reason, StyleElement.REPORT_UNLESS_FALLBACK_AVAILABLE); } } else { if (assumedSaxonElement) { // We've got an element such as saxon:call-template but the // user didn't declare the Saxon namespace as an extension element // namespace. Chances are he just forgot. try { XPathException te = new XPathException("saxon:" + localname + " is not being treated as an extension instruction because the namespace " + " http://saxon.sf.net/ has not been declared in extension-element-prefixes"); te.setLocator(temp); te.setErrorCode(SaxonErrorCode.SXWN9008); errorListener.warning(te); } catch (TransformerException e1) { // no action } } actualClass = LiteralResultElement.class; } } else if (temp.isExtensionNamespace(uriCode) && !toplevel) { actualClass = (Class)userStyles.get(nameCode&0xfffff); if (actualClass==null) { if (allowExtensions) { ExtensionElementFactory factory = getFactory(uriCode); if (factory != null) { actualClass = factory.getExtensionClass(localname); if (actualClass != null) { userStyles.put(nameCode&0xfffff, actualClass); // for quicker access next time } } } else { actualClass = AbsentExtensionElement.class; reason = new XPathException("Extension instructions are disabled"); temp.setValidationError(reason, StyleElement.REPORT_IF_INSTANTIATED); } if (actualClass == null) { // if we can't instantiate an extension element, we don't give up // immediately, because there might be an xsl:fallback defined. We // create a surrogate element called AbsentExtensionElement, and // save the reason for failure just in case there is no xsl:fallback actualClass = AbsentExtensionElement.class; XPathException se = new XPathException("Unknown extension instruction", temp); se.setErrorCode("XTDE1450"); reason = se; temp.setValidationError(reason, StyleElement.REPORT_IF_INSTANTIATED); } } } else { if (!toplevel && namePool.getURI(nameCode).indexOf("ElementFactory") >= 0) { // looks like the user forgot to declare an extension element namespace ExtensionElementFactory factory = getFactory(uriCode); if (factory != null) { try { XPathException te = new XPathException(namePool.getDisplayName(nameCode) + " is not being treated as an extension instruction because its namespace " + " has not been declared in extension-element-prefixes"); te.setLocator(temp); te.setErrorCode(SaxonErrorCode.SXWN9008); errorListener.warning(te); } catch (TransformerException e1) { // no action } } } actualClass = LiteralResultElement.class; } StyleElement node; if (actualClass.equals(assumedClass)) { node = temp; // the original element will do the job } else { try { node = (StyleElement)actualClass.newInstance(); } catch (InstantiationException err1) { throw new TransformerFactoryConfigurationError(err1, "Failed to create instance of " + actualClass.getName()); } catch (IllegalAccessException err2) { throw new TransformerFactoryConfigurationError(err2, "Failed to access class " + actualClass.getName()); } node.substituteFor(temp); // replace temporary node with the new one } return node; } } /** * Make an XSL element node * @param f the fingerprint of the node name * @return the constructed element node */ private StyleElement makeXSLElement(int f) { switch (f) { case StandardNames.XSL_ANALYZE_STRING: return new XSLAnalyzeString(); case StandardNames.XSL_APPLY_IMPORTS: return new XSLApplyImports(); case StandardNames.XSL_APPLY_TEMPLATES: return new XSLApplyTemplates(); case StandardNames.XSL_ATTRIBUTE: return new XSLAttribute(); case StandardNames.XSL_ATTRIBUTE_SET: return new XSLAttributeSet(); case StandardNames.XSL_CALL_TEMPLATE: return new XSLCallTemplate(); case StandardNames.XSL_CHARACTER_MAP: return new XSLCharacterMap(); case StandardNames.XSL_CHOOSE: return new XSLChoose(); case StandardNames.XSL_COMMENT: return new XSLComment(); case StandardNames.XSL_COPY: return new XSLCopy(); case StandardNames.XSL_COPY_OF: return new XSLCopyOf(); case StandardNames.XSL_DECIMAL_FORMAT: return new XSLDecimalFormat(); case StandardNames.XSL_DOCUMENT: return new XSLDocument(); case StandardNames.XSL_ELEMENT: return new XSLElement(); case StandardNames.XSL_FALLBACK: return new XSLFallback(); case StandardNames.XSL_FOR_EACH: return new XSLForEach(); case StandardNames.XSL_FOR_EACH_GROUP: return new XSLForEachGroup(); case StandardNames.XSL_FUNCTION: return new XSLFunction(); case StandardNames.XSL_IF: return new XSLIf(); case StandardNames.XSL_IMPORT: return new XSLImport(); case StandardNames.XSL_IMPORT_SCHEMA: return new XSLImportSchema(); case StandardNames.XSL_INCLUDE: return new XSLInclude(); case StandardNames.XSL_KEY: return new XSLKey(); case StandardNames.XSL_MATCHING_SUBSTRING: return new XSLMatchingSubstring(); case StandardNames.XSL_MESSAGE: return new XSLMessage(); case StandardNames.XSL_NEXT_MATCH: return new XSLNextMatch(); case StandardNames.XSL_NON_MATCHING_SUBSTRING: return new XSLMatchingSubstring(); //sic case StandardNames.XSL_NUMBER: return new XSLNumber(); case StandardNames.XSL_NAMESPACE: return new XSLNamespace(); case StandardNames.XSL_NAMESPACE_ALIAS: return new XSLNamespaceAlias(); case StandardNames.XSL_OTHERWISE: return new XSLOtherwise(); case StandardNames.XSL_OUTPUT: return new XSLOutput(); case StandardNames.XSL_OUTPUT_CHARACTER: return new XSLOutputCharacter(); case StandardNames.XSL_PARAM: return new XSLParam(); case StandardNames.XSL_PERFORM_SORT: return new XSLPerformSort(); case StandardNames.XSL_PRESERVE_SPACE: return new XSLPreserveSpace(); case StandardNames.XSL_PROCESSING_INSTRUCTION: return new XSLProcessingInstruction(); case StandardNames.XSL_RESULT_DOCUMENT: return new XSLResultDocument(); case StandardNames.XSL_SEQUENCE: return new XSLSequence(); case StandardNames.XSL_SORT: return new XSLSort(); case StandardNames.XSL_STRIP_SPACE: return new XSLPreserveSpace(); case StandardNames.XSL_STYLESHEET: return new XSLStylesheet(); case StandardNames.XSL_TEMPLATE: return new XSLTemplate(); case StandardNames.XSL_TEXT: return new XSLText(); case StandardNames.XSL_TRANSFORM: return new XSLStylesheet(); case StandardNames.XSL_VALUE_OF: return new XSLValueOf(); case StandardNames.XSL_VARIABLE: return new XSLVariable(); case StandardNames.XSL_WITH_PARAM: return new XSLWithParam(); case StandardNames.XSL_WHEN: return new XSLWhen(); default: return null; } } /** * Make a SAXON extension element * @param f the fingerprint of the element name * @return the constructed element node */ private StyleElement makeSaxonElement(int f) { switch (f) { case StandardNames.SAXON_ASSIGN: return new SaxonAssign(); case StandardNames.SAXON_BREAK: return new SaxonBreak(); case StandardNames.SAXON_CALL_TEMPLATE: return new SaxonCallTemplate(); case StandardNames.SAXON_COLLATION: return new SaxonCollation(); case StandardNames.SAXON_CONTINUE: return new SaxonContinue(); case StandardNames.SAXON_DOCTYPE: return new SaxonDoctype(); case StandardNames.SAXON_ENTITY_REF: return new SaxonEntityRef(); case StandardNames.SAXON_FINALLY: return new SaxonFinally(); case StandardNames.SAXON_IMPORT_QUERY: return new SaxonImportQuery(); case StandardNames.SAXON_ITERATE: return new SaxonIterate(); case StandardNames.SAXON_SCRIPT: return new SaxonScript(); case StandardNames.SAXON_WHILE: return new SaxonWhile(); default: return null; } } /** * Get the factory class for user extension elements * If there is no appropriate class, return null * @param uriCode the code for the namespace URI of the extension element * @return the appropriate ExtensionElementFactory for this namespace */ private ExtensionElementFactory getFactory(short uriCode) { String uri = namePool.getURIFromNamespaceCode(uriCode); int lastSlash = uri.lastIndexOf('/'); if (lastSlash<0 || lastSlash==uri.length()-1) { return null; } String factoryClass = uri.substring(lastSlash+1); ExtensionElementFactory factory; try { factory = (ExtensionElementFactory)config.getInstance(factoryClass, null); } catch (XPathException err) { return null; } return factory; } /** * Method to support the element-available() function * @param uri the namespace URI * @param localName the local Name * @return true if an extension element of this name is recognized */ public boolean isElementAvailable(String uri, String localName) { int fingerprint = namePool.getFingerprint(uri, localName); if (uri.equals(NamespaceConstant.XSLT)) { if (fingerprint==-1) return false; // all names are pre-registered StyleElement e = makeXSLElement(fingerprint); if (e!=null) return e.isInstruction(); } if (uri.equals(NamespaceConstant.SAXON)) { if (fingerprint==-1) return false; // all names are pre-registered StyleElement e = makeSaxonElement(fingerprint); if (e!=null) return e.isInstruction(); } if (!allowExtensions) { // extension elements are disabled return false; } short uriCode = namePool.getCodeForURI(uri); ExtensionElementFactory factory = getFactory(uriCode); if (factory==null) return false; Class actualClass = factory.getExtensionClass(localName); return (actualClass != null); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/style/XSLFallback.java0000644000175000017500000000436411033112257021477 0ustar eugeneeugenepackage net.sf.saxon.style; import net.sf.saxon.expr.Expression; import net.sf.saxon.instruct.Executable; import net.sf.saxon.om.AttributeCollection; import net.sf.saxon.trans.XPathException; /** * xsl:fallback element in stylesheet.
    */ public class XSLFallback extends StyleElement { /** * Determine whether this node is an instruction. * @return true - it is an instruction */ public boolean isInstruction() { return true; } /** * Determine whether this type of element is allowed to contain a template-body * @return true: yes, it may contain a template-body */ public boolean mayContainSequenceConstructor() { return true; } public void prepareAttributes() throws XPathException { AttributeCollection atts = getAttributeList(); for (int a=0; a */ public class XSLForEach extends StyleElement { Expression select = null; boolean containsTailCall = false; /** * Determine whether this node is an instruction. * @return true - it is an instruction */ public boolean isInstruction() { return true; } /** * Specify that xsl:sort is a permitted child */ protected boolean isPermittedChild(StyleElement child) { return (child instanceof XSLSort); } /** * Determine the type of item returned by this instruction (only relevant if * it is an instruction). * @return the item type returned */ protected ItemType getReturnedItemType() { return getCommonChildItemType(); } protected boolean markTailCalls() { if (Cardinality.allowsMany(select.getCardinality())) { return false; } else { StyleElement last = getLastChildInstruction(); containsTailCall = last != null && last.markTailCalls(); return containsTailCall; } } /** * Determine whether this type of element is allowed to contain a template-body * @return true: yes, it may contain a template-body */ public boolean mayContainSequenceConstructor() { return true; } public void prepareAttributes() throws XPathException { AttributeCollection atts = getAttributeList(); String selectAtt = null; for (int a=0; a * Note: this class implements Locator. The element * retains information about its own location in the stylesheet, which is useful when * an XSL error is found. */ public abstract class StyleElement extends ElementImpl implements Locator, Container, InstructionInfo { protected short[] extensionNamespaces = null; // a list of URI codes private short[] excludedNamespaces = null; // a list of URI codes protected BigDecimal version = null; protected StaticContext staticContext = null; protected XPathException validationError = null; protected int reportingCircumstances = REPORT_ALWAYS; protected String defaultXPathNamespace = null; protected String defaultCollationName = null; private boolean explaining = false; // true if saxon:explain="yes" private StructuredQName objectName; // for instructions that define an XSLT named object, the name of that object private XSLStylesheet containingStylesheet; // Conditions under which an error is to be reported public static final int REPORT_ALWAYS = 1; public static final int REPORT_UNLESS_FORWARDS_COMPATIBLE = 2; public static final int REPORT_IF_INSTANTIATED = 3; public static final int REPORT_UNLESS_FALLBACK_AVAILABLE = 4; /** * Constructor */ public StyleElement() { } public Executable getExecutable() { return getPrincipalStylesheet().getExecutable(); } /** * Get the LocationProvider allowing location identifiers to be resolved. */ public LocationProvider getLocationProvider() { return getExecutable().getLocationMap(); } /** * Get the static context for expressions on this element * * @return the static context */ public StaticContext getStaticContext() { if (staticContext == null) { staticContext = new ExpressionContext(this); } return staticContext; } /** * Make an expression visitor * @return the expression visitor */ public ExpressionVisitor makeExpressionVisitor() { ExpressionVisitor visitor = ExpressionVisitor.make(staticContext); visitor.setExecutable(getExecutable()); return visitor; } // public int getLineNumber() { // return lineNumber; // } // // public void setLineNumber(int lineNumber) { // this.lineNumber = lineNumber; // } /** * Determine whether saxon:explain has been set to "yes" * @return true if saxon:explain has been set to "yes" on this element */ protected boolean isExplaining() { return explaining; } /** * Make this node a substitute for a temporary one previously added to the tree. See * StyleNodeFactory for details. "A node like the other one in all things but its class". * Note that at this stage, the node will not yet be known to its parent, though it will * contain a reference to its parent; and it will have no children. * @param temp the element which this one is substituting for */ public void substituteFor(StyleElement temp) { parent = temp.parent; attributeList = temp.attributeList; namespaceList = temp.namespaceList; nameCode = temp.nameCode; sequence = temp.sequence; extensionNamespaces = temp.extensionNamespaces; excludedNamespaces = temp.excludedNamespaces; version = temp.version; staticContext = temp.staticContext; validationError = temp.validationError; reportingCircumstances = temp.reportingCircumstances; //lineNumber = temp.lineNumber; } /** * Set a validation error. This is an error detected during construction of this element on the * stylesheet, but which is not to be reported until later. * @param reason the details of the error * @param circumstances a code identifying the circumstances under which the error is to be reported */ protected void setValidationError(TransformerException reason, int circumstances) { validationError = XPathException.makeXPathException(reason); reportingCircumstances = circumstances; } /** * Determine whether this node is an instruction. The default implementation says it isn't. * @return true if this element is an instruction */ public boolean isInstruction() { return false; } /** * Determine the type of item returned by this instruction (only relevant if * it is an instruction). Default implementation returns Type.ITEM, indicating * that we don't know, it might be anything. Returns null in the case of an element * such as xsl:sort or xsl:variable that can appear in a sequence constructor but * contributes nothing to the result sequence. * * @return the item type returned */ protected ItemType getReturnedItemType() { return AnyItemType.getInstance(); } /** * Get the most general type of item returned by the children of this instruction * * @return the lowest common supertype of the item types returned by the children */ protected ItemType getCommonChildItemType() { final TypeHierarchy th = getConfiguration().getTypeHierarchy(); ItemType t = EmptySequenceTest.getInstance(); AxisIterator children = iterateAxis(Axis.CHILD); while (true) { NodeInfo next = (NodeInfo)children.next(); if (next == null) { return t; } if (next instanceof StyleElement) { ItemType ret = ((StyleElement)next).getReturnedItemType(); if (ret != null) { t = Type.getCommonSuperType(t, ret, th); } } else { t = Type.getCommonSuperType(t, NodeKindTest.TEXT, th); } if (t == AnyItemType.getInstance()) { return t; // no point looking any further } } } /** * Mark tail-recursive calls on templates and functions. * For most instructions, this returns false. * @return true if one or more tail calls were identified */ protected boolean markTailCalls() { return false; } /** * Determine whether this type of element is allowed to contain a sequence constructor * @return true if this instruction is allowed to contain a sequence constructor */ protected boolean mayContainSequenceConstructor() { return false; } /** * Determine whether this type of element is allowed to contain an xsl:fallback * instruction * @return true if this element is allowed to contain an xsl:fallback */ protected boolean mayContainFallback() { return mayContainSequenceConstructor(); } /** * Determine whether this type of element is allowed to contain an xsl:param element * @return true if this element is allowed to contain an xsl:param */ protected boolean mayContainParam() { return false; } /** * Get the containing XSLStylesheet element * @return the XSLStylesheet element representing the outermost element of the containing * stylesheet module. Exceptionally, return null if there is no containing XSLStylesheet element */ public XSLStylesheet getContainingStylesheet() { if (containingStylesheet == null) { if (this instanceof XSLStylesheet) { containingStylesheet = (XSLStylesheet)this; } else { NodeInfo parent = getParent(); if (parent instanceof StyleElement) { containingStylesheet = ((StyleElement)parent).getContainingStylesheet(); } else { // this can happen when early errors are detected in a simplified stylesheet, return null; } } } return containingStylesheet; } /** * Get the import precedence of this stylesheet element. * @return the import precedence. The actual numeric value is arbitrary, but a higher number * indicates a higher precedence. */ public int getPrecedence() { return getContainingStylesheet().getPrecedence(); } /** * Make a structured QName, using this Element as the context for namespace resolution, and * registering the code in the namepool. If the name is unprefixed, the * default namespace is not used. * * @param lexicalQName The lexical QName as written, in the form "[prefix:]localname". The name must have * already been validated as a syntactically-correct QName. Leading and trailing whitespace * will be trimmed * @return the StructuredQName representation of this lexical QName * @throws XPathException if the qname is not a lexically-valid QName, or if the name * is in a reserved namespace. * @throws NamespaceException if the prefix of the qname has not been declared */ public final StructuredQName makeQName(String lexicalQName) throws XPathException, NamespaceException { StructuredQName qName; try { qName = StructuredQName.fromLexicalQName(lexicalQName, false, getConfiguration().getNameChecker(), this); } catch (XPathException e) { e.setIsStaticError(true); if ("FONS0004".equals(e.getErrorCodeLocalPart())) { e.setErrorCode("XTSE0280"); } else if ("FOCA0002".equals(e.getErrorCodeLocalPart())) { e.setErrorCode("XTSE0020"); } else if (e.getErrorCodeLocalPart() == null) { e.setErrorCode("XTSE0020"); } throw e; } if (NamespaceConstant.isReserved(qName.getNamespaceURI())) { XPathException err = new XPathException("Namespace prefix " + qName.getPrefix() + " refers to a reserved namespace"); err.setIsStaticError(true); err.setErrorCode("XTSE0080"); throw err; } return qName; } /** * Make a NamespaceContext object representing the list of in-scope namespaces. This will * be a copy of the namespace context with no references to objects in the stylesheet tree, * so that it can be kept until run-time without locking the tree down in memory. * @return a copy of the namespace context */ public SavedNamespaceContext makeNamespaceContext() { return new SavedNamespaceContext(getInScopeNamespaceCodes(), getNamePool()); } /** * Get the namespace context of the instruction. * @return the namespace context. This method does not make a copy of the namespace context, * so a reference to the returned NamespaceResolver will lock the stylesheet tree in memory. */ public NamespaceResolver getNamespaceResolver() { return this; } /** * Process the attributes of this element and all its children * @throws XPathException in the event of a static error being detected */ protected void processAllAttributes() throws XPathException { if (!(this instanceof LiteralResultElement)) { processDefaultCollationAttribute(StandardNames.DEFAULT_COLLATION); } staticContext = new ExpressionContext(this); processAttributes(); AxisIterator kids = iterateAxis(Axis.CHILD); while (true) { NodeInfo child = (NodeInfo)kids.next(); if (child == null) { return; } if (child instanceof StyleElement) { ((StyleElement)child).processAllAttributes(); if (((StyleElement)child).explaining) { // saxon:explain on any element in a template/function now causes an explanation at the // level of the template/function explaining = true; } } } } /** * Get an attribute value given the Clark name of the attribute (that is, * the name in {uri}local format). * @param clarkName the name of the attribute in {uri}local format * @return the value of the attribute if it exists, or null otherwise */ public String getAttributeValue(String clarkName) { int fp = getNamePool().allocateClarkName(clarkName); return getAttributeValue(fp); } /** * Process the attribute list for the element. This is a wrapper method that calls * prepareAttributes (provided in the subclass) and traps any exceptions */ protected final void processAttributes() throws XPathException { try { prepareAttributes(); } catch (XPathException err) { compileError(err); } } /** * Check whether an unknown attribute is permitted. * * @param nc The name code of the attribute name * @throws XPathException (and reports the error) if this is an attribute * that is not permitted on the containing element */ protected void checkUnknownAttribute(int nc) throws XPathException { String attributeURI = getNamePool().getURI(nc); String elementURI = getURI(); String clarkName = getNamePool().getClarkName(nc); if (clarkName.equals(StandardNames.SAXON_EXPLAIN)) { explaining = "yes".equals(getAttributeValue(nc & 0xfffff)); } if (forwardsCompatibleModeIsEnabled()) { // then unknown attributes are permitted and ignored return; } // allow xsl:extension-element-prefixes etc on an extension element if (isInstruction() && clarkName.startsWith('{' + NamespaceConstant.XSLT) && !(elementURI.equals(NamespaceConstant.XSLT)) && (clarkName.endsWith("}default-collation") || clarkName.endsWith("}xpath-default-namespace") || clarkName.endsWith("}extension-element-prefixes") || clarkName.endsWith("}exclude-result-prefixes") || clarkName.endsWith("}version") || clarkName.endsWith("}use-when"))) { return; } // allow standard attributes on an XSLT element if (elementURI.equals(NamespaceConstant.XSLT) && (clarkName.equals(StandardNames.DEFAULT_COLLATION) || clarkName.equals(StandardNames.XPATH_DEFAULT_NAMESPACE) || clarkName.equals(StandardNames.EXTENSION_ELEMENT_PREFIXES) || clarkName.equals(StandardNames.EXCLUDE_RESULT_PREFIXES) || clarkName.equals(StandardNames.VERSION) || clarkName.equals(StandardNames.USE_WHEN))) { return; } if ("".equals(attributeURI) || NamespaceConstant.XSLT.equals(attributeURI)) { compileError("Attribute " + Err.wrap(getNamePool().getDisplayName(nc), Err.ATTRIBUTE) + " is not allowed on element " + Err.wrap(getDisplayName(), Err.ELEMENT), "XTSE0090"); } } /** * Set the attribute list for the element. This is called to process the attributes (note * the distinction from processAttributes in the superclass). * Must be supplied in a subclass */ protected abstract void prepareAttributes() throws XPathException; /** * Find the last child instruction of this instruction. Returns null if * there are no child instructions, or if the last child is a text node. * @return the last child instruction, or null if there are no child instructions */ protected StyleElement getLastChildInstruction() { StyleElement last = null; AxisIterator kids = iterateAxis(Axis.CHILD); while (true) { NodeInfo child = (NodeInfo)kids.next(); if (child == null) { return last; } if (child instanceof StyleElement) { last = (StyleElement)child; } else { last = null; } } } /** * Compile an XPath expression in the context of this stylesheet element * @param expression the source text of the XPath expression * @return the compiled expression tree for the XPath expression */ public Expression makeExpression(String expression) throws XPathException { try { return ExpressionTool.make(expression, staticContext, 0, Token.EOF, getLineNumber(), getPreparedStylesheet().isCompileWithTracing()); } catch (XPathException err) { err.setLocator(this); compileError(err); ErrorExpression erexp = new ErrorExpression(err); erexp.setLocationId(allocateLocationId(getSystemId(), getLineNumber())); erexp.setContainer(this); return erexp; } } /** * Make a pattern in the context of this stylesheet element * @param pattern the source text of the pattern * @return the compiled pattern */ public Pattern makePattern(String pattern) throws XPathException { try { return Pattern.make(pattern, staticContext, getPrincipalStylesheet().getExecutable()); } catch (XPathException err) { compileError(err); return new NodeTestPattern(AnyNodeTest.getInstance()); } } /** * Make an attribute value template in the context of this stylesheet element * @param expression the source text of the attribute value template * @return a compiled XPath expression that computes the value of the attribute (including * concatenating the results of embedded expressions with any surrounding fixed text) */ protected Expression makeAttributeValueTemplate(String expression) throws XPathException { try { return AttributeValueTemplate.make(expression, getLineNumber(), staticContext); } catch (XPathException err) { compileError(err); return new StringLiteral(expression); } } /** * Process an attribute whose value is a SequenceType * @param sequenceType the source text of the attribute * @return the processed sequence type * @throws XPathException if the syntax is invalid or for example if it refers to a type * that is not in the static context */ public SequenceType makeSequenceType(String sequenceType) throws XPathException { getStaticContext(); try { ExpressionParser parser = new ExpressionParser(); return parser.parseSequenceType(sequenceType, staticContext); } catch (XPathException err) { compileError(err); // recovery path after reporting an error, e.g. undeclared namespace prefix return SequenceType.ANY_SEQUENCE; } } /** * Process the [xsl:]extension-element-prefixes attribute if there is one * * @param nc the Clark name of the attribute required */ protected void processExtensionElementAttribute(String nc) throws XPathException { String ext = getAttributeValue(nc); if (ext != null) { // go round twice, once to count the values and next to add them to the array int count = 0; StringTokenizer st1 = new StringTokenizer(ext, " \t\n\r", false); while (st1.hasMoreTokens()) { st1.nextToken(); count++; } extensionNamespaces = new short[count]; count = 0; StringTokenizer st2 = new StringTokenizer(ext, " \t\n\r", false); while (st2.hasMoreTokens()) { String s = st2.nextToken(); if ("#default".equals(s)) { s = ""; } try { short uriCode = getURICodeForPrefix(s); extensionNamespaces[count++] = uriCode; } catch (NamespaceException err) { extensionNamespaces = null; compileError(err.getMessage(), "XTSE1430"); } } } } /** * Process the [xsl:]exclude-result-prefixes attribute if there is one * * @param nc the Clark name of the attribute required */ protected void processExcludedNamespaces(String nc) throws XPathException { String ext = getAttributeValue(nc); if (ext != null) { if ("#all".equals(Whitespace.trim(ext))) { int[] codes = getInScopeNamespaceCodes(); excludedNamespaces = new short[codes.length]; for (int i = 0; i < codes.length; i++) { excludedNamespaces[i] = (short)(codes[i] & 0xffff); } } else { // go round twice, once to count the values and next to add them to the array int count = 0; StringTokenizer st1 = new StringTokenizer(ext, " \t\n\r", false); while (st1.hasMoreTokens()) { st1.nextToken(); count++; } excludedNamespaces = new short[count]; count = 0; StringTokenizer st2 = new StringTokenizer(ext, " \t\n\r", false); while (st2.hasMoreTokens()) { String s = st2.nextToken(); if ("#default".equals(s)) { s = ""; } else if ("#all".equals(s)) { compileError("In exclude-result-prefixes, cannot mix #all with other values", "XTSE0020"); } try { short uriCode = getURICodeForPrefix(s); excludedNamespaces[count++] = uriCode; if (s.length() == 0 && uriCode==0) { compileError("Cannot exclude the #default namespace when no default namespace is declared", "XTSE0809"); } } catch (NamespaceException err) { excludedNamespaces = null; compileError(err.getMessage(), "XTSE0808"); } } } } } /** * Process the [xsl:]version attribute if there is one * * @param nc the Clark name of the attribute required */ protected void processVersionAttribute(String nc) throws XPathException { String v = Whitespace.trim(getAttributeValue(nc)); if (v != null) { ConversionResult val = DecimalValue.makeDecimalValue(v, true); if (val instanceof ValidationFailure) { compileError("The version attribute must be a decimal literal", "XTSE0110"); version = new BigDecimal("2.0"); } else { version = ((DecimalValue)val).getDecimalValue(); } } } /** * Get the numeric value of the version number on this element, * or inherited from its ancestors * @return the version number as a decimal */ public BigDecimal getVersion() { if (version == null) { NodeInfo node = getParent(); if (node instanceof StyleElement) { version = ((StyleElement)node).getVersion(); } else { return new BigDecimal("2.0"); // defensive programming } } return version; } /** * Determine whether forwards-compatible mode is enabled for this element * @return true if forwards-compatible mode is enabled */ public boolean forwardsCompatibleModeIsEnabled() { return getVersion().compareTo(BigDecimal.valueOf(2)) > 0; } /** * Determine whether backwards-compatible mode is enabled for this element * @return true if backwards compatable mode is enabled, that is, if this or an enclosing * element specifies [xsl:]version="1.0" */ public boolean backwardsCompatibleModeIsEnabled() { return getVersion().compareTo(BigDecimal.valueOf(2)) < 0; } /** * Process the [xsl:]default-xpath-namespace attribute if there is one * * @param nc the Clark name of the attribute required */ protected void processDefaultCollationAttribute(String nc) throws XPathException { String v = getAttributeValue(nc); if (v != null) { StringTokenizer st = new StringTokenizer(v, " \t\n\r", false); while (st.hasMoreTokens()) { String uri = st.nextToken(); if (uri.equals(NamespaceConstant.CODEPOINT_COLLATION_URI)) { defaultCollationName = uri; return; } else if (uri.startsWith("http://saxon.sf.net/")) { defaultCollationName = uri; return; } else { URI collationURI; try { collationURI = new URI(uri); if (!collationURI.isAbsolute()) { URI base = new URI(getBaseURI()); collationURI = base.resolve(collationURI); uri = collationURI.toString(); } } catch (URISyntaxException err) { compileError("default collation '" + uri + "' is not a valid URI"); uri = NamespaceConstant.CODEPOINT_COLLATION_URI; } if (uri.startsWith("http://saxon.sf.net/")) { defaultCollationName = uri; return; } if (getPrincipalStylesheet().getExecutable().getNamedCollation(uri) != null) { defaultCollationName = uri; return; } if (getPrincipalStylesheet().findCollation(uri) != null) { defaultCollationName = uri; return; } } // if not recognized, try the next URI in order } compileError("No recognized collation URI found in default-collation attribute", "XTSE0125"); } } /** * Get the default collation for this stylesheet element. If no default collation is * specified in the stylesheet, return the Unicode codepoint collation name. * @return the name of the default collation */ protected String getDefaultCollationName() { StyleElement e = this; while (true) { if (e.defaultCollationName != null) { return e.defaultCollationName; } NodeInfo p = e.getParent(); if (!(p instanceof StyleElement)) { break; } e = (StyleElement)p; } return NamespaceConstant.CODEPOINT_COLLATION_URI; } /** * Check whether a particular extension element namespace is defined on this node. * This checks this node only, not the ancestor nodes. * The implementation checks whether the prefix is included in the * [xsl:]extension-element-prefixes attribute. * * @param uriCode the namespace URI code being tested * @return true if this namespace is defined on this element as an extension element namespace */ protected boolean definesExtensionElement(short uriCode) { if (extensionNamespaces == null) { return false; } for (int i = 0; i < extensionNamespaces.length; i++) { if (extensionNamespaces[i] == uriCode) { return true; } } return false; } /** * Check whether a namespace uri defines an extension element. This checks whether the * namespace is defined as an extension namespace on this or any ancestor node. * * @param uriCode the namespace URI code being tested * @return true if the URI is an extension element namespace URI */ public boolean isExtensionNamespace(short uriCode) { NodeInfo anc = this; while (anc instanceof StyleElement) { if (((StyleElement)anc).definesExtensionElement(uriCode)) { return true; } anc = anc.getParent(); } return false; } /** * Check whether this node excludes a particular namespace from the result. * This method checks this node only, not the ancestor nodes. * * @param uriCode the code of the namespace URI being tested * @return true if the namespace is excluded by virtue of an [xsl:]exclude-result-prefixes attribute */ protected boolean definesExcludedNamespace(short uriCode) { if (excludedNamespaces == null) { return false; } for (int i = 0; i < excludedNamespaces.length; i++) { if (excludedNamespaces[i] == uriCode) { return true; } } return false; } /** * Check whether a namespace uri defines an namespace excluded from the result. * This checks whether the namespace is defined as an excluded namespace on this * or any ancestor node. * * @param uriCode the code of the namespace URI being tested * @return true if this namespace URI is a namespace excluded by virtue of exclude-result-prefixes * on this element or on an ancestor element */ public boolean isExcludedNamespace(short uriCode) { if (uriCode == NamespaceConstant.XSLT_CODE || uriCode == NamespaceConstant.XML_CODE) { return true; } if (isExtensionNamespace(uriCode)) { return true; } NodeInfo anc = this; while (anc instanceof StyleElement) { if (((StyleElement)anc).definesExcludedNamespace(uriCode)) { return true; } anc = anc.getParent(); } return false; } /** * Process the [xsl:]default-xpath-namespace attribute if there is one * * @param nc the Clark name of the attribute required */ protected void processDefaultXPathNamespaceAttribute(String nc) { String v = getAttributeValue(nc); if (v != null) { defaultXPathNamespace = v; } } /** * Get the default XPath namespace for elements and types * @return the default namespace for elements and types. * Return {@link NamespaceConstant#NULL} for the non-namespace */ protected String getDefaultXPathNamespace() { NodeInfo anc = this; while (anc instanceof StyleElement) { String x = ((StyleElement)anc).defaultXPathNamespace; if (x != null) { return x; } anc = anc.getParent(); } return NamespaceConstant.NULL; // indicates that the default namespace is the null namespace } /** * Get the Schema type definition for a type named in the stylesheet (in a * "type" attribute). * @param typeAtt the value of the type attribute * @return the corresponding schema type * @throws XPathException if the type is not declared in an * imported schema, or is not a built-in type */ public SchemaType getSchemaType(String typeAtt) throws XPathException { try { String[] parts = getConfiguration().getNameChecker().getQNameParts(typeAtt); String lname = parts[1]; String uri; if ("".equals(parts[0])) { // Name is unprefixed: use the default-xpath-namespace uri = getDefaultXPathNamespace(); } else { uri = getURIForPrefix(parts[0], false); if (uri == null) { compileError("Namespace prefix for type annotation is undeclared", "XTSE1520"); return null; } } int nameCode = getNamePool().allocate(parts[0], uri, lname); if (uri.equals(NamespaceConstant.SCHEMA)) { if ("untyped".equals(lname)) { compileError("Cannot validate a node as 'untyped'", "XTSE1520"); } SchemaType t = BuiltInType.getSchemaType(StandardNames.getFingerprint(uri, lname)); if (t == null) { compileError("Unknown built-in type " + typeAtt, "XTSE1520"); return null; } return t; } // not a built-in type: look in the imported schemas if (!getPrincipalStylesheet().isImportedSchema(uri)) { compileError("There is no imported schema for the namespace of type " + typeAtt, "XTSE1520"); return null; } SchemaType stype = getConfiguration().getSchemaType(nameCode & 0xfffff); if (stype == null) { compileError("There is no type named " + typeAtt + " in an imported schema", "XTSE1520"); } return stype; } catch (QNameException err) { compileError("Invalid type name. " + err.getMessage(), "XTSE1520"); } return null; } /** * Get the type annotation to use for a given schema type * @param schemaType the schema type * @return the corresponding numeric type annotation */ public int getTypeAnnotation(SchemaType schemaType) { if (schemaType != null) { return schemaType.getFingerprint(); } else { return -1; } } /** * Check that the stylesheet element is valid. This is called once for each element, after * the entire tree has been built. As well as validation, it can perform first-time * initialisation. The default implementation does nothing; it is normally overriden * in subclasses. */ public void validate() throws XPathException { } /** * Hook to allow additional validation of a parent element immediately after its * children have been validated. */ public void postValidate() throws XPathException { } /** * Type-check an expression. This is called to check each expression while the containing * instruction is being validated. It is not just a static type-check, it also adds code * to perform any necessary run-time type checking and/or conversion. * @param name the name of the attribute containing the expression to be checked (used for diagnostics) * @param exp the expression to be checked * @return the (possibly rewritten) expression after type checking */ // Note: the typeCheck() call is done at the level of individual path expression; the optimize() call is done // for a template or function as a whole. We can't do it all at the function/template level because // the static context (e.g. namespaces) changes from one XPath expression to another. public Expression typeCheck(String name, Expression exp) throws XPathException { if (exp == null) { return null; } exp.setContainer(this); // temporary, until the instruction is compiled try { exp = makeExpressionVisitor().typeCheck(exp, Type.ITEM_TYPE); exp = ExpressionTool.resolveCallsToCurrentFunction(exp, getConfiguration()); // if (explaining) { // System.err.println("Attribute '" + name + "' of element '" + getDisplayName() + "' at line " + getLineNumber() + ':'); // System.err.println("Static type: " + // SequenceType.makeSequenceType(exp.getItemType(), exp.getCardinality())); // System.err.println("Optimized expression tree:"); // exp.display(10, getNamePool(), System.err); // } if (getPreparedStylesheet().isCompileWithTracing()) { InstructionDetails details = new InstructionDetails(); details.setConstructType(Location.XPATH_IN_XSLT); details.setLineNumber(getLineNumber()); details.setSystemId(getSystemId()); details.setProperty("attribute-name", name); TraceWrapper trace = new TraceInstruction(exp, details); trace.setLocationId(allocateLocationId(getSystemId(), getLineNumber())); trace.setContainer(this); exp = trace; } return exp; } catch (XPathException err) { // we can't report a dynamic error such as divide by zero unless the expression // is actually executed. if (err.isStaticError() || err.isTypeError()) { compileError(err); return exp; } else { ErrorExpression erexp = new ErrorExpression(err); erexp.setLocationId(allocateLocationId(getSystemId(), getLineNumber())); return erexp; } } } /** * Allocate slots in the local stack frame to range variables used in an XPath expression * * @param exp the XPath expression for which slots are to be allocated */ public void allocateSlots(Expression exp) { SlotManager slotManager = getContainingSlotManager(); if (slotManager == null) { throw new AssertionError("Slot manager has not been allocated"); // previous code: ExpressionTool.allocateSlots(exp, 0, null); } else { int firstSlot = slotManager.getNumberOfVariables(); int highWater = ExpressionTool.allocateSlots(exp, firstSlot, slotManager); if (highWater > firstSlot) { slotManager.setNumberOfVariables(highWater); // This algorithm is not very efficient because it never reuses // a slot when a variable goes out of scope. But at least it is safe. // Note that range variables within XPath expressions need to maintain // a slot until the instruction they are part of finishes, e.g. in // xsl:for-each. } } } /** * Allocate slots to any variables used within a pattern. This is needed only for "free-standing" * patterns such as template match or key match; other cases are handed by the containing PatternSponsor * @param pattern the pattern whose slots are to be allocated */ // private void allocateSlots(Pattern pattern) { // if (pattern instanceof LocationPathPattern) { // ((LocationPathPattern)pattern).allocateSlots((ExpressionContext)getStaticContext(), 0); // } // } /** * Allocate space for range variables within predicates in the match pattern. The xsl:template * element has no XPath expressions among its attributes, so if this method is called on this * object it can only be because there are variables used in the match pattern. We work out * how many slots are needed for the match pattern in each template rule, and then apply-templates * can allocate a stack frame that is large enough for the most demanding match pattern in the * entire stylesheet. * @param match the pattern * @param frame the stackframe outline for this pattern */ public void allocatePatternSlots(Pattern match, SlotManager frame) { int highWater = match.allocateSlots(getStaticContext(), frame, 0); //int highWater = frame.getNumberOfVariables(); getPrincipalStylesheet().allocatePatternSlots(highWater); } /** * Type-check a pattern. This is called to check each pattern while the containing * instruction is being validated. It is not just a static type-check, it also adds code * to perform any necessary run-time type checking and/or conversion. * @param name the name of the attribute holding the pattern, for example "match": used in * diagnostics * @param pattern the compiled pattern * @return the original pattern, or a substitute pattern if it has been rewritten */ public Pattern typeCheck(String name, Pattern pattern) throws XPathException { if (pattern == null) { return null; } try { pattern = pattern.analyze(makeExpressionVisitor(), Type.NODE_TYPE); boolean usesCurrent = false; if (pattern instanceof LocationPathPattern) { Iterator sub = pattern.iterateSubExpressions(); while (sub.hasNext()) { Expression filter = (Expression)sub.next(); if (ExpressionTool.callsFunction(filter, Current.FN_CURRENT)) { usesCurrent = true; break; } } if (usesCurrent) { Configuration config = getConfiguration(); LetExpression let = new LetExpression(); let.setVariableQName(new StructuredQName("saxon", NamespaceConstant.SAXON, "current" + hashCode())); let.setRequiredType(SequenceType.SINGLE_ITEM); let.setSequence(new ContextItemExpression()); let.setAction(Literal.makeEmptySequence()); PromotionOffer offer = new PromotionOffer(config.getOptimizer()); offer.action = PromotionOffer.REPLACE_CURRENT; offer.containingExpression = let; ((LocationPathPattern)pattern).resolveCurrent(let, offer, true); //allocateSlots(let); //redundant, done again later } } return pattern; } catch (XPathException err) { // we can't report a dynamic error such as divide by zero unless the pattern // is actually executed. We don't have an error pattern available, so we // construct one if (err.isStaticError() || err.isTypeError()) { XPathException e2 = new XPathException("Error in " + name + " pattern", err); e2.setLocator(err.getLocator()); e2.setErrorCode(err.getErrorCodeLocalPart()); throw e2; } else { LocationPathPattern errpat = new LocationPathPattern(); errpat.setExecutable(getExecutable()); errpat.addFilter(new ErrorExpression(err)); return errpat; } } } /** * Fix up references from XPath expressions. Overridden for function declarations * and variable declarations */ public void fixupReferences() throws XPathException { AxisIterator kids = iterateAxis(Axis.CHILD); while (true) { NodeInfo child = (NodeInfo)kids.next(); if (child == null) { return; } if (child instanceof StyleElement) { ((StyleElement)child).fixupReferences(); } } } /** * Get the SlotManager for the containing Procedure definition * * @return the SlotManager associated with the containing Function, Template, etc, * or null if there is no such containing Function, Template etc. */ public SlotManager getContainingSlotManager() { NodeInfo node = this; while (true) { NodeInfo next = node.getParent(); if (next instanceof XSLStylesheet) { if (node instanceof StylesheetProcedure) { return ((StylesheetProcedure)node).getSlotManager(); } else { return null; } } node = next; } } /** * Recursive walk through the stylesheet to validate all nodes */ public void validateSubtree() throws XPathException { if (validationError != null) { if (reportingCircumstances == REPORT_ALWAYS) { compileError(validationError); } else if (reportingCircumstances == REPORT_UNLESS_FORWARDS_COMPATIBLE && !forwardsCompatibleModeIsEnabled()) { compileError(validationError); } else if (reportingCircumstances == REPORT_UNLESS_FALLBACK_AVAILABLE) { boolean hasFallback = false; AxisIterator kids = iterateAxis(Axis.CHILD); while (true) { NodeInfo child = (NodeInfo)kids.next(); if (child == null) { break; } if (child instanceof XSLFallback) { hasFallback = true; ((XSLFallback)child).validateSubtree(); } } if (!hasFallback) { compileError(validationError); } } } else { try { validate(); } catch (XPathException err) { compileError(err); } validateChildren(); postValidate(); } } /** * Validate the children of this node, recursively. Overridden for top-level * data elements. */ protected void validateChildren() throws XPathException { boolean containsInstructions = mayContainSequenceConstructor(); AxisIterator kids = iterateAxis(Axis.CHILD); StyleElement lastChild = null; while (true) { NodeInfo child = (NodeInfo)kids.next(); if (child == null) { break; } if (child instanceof StyleElement) { if (containsInstructions && !((StyleElement)child).isInstruction() && !isPermittedChild((StyleElement)child)) { ((StyleElement)child).compileError("An " + getDisplayName() + " element must not contain an " + child.getDisplayName() + " element", "XTSE0010"); } ((StyleElement)child).validateSubtree(); lastChild = (StyleElement)child; } } if (lastChild instanceof XSLVariable && !(this instanceof XSLStylesheet)) { lastChild.compileWarning("A variable with no following sibling instructions has no effect", SaxonErrorCode.SXWN9001); } } /** * Check whether a given child is permitted for this element. This method is used when a non-instruction * child element such as xsl:sort is encountered in a context where instructions would normally be expected. * @param child the child that may or may not be permitted * @return true if the child is permitted. */ protected boolean isPermittedChild(StyleElement child) { return false; } /** * Get the principal XSLStylesheet node. This gets the principal style sheet, i.e. the * one originally loaded, that forms the root of the import/include tree * @return the xsl:stylesheet element at the root of the principal stylesheet module. * Exceptionally (with early errors in a simplified stylesheet module) return null. */ public XSLStylesheet getPrincipalStylesheet() { XSLStylesheet sheet = getContainingStylesheet(); if (sheet == null) { return null; } while (true) { XSLStylesheet next = sheet.getImporter(); if (next == null) { return sheet; } sheet = next; } } /** * Get the PreparedStylesheet object. * * @return the PreparedStylesheet to which this stylesheet element belongs. * Exceptionally (with early errors in a simplified stylesheet module) return null. */ public PreparedStylesheet getPreparedStylesheet() { XSLStylesheet principalStylesheet = getPrincipalStylesheet(); if (principalStylesheet == null) { return null; } return principalStylesheet.getPreparedStylesheet(); } /** * Check that the stylesheet element is within a sequence constructor * * @throws XPathException if not within a sequence constructor */ public void checkWithinTemplate() throws XPathException { // Parent elements now check their children, not the other way around // StyleElement parent = (StyleElement)getParent(); // if (!parent.mayContainSequenceConstructor()) { // compileError("Element must be used only within a sequence constructor", "XT0010"); // } } /** * Check that among the children of this element, any xsl:sort elements precede any other elements * * @param sortRequired true if there must be at least one xsl:sort element * @throws XPathException if invalid */ protected void checkSortComesFirst(boolean sortRequired) throws XPathException { AxisIterator kids = iterateAxis(Axis.CHILD); boolean sortFound = false; boolean nonSortFound = false; while (true) { NodeInfo child = (NodeInfo)kids.next(); if (child == null) { break; } if (child instanceof XSLSort) { if (nonSortFound) { ((XSLSort)child).compileError("Within " + getDisplayName() + ", xsl:sort elements must come before other instructions", "XTSE0010"); } sortFound = true; } else if (child.getNodeKind() == Type.TEXT) { // with xml:space=preserve, white space nodes may still be there if (!Whitespace.isWhite(child.getStringValueCS())) { nonSortFound = true; } } else { nonSortFound = true; } } if (sortRequired && !sortFound) { compileError(getDisplayName() + " must have at least one xsl:sort child", "XTSE0010"); } } /** * Convenience method to check that the stylesheet element is at the top level * @param errorCode the error to throw if it is not at the top level; defaults to XTSE0010 * if the value is null * @throws XPathException if not at top level */ public void checkTopLevel(String errorCode) throws XPathException { if (!(getParent() instanceof XSLStylesheet)) { compileError("Element must be used only at top level of stylesheet", (errorCode==null ? "XTSE0010" : errorCode)); } } /** * Convenience method to check that the stylesheet element is empty * * @throws XPathException if it is not empty */ public void checkEmpty() throws XPathException { if (hasChildNodes()) { compileError("Element must be empty", "XTSE0260"); } } /** * Convenience method to report the absence of a mandatory attribute * @param attribute the name of the attribute whose absence is to be reported * @throws XPathException if the attribute is missing */ public void reportAbsence(String attribute) throws XPathException { compileError("Element must have a \"" + attribute + "\" attribute", "XTSE0010"); } /** * Compile the instruction on the stylesheet tree into an executable instruction * for use at run-time. * @param exec the Executable * @return either a ComputedExpression, or null. The value null is returned when compiling an instruction * that returns a no-op, or when compiling a top-level object such as an xsl:template that compiles * into something other than an instruction. */ public abstract Expression compile(Executable exec) throws XPathException; /** * Compile the children of this instruction on the stylesheet tree, adding the * subordinate instructions to the parent instruction on the execution tree. * @param exec the Executable * @param iter Iterator over the children. This is used in the case where there are children * that are not part of the sequence constructor, for example the xsl:sort children of xsl:for-each; * the iterator can be positioned past such elements. * @param includeParams true if xsl:param elements are to be treated as child instructions (true * for templates but not for functions) * @return an Expression tree representing the children of this instruction */ public Expression compileSequenceConstructor(Executable exec, SequenceIterator iter, boolean includeParams) throws XPathException { Expression result = Literal.makeEmptySequence(); int locationId = allocateLocationId(getSystemId(), getLineNumber()); while (true) { int lineNumber = getLineNumber(); NodeInfo node = ((NodeInfo)iter.next()); if (node == null) { return result; } if (node instanceof StyleElement) { lineNumber = node.getLineNumber(); // this is to get a line number for the next text node } if (node.getNodeKind() == Type.TEXT) { // handle literal text nodes by generating an xsl:value-of instruction AxisIterator lookahead = node.iterateAxis(Axis.FOLLOWING_SIBLING); NodeInfo sibling = (NodeInfo)lookahead.next(); if (!(sibling instanceof XSLParam || sibling instanceof XSLSort)) { // The test for XSLParam and XSLSort is to eliminate whitespace nodes that have been retained // because of xml:space="preserve" ValueOf text = new ValueOf(new StringLiteral(node.getStringValue()), false, false); text.setLocationId(allocateLocationId(getSystemId(), lineNumber)); result = Block.makeBlock(result, text); result.setLocationId(locationId); } } else if (node instanceof XSLVariable) { Expression var = ((XSLVariable)node).compileLocalVariable(exec); if (var == null) { // this means that the variable declaration is redundant //continue; } else { LocalVariable lv = (LocalVariable)var; Expression tail = compileSequenceConstructor(exec, iter, includeParams); if (tail == null || Literal.isEmptySequence(tail)) { // this doesn't happen, because if there are no instructions following // a variable, we'll have taken the var==null path above return result; } else { LetExpression let = new LetExpression(); let.setRequiredType(lv.getRequiredType()); let.setVariableQName(lv.getVariableQName()); let.setSequence(lv.getSelectExpression()); let.setAction(tail); ((XSLVariable)node).fixupBinding(let); locationId = allocateLocationId(node.getSystemId(), node.getLineNumber()); let.setLocationId(locationId); if (getPreparedStylesheet().isCompileWithTracing()) { TraceExpression t = new TraceExpression(let); t.setConstructType(Location.LET_EXPRESSION); t.setObjectName(lv.getVariableQName()); t.setSystemId(node.getSystemId()); t.setLineNumber(node.getLineNumber()); result = Block.makeBlock(result, t); } else { result = Block.makeBlock(result, let); } result.setLocationId(locationId); } } } else if (node instanceof StyleElement) { StyleElement snode = (StyleElement)node; Expression child; if (snode.validationError != null && !(this instanceof AbsentExtensionElement)) { child = fallbackProcessing(exec, snode); } else { child = snode.compile(exec); if (child != null) { if (child.getContainer() == null) { // for the time being, the XSLT stylesheet element acts as the container // for the XPath expressions within. This will later be replaced by a // compiled template, variable, or other top-level construct child.setContainer(this); } locationId = allocateLocationId(getSystemId(), snode.getLineNumber()); child.setLocationId(locationId); if (includeParams || !(node instanceof XSLParam)) { if (getPreparedStylesheet().isCompileWithTracing()) { child = makeTraceInstruction(snode, child); } } } } result = Block.makeBlock(result, child); if (result != null) { result.setLocationId(locationId); } } } } /** * Create a trace instruction to wrap a real instruction * @param source the parent element * @param child the compiled expression tree for the instruction to be traced * @return a wrapper instruction that performs the tracing (if activated at run-time) */ protected static TraceWrapper makeTraceInstruction(StyleElement source, Expression child) { if (child instanceof TraceWrapper) { return (TraceWrapper)child; // this can happen, for example, after optimizing a compile-time xsl:if } TraceWrapper trace = new TraceInstruction(child, source); trace.setLocationId(source.allocateLocationId(source.getSystemId(), source.getLineNumber())); trace.setContainer(source); return trace; } /** * Perform fallback processing. Generate fallback code for an extension * instruction that is not recognized by the implementation. * @param exec the Executable * @param instruction The unknown extension instruction * @return the expression tree representing the fallback code */ protected Expression fallbackProcessing(Executable exec, StyleElement instruction) throws XPathException { // process any xsl:fallback children; if there are none, // generate code to report the original failure reason Expression fallback = null; AxisIterator kids = instruction.iterateAxis(Axis.CHILD); while (true) { NodeInfo child = (NodeInfo)kids.next(); if (child == null) { break; } if (child instanceof XSLFallback) { //fallback.setLocationId(allocateLocationId(getSystemId(), child.getLineNumber())); //((XSLFallback)child).compileChildren(exec, fallback, true); Expression b = ((XSLFallback)child).compileSequenceConstructor(exec, child.iterateAxis(Axis.CHILD), true); if (b == null) { b = Literal.makeEmptySequence(); } if (fallback == null) { fallback = b; } else { fallback = Block.makeBlock(fallback, b); fallback.setLocationId( allocateLocationId(getSystemId(), getLineNumber())); } } } if (fallback != null) { return fallback; } else { return new ErrorExpression(instruction.validationError); // compileError(instruction.validationError); // return EmptySequence.getInstance(); } } /** * Allocate a location identifier * @param systemId identifies the module containing the instruction * @param lineNumber the line number of the instruction * @return an integer location ID which can be used to report the location of the instruction, * by reference to a {@link LocationProvider} */ protected int allocateLocationId(String systemId, int lineNumber) { return getStaticContext().getLocationMap().allocateLocationId(systemId, lineNumber); } /** * Construct sort keys for a SortedIterator * * @return an array of SortKeyDefinition objects if there are any sort keys; * or null if there are none. */ protected SortKeyDefinition[] makeSortKeys() throws XPathException { // handle sort keys if any int numberOfSortKeys = 0; AxisIterator kids = iterateAxis(Axis.CHILD); while (true) { Item child = kids.next(); if (child == null) { break; } if (child instanceof XSLSort) { ((XSLSort)child).compile(getExecutable()); if (numberOfSortKeys != 0 && ((XSLSort)child).getStable() != null) { compileError("stable attribute may appear only on the first xsl:sort element", "XTSE1017"); } numberOfSortKeys++; } } if (numberOfSortKeys > 0) { SortKeyDefinition[] keys = new SortKeyDefinition[numberOfSortKeys]; kids = iterateAxis(Axis.CHILD); int k = 0; while (true) { NodeInfo child = (NodeInfo)kids.next(); if (child == null) { break; } if (child instanceof XSLSort) { keys[k++] = ((XSLSort)child).getSortKeyDefinition().simplify(makeExpressionVisitor()); } } return keys; } else { return null; } } /** * Get the list of attribute-sets associated with this element. * This is used for xsl:element, xsl:copy, xsl:attribute-set, and on literal * result elements * * @param use the original value of the [xsl:]use-attribute-sets attribute * @param list an empty list to hold the list of XSLAttributeSet elements in the stylesheet tree. * Or null, if these are not required. * @return an array of AttributeList instructions representing the compiled attribute sets */ protected AttributeSet[] getAttributeSets(String use, List list) throws XPathException { if (list == null) { list = new ArrayList(4); } XSLStylesheet stylesheet = getPrincipalStylesheet(); List toplevel = stylesheet.getTopLevel(); StringTokenizer st = new StringTokenizer(use, " \t\n\r", false); while (st.hasMoreTokens()) { String asetname = st.nextToken(); StructuredQName fprint; try { fprint = makeQName(asetname); } catch (NamespaceException err) { compileError(err.getMessage(), "XTSE0710"); fprint = null; } catch (XPathException err) { compileError(err.getMessage(), "XTSE0710"); fprint = null; } boolean found = false; // search for the named attribute set, using all of them if there are several with the // same name for (int i = 0; i < toplevel.size(); i++) { if (toplevel.get(i) instanceof XSLAttributeSet) { XSLAttributeSet t = (XSLAttributeSet)toplevel.get(i); if (t.getAttributeSetName().equals(fprint)) { list.add(t); found = true; } } } if (!found) { compileError("No attribute-set exists named " + asetname, "XTSE0710"); } } AttributeSet[] array = new AttributeSet[list.size()]; for (int i = 0; i < list.size(); i++) { XSLAttributeSet aset = (XSLAttributeSet)list.get(i); aset.incrementReferenceCount(); array[i] = aset.getInstruction(); } return array; } /** * Get the list of xsl:with-param elements for a calling element (apply-templates, * call-template, apply-imports, next-match). This method can be used to get either * the tunnel parameters, or the non-tunnel parameters. * @param exec the Executable * @param tunnel true if the tunnel="yes" parameters are wanted, false to get * @param caller the calling instruction (for example xsl:apply-templates * @return an array of WithParam objects for either the ordinary parameters * or the tunnel parameters */ protected WithParam[] getWithParamInstructions(Executable exec, boolean tunnel, Instruction caller) throws XPathException { int count = 0; AxisIterator kids = iterateAxis(Axis.CHILD); while (true) { NodeInfo child = (NodeInfo)kids.next(); if (child == null) { break; } if (child instanceof XSLWithParam) { XSLWithParam wp = (XSLWithParam)child; if (wp.isTunnelParam() == tunnel) { count++; } } } WithParam[] array = new WithParam[count]; count = 0; kids = iterateAxis(Axis.CHILD); while (true) { NodeInfo child = (NodeInfo)kids.next(); if (child == null) { return array; } if (child instanceof XSLWithParam) { XSLWithParam wp = (XSLWithParam)child; if (wp.isTunnelParam() == tunnel) { WithParam p = (WithParam)wp.compile(exec); ExpressionTool.copyLocationInfo(caller, p); array[count++] = p; } } } } /** * Report an error with diagnostic information * @param error contains information about the error * @throws XPathException always, after reporting the error to the ErrorListener */ protected void compileError(XPathException error) throws XPathException { error.setIsStaticError(true); // Set the location of the error if there is not current location information, // or if the current location information is local to the XPath expression if (error.getLocator() == null || error.getLocator() instanceof ExpressionLocation || error.getLocator() instanceof Expression) { error.setLocator(this); } PreparedStylesheet pss = getPreparedStylesheet(); try { if (pss == null) { // it is null before the stylesheet has been fully built throw error; } else { pss.reportError(error); } } catch (TransformerException err2) { if (err2.getLocator() == null) { err2.setLocator(this); } throw XPathException.makeXPathException(err2); } } /** * Report a static error in the stylesheet * @param message the error message * @throws XPathException always, after reporting the error to the ErrorListener */ protected void compileError(String message) throws XPathException { XPathException tce = new XPathException(message); tce.setLocator(this); compileError(tce); } /** * Compile time error, specifying an error code * * @param message the error message * @param errorCode the error code. May be null if not known or not defined * @throws XPathException */ protected void compileError(String message, String errorCode) throws XPathException { XPathException tce = new XPathException(message); tce.setErrorCode(errorCode); tce.setLocator(this); compileError(tce); } protected void undeclaredNamespaceError(String prefix, String errorCode) throws XPathException { if (errorCode == null) { errorCode = "XTSE0280"; } compileError("Undeclared namespace prefix " + Err.wrap(prefix), errorCode); } protected void compileWarning(String message, String errorCode) throws XPathException { XPathException tce = new XPathException(message); tce.setErrorCode(errorCode); tce.setLocator(this); PreparedStylesheet pss = getPreparedStylesheet(); if (pss != null) { pss.reportWarning(tce); } } /** * Report a warning to the error listener * @param error an exception containing the warning text */ protected void issueWarning(TransformerException error) { if (error.getLocator() == null) { error.setLocator(this); } PreparedStylesheet pss = getPreparedStylesheet(); if (pss != null) { // it is null before the stylesheet has been fully built - ignore it pss.reportWarning(error); } } /** * Report a warning to the error listener * @param message the warning message text * @param locator the location of the problem in the source stylesheet */ protected void issueWarning(String message, SourceLocator locator) { TransformerConfigurationException tce = new TransformerConfigurationException(message); if (locator == null) { tce.setLocator(this); } else { tce.setLocator(locator); } issueWarning(tce); } /** * Test whether this is a top-level element * @return true if the element is a child of the xsl:stylesheet element */ public boolean isTopLevel() { return (getParent() instanceof XSLStylesheet); } /** * Bind a variable used in this element to the compiled form of the XSLVariable element in which it is * declared * * @param qName The name of the variable * @return the XSLVariableDeclaration (that is, an xsl:variable or xsl:param instruction) for the variable * @throws XPathException if the variable has not been declared */ public XSLVariableDeclaration bindVariable(StructuredQName qName) throws XPathException { XSLVariableDeclaration binding = getVariableBinding(qName); if (binding == null) { XPathException err = new XPathException("Variable " + qName.getDisplayName() + " has not been declared"); err.setErrorCode("XPST0008"); err.setIsStaticError(true); throw err; } return binding; } /** * Bind a variable used in this element to the declaration in the stylesheet * * @param qName The absolute name of the variable (including namespace URI) * @return the XSLVariableDeclaration, or null if it has not been declared */ private XSLVariableDeclaration getVariableBinding(StructuredQName qName) { NodeInfo curr = this; NodeInfo prev = this; // first search for a local variable declaration if (!isTopLevel()) { AxisIterator preceding = curr.iterateAxis(Axis.PRECEDING_SIBLING); while (true) { curr = (NodeInfo)preceding.next(); while (curr == null) { curr = prev.getParent(); while (curr instanceof XSLFallback) { // a local variable is not visible within a sibling xsl:fallback element curr = curr.getParent(); } prev = curr; if (curr.getParent() instanceof XSLStylesheet) { break; // top level } preceding = curr.iterateAxis(Axis.PRECEDING_SIBLING); curr = (NodeInfo)preceding.next(); } if (curr.getParent() instanceof XSLStylesheet) { break; } if (curr instanceof XSLVariableDeclaration) { XSLVariableDeclaration var = (XSLVariableDeclaration)curr; if (var.getVariableQName().equals(qName)) { return var; } } } } // Now check for a global variable // we rely on the search following the order of decreasing import precedence. XSLStylesheet root = getPrincipalStylesheet(); return root.getGlobalVariable(qName); } /** * Get a FunctionCall declared using an xsl:function element in the stylesheet * * @param qName the name of the function * @param arity the number of arguments in the function call. The value -1 * indicates that any arity will do (this is used to support the function-available() function). * @return the XSLFunction object representing the function declaration * in the stylesheet, or null if no such function is defined. */ public XSLFunction getStylesheetFunction(StructuredQName qName, int arity) { // we rely on the search following the order of decreasing import precedence. XSLStylesheet root = getPrincipalStylesheet(); List toplevel = root.getTopLevel(); for (int i = toplevel.size() - 1; i >= 0; i--) { Object child = toplevel.get(i); if (child instanceof XSLFunction && ((XSLFunction)child).getObjectName().equals(qName) && (arity == -1 || ((XSLFunction)child).getNumberOfArguments() == arity)) { return (XSLFunction)child; } } return null; } /** * Get a list of all stylesheet functions, excluding any that are masked by one of higher precedence * @return a list of all stylesheet functions. The members of the list are instances of class XSLFunction */ public List getAllStylesheetFunctions() { // The performance of this algorithm is appalling, but it's only used for diagnostic explain output List output = new ArrayList(); XSLStylesheet root = getPrincipalStylesheet(); List toplevel = root.getTopLevel(); for (int i = toplevel.size() - 1; i >= 0; i--) { Object child = toplevel.get(i); if (child instanceof XSLFunction) { StructuredQName name = ((XSLFunction)child).getObjectName(); int arity = ((XSLFunction)child).getNumberOfArguments(); if (getStylesheetFunction(name, arity) == child) { output.add(child); } } } return output; } /** * Get the type of construct. This will be a constant in * class {@link Location}. This method is part of the {@link InstructionInfo} interface */ public int getConstructType() { return getFingerprint(); } /** * Get a name identifying the object of the expression, for example a function name, template name, * variable name, key name, element name, etc. This is used only where the name is known statically. * If there is no name, the value will be null. * @return the name of the object declared in this element, if any */ public StructuredQName getObjectName() { return objectName; } /** * Set the object name, for example the name of a function, variable, or template declared on this element * @param qName the object name as a QName */ public void setObjectName(StructuredQName qName) { objectName = qName; } /** * Get the value of a particular property of the instruction. This is part of the * {@link InstructionInfo} interface for run-time tracing and debugging. The properties * available include all the attributes of the source instruction (named by the attribute name): * these are all provided as string values. * * @param name The name of the required property * @return The value of the requested property, or null if the property is not available */ public Object getProperty(String name) { return getAttributeValue(name); } /** * Get an iterator over all the properties available. The values returned by the iterator * will be of type String, and each string can be supplied as input to the getProperty() * method to retrieve the value of the property. */ public Iterator getProperties() { NamePool pool = getNamePool(); List list = new ArrayList(10); AxisIterator it = iterateAxis(Axis.ATTRIBUTE); while (true) { NodeInfo a = (NodeInfo)it.next(); if (a == null) { break; } list.add(pool.getClarkName(a.getNameCode())); } return list.iterator(); } public String getSystemId(long locationId) { return getSystemId(); } public int getLineNumber(long locationId) { return getLineNumber(); } public int getColumnNumber(long locationId) { return getColumnNumber(); } /** * Get the host language (XSLT, XQuery, XPath) used to implement the code in this container * @return typically {@link net.sf.saxon.Configuration#XSLT} or {@link net.sf.saxon.Configuration#XQUERY} */ public int getHostLanguage() { return Configuration.XSLT; } /** * Replace one subexpression by a replacement subexpression * @param original the original subexpression * @param replacement the replacement subexpression * @return true if the original subexpression is found */ public boolean replaceSubExpression(Expression original, Expression replacement) { throw new IllegalArgumentException("Invalid replacement"); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/style/XSLNamespace.java0000644000175000017500000001007411033112257021667 0ustar eugeneeugenepackage net.sf.saxon.style; import net.sf.saxon.expr.Expression; import net.sf.saxon.expr.StringLiteral; import net.sf.saxon.instruct.Executable; import net.sf.saxon.instruct.Namespace; import net.sf.saxon.om.*; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.Type; import net.sf.saxon.value.StringValue; import net.sf.saxon.value.Whitespace; /** * An xsl:namespace element in the stylesheet. (XSLT 2.0) */ public class XSLNamespace extends XSLStringConstructor { Expression name; public void prepareAttributes() throws XPathException { String nameAtt = null; String selectAtt = null; AttributeCollection atts = getAttributeList(); for (int a=0; a1)) { compileError("mode='#all' cannot be combined with other modes", "XTSE0550"); } } } catch (NamespaceException err) { compileError(err.getMessage(), "XTSE0280"); } catch (XPathException err) { if (err.getErrorCodeLocalPart() == null) { err.setErrorCode("XTSE0280"); } else if (err.getErrorCodeLocalPart().equals("XTSE0020")) { err.setErrorCode("XTSE0550"); } err.setIsStaticError(true); compileError(err); } try{ if (nameAtt!=null) { StructuredQName qName = makeQName(nameAtt); setObjectName(qName); diagnosticId = nameAtt; } } catch (NamespaceException err) { compileError(err.getMessage(), "XTSE0280"); } catch (XPathException err) { if (err.getErrorCodeLocalPart() == null) { err.setErrorCode("XTSE0280"); } err.setIsStaticError(true); compileError(err); } prioritySpecified = (priorityAtt != null); if (prioritySpecified) { if (matchAtt==null) { compileError("The priority attribute must be absent if the match attribute is absent", "XTSE0500"); } try { // it's got to be a valid decimal, but we want it as a double, so parse it twice if (!DecimalValue.castableAsDecimal(priorityAtt)) { compileError("Invalid numeric value for priority (" + priority + ')', "XTSE0530"); } priority = Double.parseDouble(priorityAtt); } catch (NumberFormatException err) { // shouldn't happen compileError("Invalid numeric value for priority (" + priority + ')', "XTSE0530"); } } if (matchAtt != null) { match = makePattern(matchAtt); if (diagnosticId == null) { diagnosticId = "match=\"" + matchAtt + '\"'; if (modeAtt != null) { diagnosticId += " mode=\"" + modeAtt + '\"'; } } } if (match==null && nameAtt==null) compileError("xsl:template must have a name or match attribute (or both)", "XTSE0500"); if (asAtt != null) { requiredType = makeSequenceType(asAtt); } } public void validate() throws XPathException { stackFrameMap = getConfiguration().makeSlotManager(); checkTopLevel(null); // the check for duplicates is now done in the buildIndexes() method of XSLStylesheet if (match != null) { match = typeCheck("match", match); if (match.getNodeTest() instanceof EmptySequenceTest) { try { getConfiguration().getErrorListener().warning( new TransformerException("Match pattern cannot match any nodes", this)); } catch (TransformerException e) { compileError(XPathException.makeXPathException(e)); } } } // See if there are any required parameters. AxisIterator kids = iterateAxis(Axis.CHILD); while(true) { NodeInfo param = (NodeInfo)kids.next(); if (param == null) { break; } if (param instanceof XSLParam && ((XSLParam)param).isRequiredParam()) { hasRequiredParams = true; break; } } } public void postValidate() throws XPathException { markTailCalls(); } /** * Mark tail-recursive calls on templates and functions. */ public boolean markTailCalls() { StyleElement last = getLastChildInstruction(); return last != null && last.markTailCalls(); } /** * Compile: this registers the template with the rule manager, and ensures * space is available for local variables */ public Expression compile(Executable exec) throws XPathException { Expression block = compileSequenceConstructor(exec, iterateAxis(Axis.CHILD), true); if (block == null) { block = Literal.makeEmptySequence(); } compiledTemplate.setMatchPattern(match); compiledTemplate.setBody(block); compiledTemplate.setStackFrameMap(stackFrameMap); compiledTemplate.setExecutable(getExecutable()); compiledTemplate.setSystemId(getSystemId()); compiledTemplate.setLineNumber(getLineNumber()); compiledTemplate.setHasRequiredParams(hasRequiredParams); compiledTemplate.setRequiredType(requiredType); Expression exp = null; try { exp = makeExpressionVisitor().simplify(block); } catch (XPathException e) { compileError(e); } try { if (requiredType != null) { RoleLocator role = new RoleLocator(RoleLocator.TEMPLATE_RESULT, diagnosticId, 0); //role.setSourceLocator(new ExpressionLocation(this)); role.setErrorCode("XTTE0505"); exp = TypeChecker.staticTypeCheck(exp, requiredType, false, role, makeExpressionVisitor()); } } catch (XPathException err) { compileError(err); } compiledTemplate.setBody(exp); compiledTemplate.init ( getObjectName(), getPrecedence(), getMinImportPrecedence()); if (getConfiguration().isCompileWithTracing()) { TraceWrapper trace = new TraceInstruction(exp, this); trace.setLocationId(allocateLocationId(getSystemId(), getLineNumber())); trace.setContainer(compiledTemplate); exp = trace; compiledTemplate.setBody(exp); } ItemType contextItemType = Type.ITEM_TYPE; if (getObjectName() == null) { // the template can't be called by name, so the context item must match the match pattern contextItemType = match.getNodeTest(); } ExpressionVisitor visitor = makeExpressionVisitor(); try { // We've already done the typecheck of each XPath expression, but it's worth doing again at this // level because we have more information now. Expression exp2 = visitor.typeCheck(exp, contextItemType); exp2 = visitor.optimize(exp2, contextItemType); if (exp != exp2) { compiledTemplate.setBody(exp2); exp = exp2; } } catch (XPathException e) { compileError(e); } // Try to extract new global variables from the body of the function // ExpressionPresenter presenter = ExpressionPresenter.make(getConfiguration()); // exp.explain(presenter); // presenter.close(); if (!getConfiguration().isCompileWithTracing()) { Expression exp2 = getConfiguration().getOptimizer().promoteExpressionsToGlobal(exp, visitor); if (exp != exp2) { compiledTemplate.setBody(exp2); exp = exp2; } } allocateSlots(exp); if (match != null) { RuleManager mgr = getPrincipalStylesheet().getRuleManager(); for (int i=0; i */ public class XSLText extends XSLStringConstructor { private boolean disable = false; private StringValue value; /** * Determine the type of item returned by this instruction (only relevant if * it is an instruction). * @return the item type returned */ protected ItemType getReturnedItemType() { return NodeKindTest.TEXT; } public void prepareAttributes() throws XPathException { String disableAtt = null; AttributeCollection atts = getAttributeList(); for (int a=0; a */ public class XSLKey extends StyleElement implements StylesheetProcedure { private Pattern match; private Expression use; private String collationName; private StructuredQName keyName; SlotManager stackFrameMap; // needed if variables are used /** * Determine whether this type of element is allowed to contain a sequence constructor * @return true: yes, it may contain a sequence constructor */ public boolean mayContainSequenceConstructor() { return true; } /** * Get the Procedure object that looks after any local variables declared in the content constructor */ public SlotManager getSlotManager() { return stackFrameMap; } public void prepareAttributes() throws XPathException { String nameAtt = null; String matchAtt = null; String useAtt = null; AttributeCollection atts = getAttributeList(); for (int a=0; a */ public final class XSLAttribute extends XSLStringConstructor { private Expression attributeName; private Expression separator; private Expression namespace = null; private int validationAction = Validation.PRESERVE; private SimpleType schemaType; public void prepareAttributes() throws XPathException { AttributeCollection atts = getAttributeList(); String nameAtt = null; String namespaceAtt = null; String selectAtt = null; String separatorAtt = null; String validationAtt = null; String typeAtt = null; for (int a=0; a */ public class XSLOtherwise extends StyleElement { /** * Determine the type of item returned by this instruction (only relevant if * it is an instruction). * @return the item type returned */ protected ItemType getReturnedItemType() { return getCommonChildItemType(); } public void prepareAttributes() throws XPathException { AttributeCollection atts = getAttributeList(); for (int a=0; a * The xsl:while element has a mandatory attribute test, a boolean expression. */ public class XSLWhen extends StyleElement { private Expression test; public Expression getCondition() { return test; } /** * Determine the type of item returned by this instruction (only relevant if * it is an instruction). * @return the item type returned */ protected ItemType getReturnedItemType() { return getCommonChildItemType(); } public void prepareAttributes() throws XPathException { String testAtt=null; AttributeCollection atts = getAttributeList(); for (int a=0; a */ public class SaxonFinally extends StyleElement { /** * Determine whether this node is an instruction. * @return true - it is an instruction */ public boolean isInstruction() { return true; } /** * Determine whether this type of element is allowed to contain a template-body * @return true: yes, it may contain a template-body */ public boolean mayContainSequenceConstructor() { return true; } public void prepareAttributes() throws XPathException { AttributeCollection atts = getAttributeList(); for (int a=0; a * The xsl:sequence element takes attributes:
      *
    • a mandatory attribute select="expression".
    • *
    */ public final class XSLSequence extends StyleElement { private Expression select; /** * Determine whether this node is an instruction. * @return true - it is an instruction */ public boolean isInstruction() { return true; } /** * Determine the type of item returned by this instruction (only relevant if * it is an instruction). * @return the item type returned */ protected ItemType getReturnedItemType() { final TypeHierarchy th = getConfiguration().getTypeHierarchy(); return select.getItemType(th); } /** * Determine whether this type of element is allowed to contain a template-body * @return true: yes, it may contain a template-body */ public boolean mayContainSequenceConstructor() { return false; } /** * Determine whether this type of element is allowed to contain an xsl:fallback * instruction */ public boolean mayContainFallback() { return true; } public void prepareAttributes() throws XPathException { String selectAtt = null; AttributeCollection atts = getAttributeList(); for (int a=0; asaxon:collation

    is deprecated from Saxon 8.8

    */ public class SaxonCollation extends StyleElement { private String collationName; private StringCollator collator; public void prepareAttributes() throws XPathException { AttributeCollection atts = getAttributeList(); String nameAtt = null; // collation name for use in expressions String defaultAtt = null; Properties props = new Properties(); for (int a=0; aafter the startElement event, and before * any children for the element. The namespaces that are reported are only required * to include those that are different from the parent element; however, duplicates may be reported. * A namespace must not conflict with any namespaces already used for element or attribute names. * * @param namespaceCode an integer: the top half is a prefix code, the bottom half a URI code. * These may be translated into an actual prefix and URI using the name pool. A prefix code of * zero represents the empty prefix (that is, the default namespace). A URI code of zero represents * a URI of "", that is, a namespace undeclaration. * @throws IllegalStateException: attempt to output a namespace when there is no open element * start tag */ public void namespace(int namespaceCode, int properties) throws XPathException { if (depthOfHole == 0) { nextReceiver.namespace(namespaceCode, properties); } } /** * Notify an attribute. Attributes are notified after the startElement event, and before any * children. Namespaces and attributes may be intermingled. * * @param nameCode The name of the attribute, as held in the name pool * @param typeCode The type of the attribute, as held in the name pool * @param properties Bit significant value. The following bits are defined: *
    DISABLE_ESCAPING
    Disable escaping for this attribute
    *
    NO_SPECIAL_CHARACTERS
    Attribute value contains no special characters
    * @throws IllegalStateException: attempt to output an attribute when there is no open element * start tag */ public void attribute(int nameCode, int typeCode, CharSequence value, int locationId, int properties) throws XPathException { if (depthOfHole == 0) { nextReceiver.attribute(nameCode, typeCode, value, locationId, properties); } } /** * Notify the start of the content, that is, the completion of all attributes and namespaces. * Note that the initial receiver of output from XSLT instructions will not receive this event, * it has to detect it itself. Note that this event is reported for every element even if it has * no attributes, no namespaces, and no content. */ public void startContent() throws XPathException { if (depthOfHole == 0) { nextReceiver.startContent(); } } /** * End of element */ public void endElement() throws XPathException { defaultNamespaceStack.pop(); if (depthOfHole > 0) { depthOfHole--; } else { nextReceiver.endElement(); } } /** * Character data */ public void characters(CharSequence chars, int locationId, int properties) throws XPathException { if (depthOfHole == 0) { nextReceiver.characters(chars, locationId, properties); } } /** * Processing Instruction */ public void processingInstruction(String target, CharSequence data, int locationId, int properties) { // these are ignored in a stylesheet } /** * Output a comment */ public void comment(CharSequence chars, int locationId, int properties) throws XPathException { // these are ignored in a stylesheet } /** * Evaluate a use-when attribute * @param expression the expression to be evaluated * @param locationId identifies the location of the expression in case error need to be reported * @return the effective boolean value of the result of evaluating the expression */ public boolean evaluateUseWhen(String expression, int locationId) throws XPathException { UseWhenStaticContext staticContext = new UseWhenStaticContext(getConfiguration(), startTag); // TODO: The following doesn't take account of xml:base attributes staticContext.setBaseURI(getDocumentLocator().getSystemId(locationId)); staticContext.setDefaultElementNamespace(NamespaceConstant.NULL); for (int i=defaultNamespaceStack.size()-1; i>=0; i--) { String uri = (String)defaultNamespaceStack.get(i); if (uri != null) { staticContext.setDefaultElementNamespace(uri); break; } } Expression expr = ExpressionTool.make(expression, staticContext, 0, Token.EOF, getDocumentLocator().getLineNumber(locationId), false); expr.setContainer(staticContext); ItemType contextItemType = Type.ITEM_TYPE; ExpressionVisitor visitor = ExpressionVisitor.make(staticContext); expr = visitor.typeCheck(expr, contextItemType); SlotManager stackFrameMap = getPipelineConfiguration().getConfiguration().makeSlotManager(); ExpressionTool.allocateSlots(expr, stackFrameMap.getNumberOfVariables(), stackFrameMap); Controller controller = new Controller(getConfiguration()); controller.setURIResolver(new URIPreventer()); controller.setCurrentDateTime(currentDateTime); // this is to ensure that all use-when expressions in a module use the same date and time XPathContext dynamicContext = controller.newXPathContext(); dynamicContext = dynamicContext.newCleanContext(); ((XPathContextMajor)dynamicContext).openStackFrame(stackFrameMap); return expr.effectiveBooleanValue(dynamicContext); } /** * Define a URIResolver that disallows all URIs */ private static class URIPreventer implements URIResolver { /** * Called by the processor when it encounters * an xsl:include, xsl:import, or document() function. * * @param href An href attribute, which may be relative or absolute. * @param base The base URI against which the first argument will be made * absolute if the absolute URI is required. * @return A Source object, or null if the href cannot be resolved, * and the processor should try to resolve the URI itself. * @throws javax.xml.transform.TransformerException * if an error occurs when trying to * resolve the URI. */ public Source resolve(String href, String base) throws TransformerException { throw new TransformerException("No external documents are available within an [xsl]use-when expression"); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/style/XSLSort.java0000644000175000017500000002311611033112257020723 0ustar eugeneeugenepackage net.sf.saxon.style; import net.sf.saxon.expr.*; import net.sf.saxon.instruct.Executable; import net.sf.saxon.om.AttributeCollection; import net.sf.saxon.om.Axis; import net.sf.saxon.om.NamespaceConstant; import net.sf.saxon.om.StandardNames; import net.sf.saxon.sort.CodepointCollator; import net.sf.saxon.sort.SortKeyDefinition; import net.sf.saxon.sort.StringCollator; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ItemType; import net.sf.saxon.value.EmptySequence; import net.sf.saxon.value.SequenceType; import net.sf.saxon.value.StringValue; import net.sf.saxon.value.Whitespace; import java.net.URI; import java.net.URISyntaxException; /** * An xsl:sort element in the stylesheet.
    */ public class XSLSort extends StyleElement { private SortKeyDefinition sortKeyDefinition; private Expression select; private Expression order; private Expression dataType = null; private Expression caseOrder; private Expression lang; private Expression collationName; private Expression stable; private boolean useDefaultCollation = true; /** * Determine whether this type of element is allowed to contain a sequence constructor * @return true: yes, it may contain a sequence constructor */ public boolean mayContainSequenceConstructor() { return true; } public void prepareAttributes() throws XPathException { AttributeCollection atts = getAttributeList(); String selectAtt = null; String orderAtt = null; String dataTypeAtt = null; String caseOrderAtt = null; String langAtt = null; String collationAtt = null; String stableAtt = null; for (int a=0; a * The xsl:value-of element takes attributes:
      *
    • a mandatory attribute select="expression". * This must be a valid String expression
    • *
    • an optional disable-output-escaping attribute, value "yes" or "no"
    • *
    • an optional separator attribute
    • *
    */ public final class XSLValueOf extends XSLStringConstructor { private boolean disable = false; private Expression separator; /** * Determine the type of item returned by this instruction (only relevant if * it is an instruction). * @return the item type returned */ protected ItemType getReturnedItemType() { return NodeKindTest.TEXT; } public void prepareAttributes() throws XPathException { String selectAtt = null; String disableAtt = null; String separatorAtt = null; AttributeCollection atts = getAttributeList(); for (int a=0; a */ public class XSLNamespaceAlias extends StyleElement { private short stylesheetURICode; private int resultNamespaceCode; public void prepareAttributes() throws XPathException { String stylesheetPrefix=null; String resultPrefix=null; AttributeCollection atts = getAttributeList(); for (int a=0; a * The xsl:if element has a mandatory attribute test, a boolean expression. * The content is output if the test condition is true. */ public class XSLIf extends StyleElement { private Expression test; /** * Determine whether this node is an instruction. * @return true - it is an instruction */ public boolean isInstruction() { return true; } /** * Determine the type of item returned by this instruction (only relevant if * it is an instruction). * @return the item type returned */ protected ItemType getReturnedItemType() { return getCommonChildItemType(); } /** * Determine whether this type of element is allowed to contain a template-body * @return true: yes, it may contain a template-body */ public boolean mayContainSequenceConstructor() { return true; } public void prepareAttributes() throws XPathException { String testAtt=null; AttributeCollection atts = getAttributeList(); for (int a=0; a */ public class XSLAttributeSet extends StyleElement implements StylesheetProcedure { private String nameAtt; // the name of the attribute set as written private String useAtt; // the value of the use-attribute-sets attribute, as supplied private SlotManager stackFrameMap; // needed if variables are used private List attributeSetElements = null; // list of XSLAttributeSet objects referenced by this one private AttributeSet[] useAttributeSets = null; // compiled instructions for the attribute sets used by this one private AttributeSet procedure = new AttributeSet(); // the compiled form of this attribute set private int referenceCount = 0; // the number of references to this attribute set private boolean validated = false; /** * Get the name of this attribute set * @return the name of the attribute set, as a QName */ public StructuredQName getAttributeSetName() { return getObjectName(); } /** * Get the compiled code produced for this XSLT element * @return the compiled AttributeSet */ public AttributeSet getInstruction() { return procedure; } /** * Increment the number of references found to this attribute set */ public void incrementReferenceCount() { referenceCount++; } public void prepareAttributes() throws XPathException { useAtt = null; AttributeCollection atts = getAttributeList(); for (int a=0; a 0 ) { Expression body = compileSequenceConstructor(exec, iterateAxis(Axis.CHILD), true); if (body == null) { body = Literal.makeEmptySequence(); } try { ExpressionVisitor visitor = makeExpressionVisitor(); body = visitor.simplify(body); if (getConfiguration().isCompileWithTracing()) { TraceWrapper trace = new TraceInstruction(body, this); trace.setLocationId(allocateLocationId(getSystemId(), getLineNumber())); trace.setContainer(procedure); body = trace; } procedure.setUseAttributeSets(useAttributeSets); procedure.setName(getObjectName()); procedure.setBody(body); procedure.setSystemId(getSystemId()); procedure.setLineNumber(getLineNumber()); procedure.setExecutable(exec); Expression exp2 = body.optimize(visitor, AnyItemType.getInstance()); if (body != exp2) { procedure.setBody(exp2); body = exp2; } super.allocateSlots(body); procedure.setStackFrameMap(stackFrameMap); } catch (XPathException e) { compileError(e); } } return null; } /** * Get the type of construct. This will be a constant in * class {@link net.sf.saxon.trace.Location}. This method is part of * the {@link net.sf.saxon.trace.InstructionInfo} interface */ public int getConstructType() { return StandardNames.XSL_ATTRIBUTE_SET; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/style/XSLResultDocument.java0000644000175000017500000003224411033112257022753 0ustar eugeneeugenepackage net.sf.saxon.style; import net.sf.saxon.Configuration; import net.sf.saxon.expr.Expression; import net.sf.saxon.expr.Literal; import net.sf.saxon.expr.StringLiteral; import net.sf.saxon.instruct.Executable; import net.sf.saxon.instruct.ResultDocument; import net.sf.saxon.om.*; import net.sf.saxon.sort.IntHashMap; import net.sf.saxon.sort.IntHashSet; import net.sf.saxon.sort.IntIterator; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.SchemaType; import net.sf.saxon.value.EmptySequence; import net.sf.saxon.value.Whitespace; import java.util.HashSet; import java.util.Properties; /** * An xsl:result-document element in the stylesheet.
    * The xsl:result-document element takes an attribute href="filename". The filename will * often contain parameters, e.g. {position()} to ensure that a different file is produced * for each element instance.
    * There is a further attribute "name" which determines the format of the * output file, it identifies the name of an xsl:output element containing the output * format details. */ public class XSLResultDocument extends StyleElement { private static final HashSet fans = new HashSet(25); // formatting attribute names static { fans.add(StandardNames.METHOD); fans.add(StandardNames.OUTPUT_VERSION); fans.add(StandardNames.BYTE_ORDER_MARK); fans.add(StandardNames.INDENT); fans.add(StandardNames.ENCODING); fans.add(StandardNames.MEDIA_TYPE); fans.add(StandardNames.DOCTYPE_SYSTEM); fans.add(StandardNames.DOCTYPE_PUBLIC); fans.add(StandardNames.OMIT_XML_DECLARATION); fans.add(StandardNames.STANDALONE); fans.add(StandardNames.CDATA_SECTION_ELEMENTS); fans.add(StandardNames.INCLUDE_CONTENT_TYPE); fans.add(StandardNames.ESCAPE_URI_ATTRIBUTES); fans.add(StandardNames.UNDECLARE_PREFIXES); fans.add(StandardNames.NORMALIZATION_FORM); fans.add(StandardNames.SAXON_NEXT_IN_CHAIN); fans.add(StandardNames.SAXON_CHARACTER_REPRESENTATION); fans.add(StandardNames.SAXON_INDENT_SPACES); fans.add(StandardNames.SAXON_REQUIRE_WELL_FORMED); fans.add(StandardNames.SAXON_SUPPRESS_INDENTATION); } private Expression href; private StructuredQName formatQName; // used when format is a literal string private Expression formatExpression; // used when format is an AVT private int validationAction = Validation.STRIP; private SchemaType schemaType = null; private IntHashMap serializationAttributes = new IntHashMap(10); /** * Determine whether this node is an instruction. * @return true - it is an instruction */ public boolean isInstruction() { return true; } /** * Determine whether this type of element is allowed to contain a template-body * @return true: yes, it may contain a template-body */ public boolean mayContainSequenceConstructor() { return true; } /** * Determine the type of item returned by this instruction (only relevant if * it is an instruction). Default implementation returns Type.ITEM, indicating * that we don't know, it might be anything. Returns null in the case of an element * such as xsl:sort or xsl:variable that can appear in a sequence constructor but * contributes nothing to the result sequence. * @return the item type returned */ protected ItemType getReturnedItemType() { return null; } public void prepareAttributes() throws XPathException { AttributeCollection atts = getAttributeList(); String formatAttribute = null; String hrefAttribute = null; String validationAtt = null; String typeAtt = null; String useCharacterMapsAtt = null; for (int a=0; a * The xsl:include and xsl:import elements have mandatory attribute href */ public abstract class XSLGeneralIncorporate extends StyleElement { String href; DocumentImpl includedDoc; /** * isImport() returns true if this is an xsl:import declaration rather than an xsl:include * @return true if this is an xsl:import declaration, false if it is an xsl:include */ public abstract boolean isImport(); public void prepareAttributes() throws XPathException { AttributeCollection atts = getAttributeList(); for (int a=0; a 0) { if (hash+1 < relative.length()) { fragment = relative.substring(hash+1); } relative = relative.substring(0, hash); } Source source; try { source = resolver.resolve(relative, getBaseURI()); } catch (TransformerException e) { throw XPathException.makeXPathException(e); } // if a user URI resolver returns null, try the standard one // (Note, the standard URI resolver never returns null) if (source==null) { source = config.getSystemURIResolver().resolve(relative, getBaseURI()); } if (fragment != null) { IDFilter filter = new IDFilter(fragment); source = AugmentedSource.makeAugmentedSource(source); ((AugmentedSource)source).addFilter(filter); } // check for recursion XSLStylesheet anc = thisSheet; if (source.getSystemId() != null) { while(anc!=null) { if (source.getSystemId().equals(anc.getSystemId())) { compileError("A stylesheet cannot " + getLocalPart() + " itself", (this instanceof XSLInclude ? "XTSE0180" : "XTSE0210")); return null; } anc = anc.getImporter(); } } StyleNodeFactory snFactory = new StyleNodeFactory(config, pss.getErrorListener()); includedDoc = pss.loadStylesheetModule(source, snFactory); // allow the included document to use "Literal Result Element as Stylesheet" syntax ElementImpl outermost = includedDoc.getDocumentElement(); if (outermost instanceof LiteralResultElement) { includedDoc = ((LiteralResultElement)outermost) .makeStylesheet(getPreparedStylesheet(), snFactory); outermost = includedDoc.getDocumentElement(); } if (!(outermost instanceof XSLStylesheet)) { compileError("Included document " + href + " is not a stylesheet", "XTSE0165"); return null; } XSLStylesheet incSheet = (XSLStylesheet)outermost; incSheet.validate(); if (incSheet.validationError!=null) { if (reportingCircumstances == REPORT_ALWAYS) { incSheet.compileError(incSheet.validationError); } else if (incSheet.reportingCircumstances == REPORT_UNLESS_FORWARDS_COMPATIBLE // not sure if this can still happen /*&& !incSheet.forwardsCompatibleModeIsEnabled()*/) { incSheet.compileError(incSheet.validationError); } } incSheet.setPrecedence(precedence); incSheet.setImporter(importer); incSheet.spliceIncludes(); // resolve any nested includes; // Check the consistency of input-type-annotations //assert thisSheet != null; thisSheet.setInputTypeAnnotations(incSheet.getInputTypeAnnotationsAttribute() | incSheet.getInputTypeAnnotations()); return incSheet; } catch (XPathException err) { err.setErrorCode("XTSE0165"); err.setIsStaticError(true); compileError(err); return null; } } public Expression compile(Executable exec) throws XPathException { return null; // no action. The node will never be compiled, because it replaces itself // by the contents of the included file. } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/style/XSLElement.java0000644000175000017500000002346211033112257021371 0ustar eugeneeugenepackage net.sf.saxon.style; import net.sf.saxon.Configuration; import net.sf.saxon.trans.Err; import net.sf.saxon.expr.*; import net.sf.saxon.instruct.*; import net.sf.saxon.om.*; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.SchemaType; import net.sf.saxon.value.AnyURIValue; import net.sf.saxon.value.EmptySequence; import net.sf.saxon.value.Whitespace; /** * An xsl:element element in the stylesheet.
    */ public class XSLElement extends StyleElement { private Expression elementName; private Expression namespace = null; private String use; private AttributeSet[] attributeSets = null; private int validation; private SchemaType schemaType = null; private boolean inheritNamespaces = true; /** * Determine whether this node is an instruction. * * @return true - it is an instruction */ public boolean isInstruction() { return true; } /** * Determine whether this type of element is allowed to contain a template-body * * @return true: yes, it may contain a template-body */ public boolean mayContainSequenceConstructor() { return true; } public void prepareAttributes() throws XPathException { AttributeCollection atts = getAttributeList(); String nameAtt = null; String namespaceAtt = null; String validationAtt = null; String typeAtt = null; String inheritAtt = null; for (int a = 0; a < atts.getLength(); a++) { int nc = atts.getNameCode(a); String f = getNamePool().getClarkName(nc); if (f.equals(StandardNames.NAME)) { nameAtt = Whitespace.trim(atts.getValue(a)); } else if (f.equals(StandardNames.NAMESPACE)) { namespaceAtt = atts.getValue(a); } else if (f.equals(StandardNames.VALIDATION)) { validationAtt = Whitespace.trim(atts.getValue(a)); } else if (f.equals(StandardNames.TYPE)) { typeAtt = Whitespace.trim(atts.getValue(a)); } else if (f.equals(StandardNames.INHERIT_NAMESPACES)) { inheritAtt = Whitespace.trim(atts.getValue(a)); } else if (f.equals(StandardNames.USE_ATTRIBUTE_SETS)) { use = atts.getValue(a); } else { checkUnknownAttribute(nc); } } if (nameAtt == null) { reportAbsence("name"); } else { elementName = makeAttributeValueTemplate(nameAtt); if (elementName instanceof StringLiteral) { if (!getConfiguration().getNameChecker().isQName(((StringLiteral)elementName).getStringValue())) { compileError("Element name " + Err.wrap(((StringLiteral)elementName).getStringValue(), Err.ELEMENT) + " is not a valid QName", "XTDE0820"); // to prevent duplicate error messages: elementName = new StringLiteral("saxon-error-element"); } } } if (namespaceAtt != null) { namespace = makeAttributeValueTemplate(namespaceAtt); if (namespace instanceof StringLiteral) { if (!AnyURIValue.isValidURI(((StringLiteral)namespace).getStringValue())) { compileError("The value of the namespace attribute must be a valid URI", "XTDE0835"); } } } if (validationAtt != null) { validation = Validation.getCode(validationAtt); if (validation != Validation.STRIP && !getConfiguration().isSchemaAware(Configuration.XSLT)) { compileError("To perform validation, a schema-aware XSLT processor is needed", "XTSE1660"); } if (validation == Validation.INVALID) { compileError("Invalid value for @validation attribute. " + "Permitted values are (strict, lax, preserve, strip)", "XTSE0020"); } } else { validation = getContainingStylesheet().getDefaultValidation(); } if (typeAtt != null) { if (!getConfiguration().isSchemaAware(Configuration.XSLT)) { compileError("The @type attribute is available only with a schema-aware XSLT processor", "XTSE1660"); } schemaType = getSchemaType(typeAtt); validation = Validation.BY_TYPE; } if (typeAtt != null && validationAtt != null) { compileError("The @validation and @type attributes are mutually exclusive", "XTSE1505"); } if (inheritAtt != null) { if (inheritAtt.equals("yes")) { inheritNamespaces = true; } else if (inheritAtt.equals("no")) { inheritNamespaces = false; } else { compileError("The @inherit-namespaces attribute has permitted values (yes, no)", "XTSE0020"); } } } public void validate() throws XPathException { if (use != null) { attributeSets = getAttributeSets(use, null); // find any referenced attribute sets } elementName = typeCheck("name", elementName); namespace = typeCheck("namespace", namespace); } public Expression compile(Executable exec) throws XPathException { NamespaceResolver nsContext = null; // deal specially with the case where the element name is known statically if (elementName instanceof StringLiteral) { CharSequence qName = ((StringLiteral)elementName).getStringValue(); String[] parts; try { parts = getConfiguration().getNameChecker().getQNameParts(qName); } catch (QNameException e) { compileError("Invalid element name: " + qName, "XTDE0820"); return null; } String nsuri = null; if (namespace instanceof StringLiteral) { nsuri = ((StringLiteral)namespace).getStringValue(); if (nsuri.length() == 0) { parts[0] = ""; } } else if (namespace == null) { nsuri = getURIForPrefix(parts[0], true); if (nsuri == null) { undeclaredNamespaceError(parts[0], "XTDE0830"); } } if (nsuri != null) { // Local name and namespace are both known statically: generate a FixedElement instruction int nameCode = getNamePool().allocate(parts[0], nsuri, parts[1]); FixedElement inst = new FixedElement(nameCode, null, inheritNamespaces, schemaType, validation); inst.setBaseURI(getBaseURI()); Expression content = compileSequenceConstructor(exec, iterateAxis(Axis.CHILD), true); if (attributeSets != null) { UseAttributeSets use = new UseAttributeSets(attributeSets); if (content == null) { content = use; } else { content = Block.makeBlock(use, content); content.setLocationId( allocateLocationId(getSystemId(), getLineNumber())); } } if (content == null) { content = new Literal(EmptySequence.getInstance()); } inst.setContentExpression(content); return inst; } } else { // if the namespace URI must be deduced at run-time from the element name // prefix, we need to save the namespace context of the instruction if (namespace == null) { nsContext = makeNamespaceContext(); } } ComputedElement inst = new ComputedElement(elementName, namespace, nsContext, //(nsContext==null ? null : nsContext.getURIForPrefix("", true)), schemaType, validation, inheritNamespaces, false); Expression content = compileSequenceConstructor(exec, iterateAxis(Axis.CHILD), true); if (attributeSets != null) { UseAttributeSets use = new UseAttributeSets(attributeSets); if (content == null) { content = use; } else { content = Block.makeBlock(use, content); content.setLocationId( allocateLocationId(getSystemId(), getLineNumber())); } } if (content == null) { content = new Literal(EmptySequence.getInstance()); } inst.setContentExpression(content); return inst; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/style/XSLAnalyzeString.java0000644000175000017500000002027211033112257022566 0ustar eugeneeugenepackage net.sf.saxon.style; import net.sf.saxon.Configuration; import net.sf.saxon.Platform; import net.sf.saxon.expr.*; import net.sf.saxon.instruct.AnalyzeString; import net.sf.saxon.instruct.Executable; import net.sf.saxon.om.*; import net.sf.saxon.regex.RegularExpression; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ItemType; import net.sf.saxon.value.SequenceType; /** * An xsl:analyze-string elements in the stylesheet. New at XSLT 2.0
    */ public class XSLAnalyzeString extends StyleElement { private Expression select; private Expression regex; private Expression flags; private StyleElement matching; private StyleElement nonMatching; private RegularExpression pattern; /** * Determine whether this node is an instruction. * @return true - it is an instruction */ public boolean isInstruction() { return true; } /** * Determine whether this type of element is allowed to contain an xsl:fallback * instruction */ public boolean mayContainFallback() { return true; } /** * Determine the type of item returned by this instruction (only relevant if * it is an instruction). * @return the item type returned */ protected ItemType getReturnedItemType() { return getCommonChildItemType(); } public void prepareAttributes() throws XPathException { String selectAtt = null; String regexAtt = null; String flagsAtt = null; AttributeCollection atts = getAttributeList(); for (int a=0; a getPrecedence()) { // ignore this value, the other has higher precedence } else if (op == getPrecedence()) { compileError("Conflicting values for output property " + property, "XTSE1560"); } else { // this has higher precedence: can't happen throw new IllegalStateException("Output properties must be processed in decreasing precedence order"); } } } /** * Process the use-character-maps attribute * @param element the stylesheet element on which the use-character-maps attribute appears * @param useCharacterMaps the value of the use-character-maps attribute * @param details The existing output properties * @return the augmented value of the use-character-maps attribute in Clark notation * @throws XPathException if the value is invalid */ public static String prepareCharacterMaps(StyleElement element, String useCharacterMaps, Properties details) throws XPathException { XSLStylesheet principal = element.getPrincipalStylesheet(); String existing = details.getProperty(SaxonOutputKeys.USE_CHARACTER_MAPS); if (existing==null) { existing = ""; } String s = ""; StringTokenizer st = new StringTokenizer(useCharacterMaps, " \t\n\r", false); while (st.hasMoreTokens()) { String displayname = st.nextToken(); try { StructuredQName qName = element.makeQName(displayname); XSLCharacterMap ref = principal.getCharacterMap(qName); if (ref == null) { element.compileError("No character-map named '" + displayname + "' has been defined", "XTSE1590"); } s += " " + qName.getClarkName(); } catch (NamespaceException err) { element.undeclaredNamespaceError(err.getPrefix(), "XTSE0280"); } } existing = s + existing; return existing; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/style/XSLNextMatch.java0000644000175000017500000000657311033112257021677 0ustar eugeneeugenepackage net.sf.saxon.style; import net.sf.saxon.expr.Expression; import net.sf.saxon.instruct.Executable; import net.sf.saxon.instruct.NextMatch; import net.sf.saxon.om.AttributeCollection; import net.sf.saxon.om.Axis; import net.sf.saxon.om.AxisIterator; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.Type; import net.sf.saxon.value.Whitespace; /** * An xsl:next-match element in the stylesheet */ public class XSLNextMatch extends StyleElement { private boolean useTailRecursion = false; /** * Determine whether this node is an instruction. * @return true - it is an instruction */ public boolean isInstruction() { return true; } /** * Determine whether this type of element is allowed to contain an xsl:fallback * instruction */ public boolean mayContainFallback() { return true; } public void prepareAttributes() throws XPathException { AttributeCollection atts = getAttributeList(); for (int a=0; a */ public class XSLOutputCharacter extends StyleElement { private int codepoint = -1; // the character to be substituted, as a Unicode codepoint (may be > 65535) private String replacementString = null; public void prepareAttributes() throws XPathException { AttributeCollection atts = getAttributeList(); for (int a=0; a */ public class XSLDecimalFormat extends StyleElement { boolean prepared = false; String name; String decimalSeparator; String groupingSeparator; String infinity; String minusSign; String NaN; String percent; String perMille; String zeroDigit; String digit; String patternSeparator; public void prepareAttributes() throws XPathException { if (prepared) { return; } prepared = true; AttributeCollection atts = getAttributeList(); for (int a=0; a */ public class XSLCopy extends StyleElement { private String use; // value of use-attribute-sets attribute private AttributeSet[] attributeSets = null; private boolean copyNamespaces = true; private boolean inheritNamespaces = true; private int validationAction = Validation.PRESERVE; private SchemaType schemaType = null; /** * Determine whether this node is an instruction. * @return true - it is an instruction */ public boolean isInstruction() { return true; } /** * Determine whether this type of element is allowed to contain a template-body * @return true: yes, it may contain a template-body */ public boolean mayContainSequenceConstructor() { return true; } public void prepareAttributes() throws XPathException { AttributeCollection atts = getAttributeList(); String copyNamespacesAtt = null; String validationAtt = null; String typeAtt = null; String inheritAtt = null; for (int a=0; a * Attributes:
    * name gives the name of the function * saxon:memo-function=yes|no indicates whether it acts as a memo function. */ public class XSLFunction extends StyleElement implements StylesheetProcedure { private String nameAtt = null; private String asAtt = null; private String overrideAtt = null; private SequenceType resultType; private String functionName; private SlotManager stackFrameMap; private boolean memoFunction = false; private boolean override = true; private int numberOfArguments = -1; // -1 means not yet known private UserFunction compiledFunction; // List of UserFunctionCall objects that reference this XSLFunction List references = new ArrayList(10); /** * Method called by UserFunctionCall to register the function call for * subsequent fixup. * @param ref the UserFunctionCall to be registered */ public void registerReference(UserFunctionCall ref) { references.add(ref); } public void prepareAttributes() throws XPathException { AttributeCollection atts = getAttributeList(); overrideAtt = "yes"; for (int a=0; a=0; i--) { Object child = toplevel.get(i); if (child instanceof XSLFunction && !(child == this) && ((XSLFunction)child).getObjectName().equals(getObjectName()) && ((XSLFunction)child).getNumberOfArguments() == numberOfArguments) { if (((XSLFunction)child).getPrecedence() == getPrecedence()) { isDuplicate = true; } if (((XSLFunction)child).getPrecedence() > getPrecedence()) { // it's not an error to have duplicates if there is another with higher precedence isDuplicate = false; break; } } } if (isDuplicate) { compileError("Duplicate function declaration", "XTSE0770"); } } /** * Compile the function definition to create an executable representation * @return an Instruction, or null. The instruction returned is actually * rather irrelevant; the compile() method has the side-effect of binding * all references to the function to the executable representation * (a UserFunction object) * @throws XPathException */ public Expression compile(Executable exec) throws XPathException { compileAsExpression(exec); return null; } /** * Compile the function into a UserFunction object, which treats the function * body as a single XPath expression. This involves recursively translating * xsl:variable declarations into let expressions, withe the action part of the * let expression containing the rest of the function body. * The UserFunction that is created will be linked from all calls to * this function, so nothing else needs to be done with the result. If there are * no calls to it, the compiled function will be garbage-collected away. * @param exec the Executable * @throws XPathException */ private void compileAsExpression(Executable exec) throws XPathException { Expression exp = compileSequenceConstructor(exec, iterateAxis(Axis.CHILD), false); if (exp == null) { exp = Literal.makeEmptySequence(); } UserFunction fn = new UserFunction(); fn.setHostLanguage(Configuration.XSLT); fn.setBody(exp); fn.setFunctionName(getObjectName()); setParameterDefinitions(fn); fn.setResultType(getResultType()); fn.setLineNumber(getLineNumber()); fn.setSystemId(getSystemId()); fn.setStackFrameMap(stackFrameMap); fn.setMemoFunction(memoFunction); fn.setExecutable(exec); Expression exp2 = exp; ExpressionVisitor visitor = makeExpressionVisitor(); try { // We've already done the typecheck of each XPath expression, but it's worth doing again at this // level because we have more information now. exp2 = visitor.typeCheck(exp, null); if (resultType != null) { RoleLocator role = new RoleLocator(RoleLocator.FUNCTION_RESULT, functionName, 0); //role.setSourceLocator(new ExpressionLocation(this)); role.setErrorCode("XTTE0780"); exp2 = TypeChecker.staticTypeCheck(exp2, resultType, false, role, visitor); } exp2 = exp2.optimize(visitor, null); } catch (XPathException err) { err.maybeSetLocation(this); compileError(err); } // Try to extract new global variables from the body of the function exp2 = getConfiguration().getOptimizer().promoteExpressionsToGlobal(exp2, visitor); // Add trace wrapper code if required if (getPreparedStylesheet().isCompileWithTracing()) { TraceWrapper trace = new TraceInstruction(exp2, this); trace.setLocationId(allocateLocationId(getSystemId(), getLineNumber())); exp2 = trace; } allocateSlots(exp2); if (exp2 != exp) { fn.setBody(exp2); } int tailCalls = ExpressionTool.markTailFunctionCalls(exp2, getObjectName(), getNumberOfArguments()); if (tailCalls != 0) { fn.setTailRecursive(tailCalls > 0, tailCalls > 1); fn.setBody(new TailCallLoop(fn)); } fixupInstruction(fn); compiledFunction = fn; fn.computeEvaluationMode(); if (isExplaining()) { exp2.explain(System.err); } } /** * Fixup all function references. * @param compiledFunction the Instruction representing this function in the compiled code * @throws XPathException if an error occurs. */ private void fixupInstruction(UserFunction compiledFunction) throws XPathException { ExpressionVisitor visitor = makeExpressionVisitor(); try { Iterator iter = references.iterator(); while (iter.hasNext()) { UserFunctionCall call = ((UserFunctionCall)iter.next()); call.setFunction(compiledFunction); call.checkFunctionCall(compiledFunction, visitor); call.computeArgumentEvaluationModes(); } } catch (XPathException err) { compileError(err); } } /** * Get associated Procedure (for details of stack frame). * @return the associated Procedure object */ public SlotManager getSlotManager() { return stackFrameMap; } /** * Get the type of value returned by this function * @return the declared result type, or the inferred result type * if this is more precise */ public SequenceType getResultType() { return resultType; } /** * Get the number of arguments declared by this function (that is, its arity). * @return the arity of the function */ public int getNumberOfArguments() { if (numberOfArguments == -1) { numberOfArguments = 0; AxisIterator kids = iterateAxis(Axis.CHILD); while (true) { Item child = kids.next(); if (child instanceof XSLParam) { numberOfArguments++; } else { return numberOfArguments; } } } return numberOfArguments; } /** * Set the definitions of the parameters in the compiled function, as an array. * @param fn the compiled object representing the user-written function */ public void setParameterDefinitions(UserFunction fn) { UserFunctionParameter[] params = new UserFunctionParameter[getNumberOfArguments()]; fn.setParameterDefinitions(params); int count = 0; AxisIterator kids = iterateAxis(Axis.CHILD); while (true) { NodeInfo node = (NodeInfo)kids.next(); if (node == null) { return; } if (node instanceof XSLParam) { UserFunctionParameter param = new UserFunctionParameter(); params[count++] = param; param.setRequiredType(((XSLParam)node).getRequiredType()); param.setVariableQName(((XSLParam)node).getVariableQName()); param.setSlotNumber(((XSLParam)node).getSlotNumber()); ((XSLParam)node).fixupBinding(param); int refs = ExpressionTool.getReferenceCount(fn.getBody(), param, false); param.setReferenceCount(refs); } } } /** * Get the compiled function * @return the object representing the compiled user-written function */ public UserFunction getCompiledFunction() { return compiledFunction; } /** * Get the type of construct. This will be a constant in * class {@link net.sf.saxon.trace.Location}. This method is part of the * {@link net.sf.saxon.trace.InstructionInfo} interface */ public int getConstructType() { return StandardNames.XSL_FUNCTION; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/style/package.html0000644000175000017500000000406711033112257021027 0ustar eugeneeugene Package overview: net.sf.saxon.style

    This package provides classes used during the compilation of an XSLT stylesheet. The instances of these classes are discarded once compilation is complete, and they play no role in executing the transformation at run-time, except when tracing and debugging are invoked.

    The class StyleElement represents an element node on the stylesheet tree. Subclasses of StyleElement represent individual stylesheet elements, and are generally named according to the XSLT element name, for example XSLApplyTemplates, XSLChoose. The class XSLStylesheet is used for the xsl:stylesheet element in each stylesheet module, and in particular for the xsl:stylesheet element in the principal stylesheet module.

    During construction of the stylesheet tree, the class StyleNodeFactory is nominated to the Builder as the factory class responsible for creating element nodes on the tree. It is this class that decides which subclass of StyleElement to use for each element appearing in the stylesheet. For extension elements, the decision is delegated to a user-created ExtensionElementFactory.

    Each class provides a number of methods supporting the various phases of processing. The sequence of events sometimes varies slightly, but in general the first phase is done by prepareAttributes, which performs local validation of the attributes of each instruction. The second phase is represented by the validate method, which does global validation, fixup of references, and type checking. The third phase is done by the compile method, which generates Instruction and Expression objects. Further processing (local and global optimization) is then done on these Instruction objects, and is no longer the responsibility of this package.


    Michael H. Kay
    Saxonica Limited
    9 February 2005

    saxonb-9.1.0.8/bj/net/sf/saxon/codenorm/0000755000175000017500000000000012216261751017215 5ustar eugeneeugenesaxonb-9.1.0.8/bj/net/sf/saxon/codenorm/UnicodeDataParser.java0000644000175000017500000001664511033112257023421 0ustar eugeneeugenepackage net.sf.saxon.codenorm; import net.sf.saxon.sort.IntHashMap; import net.sf.saxon.sort.IntToIntHashMap; import net.sf.saxon.sort.IntToIntMap; import java.util.ArrayList; import java.util.BitSet; import java.util.StringTokenizer; /** * This class reads the data compiled into class UnicodeData, and builds hash tables * that can be used by the Unicode normalization routines. This operation is performed * once only, the first time normalization is attempted after Saxon is loaded. */ class UnicodeDataParser { // This class is never instantiated private UnicodeDataParser(){} /** * Called exactly once by NormalizerData to build the static data */ static NormalizerData build() { IntToIntMap canonicalClass = new IntToIntHashMap(400); canonicalClass.setDefaultValue(0); IntHashMap decompose = new IntHashMap(18000); IntToIntMap compose = new IntToIntHashMap(15000); compose.setDefaultValue(NormalizerData.NOT_COMPOSITE); BitSet isCompatibility = new BitSet(128000); BitSet isExcluded = new BitSet(128000); readExclusionList(isExcluded); readCompatibilityList(isCompatibility); readCanonicalClassTable(canonicalClass); readDecompositionTable(decompose, compose, isExcluded, isCompatibility); return new NormalizerData(canonicalClass, decompose, compose, isCompatibility, isExcluded); } /** * Reads exclusion list and stores the data */ private static void readExclusionList(BitSet isExcluded) { for (int i=0; i 1) { first = second; second = value.charAt(1); } // store composition pair in single integer int pair = (first << 16) | second; compose.put(pair, key); } } } // Add algorithmic Hangul decompositions // This fragment code is copied from the normalization code published by Unicode consortium. // See module net.sf.saxon.codenorm.Normalizer for applicable copyright information. for (int SIndex = 0; SIndex < SCount; ++SIndex) { int TIndex = SIndex % TCount; char first, second; if (TIndex != 0) { // triple first = (char)(SBase + SIndex - TIndex); second = (char)(TBase + TIndex); } else { first = (char)(LBase + SIndex / NCount); second = (char)(VBase + (SIndex % NCount) / TCount); } int pair = (first << 16) | second; int key = SIndex + SBase; decompose.put(key, String.valueOf(first) + second); compose.put(pair, key); } } /** * Hangul composition constants */ private static final int SBase = 0xAC00, LBase = 0x1100, VBase = 0x1161, TBase = 0x11A7, LCount = 19, VCount = 21, TCount = 28, NCount = VCount * TCount, // 588 SCount = LCount * NCount; // 11172 // end of Unicode consortium code } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // The code for generating Hangul decompositions is Copyright (C) Unicode, Inc. All Rights Reserved. // See statement below. // // Contributor(s): none. // // * Copyright (c) 1991-2005 Unicode, Inc. // * For terms of use, see http://www.unicode.org/terms_of_use.html // * For documentation, see UAX#15.
    // * The Unicode Consortium makes no expressed or implied warranty of any // * kind, and assumes no liability for errors or omissions. // * No liability is assumed for incidental and consequential damages // * in connection with or arising out of the use of the information here.saxonb-9.1.0.8/bj/net/sf/saxon/codenorm/UnicodeDataGenerator.java0000644000175000017500000004124111033112257024101 0ustar eugeneeugenepackage net.sf.saxon.codenorm; import net.sf.saxon.om.FastStringBuffer; import java.io.*; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /** * This class reads the Unicode character database, extracts information needed * to perform unicode normalization, and writes this information out in the form of the * Java "source" module UnicodeData.java. This class is therefore executed (via its main() * method) at the time Saxon is built - it only needs to be rerun when the Unicode data tables * have changed. *

    * The class is derived from the sample program NormalizerData.java published by the * Unicode consortium. That code has been modified so that instead of building the run-time * data structures directly, they are written to a Java "source" module, which is then * compiled. Also, the ability to construct a condensed version of the data tables has been * removed. *

    * Copyright (c) 1991-2005 Unicode, Inc. * For terms of use, see http://www.unicode.org/terms_of_use.html * For documentation, see UAX#15.
    * @author Mark Davis * @author Michael Kay: Saxon modifications. */ class UnicodeDataGenerator { static final String copyright = "Copyright © 1998-1999 Unicode, Inc."; /** * Testing flags */ private static final boolean DEBUG = false; /** * Constants for the data file version to use. */ // static final boolean NEW_VERSION = true; private static String dir; private static String UNICODE_DATA = "UnicodeData.txt"; private static String COMPOSITION_EXCLUSIONS = "CompositionExclusions.txt"; private static List canonicalClassKeys = new ArrayList(30000); private static List canonicalClassValues = new ArrayList(30000); private static List decompositionKeys = new ArrayList(6000); private static List decompositionValues = new ArrayList(6000); private static List exclusionList = new ArrayList(200); private static List compatibilityList = new ArrayList(8000); private UnicodeDataGenerator() { } /** * Called exactly once by NormalizerData to build the static data */ static void build() { try { readExclusionList(); buildDecompositionTables(); } catch (java.io.IOException e) { System.err.println("Can't load data file." + e + ", " + e.getMessage()); } } // ============================================================= // Building Decomposition Tables // ============================================================= /** * Reads exclusion list and stores the data */ // Modified by MHK: the original code expects the hex character code to be always four hex digits private static void readExclusionList() throws java.io.IOException { if (DEBUG) System.out.println("Reading Exclusions"); BufferedReader in = new BufferedReader(new FileReader(dir + '/' + COMPOSITION_EXCLUSIONS), 5*1024); while (true) { // read a line, discarding comments and blank lines String line = in.readLine(); if (line == null) break; int comment = line.indexOf('#'); // strip comments if (comment != -1) line = line.substring(0,comment); if (line.length() == 0) continue; // ignore blanks // store -1 in the excluded table for each character hit int z = line.indexOf(' '); if (z < 0) { z = line.length(); } int value = Integer.parseInt(line.substring(0,z),16); exclusionList.add(new Integer(value)); } in.close(); } /** * Builds a decomposition table from a UnicodeData file */ private static void buildDecompositionTables() throws java.io.IOException { if (DEBUG) System.out.println("Reading Unicode Character Database"); BufferedReader in = new BufferedReader(new FileReader(dir + '/' + UNICODE_DATA), 64*1024); int value; int counter = 0; while (true) { // read a line, discarding comments and blank lines String line = in.readLine(); if (line == null) break; int comment = line.indexOf('#'); // strip comments if (comment != -1) line = line.substring(0,comment); if (line.length() == 0) continue; if (DEBUG) { counter++; if ((counter & 0xFF) == 0) System.out.println("At: " + line); } // find the values of the particular fields that we need // Sample line: 00C0;LATIN ...A GRAVE;Lu;0;L;0041 0300;;;;N;LATIN ... GRAVE;;;00E0; int start = 0; int end = line.indexOf(';'); // code try { value = Integer.parseInt(line.substring(start,end),16); } catch (NumberFormatException e) { throw new IllegalStateException("Bad hex value in line:\n" + line); } if (true && value == '\u00c0') { System.out.println("debug: " + line); } end = line.indexOf(';', end+1); // name //String name = line.substring(start,end); end = line.indexOf(';', end+1); // general category end = line.indexOf(';', start=end+1); // canonical class // check consistency: canonical classes must be from 0 to 255 int cc = Integer.parseInt(line.substring(start,end)); if (cc != (cc & 0xFF)) System.err.println("Bad canonical class at: " + line); canonicalClassKeys.add(new Integer(value)); canonicalClassValues.add(new Integer(cc)); //canonicalClass.put(value,cc); end = line.indexOf(';', end+1); // BIDI end = line.indexOf(';', start=end+1); // decomp // decomp requires more processing. // store whether it is canonical or compatibility. // store the decomp in one table, and the reverse mapping (from pairs) in another if (start != end) { String segment = line.substring(start, end); boolean compat = segment.charAt(0) == '<'; if (compat) { compatibilityList.add(new Integer(value)); //isCompatibility.set(value); } String decomp = fromHex(segment); // check consistency: all canon decomps must be singles or pairs! if (decomp.length() < 1 || decomp.length() > 2 && !compat) { System.err.println("Bad decomp at: " + line); } decompositionKeys.add(new Integer(value)); decompositionValues.add(decomp); //decompose.put(value, decomp); // only compositions are canonical pairs // skip if script exclusion // if (!compat && !isExcluded.get(value)) { // char first = '\u0000'; // char second = decomp.charAt(0); // if (decomp.length() > 1) { // first = second; // second = decomp.charAt(1); // } // // // store composition pair in single integer // // pair = (first << 16) | second; // if (DEBUG && value == '\u00C0') { // System.out.println("debug2: " + line); // } // compose.put(pair, value); // } else if (DEBUG) { // System.out.println("Excluding: " + decomp); // } } } in.close(); if (DEBUG) System.out.println("Done reading Unicode Character Database"); // add algorithmic Hangul decompositions // this is more compact if done at runtime, but for simplicity we // do it this way. // if (DEBUG) System.out.println("Adding Hangul"); // // for (int SIndex = 0; SIndex < SCount; ++SIndex) { // int TIndex = SIndex % TCount; // char first, second; // if (TIndex != 0) { // triple // first = (char)(SBase + SIndex - TIndex); // second = (char)(TBase + TIndex); // } else { // first = (char)(LBase + SIndex / NCount); // second = (char)(VBase + (SIndex % NCount) / TCount); // } // pair = (first << 16) | second; // value = SIndex + SBase; // decompose.put(value, String.valueOf(first) + second); // compose.put(pair, value); // } // if (DEBUG) System.out.println("Done adding Hangul"); } /** * Hangul composition constants */ // static final int // SBase = 0xAC00, LBase = 0x1100, VBase = 0x1161, TBase = 0x11A7, // LCount = 19, VCount = 21, TCount = 28, // NCount = VCount * TCount, // 588 // SCount = LCount * NCount; // 11172 /** * Utility: Parses a sequence of hex Unicode characters separated by spaces */ // Modified by MHK. Original code assumed the characters were each 4 hex digits! public static String fromHex(String source) { FastStringBuffer result = new FastStringBuffer(5); for (int i = 0; i < source.length(); ++i) { char c = source.charAt(i); switch (c) { case ' ': break; // ignore case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': int z = source.indexOf(' ',i); if (z < 0) { z = source.length(); } try { result.append((char)Integer.parseInt(source.substring(i, z),16)); } catch (NumberFormatException e) { throw new IllegalArgumentException("Bad hex value in " + source); } i = z; // skip rest of number break; case '<': int j = source.indexOf('>',i); // skip <...> if (j > 0) { i = j; break; } // else fall through--error default: throw new IllegalArgumentException("Bad hex value in " + source); } } return result.toString(); } /** * Utility: Supplies a zero-padded hex representation of a Unicode character (without 0x, \\u) */ public static String hex(char i) { String result = Integer.toString(i, 16).toUpperCase(); return "0000".substring(result.length(),4) + result; } /** * Utility: Supplies a zero-padded hex representation of a Unicode character (without 0x, \\u) */ public static String hex(String s, String sep) { FastStringBuffer result = new FastStringBuffer(20); for (int i = 0; i < s.length(); ++i) { if (i != 0) result.append(sep); result.append(hex(s.charAt(i))); } return result.toString(); } /** * Generate the Java output from the data structure */ private static void generateJava(PrintStream o) { o.println("package net.sf.saxon.codenorm;"); o.println(""); o.println("//This module was generated by running net.sf.saxon.codenorm.UnicodeDataGenerator"); o.println("//*** DO NOT EDIT! ***"); o.println("//The strange format of this file is carefully chosen to avoid breaking Java compiler limits"); o.println(""); o.println("public class UnicodeData {"); // Output the canonical class table o.println("public static final String[] canonicalClassKeys = {"); printArray(o, canonicalClassKeys.iterator()); o.println("};"); o.println("public static final String[] canonicalClassValues = {"); printArray(o, canonicalClassValues.iterator()); o.println("};"); // Output the decomposition values (not including Hangul algorithmic decompositions) o.println("public static final String[] decompositionKeys = {"); printArray(o, decompositionKeys.iterator()); o.println("};"); o.println("public static final String[] decompositionValues = {"); printStringArray(o, decompositionValues.iterator()); o.println("};"); // Output the composition exclusions o.println("public static final String[] exclusionList = {"); printArray(o, exclusionList.iterator()); o.println("};"); // Output the compatibility list o.println("public static final String[] compatibilityList = {"); printArray(o, compatibilityList.iterator()); o.println("};"); o.println("}"); } /** * Output an array of integer values */ private static void printArray(PrintStream o, Iterator iter) { int count = 0; FastStringBuffer buff = new FastStringBuffer(120); if (!iter.hasNext()) return; buff.append('"'); while (true) { if (++count == 20) { count = 0; buff.append("\","); o.println(buff.toString()); buff.setLength(0); buff.append('"'); } int next = ((Integer)iter.next()).intValue(); buff.append(Integer.toString(next, 32)); // values are written in base-32 notation if (iter.hasNext()) { buff.append(","); } else { buff.append("\""); o.println(buff.toString()); return; } } } /** * Output an array of string values (using backslash-uuuu notation where appropriate) */ private static void printStringArray(PrintStream o, Iterator iter) { int count = 0; FastStringBuffer buff = new FastStringBuffer(120); if (!iter.hasNext()) return; while (true) { if (++count == 20) { count = 0; o.println(buff.toString()); buff.setLength(0); } String next = (String)iter.next(); appendJavaString(next, buff); if (iter.hasNext()) { buff.append(", "); } else { o.println(buff.toString()); return; } } } private static void appendJavaString(String value, FastStringBuffer buff) { buff.append('"'); for (int i=0; i 32 && c < 127) { buff.append(c); } else { buff.append("\\u"); char b0 = "0123456789abcdef".charAt(c & 0xf); char b1 = "0123456789abcdef".charAt((c>>4) & 0xf); char b2 = "0123456789abcdef".charAt((c>>8) & 0xf); char b3 = "0123456789abcdef".charAt((c>>12) & 0xf); buff.append(b3); buff.append(b2); buff.append(b1); buff.append(b0); } } buff.append('"'); } /** * Main program. Run this program to regenerate the Java module UnicodeData.java against revised data * from the Unicode character database. *

    * Usage: java UnicodeDataGenerator dir >UnicodeData.java *

    * where dir is the directory containing the files UnicodeData.text and CompositionExclusions.txt from the * Unicode character database. */ public static void main(String[] args) throws Exception { if (args.length != 2) { System.err.println("Usage: java UnicodeDataGenerator dir UnicodeData.java"); System.err.println("where dir is the directory containing the files UnicodeData.text and" + " CompositionExclusions.txt from the Unicode character database"); } dir = args[0]; build(); PrintStream o = new PrintStream(new FileOutputStream(new File(args[1]))); generateJava(o); } } saxonb-9.1.0.8/bj/net/sf/saxon/codenorm/Normalizer.java0000644000175000017500000002640611033112257022202 0ustar eugeneeugenepackage net.sf.saxon.codenorm; import net.sf.saxon.charcode.UTF16; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.Whitespace; /** * Implements Unicode Normalization Forms C, D, KC, KD. * Copyright (c) 1991-2005 Unicode, Inc. * For terms of use, see http://www.unicode.org/terms_of_use.html * For documentation, see UAX#15.
    * The Unicode Consortium makes no expressed or implied warranty of any * kind, and assumes no liability for errors or omissions. * No liability is assumed for incidental and consequential damages * in connection with or arising out of the use of the information here. * @author Mark Davis * Updates for supplementary code points: Vladimir Weinstein & Markus Scherer * Modified to remove dependency on ICU code: Michael Kay */ public class Normalizer { /** * Create a normalizer for a given form. * @param form the normalization form required: for example {@link Normalizer#C}, {@link Normalizer#D} */ public Normalizer(byte form) { this.form = form; if (data == null) { data = UnicodeDataParser.build(); // load 1st time } } /** * Create a normalizer for a given form, expressed as a character string * @param formCS the normalization form required: for example "NFC" or "NFD" */ public Normalizer(CharSequence formCS) throws XPathException { String formString = Whitespace.trim(formCS); byte fb; if (formString.length() == 0) { fb = NO_ACTION; } else if (formString.equalsIgnoreCase("NFC")) { fb = Normalizer.C; } else if (formString.equalsIgnoreCase("NFD")) { fb = Normalizer.D; } else if (formString.equalsIgnoreCase("NFKC")) { fb = Normalizer.KC; } else if (formString.equalsIgnoreCase("NFKD")) { fb = Normalizer.KD; } else { String msg = "Normalization form " + formString + " is not supported"; throw new XPathException(msg, "FOCH0003"); } form = fb; if (data == null) { data = UnicodeDataParser.build(); // load 1st time } } /** * Masks for the form selector */ static final byte COMPATIBILITY_MASK = 1, COMPOSITION_MASK = 2; /** * Normalization Form Selector */ public static final byte D = 0 , C = COMPOSITION_MASK, KD = COMPATIBILITY_MASK, KC = (byte)(COMPATIBILITY_MASK + COMPOSITION_MASK), NO_ACTION = 8; /** * Normalizes text according to the chosen form, * replacing contents of the target buffer. * @param source the original text, unnormalized * @param target the resulting normalized text * @return the modified target StringBuffer */ private StringBuffer normalize(CharSequence source, StringBuffer target) { if (form == NO_ACTION || source.length() == 0) { return new StringBuffer(source.toString()); } // First decompose the source into target, // then compose if the form requires. internalDecompose(source, target); if ((form & COMPOSITION_MASK) != 0) { internalCompose(target); } return target; } /** * Normalizes text according to the chosen form * @param source the original text, unnormalized * @return target the resulting normalized text */ public CharSequence normalize(CharSequence source) { return normalize(source, new StringBuffer(source.length()+8)); } // ====================================== // PRIVATES // ====================================== /** * The current form. */ private byte form; /** * Decomposes text, either canonical or compatibility, * replacing contents of the target buffer. // * @param form the normalization form. If COMPATIBILITY_MASK // * bit is on in this byte, then selects the recursive // * compatibility decomposition, otherwise selects // * the recursive canonical decomposition. * @param source the original text, unnormalized * @param target the resulting normalized text */ private void internalDecompose(CharSequence source, StringBuffer target) { StringBuffer buffer = new StringBuffer(8); boolean canonical = (form & COMPATIBILITY_MASK) == 0; int ch32; //for (int i = 0; i < source.length(); i += (ch32<65536 ? 1 : 2)) { for (int i = 0; i < source.length();) { buffer.setLength(0); //ch32 = UTF16.charAt(source, i); ch32 = source.charAt(i++); if (UTF16.isHighSurrogate(ch32)) { char low = source.charAt(i++); ch32 = UTF16.combinePair((char)ch32, low); } data.getRecursiveDecomposition(canonical, ch32, buffer); // add all of the characters in the decomposition. // (may be just the original character, if there was // no decomposition mapping) int ch; //for (int j = 0; j < buffer.length(); j += (ch<65536 ? 1 : 2)) { for (int j = 0; j < buffer.length();) { //ch = UTF16.charAt(buffer, j); ch = buffer.charAt(j++); if (UTF16.isHighSurrogate(ch)) { char low = buffer.charAt(j++); ch = UTF16.combinePair((char)ch, low); } int chClass = data.getCanonicalClass(ch); int k = target.length(); // insertion point if (chClass != 0) { // bubble-sort combining marks as necessary int ch2; while (k > 0) { int step = 1; ch2 = target.charAt(k-1); if (UTF16.isSurrogate(ch2)) { step = 2; char high = target.charAt(k-2); ch2 = UTF16.combinePair(high, (char)ch2); } if (data.getCanonicalClass(ch2) <= chClass) break; k -= step; } // for (; k > 0; k -= (ch2<65536 ? 1 : 2)) { // ch2 = UTF16.charAt(target, k-1); // if (data.getCanonicalClass(ch2) <= chClass) break; // } } if (ch < 65536) { target.insert(k, (char)ch); } else { char[] chars = new char[]{UTF16.highSurrogate(ch), UTF16.lowSurrogate(ch)}; target.insert(k, chars); } //target.insert(k, UTF16.valueOf(ch)); } } } /** * Composes text in place. Target must already * have been decomposed. * @param target input: decomposed text. * output: the resulting normalized text. */ private void internalCompose(StringBuffer target) { int starterPos = 0; //int starterCh = UTF16.charAt(target,0); //int compPos = (starterCh<65536 ? 1 : 2); // length of last composition int starterCh = target.charAt(0); int compPos = 1; if (UTF16.isHighSurrogate(starterCh)) { starterCh = UTF16.combinePair((char)starterCh, target.charAt(1)); compPos++; } int lastClass = data.getCanonicalClass(starterCh); if (lastClass != 0) lastClass = 256; // fix for strings staring with a combining mark int oldLen = target.length(); // Loop on the decomposed characters, combining where possible int ch; //for (int decompPos = compPos; decompPos < target.length(); decompPos += (ch<65536 ? 1 : 2)) { for (int decompPos = compPos; decompPos < target.length();) { ch = target.charAt(decompPos++); if (UTF16.isHighSurrogate(ch)) { ch = UTF16.combinePair((char)ch, target.charAt(decompPos++)); } //ch = UTF16.charAt(target, decompPos); int chClass = data.getCanonicalClass(ch); int composite = data.getPairwiseComposition(starterCh, ch); if (composite != NormalizerData.NOT_COMPOSITE && (lastClass < chClass || lastClass == 0)) { setCharAt(target, starterPos, composite); // we know that we will only be replacing non-supplementaries by non-supplementaries // so we don't have to adjust the decompPos starterCh = composite; } else { if (chClass == 0) { starterPos = compPos; starterCh = ch; } lastClass = chClass; setCharAt(target, compPos, ch); if (target.length() != oldLen) { // MAY HAVE TO ADJUST! decompPos += target.length() - oldLen; oldLen = target.length(); } compPos += (ch<65536 ? 1 : 2); } } target.setLength(compPos); } /** * Set the 32-bit character at a particular 16-bit offset in a string buffer, * replacing the previous character at that position, and taking account of the * fact that either, both, or neither of the characters might be a surrogate pair. * @param target the StringBuffer in which the data is to be inserted * @param offset the position at which the data is to be inserted * @param ch32 the character to be inserted, as a 32-bit Unicode codepoint */ private static void setCharAt(StringBuffer target, int offset, int ch32) { if (ch32 < 65536) { if (UTF16.isHighSurrogate(target.charAt(offset))) { target.setCharAt(offset, (char)ch32); target.deleteCharAt(offset+1); } else { target.setCharAt(offset, (char)ch32); } } else { if (UTF16.isHighSurrogate(target.charAt(offset))) { target.setCharAt(offset, UTF16.highSurrogate(ch32)); target.setCharAt(offset+1, UTF16.lowSurrogate(ch32)); } else { target.setCharAt(offset, UTF16.highSurrogate(ch32)); target.insert(offset+1, UTF16.lowSurrogate(ch32)); } } } /** * Contains normalization data from the Unicode Character Database. */ private static NormalizerData data = null; /** * Just accessible for testing. * @param ch a character * @return true if the character is an excluded character */ boolean getExcluded (char ch) { return data.getExcluded(ch); } /** * Just accessible for testing. * @param ch a character * @return the raw decomposition mapping of the character */ String getRawDecompositionMapping (char ch) { return data.getRawDecompositionMapping(ch); } }saxonb-9.1.0.8/bj/net/sf/saxon/codenorm/NormalizerData.java0000644000175000017500000001151711033112257022771 0ustar eugeneeugenepackage net.sf.saxon.codenorm; import net.sf.saxon.sort.IntHashMap; import net.sf.saxon.sort.IntToIntMap; import net.sf.saxon.charcode.UTF16; import java.util.BitSet; /** * Accesses the Normalization Data used for Forms C and D. *

    Copyright © 1998-1999 Unicode, Inc. All Rights Reserved.
    * The Unicode Consortium makes no expressed or implied warranty of any * kind, and assumes no liability for errors or omissions. * No liability is assumed for incidental and consequential damages * in connection with or arising out of the use of the information here.

    * @author Mark Davis */ public class NormalizerData { static final String copyright = "Copyright © 1998-1999 Unicode, Inc."; /** * Constant for use in getPairwiseComposition */ public static final int NOT_COMPOSITE = '\uFFFF'; /** * Gets the combining class of a character from the * Unicode Character Database. * @param ch the source character * @return value from 0 to 255 */ public int getCanonicalClass(int ch) { return canonicalClass.get(ch); } /** * Returns the composite of the two characters. If the two * characters don't combine, returns NOT_COMPOSITE. * Only has to worry about BMP characters, since those are the only ones that can ever compose. * @param first first character (e.g. 'c') * @param second second character (e.g. '¸' cedilla) * @return composite (e.g. 'ç') */ public char getPairwiseComposition(int first, int second) { if (first < 0 || first > 0x10FFFF || second < 0 || second > 0x10FFFF) return NOT_COMPOSITE; return (char)compose.get((first << 16) | second); } /** * Gets recursive decomposition of a character from the * Unicode Character Database. * @param canonical If true * bit is on in this byte, then selects the recursive * canonical decomposition, otherwise selects * the recursive compatibility and canonical decomposition. * @param ch the source character * @param buffer buffer to be filled with the decomposition */ public void getRecursiveDecomposition(boolean canonical, int ch, StringBuffer buffer) { String decomp = (String)decompose.get(ch); if (decomp != null && !(canonical && isCompatibility.get(ch))) { for (int i = 0; i < decomp.length(); ++i) { getRecursiveDecomposition(canonical, decomp.charAt(i), buffer); } } else { // if no decomp, append //UTF16.append(buffer, ch); if (ch<65536) { buffer.append((char)ch); } else { // output a surrogate pair buffer.append(UTF16.highSurrogate(ch)); buffer.append(UTF16.lowSurrogate(ch)); } } } // ================================================= // PRIVATES // ================================================= /** * Only accessed by NormalizerBuilder. */ NormalizerData(IntToIntMap canonicalClass, IntHashMap decompose, IntToIntMap compose, BitSet isCompatibility, BitSet isExcluded) { this.canonicalClass = canonicalClass; this.decompose = decompose; this.compose = compose; this.isCompatibility = isCompatibility; this.isExcluded = isExcluded; } /** * Just accessible for testing. */ boolean getExcluded (char ch) { return isExcluded.get(ch); } /** * Just accessible for testing. */ String getRawDecompositionMapping (char ch) { return (String)decompose.get(ch); } /** * For now, just use IntHashtable * Two-stage tables would be used in an optimized implementation. */ private IntToIntMap canonicalClass; /** * The main data table maps chars to a 32-bit int. * It holds either a pair: top = first, bottom = second * or singleton: top = 0, bottom = single. * If there is no decomposition, the value is 0. * Two-stage tables would be used in an optimized implementation. * An optimization could also map chars to a small index, then use that * index in a small array of ints. */ private IntHashMap decompose; /** * Maps from pairs of characters to single. * If there is no decomposition, the value is NOT_COMPOSITE. */ private IntToIntMap compose; /** * Tells whether decomposition is canonical or not. */ private BitSet isCompatibility = new BitSet(); /** * Tells whether character is script-excluded or not. * Used only while building, and for testing. */ private BitSet isExcluded = new BitSet(); }saxonb-9.1.0.8/bj/net/sf/saxon/codenorm/UnicodeData.java0000644000175000017500000064020611033112257022240 0ustar eugeneeugenepackage net.sf.saxon.codenorm; //This module was generated by running net.sf.saxon.codenorm.UnicodeDataGenerator //*** DO NOT EDIT! *** //The strange format of this file is carefully chosen to avoid breaking Java compiler limits public class UnicodeData { public static final String[] canonicalClassKeys = { "0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,g,h,i,", "j,k,l,m,n,o,p,q,r,s,t,u,v,10,11,12,13,14,15,16,", "17,18,19,1a,1b,1c,1d,1e,1f,1g,1h,1i,1j,1k,1l,1m,1n,1o,1p,1q,", "1r,1s,1t,1u,1v,20,21,22,23,24,25,26,27,28,29,2a,2b,2c,2d,2e,", "2f,2g,2h,2i,2j,2k,2l,2m,2n,2o,2p,2q,2r,2s,2t,2u,2v,30,31,32,", "33,34,35,36,37,38,39,3a,3b,3c,3d,3e,3f,3g,3h,3i,3j,3k,3l,3m,", "3n,3o,3p,3q,3r,3s,3t,3u,3v,40,41,42,43,44,45,46,47,48,49,4a,", "4b,4c,4d,4e,4f,4g,4h,4i,4j,4k,4l,4m,4n,4o,4p,4q,4r,4s,4t,4u,", "4v,50,51,52,53,54,55,56,57,58,59,5a,5b,5c,5d,5e,5f,5g,5h,5i,", "5j,5k,5l,5m,5n,5o,5p,5q,5r,5s,5t,5u,5v,60,61,62,63,64,65,66,", "67,68,69,6a,6b,6c,6d,6e,6f,6g,6h,6i,6j,6k,6l,6m,6n,6o,6p,6q,", "6r,6s,6t,6u,6v,70,71,72,73,74,75,76,77,78,79,7a,7b,7c,7d,7e,", "7f,7g,7h,7i,7j,7k,7l,7m,7n,7o,7p,7q,7r,7s,7t,7u,7v,80,81,82,", "83,84,85,86,87,88,89,8a,8b,8c,8d,8e,8f,8g,8h,8i,8j,8k,8l,8m,", "8n,8o,8p,8q,8r,8s,8t,8u,8v,90,91,92,93,94,95,96,97,98,99,9a,", "9b,9c,9d,9e,9f,9g,9h,9i,9j,9k,9l,9m,9n,9o,9p,9q,9r,9s,9t,9u,", "9v,a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,aa,ab,ac,ad,ae,af,ag,ah,ai,", "aj,ak,al,am,an,ao,ap,aq,ar,as,at,au,av,b0,b1,b2,b3,b4,b5,b6,", "b7,b8,b9,ba,bb,bc,bd,be,bf,bg,bh,bi,bj,bk,bl,bm,bn,bo,bp,bq,", "br,bs,bt,bu,bv,c0,c1,c2,c3,c4,c5,c6,c7,c8,c9,ca,cb,cc,cd,ce,", "cf,cg,ch,ci,cj,ck,cl,cm,cn,co,cp,cq,cr,cs,ct,cu,cv,d0,d1,d2,", "d3,d4,d5,d6,d7,d8,d9,da,db,dc,dd,de,df,dg,dh,di,dj,dk,dl,dm,", "dn,do,dp,dq,dr,ds,dt,du,dv,e0,e1,e2,e3,e4,e5,e6,e7,e8,e9,ea,", "eb,ec,ed,ee,ef,eg,eh,ei,ej,ek,el,em,en,eo,ep,eq,er,es,et,eu,", "ev,f0,f1,f2,f3,f4,f5,f6,f7,f8,f9,fa,fb,fc,fd,fe,ff,fg,fh,fi,", "fj,fk,fl,fm,fn,fo,fp,fq,fr,fs,ft,fu,fv,g0,g1,g2,g3,g4,g5,g6,", "g7,g8,g9,ga,gb,gc,gd,ge,gf,gg,gh,gi,gj,gk,gl,gm,gn,go,gp,gq,", "gr,gs,gt,gu,gv,h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,ha,hb,hc,hd,he,", "hf,hg,hh,hi,hj,hk,hl,hm,hn,ho,hp,hq,hr,hs,ht,hu,hv,i0,i1,ig,", "ih,ii,ij,ik,il,im,in,io,ip,iq,ir,is,it,iu,iv,j0,j1,j2,j3,j4,", "j5,j6,j7,j8,j9,ja,jb,jc,jd,je,jf,jg,jh,ji,jj,jk,jl,jm,jn,jo,", "jp,jq,jr,js,jt,ju,jv,k0,k1,k2,k3,k4,k5,k6,k7,k8,k9,ka,kb,kc,", "kd,ke,kf,kg,kh,ki,kj,kk,kl,km,kn,ko,kp,kq,kr,ks,kt,ku,kv,l0,", "l1,l2,l3,l4,l5,l6,l7,l8,l9,la,lb,lc,ld,le,lf,lg,lh,li,lj,lk,", "ll,lm,ln,lo,lp,lq,lr,ls,lt,lu,lv,m0,m1,m2,m3,m4,m5,m6,m7,m8,", "m9,ma,mb,mc,md,me,mf,mg,mh,mi,mj,mk,ml,mm,mn,mo,mp,mq,mr,ms,", "mt,mu,mv,n0,n1,n2,n3,n4,n5,n6,n7,n8,n9,na,nb,nc,nd,ne,nf,ng,", "nh,ni,nj,nk,nl,nm,nn,no,np,nq,nr,ns,nt,nu,nv,o0,o1,o2,o3,o4,", "o5,o6,o7,o8,o9,oa,ob,oc,od,oe,of,og,oh,oi,oj,ok,ol,om,on,oo,", "op,oq,or,os,ot,ou,ov,p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,pa,pb,pc,", "pd,pe,pf,pg,ph,pi,pj,pk,pl,pm,pn,po,pp,pq,pr,ps,pt,pu,pv,q0,", "q1,q2,q3,q4,q5,q6,q7,q8,q9,qa,qb,qc,qd,qe,qf,qg,qh,qi,qj,qk,", "ql,qm,qn,qo,qp,qq,qr,qs,qt,qu,qv,r0,r1,r2,r3,r4,r5,r6,r7,r8,", "r9,ra,rb,rc,rd,re,rf,rk,rl,rq,ru,s4,s5,s6,s7,s8,s9,sa,sc,se,", "sf,sg,sh,si,sj,sk,sl,sm,sn,so,sp,sq,sr,ss,st,su,sv,t0,t1,t3,", "t4,t5,t6,t7,t8,t9,ta,tb,tc,td,te,tf,tg,th,ti,tj,tk,tl,tm,tn,", "to,tp,tq,tr,ts,tt,tu,tv,u0,u1,u2,u3,u4,u5,u6,u7,u8,u9,ua,ub,", "uc,ud,ue,ug,uh,ui,uj,uk,ul,um,un,uo,up,uq,ur,us,ut,uu,uv,v0,", "v1,v2,v3,v4,v5,v6,v7,v8,v9,va,vb,vc,vd,ve,vf,vg,vh,vi,vj,vk,", "vl,vm,vn,vo,vp,vq,vr,vs,vt,vu,vv,100,101,102,103,104,105,106,107,108,", "109,10a,10b,10c,10d,10e,10f,10g,10h,10i,10j,10k,10l,10m,10n,10o,10p,10q,10r,10s,", "10t,10u,10v,110,111,112,113,114,115,116,117,118,119,11a,11b,11c,11d,11e,11f,11g,", "11h,11i,11j,11k,11l,11m,11n,11o,11p,11q,11r,11s,11t,11u,11v,120,121,122,123,124,", "125,126,127,128,129,12a,12b,12c,12d,12e,12f,12g,12h,12i,12j,12k,12l,12m,12n,12o,", "12p,12q,12r,12s,12t,12u,12v,130,131,132,133,134,135,136,137,138,139,13a,13b,13c,", "13d,13e,13f,13g,13h,13i,13j,13k,13l,13m,13n,13o,13p,13q,13r,13s,13t,13u,13v,140,", "141,142,143,144,145,146,148,149,14a,14b,14c,14d,14e,14f,14g,14h,14i,14j,14k,14l,", "14m,14n,14o,14p,14q,14r,14s,14t,14u,14v,150,151,152,153,154,155,156,157,158,159,", "15a,15b,15c,15d,15e,15f,15g,15h,15i,15j,15k,15l,15m,15n,15o,15p,15q,15r,15s,15t,", "15u,15v,160,161,162,163,164,165,166,167,168,169,16a,16b,16c,16d,16e,16g,16h,16i,", "16j,16k,16l,16m,16n,16o,16p,16q,16r,16s,16t,16u,16v,170,171,172,173,174,175,176,", "177,178,179,17a,17b,17c,17d,17e,17f,17g,17h,17i,17j,17k,17l,17m,17n,17o,17p,180,", "181,182,183,184,185,186,187,188,189,18a,18b,18c,18d,18e,18f,19h,19i,19j,19k,19l,", "19m,19n,19o,19p,19q,19r,19s,19t,19u,19v,1a0,1a1,1a2,1a3,1a4,1a5,1a6,1a7,1a8,1a9,", "1aa,1ab,1ac,1ad,1ae,1af,1ag,1ah,1ai,1aj,1ak,1al,1am,1ap,1aq,1ar,1as,1at,1au,1av,", "1b1,1b2,1b3,1b4,1b5,1b6,1b7,1b8,1b9,1ba,1bb,1bc,1bd,1be,1bf,1bg,1bh,1bi,1bj,1bk,", "1bl,1bm,1bn,1bo,1bp,1bq,1br,1bs,1bt,1bu,1bv,1c0,1c1,1c2,1c3,1c4,1c5,1c6,1c7,1c9,", "1ca,1ch,1ci,1cj,1ck,1cl,1cm,1cn,1co,1cp,1cq,1cr,1cs,1ct,1cu,1cv,1d0,1d1,1d2,1d3,", "1d4,1d5,1d6,1d7,1d8,1d9,1da,1db,1dc,1dd,1de,1df,1dg,1dh,1di,1dj,1dk,1dl,1dm,1dn,", "1do,1dp,1dr,1ds,1dt,1du,1dv,1e0,1e1,1e2,1e3,1e4,1e5,1e6,1e7,1eg,1eh,1ei,1ej,1ek,", "1el,1em,1en,1eo,1ep,1eq,1er,1es,1et,1eu,1ev,1f0,1f1,1f2,1f3,1f4,1f5,1f6,1f7,1f8,", "1f9,1fa,1fg,1fh,1fi,1fj,1fk,1g0,1g1,1g2,1g3,1gb,1gc,1gd,1ge,1gf,1gg,1gh,1gi,1gj,", "1gk,1gl,1gr,1gu,1gv,1h1,1h2,1h3,1h4,1h5,1h6,1h7,1h8,1h9,1ha,1hb,1hc,1hd,1he,1hf,", "1hg,1hh,1hi,1hj,1hk,1hl,1hm,1hn,1ho,1hp,1hq,1i0,1i1,1i2,1i3,1i4,1i5,1i6,1i7,1i8,", "1i9,1ia,1ib,1ic,1id,1ie,1if,1ig,1ih,1ii,1ij,1ik,1il,1im,1in,1io,1ip,1iq,1ir,1is,", "1it,1iu,1j0,1j1,1j2,1j3,1j4,1j5,1j6,1j7,1j8,1j9,1ja,1jb,1jc,1jd,1je,1jf,1jg,1jh,", "1ji,1jj,1jk,1jl,1jm,1jn,1jo,1jp,1jq,1jr,1js,1jt,1ju,1jv,1k0,1k1,1k2,1k3,1k4,1k5,", "1k6,1k7,1k8,1k9,1ka,1kb,1kc,1kd,1ke,1kf,1kg,1kh,1ki,1kj,1kk,1kl,1km,1kn,1ko,1kp,", "1kq,1kr,1ks,1kt,1ku,1kv,1l0,1l1,1l2,1l3,1l4,1l5,1l6,1l7,1l8,1l9,1la,1lb,1lc,1ld,", "1le,1lf,1lg,1lh,1li,1lj,1lk,1ll,1lm,1ln,1lo,1lp,1lq,1lr,1ls,1lt,1lu,1lv,1m0,1m1,", "1m2,1m3,1m4,1m5,1m6,1m7,1m8,1m9,1ma,1mb,1mc,1md,1me,1mf,1mg,1mh,1mi,1mj,1mk,1ml,", "1mm,1mn,1mo,1mp,1mq,1mr,1ms,1mt,1mu,1mv,1n0,1n1,1n2,1n3,1n4,1n5,1n6,1n7,1n8,1n9,", "1na,1nb,1nc,1nd,1ne,1nf,1ng,1nh,1ni,1nj,1nk,1nl,1nm,1nn,1no,1np,1nq,1nr,1ns,1nt,", "1nu,1nv,1o0,1o1,1o2,1o3,1o4,1o5,1o6,1o7,1o8,1o9,1oa,1ob,1oc,1od,1of,1og,1oh,1oi,", "1oj,1ok,1ol,1om,1on,1oo,1op,1oq,1or,1os,1ot,1ou,1ov,1p0,1p1,1p2,1p3,1p4,1p5,1p6,", "1p7,1p8,1p9,1pa,1pb,1pc,1pd,1pe,1pf,1pg,1ph,1pi,1pj,1pk,1pl,1pm,1pn,1po,1pp,1pq,", "1pr,1ps,1pt,1pu,1pv,1q0,1q1,1q2,1q3,1q4,1q5,1q6,1q7,1q8,1q9,1qa,1qd,1qe,1qf,1qg,", "1qh,1qi,1qj,1qk,1ql,1qm,1qn,1qo,1qp,1qq,1qr,1qs,1qt,1qu,1qv,1r0,1r1,1r2,1r3,1r4,", "1r5,1r6,1r7,1r8,1r9,1ra,1rb,1rc,1rd,1s0,1s1,1s2,1s3,1s4,1s5,1s6,1s7,1s8,1s9,1sa,", "1sb,1sc,1sd,1se,1sf,1sg,1sh,1si,1sj,1sk,1sl,1sm,1sn,1so,1sp,1sq,1sr,1ss,1st,1su,", "1sv,1t0,1t1,1t2,1t3,1t4,1t5,1t6,1t7,1t8,1t9,1ta,1tb,1tc,1td,1te,1tf,1tg,1th,281,", "282,283,284,285,286,287,288,289,28a,28b,28c,28d,28e,28f,28g,28h,28i,28j,28k,28l,", "28m,28n,28o,28p,28q,28r,28s,28t,28u,28v,290,291,292,293,294,295,296,297,298,299,", "29a,29b,29c,29d,29e,29f,29g,29h,29i,29j,29k,29l,29m,29n,29o,29p,29s,29t,29u,29v,", "2a0,2a1,2a2,2a3,2a4,2a5,2a6,2a7,2a8,2a9,2aa,2ab,2ac,2ad,2ag,2ah,2ai,2aj,2ak,2ao,", "2ap,2aq,2ar,2as,2at,2au,2av,2b0,2b1,2b2,2b3,2b4,2b5,2b6,2b7,2b8,2b9,2ba,2bb,2bc,", "2bd,2be,2bf,2bg,2bt,2c1,2c2,2c3,2c5,2c6,2c7,2c8,2c9,2ca,2cb,2cc,2cf,2cg,2cj,2ck,", "2cl,2cm,2cn,2co,2cp,2cq,2cr,2cs,2ct,2cu,2cv,2d0,2d1,2d2,2d3,2d4,2d5,2d6,2d7,2d8,", "2da,2db,2dc,2dd,2de,2df,2dg,2di,2dm,2dn,2do,2dp,2ds,2dt,2du,2dv,2e0,2e1,2e2,2e3,", "2e4,2e7,2e8,2eb,2ec,2ed,2ee,2en,2es,2et,2ev,2f0,2f1,2f2,2f3,2f6,2f7,2f8,2f9,2fa,", "2fb,2fc,2fd,2fe,2ff,2fg,2fh,2fi,2fj,2fk,2fl,2fm,2fn,2fo,2fp,2fq,2g1,2g2,2g3,2g5,", "2g6,2g7,2g8,2g9,2ga,2gf,2gg,2gj,2gk,2gl,2gm,2gn,2go,2gp,2gq,2gr,2gs,2gt,2gu,2gv,", "2h0,2h1,2h2,2h3,2h4,2h5,2h6,2h7,2h8,2ha,2hb,2hc,2hd,2he,2hf,2hg,2hi,2hj,2hl,2hm,", "2ho,2hp,2hs,2hu,2hv,2i0,2i1,2i2,2i7,2i8,2ib,2ic,2id,2ip,2iq,2ir,2is,2iu,2j6,2j7,", "2j8,2j9,2ja,2jb,2jc,2jd,2je,2jf,2jg,2jh,2ji,2jj,2jk,2k1,2k2,2k3,2k5,2k6,2k7,2k8,", "2k9,2ka,2kb,2kc,2kd,2kf,2kg,2kh,2kj,2kk,2kl,2km,2kn,2ko,2kp,2kq,2kr,2ks,2kt,2ku,", "2kv,2l0,2l1,2l2,2l3,2l4,2l5,2l6,2l7,2l8,2la,2lb,2lc,2ld,2le,2lf,2lg,2li,2lj,2ll,", "2lm,2ln,2lo,2lp,2ls,2lt,2lu,2lv,2m0,2m1,2m2,2m3,2m4,2m5,2m7,2m8,2m9,2mb,2mc,2md,", "2mg,2n0,2n1,2n2,2n3,2n6,2n7,2n8,2n9,2na,2nb,2nc,2nd,2ne,2nf,2nh,2o1,2o2,2o3,2o5,", "2o6,2o7,2o8,2o9,2oa,2ob,2oc,2of,2og,2oj,2ok,2ol,2om,2on,2oo,2op,2oq,2or,2os,2ot,", "2ou,2ov,2p0,2p1,2p2,2p3,2p4,2p5,2p6,2p7,2p8,2pa,2pb,2pc,2pd,2pe,2pf,2pg,2pi,2pj,", "2pl,2pm,2pn,2po,2pp,2ps,2pt,2pu,2pv,2q0,2q1,2q2,2q3,2q7,2q8,2qb,2qc,2qd,2qm,2qn,", "2qs,2qt,2qv,2r0,2r1,2r6,2r7,2r8,2r9,2ra,2rb,2rc,2rd,2re,2rf,2rg,2rh,2s2,2s3,2s5,", "2s6,2s7,2s8,2s9,2sa,2se,2sf,2sg,2si,2sj,2sk,2sl,2sp,2sq,2ss,2su,2sv,2t3,2t4,2t8,", "2t9,2ta,2te,2tf,2tg,2th,2ti,2tj,2tk,2tl,2tm,2tn,2to,2tp,2tu,2tv,2u0,2u1,2u2,2u6,", "2u7,2u8,2ua,2ub,2uc,2ud,2un,2v6,2v7,2v8,2v9,2va,2vb,2vc,2vd,2ve,2vf,2vg,2vh,2vi,", "2vj,2vk,2vl,2vm,2vn,2vo,2vp,2vq,301,302,303,305,306,307,308,309,30a,30b,30c,30e,", "30f,30g,30i,30j,30k,30l,30m,30n,30o,30p,30q,30r,30s,30t,30u,30v,310,311,312,313,", "314,315,316,317,318,31a,31b,31c,31d,31e,31f,31g,31h,31i,31j,31l,31m,31n,31o,31p,", "31u,31v,320,321,322,323,324,326,327,328,32a,32b,32c,32d,32l,32m,330,331,336,337,", "338,339,33a,33b,33c,33d,33e,33f,342,343,345,346,347,348,349,34a,34b,34c,34e,34f,", "34g,34i,34j,34k,34l,34m,34n,34o,34p,34q,34r,34s,34t,34u,34v,350,351,352,353,354,", "355,356,357,358,35a,35b,35c,35d,35e,35f,35g,35h,35i,35j,35l,35m,35n,35o,35p,35s,", "35t,35u,35v,360,361,362,363,364,366,367,368,36a,36b,36c,36d,36l,36m,36u,370,371,", "376,377,378,379,37a,37b,37c,37d,37e,37f,382,383,385,386,387,388,389,38a,38b,38c,", "38e,38f,38g,38i,38j,38k,38l,38m,38n,38o,38p,38q,38r,38s,38t,38u,38v,390,391,392,", "393,394,395,396,397,398,39a,39b,39c,39d,39e,39f,39g,39h,39i,39j,39k,39l,39m,39n,", "39o,39p,39u,39v,3a0,3a1,3a2,3a3,3a6,3a7,3a8,3aa,3ab,3ac,3ad,3an,3b0,3b1,3b6,3b7,", "3b8,3b9,3ba,3bb,3bc,3bd,3be,3bf,3c2,3c3,3c5,3c6,3c7,3c8,3c9,3ca,3cb,3cc,3cd,3ce,", "3cf,3cg,3ch,3ci,3cj,3ck,3cl,3cm,3cq,3cr,3cs,3ct,3cu,3cv,3d0,3d1,3d2,3d3,3d4,3d5,", "3d6,3d7,3d8,3d9,3da,3db,3dc,3dd,3de,3df,3dg,3dh,3dj,3dk,3dl,3dm,3dn,3do,3dp,3dq,", "3dr,3dt,3e0,3e1,3e2,3e3,3e4,3e5,3e6,3ea,3ef,3eg,3eh,3ei,3ej,3ek,3em,3eo,3ep,3eq,", "3er,3es,3et,3eu,3ev,3fi,3fj,3fk,3g1,3g2,3g3,3g4,3g5,3g6,3g7,3g8,3g9,3ga,3gb,3gc,", "3gd,3ge,3gf,3gg,3gh,3gi,3gj,3gk,3gl,3gm,3gn,3go,3gp,3gq,3gr,3gs,3gt,3gu,3gv,3h0,", "3h1,3h2,3h3,3h4,3h5,3h6,3h7,3h8,3h9,3ha,3hb,3hc,3hd,3he,3hf,3hg,3hh,3hi,3hj,3hk,", "3hl,3hm,3hn,3ho,3hp,3hq,3hv,3i0,3i1,3i2,3i3,3i4,3i5,3i6,3i7,3i8,3i9,3ia,3ib,3ic,", "3id,3ie,3if,3ig,3ih,3ii,3ij,3ik,3il,3im,3in,3io,3ip,3iq,3ir,3k1,3k2,3k4,3k7,3k8,", "3ka,3kd,3kk,3kl,3km,3kn,3kp,3kq,3kr,3ks,3kt,3ku,3kv,3l1,3l2,3l3,3l5,3l7,3la,3lb,", "3ld,3le,3lf,3lg,3lh,3li,3lj,3lk,3ll,3lm,3ln,3lo,3lp,3lr,3ls,3lt,3m0,3m1,3m2,3m3,", "3m4,3m6,3m8,3m9,3ma,3mb,3mc,3md,3mg,3mh,3mi,3mj,3mk,3ml,3mm,3mn,3mo,3mp,3ms,3mt,", "3o0,3o1,3o2,3o3,3o4,3o5,3o6,3o7,3o8,3o9,3oa,3ob,3oc,3od,3oe,3of,3og,3oh,3oi,3oj,", "3ok,3ol,3om,3on,3oo,3op,3oq,3or,3os,3ot,3ou,3ov,3p0,3p1,3p2,3p3,3p4,3p5,3p6,3p7,", "3p8,3p9,3pa,3pb,3pc,3pd,3pe,3pf,3pg,3ph,3pi,3pj,3pk,3pl,3pm,3pn,3po,3pp,3pq,3pr,", "3ps,3pt,3pu,3pv,3q0,3q1,3q2,3q3,3q4,3q5,3q6,3q7,3q9,3qa,3qb,3qc,3qd,3qe,3qf,3qg,", "3qh,3qi,3qj,3qk,3ql,3qm,3qn,3qo,3qp,3qq,3qr,3qs,3qt,3qu,3qv,3r0,3r1,3r2,3r3,3r4,", "3r5,3r6,3r7,3r8,3r9,3ra,3rh,3ri,3rj,3rk,3rl,3rm,3rn,3ro,3rp,3rq,3rr,3rs,3rt,3ru,", "3rv,3s0,3s1,3s2,3s3,3s4,3s5,3s6,3s7,3s8,3s9,3sa,3sb,3sg,3sh,3si,3sj,3sk,3sl,3sm,", "3sn,3sp,3sq,3sr,3ss,3st,3su,3sv,3t0,3t1,3t2,3t3,3t4,3t5,3t6,3t7,3t8,3t9,3ta,3tb,", "3tc,3td,3te,3tf,3tg,3th,3ti,3tj,3tk,3tl,3tm,3tn,3to,3tp,3tq,3tr,3ts,3tu,3tv,3u0,", "3u1,3u2,3u3,3u4,3u5,3u6,3u7,3u8,3u9,3ua,3ub,3uc,3uf,3ug,3uh,400,401,402,403,404,", "405,406,407,408,409,40a,40b,40c,40d,40e,40f,40g,40h,40i,40j,40k,40l,40m,40n,40o,", "40p,40q,40r,40s,40t,40u,40v,410,411,413,414,415,416,417,419,41a,41c,41d,41e,41f,", "41g,41h,41i,41m,41n,41o,41p,420,421,422,423,424,425,426,427,428,429,42a,42b,42c,", "42d,42e,42f,42g,42h,42i,42j,42k,42l,42m,42n,42o,42p,450,451,452,453,454,455,456,", "457,458,459,45a,45b,45c,45d,45e,45f,45g,45h,45i,45j,45k,45l,45m,45n,45o,45p,45q,", "45r,45s,45t,45u,45v,460,461,462,463,464,465,46g,46h,46i,46j,46k,46l,46m,46n,46o,", "46p,46q,46r,46s,46t,46u,46v,470,471,472,473,474,475,476,477,478,479,47a,47b,47c,", "47d,47e,47f,47g,47h,47i,47j,47k,47l,47m,47n,47o,47p,47q,47r,47s,480,481,482,483,", "484,485,486,487,488,489,48a,48b,48c,48d,48e,48f,48g,48h,48i,48j,48k,48l,48m,48n,", "48o,48p,48q,48r,48s,48t,48u,48v,490,491,492,493,494,495,496,497,498,499,49a,49b,", "49c,49d,49e,49f,49g,49h,49i,49j,49k,49l,49m,49n,49o,49p,49q,49r,49s,49t,49u,49v,", "4a0,4a1,4a2,4a3,4a4,4a5,4a6,4a7,4a8,4a9,4aa,4ab,4ac,4ad,4ae,4af,4ag,4ah,4ai,4aj,", "4ak,4al,4am,4an,4ao,4ap,4av,4b0,4b1,4b2,4b3,4b4,4b5,4b6,4b7,4b8,4b9,4ba,4bb,4bc,", "4bd,4be,4bf,4bg,4bh,4bi,4bj,4bk,4bl,4bm,4bn,4bo,4bp,4bq,4br,4bs,4bt,4bu,4bv,4c0,", "4c1,4c2,4c3,4c4,4c5,4c6,4c7,4c8,4c9,4ca,4cb,4cc,4cd,4ce,4cf,4cg,4ch,4ci,4cj,4ck,", "4cl,4cm,4cn,4co,4cp,4cq,4cr,4cs,4ct,4cu,4cv,4d0,4d1,4d2,4d8,4d9,4da,4db,4dc,4dd,", "4de,4df,4dg,4dh,4di,4dj,4dk,4dl,4dm,4dn,4do,4dp,4dq,4dr,4ds,4dt,4du,4dv,4e0,4e1,", "4e2,4e3,4e4,4e5,4e6,4e7,4e8,4e9,4ea,4eb,4ec,4ed,4ee,4ef,4eg,4eh,4ei,4ej,4ek,4el,", "4em,4en,4eo,4ep,4eq,4er,4es,4et,4eu,4ev,4f0,4f1,4f2,4f3,4f4,4f5,4f6,4f7,4f8,4f9,", "4fa,4fb,4fc,4fd,4fe,4ff,4fg,4fh,4fi,4fj,4fk,4fl,4fm,4fn,4fo,4fp,4g0,4g1,4g2,4g3,", "4g4,4g5,4g6,4g7,4g8,4g9,4ga,4gb,4gc,4gd,4ge,4gf,4gg,4gh,4gi,4gj,4gk,4gl,4gm,4gn,", "4go,4gp,4gq,4gr,4gs,4gt,4gu,4gv,4h0,4h1,4h2,4h3,4h4,4h5,4h6,4h7,4h8,4h9,4ha,4hb,", "4hc,4hd,4he,4hf,4hg,4hh,4hi,4hj,4hk,4hl,4hm,4hn,4ho,4hp,4hq,4hr,4hs,4ht,4hu,4hv,", "4i0,4i1,4i2,4i3,4i4,4i5,4i6,4i7,4i8,4ia,4ib,4ic,4id,4ig,4ih,4ii,4ij,4ik,4il,4im,", "4io,4iq,4ir,4is,4it,4j0,4j1,4j2,4j3,4j4,4j5,4j6,4j7,4j8,4j9,4ja,4jb,4jc,4jd,4je,", "4jf,4jg,4jh,4ji,4jj,4jk,4jl,4jm,4jn,4jo,4jp,4jq,4jr,4js,4jt,4ju,4jv,4k0,4k1,4k2,", "4k3,4k4,4k5,4k6,4k7,4k8,4ka,4kb,4kc,4kd,4kg,4kh,4ki,4kj,4kk,4kl,4km,4kn,4ko,4kp,", "4kq,4kr,4ks,4kt,4ku,4kv,4l0,4l1,4l2,4l3,4l4,4l5,4l6,4l7,4l8,4l9,4la,4lb,4lc,4ld,", "4le,4lf,4lg,4li,4lj,4lk,4ll,4lo,4lp,4lq,4lr,4ls,4lt,4lu,4m0,4m2,4m3,4m4,4m5,4m8,", "4m9,4ma,4mb,4mc,4md,4me,4mf,4mg,4mh,4mi,4mj,4mk,4ml,4mm,4mo,4mp,4mq,4mr,4ms,4mt,", "4mu,4mv,4n0,4n1,4n2,4n3,4n4,4n5,4n6,4n7,4n8,4n9,4na,4nb,4nc,4nd,4ne,4nf,4ng,4nh,", "4ni,4nj,4nk,4nl,4nm,4nn,4no,4np,4nq,4nr,4ns,4nt,4nu,4nv,4o0,4o1,4o2,4o3,4o4,4o5,", "4o6,4o7,4o8,4o9,4oa,4ob,4oc,4od,4oe,4of,4og,4oi,4oj,4ok,4ol,4oo,4op,4oq,4or,4os,", "4ot,4ou,4ov,4p0,4p1,4p2,4p3,4p4,4p5,4p6,4p7,4p8,4p9,4pa,4pb,4pc,4pd,4pe,4pf,4pg,", "4ph,4pi,4pj,4pk,4pl,4pm,4pn,4po,4pp,4pq,4pr,4ps,4pt,4pu,4pv,4q0,4q1,4q2,4q3,4q4,", "4q5,4q6,4q7,4q8,4q9,4qa,4qb,4qc,4qd,4qe,4qf,4qg,4qh,4qi,4qj,4qk,4ql,4qm,4qn,4qo,", "4qp,4qq,4qv,4r0,4r1,4r2,4r3,4r4,4r5,4r6,4r7,4r8,4r9,4ra,4rb,4rc,4rd,4re,4rf,4rg,", "4rh,4ri,4rj,4rk,4rl,4rm,4rn,4ro,4rp,4rq,4rr,4rs,4s0,4s1,4s2,4s3,4s4,4s5,4s6,4s7,", "4s8,4s9,4sa,4sb,4sc,4sd,4se,4sf,4sg,4sh,4si,4sj,4sk,4sl,4sm,4sn,4so,4sp,4t0,4t1,", "4t2,4t3,4t4,4t5,4t6,4t7,4t8,4t9,4ta,4tb,4tc,4td,4te,4tf,4tg,4th,4ti,4tj,4tk,4tl,", "4tm,4tn,4to,4tp,4tq,4tr,4ts,4tt,4tu,4tv,4u0,4u1,4u2,4u3,4u4,4u5,4u6,4u7,4u8,4u9,", "4ua,4ub,4uc,4ud,4ue,4uf,4ug,4uh,4ui,4uj,4uk,4ul,4um,4un,4uo,4up,4uq,4ur,4us,4ut,", "4uu,4uv,4v0,4v1,4v2,4v3,4v4,4v5,4v6,4v7,4v8,4v9,4va,4vb,4vc,4vd,4ve,4vf,4vg,4vh,", "4vi,4vj,4vk,501,502,503,504,505,506,507,508,509,50a,50b,50c,50d,50e,50f,50g,50h,", "50i,50j,50k,50l,50m,50n,50o,50p,50q,50r,50s,50t,50u,50v,510,511,512,513,514,515,", "516,517,518,519,51a,51b,51c,51d,51e,51f,51g,51h,51i,51j,51k,51l,51m,51n,51o,51p,", "51q,51r,51s,51t,51u,51v,520,521,522,523,524,525,526,527,528,529,52a,52b,52c,52d,", "52e,52f,52g,52h,52i,52j,52k,52l,52m,52n,52o,52p,52q,52r,52s,52t,52u,52v,530,531,", "532,533,534,535,536,537,538,539,53a,53b,53c,53d,53e,53f,53g,53h,53i,53j,53k,53l,", "53m,53n,53o,53p,53q,53r,53s,53t,53u,53v,540,541,542,543,544,545,546,547,548,549,", "54a,54b,54c,54d,54e,54f,54g,54h,54i,54j,54k,54l,54m,54n,54o,54p,54q,54r,54s,54t,", "54u,54v,550,551,552,553,554,555,556,557,558,559,55a,55b,55c,55d,55e,55f,55g,55h,", "55i,55j,55k,55l,55m,55n,55o,55p,55q,55r,55s,55t,55u,55v,560,561,562,563,564,565,", "566,567,568,569,56a,56b,56c,56d,56e,56f,56g,56h,56i,56j,56k,56l,56m,56n,56o,56p,", "56q,56r,56s,56t,56u,56v,570,571,572,573,574,575,576,577,578,579,57a,57b,57c,57d,", "57e,57f,57g,57h,57i,57j,57k,57l,57m,57n,57o,57p,57q,57r,57s,57t,57u,57v,580,581,", "582,583,584,585,586,587,588,589,58a,58b,58c,58d,58e,58f,58g,58h,58i,58j,58k,58l,", "58m,58n,58o,58p,58q,58r,58s,58t,58u,58v,590,591,592,593,594,595,596,597,598,599,", "59a,59b,59c,59d,59e,59f,59g,59h,59i,59j,59k,59l,59m,59n,59o,59p,59q,59r,59s,59t,", "59u,59v,5a0,5a1,5a2,5a3,5a4,5a5,5a6,5a7,5a8,5a9,5aa,5ab,5ac,5ad,5ae,5af,5ag,5ah,", "5ai,5aj,5ak,5al,5am,5an,5ao,5ap,5aq,5ar,5as,5at,5au,5av,5b0,5b1,5b2,5b3,5b4,5b5,", "5b6,5b7,5b8,5b9,5ba,5bb,5bc,5bd,5be,5bf,5bg,5bh,5bi,5bj,5bk,5bl,5bm,5bn,5bo,5bp,", "5bq,5br,5bs,5bt,5bu,5bv,5c0,5c1,5c2,5c3,5c4,5c5,5c6,5c7,5c8,5c9,5ca,5cb,5cc,5cd,", "5ce,5cf,5cg,5ch,5ci,5cj,5ck,5cl,5cm,5cn,5co,5cp,5cq,5cr,5cs,5ct,5cu,5cv,5d0,5d1,", "5d2,5d3,5d4,5d5,5d6,5d7,5d8,5d9,5da,5db,5dc,5dd,5de,5df,5dg,5dh,5di,5dj,5dk,5dl,", "5dm,5dn,5do,5dp,5dq,5dr,5ds,5dt,5du,5dv,5e0,5e1,5e2,5e3,5e4,5e5,5e6,5e7,5e8,5e9,", "5ea,5eb,5ec,5ed,5ee,5ef,5eg,5eh,5ei,5ej,5ek,5el,5em,5en,5eo,5ep,5eq,5er,5es,5et,", "5eu,5ev,5f0,5f1,5f2,5f3,5f4,5f5,5f6,5f7,5f8,5f9,5fa,5fb,5fc,5fd,5fe,5ff,5fg,5fh,", "5fi,5fj,5fk,5fl,5fm,5fn,5fo,5fp,5fq,5fr,5fs,5ft,5fu,5fv,5g0,5g1,5g2,5g3,5g4,5g5,", "5g6,5g7,5g8,5g9,5ga,5gb,5gc,5gd,5ge,5gf,5gg,5gh,5gi,5gj,5gk,5gl,5gm,5gn,5go,5gp,", "5gq,5gr,5gs,5gt,5gu,5gv,5h0,5h1,5h2,5h3,5h4,5h5,5h6,5h7,5h8,5h9,5ha,5hb,5hc,5hd,", "5he,5hf,5hg,5hh,5hi,5hj,5hk,5hl,5hm,5hn,5ho,5hp,5hq,5hr,5hs,5ht,5hu,5hv,5i0,5i1,", "5i2,5i3,5i4,5i5,5i6,5i7,5i8,5i9,5ia,5ib,5ic,5id,5ie,5if,5ig,5ih,5ii,5ij,5ik,5il,", "5im,5in,5io,5ip,5iq,5ir,5is,5it,5iu,5iv,5j0,5j1,5j2,5j3,5j4,5j5,5j6,5j7,5j8,5j9,", "5ja,5jb,5jc,5jd,5je,5jf,5jg,5jh,5ji,5jj,5jk,5jl,5jm,5k0,5k1,5k2,5k3,5k4,5k5,5k6,", "5k7,5k8,5k9,5ka,5kb,5kc,5kd,5ke,5kf,5kg,5kh,5ki,5kj,5kk,5kl,5km,5kn,5ko,5kp,5kq,", "5kr,5ks,5l0,5l1,5l2,5l3,5l4,5l5,5l6,5l7,5l8,5l9,5la,5lb,5lc,5ld,5le,5lf,5lg,5lh,", "5li,5lj,5lk,5ll,5lm,5ln,5lo,5lp,5lq,5lr,5ls,5lt,5lu,5lv,5m0,5m1,5m2,5m3,5m4,5m5,", "5m6,5m7,5m8,5m9,5ma,5mb,5mc,5md,5me,5mf,5mg,5mh,5mi,5mj,5mk,5ml,5mm,5mn,5mo,5mp,", "5mq,5mr,5ms,5mt,5mu,5mv,5n0,5n1,5n2,5n3,5n4,5n5,5n6,5n7,5n8,5n9,5na,5nb,5nc,5nd,", "5ne,5nf,5ng,5o0,5o1,5o2,5o3,5o4,5o5,5o6,5o7,5o8,5o9,5oa,5ob,5oc,5oe,5of,5og,5oh,", "5oi,5oj,5ok,5p0,5p1,5p2,5p3,5p4,5p5,5p6,5p7,5p8,5p9,5pa,5pb,5pc,5pd,5pe,5pf,5pg,", "5ph,5pi,5pj,5pk,5pl,5pm,5q0,5q1,5q2,5q3,5q4,5q5,5q6,5q7,5q8,5q9,5qa,5qb,5qc,5qd,", "5qe,5qf,5qg,5qh,5qi,5qj,5r0,5r1,5r2,5r3,5r4,5r5,5r6,5r7,5r8,5r9,5ra,5rb,5rc,5re,", "5rf,5rg,5ri,5rj,5s0,5s1,5s2,5s3,5s4,5s5,5s6,5s7,5s8,5s9,5sa,5sb,5sc,5sd,5se,5sf,", "5sg,5sh,5si,5sj,5sk,5sl,5sm,5sn,5so,5sp,5sq,5sr,5ss,5st,5su,5sv,5t0,5t1,5t2,5t3,", "5t4,5t5,5t6,5t7,5t8,5t9,5ta,5tb,5tc,5td,5te,5tf,5tg,5th,5ti,5tj,5tk,5tl,5tm,5tn,", "5to,5tp,5tq,5tr,5ts,5tt,5tu,5tv,5u0,5u1,5u2,5u3,5u4,5u5,5u6,5u7,5u8,5u9,5ua,5ub,", "5uc,5ud,5ue,5uf,5ug,5uh,5ui,5uj,5uk,5ul,5um,5un,5uo,5up,5uq,5ur,5us,5ut,5v0,5v1,", "5v2,5v3,5v4,5v5,5v6,5v7,5v8,5v9,5vg,5vh,5vi,5vj,5vk,5vl,5vm,5vn,5vo,5vp,600,601,", "602,603,604,605,606,607,608,609,60a,60b,60c,60d,60e,60g,60h,60i,60j,60k,60l,60m,", "60n,60o,60p,610,611,612,613,614,615,616,617,618,619,61a,61b,61c,61d,61e,61f,61g,", "61h,61i,61j,61k,61l,61m,61n,61o,61p,61q,61r,61s,61t,61u,61v,620,621,622,623,624,", "625,626,627,628,629,62a,62b,62c,62d,62e,62f,62g,62h,62i,62j,62k,62l,62m,62n,62o,", "62p,62q,62r,62s,62t,62u,62v,630,631,632,633,634,635,636,637,638,639,63a,63b,63c,", "63d,63e,63f,63g,63h,63i,63j,63k,63l,63m,63n,640,641,642,643,644,645,646,647,648,", "649,64a,64b,64c,64d,64e,64f,64g,64h,64i,64j,64k,64l,64m,64n,64o,64p,64q,64r,64s,", "64t,64u,64v,650,651,652,653,654,655,656,657,658,659,680,681,682,683,684,685,686,", "687,688,689,68a,68b,68c,68d,68e,68f,68g,68h,68i,68j,68k,68l,68m,68n,68o,68p,68q,", "68r,68s,690,691,692,693,694,695,696,697,698,699,69a,69b,69g,69h,69i,69j,69k,69l,", "69m,69n,69o,69p,69q,69r,6a0,6a4,6a5,6a6,6a7,6a8,6a9,6aa,6ab,6ac,6ad,6ae,6af,6ag,", "6ah,6ai,6aj,6ak,6al,6am,6an,6ao,6ap,6aq,6ar,6as,6at,6au,6av,6b0,6b1,6b2,6b3,6b4,", "6b5,6b6,6b7,6b8,6b9,6ba,6bb,6bc,6bd,6bg,6bh,6bi,6bj,6bk,6c0,6c1,6c2,6c3,6c4,6c5,", "6c6,6c7,6c8,6c9,6ca,6cb,6cc,6cd,6ce,6cf,6cg,6ch,6ci,6cj,6ck,6cl,6cm,6cn,6co,6cp,", "6cq,6cr,6cs,6ct,6cu,6cv,6d0,6d1,6d2,6d3,6d4,6d5,6d6,6d7,6d8,6d9,6dg,6dh,6di,6dj,", "6dk,6dl,6dm,6dn,6do,6dp,6dq,6dr,6ds,6dt,6du,6dv,6e0,6e1,6e2,6e3,6e4,6e5,6e6,6e7,", "6e8,6e9,6eg,6eh,6ei,6ej,6ek,6el,6em,6en,6eo,6ep,6eu,6ev,6f0,6f1,6f2,6f3,6f4,6f5,", "6f6,6f7,6f8,6f9,6fa,6fb,6fc,6fd,6fe,6ff,6fg,6fh,6fi,6fj,6fk,6fl,6fm,6fn,6fo,6fp,", "6fq,6fr,6fs,6ft,6fu,6fv,6g0,6g1,6g2,6g3,6g4,6g5,6g6,6g7,6g8,6g9,6ga,6gb,6gc,6gd,", "6ge,6gf,6gg,6gh,6gi,6gj,6gk,6gl,6gm,6gn,6go,6gp,6gq,6gr,6gu,6gv,780,781,782,783,", "784,785,786,787,788,789,78a,78b,78c,78d,78e,78f,78g,78h,78i,78j,78k,78l,78m,78n,", "78o,78p,78q,78r,78s,78t,78u,78v,790,791,792,793,794,795,796,797,798,799,79a,79b,", "79c,79d,79e,79f,79g,79h,79i,79j,79k,79l,79m,79n,79o,79p,79q,79r,79s,79t,79u,79v,", "7a0,7a1,7a2,7a3,7a4,7a5,7a6,7a7,7a8,7a9,7aa,7ab,7ac,7ad,7ae,7af,7ag,7ah,7ai,7aj,", "7ak,7al,7am,7an,7ao,7ap,7aq,7ar,7as,7at,7au,7av,7b0,7b1,7b2,7b3,7b4,7b5,7b6,7b7,", "7b8,7b9,7ba,7bb,7bc,7bd,7be,7bf,7bg,7bh,7bi,7bj,7bk,7bl,7bm,7bn,7bo,7bp,7bq,7br,", "7bs,7bt,7bu,7bv,7c0,7c1,7c2,7c3,7c4,7c5,7c6,7c7,7c8,7c9,7ca,7cb,7cc,7cd,7ce,7cf,", "7cg,7ch,7ci,7cj,7ck,7cl,7cm,7cn,7co,7cp,7cq,7cr,7cs,7ct,7cu,7cv,7d0,7d1,7d2,7d3,", "7d4,7d5,7d6,7d7,7d8,7d9,7da,7db,7dc,7dd,7de,7df,7dg,7dh,7di,7dj,7dk,7dl,7dm,7dn,", "7do,7dp,7dq,7dr,7ds,7dt,7du,7dv,7e0,7e1,7e2,7e3,7g0,7g1,7g2,7g3,7g4,7g5,7g6,7g7,", "7g8,7g9,7ga,7gb,7gc,7gd,7ge,7gf,7gg,7gh,7gi,7gj,7gk,7gl,7gm,7gn,7go,7gp,7gq,7gr,", "7gs,7gt,7gu,7gv,7h0,7h1,7h2,7h3,7h4,7h5,7h6,7h7,7h8,7h9,7ha,7hb,7hc,7hd,7he,7hf,", "7hg,7hh,7hi,7hj,7hk,7hl,7hm,7hn,7ho,7hp,7hq,7hr,7hs,7ht,7hu,7hv,7i0,7i1,7i2,7i3,", "7i4,7i5,7i6,7i7,7i8,7i9,7ia,7ib,7ic,7id,7ie,7if,7ig,7ih,7ii,7ij,7ik,7il,7im,7in,", "7io,7ip,7iq,7ir,7is,7it,7iu,7iv,7j0,7j1,7j2,7j3,7j4,7j5,7j6,7j7,7j8,7j9,7ja,7jb,", "7jc,7jd,7je,7jf,7jg,7jh,7ji,7jj,7jk,7jl,7jm,7jn,7jo,7jp,7jq,7jr,7js,7jt,7ju,7jv,", "7k0,7k1,7k2,7k3,7k4,7k5,7k6,7k7,7k8,7k9,7ka,7kb,7kc,7kd,7ke,7kf,7kg,7kh,7ki,7kj,", "7kk,7kl,7km,7kn,7ko,7kp,7kq,7kr,7l0,7l1,7l2,7l3,7l4,7l5,7l6,7l7,7l8,7l9,7la,7lb,", "7lc,7ld,7le,7lf,7lg,7lh,7li,7lj,7lk,7ll,7lm,7ln,7lo,7lp,7lq,7lr,7ls,7lt,7lu,7lv,", "7m0,7m1,7m2,7m3,7m4,7m5,7m6,7m7,7m8,7m9,7ma,7mb,7mc,7md,7me,7mf,7mg,7mh,7mi,7mj,", "7mk,7ml,7mm,7mn,7mo,7mp,7mq,7mr,7ms,7mt,7mu,7mv,7n0,7n1,7n2,7n3,7n4,7n5,7n6,7n7,", "7n8,7n9,7na,7nb,7nc,7nd,7ne,7nf,7ng,7nh,7ni,7nj,7nk,7nl,7nm,7nn,7no,7np,7o0,7o1,", "7o2,7o3,7o4,7o5,7o6,7o7,7o8,7o9,7oa,7ob,7oc,7od,7oe,7of,7og,7oh,7oi,7oj,7ok,7ol,", "7oo,7op,7oq,7or,7os,7ot,7p0,7p1,7p2,7p3,7p4,7p5,7p6,7p7,7p8,7p9,7pa,7pb,7pc,7pd,", "7pe,7pf,7pg,7ph,7pi,7pj,7pk,7pl,7pm,7pn,7po,7pp,7pq,7pr,7ps,7pt,7pu,7pv,7q0,7q1,", "7q2,7q3,7q4,7q5,7q8,7q9,7qa,7qb,7qc,7qd,7qg,7qh,7qi,7qj,7qk,7ql,7qm,7qn,7qp,7qr,", "7qt,7qv,7r0,7r1,7r2,7r3,7r4,7r5,7r6,7r7,7r8,7r9,7ra,7rb,7rc,7rd,7re,7rf,7rg,7rh,", "7ri,7rj,7rk,7rl,7rm,7rn,7ro,7rp,7rq,7rr,7rs,7rt,7s0,7s1,7s2,7s3,7s4,7s5,7s6,7s7,", "7s8,7s9,7sa,7sb,7sc,7sd,7se,7sf,7sg,7sh,7si,7sj,7sk,7sl,7sm,7sn,7so,7sp,7sq,7sr,", "7ss,7st,7su,7sv,7t0,7t1,7t2,7t3,7t4,7t5,7t6,7t7,7t8,7t9,7ta,7tb,7tc,7td,7te,7tf,", "7tg,7th,7ti,7tj,7tk,7tm,7tn,7to,7tp,7tq,7tr,7ts,7tt,7tu,7tv,7u0,7u1,7u2,7u3,7u4,", "7u6,7u7,7u8,7u9,7ua,7ub,7uc,7ud,7ue,7uf,7ug,7uh,7ui,7uj,7um,7un,7uo,7up,7uq,7ur,", "7ut,7uu,7uv,7v0,7v1,7v2,7v3,7v4,7v5,7v6,7v7,7v8,7v9,7va,7vb,7vc,7vd,7ve,7vf,7vi,", "7vj,7vk,7vm,7vn,7vo,7vp,7vq,7vr,7vs,7vt,7vu,800,801,802,803,804,805,806,807,808,", "809,80a,80b,80c,80d,80e,80f,80g,80h,80i,80j,80k,80l,80m,80n,80o,80p,80q,80r,80s,", "80t,80u,80v,810,811,812,813,814,815,816,817,818,819,81a,81b,81c,81d,81e,81f,81g,", "81h,81i,81j,81k,81l,81m,81n,81o,81p,81q,81r,81s,81t,81u,81v,820,821,822,823,824,", "825,826,827,828,829,82a,82b,82c,82d,82e,82f,82g,82h,82i,82j,82k,82l,82m,82n,82o,", "82p,82q,82r,82s,82t,82u,82v,830,831,832,833,83a,83b,83c,83d,83e,83f,83g,83h,83k,", "83l,83m,83n,83o,83p,83q,83r,83s,83t,83u,83v,840,841,842,843,844,845,846,847,848,", "849,84a,84b,84c,84d,84e,84g,84h,84i,84j,84k,850,851,852,853,854,855,856,857,858,", "859,85a,85b,85c,85d,85e,85f,85g,85h,85i,85j,85k,85l,86g,86h,86i,86j,86k,86l,86m,", "86n,86o,86p,86q,86r,86s,86t,86u,86v,870,871,872,873,874,875,876,877,878,879,87a,", "87b,880,881,882,883,884,885,886,887,888,889,88a,88b,88c,88d,88e,88f,88g,88h,88i,", "88j,88k,88l,88m,88n,88o,88p,88q,88r,88s,88t,88u,88v,890,891,892,893,894,895,896,", "897,898,899,89a,89b,89c,89d,89e,89f,89g,89h,89i,89j,89k,89l,89m,89n,89o,89p,89q,", "89r,89s,89t,89u,89v,8a0,8a1,8a2,8a3,8a4,8a5,8a6,8a7,8a8,8a9,8aa,8ab,8ac,8aj,8ak,", "8al,8am,8an,8ao,8ap,8aq,8ar,8as,8at,8au,8av,8b0,8b1,8b2,8b3,8b4,8b5,8b6,8b7,8b8,", "8b9,8ba,8bb,8bc,8bd,8be,8bf,8bg,8bh,8bi,8bj,8bk,8bl,8bm,8bn,8bo,8bp,8bq,8br,8bs,", "8bt,8bu,8bv,8c0,8c1,8c2,8c3,8cg,8ch,8ci,8cj,8ck,8cl,8cm,8cn,8co,8cp,8cq,8cr,8cs,", "8ct,8cu,8cv,8d0,8d1,8d2,8d3,8d4,8d5,8d6,8d7,8d8,8d9,8da,8db,8dc,8dd,8de,8df,8dg,", "8dh,8di,8dj,8dk,8dl,8dm,8dn,8do,8dp,8dq,8dr,8ds,8dt,8du,8dv,8e0,8e1,8e2,8e3,8e4,", "8e5,8e6,8e7,8e8,8e9,8ea,8eb,8ec,8ed,8ee,8ef,8eg,8eh,8ei,8ej,8ek,8el,8em,8en,8eo,", "8ep,8eq,8er,8es,8et,8eu,8ev,8f0,8f1,8f2,8f3,8f4,8f5,8f6,8f7,8f8,8f9,8fa,8fb,8fc,", "8fd,8fe,8ff,8fg,8fh,8fi,8fj,8fk,8fl,8fm,8fn,8fo,8fp,8fq,8fr,8fs,8ft,8fu,8fv,8g0,", "8g1,8g2,8g3,8g4,8g5,8g6,8g7,8g8,8g9,8ga,8gb,8gc,8gd,8ge,8gf,8gg,8gh,8gi,8gj,8gk,", "8gl,8gm,8gn,8go,8gp,8gq,8gr,8gs,8gt,8gu,8gv,8h0,8h1,8h2,8h3,8h4,8h5,8h6,8h7,8h8,", "8h9,8ha,8hb,8hc,8hd,8he,8hf,8hg,8hh,8hi,8hj,8hk,8hl,8hm,8hn,8ho,8hp,8hq,8hr,8hs,", "8ht,8hu,8hv,8i0,8i1,8i2,8i3,8i4,8i5,8i6,8i7,8i8,8i9,8ia,8ib,8ic,8id,8ie,8if,8ig,", "8ih,8ii,8ij,8ik,8il,8im,8in,8io,8ip,8iq,8ir,8is,8it,8iu,8iv,8j0,8j1,8j2,8j3,8j4,", "8j5,8j6,8j7,8j8,8j9,8ja,8jb,8jc,8jd,8je,8jf,8jg,8jh,8ji,8jj,8jk,8jl,8jm,8jn,8jo,", "8jp,8jq,8jr,8js,8jt,8ju,8jv,8k0,8k1,8k2,8k3,8k4,8k5,8k6,8k7,8k8,8k9,8ka,8kb,8kc,", "8kd,8ke,8kf,8kg,8kh,8ki,8kj,8kk,8kl,8km,8kn,8ko,8kp,8kq,8kr,8ks,8kt,8ku,8kv,8l0,", "8l1,8l2,8l3,8l4,8l5,8l6,8l7,8l8,8l9,8la,8lb,8lc,8ld,8le,8lf,8lg,8lh,8li,8lj,8lk,", "8ll,8lm,8ln,8lo,8lp,8lq,8lr,8ls,8lt,8lu,8lv,8m0,8m1,8m2,8m3,8m4,8m5,8m6,8m7,8m8,", "8m9,8ma,8mb,8mc,8md,8me,8mf,8mg,8mh,8mi,8mj,8mk,8ml,8mm,8mn,8mo,8mp,8mq,8mr,8ms,", "8mt,8mu,8mv,8n0,8n1,8n2,8n3,8n4,8n5,8n6,8n7,8n8,8n9,8na,8nb,8nc,8nd,8ne,8nf,8ng,", "8nh,8ni,8nj,8nk,8nl,8nm,8nn,8no,8np,8nq,8nr,8ns,8nt,8nu,8nv,8o0,8o1,8o2,8o3,8o4,", "8o5,8o6,8o7,8o8,8o9,8oa,8ob,8oc,8od,8oe,8of,8og,8oh,8oi,8oj,8ok,8ol,8om,8on,8oo,", "8op,8oq,8or,8os,8ot,8ou,8ov,8p0,8p1,8p2,8p3,8p4,8p5,8p6,8p7,8p8,8p9,8pa,8pb,8pc,", "8pd,8pe,8pf,8pg,8ph,8pi,8pj,8pk,8pl,8pm,8pn,8po,8pp,8pq,8pr,8ps,8pt,8pu,8pv,8q0,", "8q1,8q2,8q3,8q4,8q5,8q6,8q7,8q8,8q9,8qa,8qb,8qc,8qd,8qe,8qf,8qg,8qh,8qi,8qj,8qk,", "8ql,8qm,8qn,8qo,8qp,8qq,8qr,8qs,8qt,8qu,8qv,8r0,8r1,8r2,8r3,8r4,8r5,8r6,8r7,8r8,", "8r9,8ra,8rb,8rc,8rd,8re,8rf,8rg,8rh,8ri,8rj,8rk,8rl,8rm,8rn,8ro,8rp,8rq,8rr,8rs,", "8rt,8ru,8rv,8s0,8s1,8s2,8s3,8s4,8s5,8s6,8s7,8s8,8s9,8sa,8sb,8sc,8sd,8se,8sf,8sg,", "8sh,8si,8sj,8sk,8sl,8sm,8sn,8so,8sp,8sq,8sr,8ss,8st,8su,8sv,8t0,8t1,8t2,8t3,8t4,", "8t5,8t6,8t7,8t8,8t9,8ta,8tb,8tc,8td,8te,8tf,8tg,8th,8ti,8tj,8tk,8tl,8tm,8tn,8to,", "8tp,8tq,8tr,8ts,8tt,8tu,8tv,8u0,8u1,8u2,8u3,8u4,8u5,8u6,8u7,8u8,8u9,8ua,8ub,8uc,", "8ud,8ue,8uf,8ug,8uh,8ui,8uj,8uk,8ul,8um,8un,8uo,8up,8uq,8ur,900,901,902,903,904,", "905,906,907,908,909,90a,90b,90c,90d,90e,90f,90g,90h,90i,90j,90k,90l,90m,90n,90o,", "90p,90q,90r,90s,90t,90u,90v,910,911,912,913,914,915,916,920,921,922,923,924,925,", "926,927,928,929,92a,930,931,932,933,934,935,936,937,938,939,93a,93b,93c,93d,93e,", "93f,93g,93h,93i,93j,93k,93l,93m,93n,93o,93p,93q,93r,93s,93t,93u,93v,940,941,942,", "943,944,945,946,947,948,949,94a,94b,94c,94d,94e,94f,94g,94h,94i,94j,94k,94l,94m,", "94n,94o,94p,94q,94r,94s,94t,94u,94v,950,951,952,953,954,955,956,957,958,959,95a,", "95b,95c,95d,95e,95f,95g,95h,95i,95j,95k,95l,95m,95n,95o,95p,95q,95r,95s,95t,95u,", "95v,960,961,962,963,964,965,966,967,968,969,96a,96b,96c,96d,96e,96f,96g,96h,96i,", "96j,96k,96l,96m,96n,96o,96p,96q,96r,96s,96t,96u,96v,970,971,972,973,974,975,976,", "977,978,979,97a,97b,97c,97d,97e,97f,97g,97h,97i,97j,97k,97l,97m,97n,97o,97p,97q,", "97r,97s,97t,97u,97v,980,981,982,983,984,985,986,987,988,989,98a,98b,98c,98d,98e,", "98f,98g,98h,98i,98j,98k,98l,98m,98n,98o,98p,98q,98r,98s,98t,98u,98v,990,991,992,", "993,994,995,996,997,998,999,99a,99b,99c,99d,99e,99f,99g,99h,99i,99j,99k,99l,99m,", "99n,99o,99p,99q,99r,99s,99t,99u,99v,9a0,9a1,9a2,9a3,9a4,9a5,9a6,9a7,9a8,9a9,9aa,", "9ab,9ac,9ad,9ae,9af,9ag,9ah,9ai,9aj,9ak,9al,9am,9an,9ao,9ap,9aq,9ar,9as,9at,9au,", "9av,9b0,9b1,9b2,9b3,9b4,9b5,9b6,9b7,9b8,9b9,9ba,9bb,9bc,9bd,9be,9bf,9bg,9bh,9bi,", "9bj,9bk,9bl,9bm,9bn,9bo,9bp,9bq,9br,9bs,9bt,9bu,9bv,9c0,9c1,9c2,9c3,9c4,9c5,9c6,", "9c7,9c8,9c9,9ca,9cb,9cc,9cd,9ce,9cf,9cg,9ch,9ci,9cj,9ck,9cl,9cm,9cn,9co,9cp,9cq,", "9cr,9cs,9ct,9cu,9cv,9d0,9d1,9d2,9d3,9d4,9d5,9d6,9d7,9d8,9d9,9da,9db,9dc,9dd,9de,", "9df,9dg,9dh,9di,9dj,9dk,9dl,9dm,9dn,9do,9dp,9dq,9dr,9ds,9dt,9du,9dv,9e0,9e1,9e2,", "9e3,9e4,9e5,9e6,9e7,9e8,9e9,9ea,9eb,9ec,9ed,9ee,9ef,9eg,9eh,9ei,9ej,9ek,9el,9em,", "9en,9eo,9ep,9eq,9er,9es,9et,9eu,9ev,9f0,9f1,9f2,9f3,9f4,9f5,9f6,9f7,9f8,9f9,9fa,", "9fb,9fc,9fd,9fe,9ff,9fg,9fh,9fi,9fj,9fk,9fl,9fm,9fn,9fo,9fp,9fq,9fr,9fs,9ft,9fu,", "9fv,9g0,9g1,9g2,9g3,9g4,9g5,9g6,9g7,9g8,9g9,9ga,9gb,9gc,9gd,9ge,9gf,9gg,9gh,9gi,", "9gj,9gk,9gl,9gm,9gn,9go,9gp,9gq,9gr,9gs,9gt,9gu,9gv,9h0,9h1,9h2,9h3,9h4,9h5,9h6,", "9h7,9h8,9h9,9ha,9hb,9hc,9hd,9he,9hf,9hg,9hh,9hi,9hj,9hk,9hl,9hm,9hn,9ho,9hp,9hq,", "9hr,9hs,9ht,9hu,9hv,9i0,9i1,9i2,9i3,9i4,9i5,9i6,9i7,9i8,9i9,9ia,9ib,9ic,9id,9ie,", "9if,9ig,9ih,9ii,9ij,9ik,9il,9im,9in,9io,9ip,9iq,9ir,9is,9it,9iu,9iv,9j0,9j1,9j2,", "9j3,9j4,9j5,9j6,9j7,9j8,9j9,9ja,9jb,9jc,9jd,9je,9jf,9jg,9jh,9ji,9jj,9jk,9jl,9jm,", "9jn,9jo,9jp,9jq,9jr,9js,9jt,9ju,9jv,9k0,9k1,9k2,9k3,9k4,9k5,9k6,9k7,9k8,9k9,9ka,", "9kb,9kc,9kd,9ke,9kf,9kg,9kh,9ki,9kj,9kk,9kl,9km,9kn,9ko,9kp,9kq,9kr,9ks,9l0,9l1,", "9l2,9l3,9l4,9l5,9l6,9l7,9l8,9l9,9la,9lb,9lc,9ld,9le,9lf,9lg,9lh,9o1,9o2,9o3,9o4,", "9o6,9o7,9o8,9o9,9oc,9od,9oe,9of,9og,9oh,9oi,9oj,9ok,9ol,9om,9on,9oo,9op,9oq,9or,", "9os,9ot,9ou,9ov,9p0,9p1,9p2,9p3,9p4,9p5,9p6,9p7,9p9,9pa,9pb,9pc,9pd,9pe,9pf,9pg,", "9ph,9pi,9pj,9pk,9pl,9pm,9pn,9po,9pp,9pq,9pr,9ps,9pt,9pu,9pv,9q0,9q1,9q2,9q3,9q4,", "9q5,9q6,9q7,9q8,9q9,9qa,9qb,9qd,9qf,9qg,9qh,9qi,9qm,9qo,9qp,9qq,9qr,9qs,9qt,9qu,", "9r1,9r2,9r3,9r4,9r5,9r6,9r7,9r8,9r9,9ra,9rb,9rc,9rd,9re,9rf,9rg,9rh,9ri,9rj,9rk,", "9rl,9rm,9rn,9ro,9rp,9rq,9rr,9rs,9rt,9ru,9rv,9s0,9s1,9s2,9s3,9s4,9s5,9s6,9s7,9s8,", "9s9,9sa,9sb,9sc,9sd,9se,9sf,9sg,9sh,9si,9sj,9sk,9so,9sp,9sq,9sr,9ss,9st,9su,9sv,", "9t0,9t1,9t2,9t3,9t4,9t5,9t6,9t7,9t8,9t9,9ta,9tb,9tc,9td,9te,9tf,9th,9ti,9tj,9tk,", "9tl,9tm,9tn,9to,9tp,9tq,9tr,9ts,9tt,9tu,9u0,9u1,9u2,9u3,9u4,9u5,9u6,9ug,9uh,9ui,", "9uj,9uk,9ul,9um,9un,9uo,9up,9uq,9ur,9us,9ut,9uu,9uv,9v0,9v1,9v2,9v3,9v4,9v5,9v6,", "9v7,9v8,9v9,9va,9vb,9vg,9vh,9vi,9vj,9vk,9vl,9vm,9vn,9vo,9vp,9vq,9vr,9vs,9vt,9vu,", "9vv,a00,a01,a02,a03,a04,a05,a06,a07,a08,a09,a0a,a0b,a0c,a0d,a0e,a0f,a0g,a0h,a0i,", "a0j,a0k,a0l,a0m,a0n,a0o,a0p,a0q,a0r,a0s,a0t,a0u,a0v,a10,a11,a12,a13,a14,a15,a16,", "a17,a18,a19,a1a,a1b,a1c,a1d,a1e,a1f,a1g,a1h,a1i,a1j,a1k,a1l,a1m,a1n,a1o,a1p,a1q,", "a1r,a1s,a1t,a1u,a1v,a20,a21,a22,a23,a24,a25,a26,a27,a28,a29,a2a,a2b,a2c,a2d,a2e,", "a2f,a2g,a2h,a2i,a2j,a2k,a2l,a2m,a2n,a2o,a2p,a2q,a2r,a2s,a2t,a2u,a2v,a30,a31,a32,", "a33,a34,a35,a36,a37,a38,a39,a3a,a3b,a3c,a3d,a3e,a3f,a3g,a3h,a3i,a3j,a3k,a3l,a3m,", "a3n,a3o,a3p,a3q,a3r,a3s,a3t,a3u,a3v,a40,a41,a42,a43,a44,a45,a46,a47,a48,a49,a4a,", "a4b,a4c,a4d,a4e,a4f,a4g,a4h,a4i,a4j,a4k,a4l,a4m,a4n,a4o,a4p,a4q,a4r,a4s,a4t,a4u,", "a4v,a50,a51,a52,a53,a54,a55,a56,a57,a58,a59,a5a,a5b,a5c,a5d,a5e,a5f,a5g,a5h,a5i,", "a5j,a5k,a5l,a5m,a5n,a5o,a5p,a5q,a5r,a5s,a5t,a5u,a5v,a60,a61,a62,a63,a64,a65,a66,", "a67,a68,a69,a6a,a6b,a6c,a6d,a6e,a6f,a6g,a6h,a6i,a6j,a6k,a6l,a6m,a6n,a6o,a6p,a6q,", "a6r,a6s,a6t,a6u,a6v,a70,a71,a72,a73,a74,a75,a76,a77,a78,a79,a7a,a7b,a7c,a7d,a7e,", "a7f,a7g,a7h,a7i,a7j,a7k,a7l,a7m,a7n,a7o,a7p,a7q,a7r,a7s,a7t,a7u,a7v,a80,a81,a82,", "a83,a84,a85,a86,a87,a88,a89,a8a,a8b,a8c,a8d,a8e,a8f,a8g,a8h,a8i,a8j,a8k,a8l,a8m,", "a8n,a8o,a8p,a8q,a8r,a8s,a8t,a8u,a8v,a90,a91,a92,a93,a94,a95,a96,a97,a98,a99,a9a,", "a9b,a9c,a9d,a9e,a9f,a9g,a9h,a9i,a9j,a9k,a9l,a9m,a9n,a9o,a9p,a9q,a9r,a9s,a9t,a9u,", "a9v,aa0,aa1,aa2,aa3,aa4,aa5,aa6,aa7,aa8,aa9,aaa,aab,aac,aad,aae,aaf,aag,aah,aai,", "aaj,aak,aal,aam,aan,aao,aap,aaq,aar,aas,aat,aau,aav,ab0,ab1,ab2,ab3,ab4,ab5,ab6,", "ab7,ab8,ab9,aba,abb,abc,abd,abe,abf,abg,abh,abi,abj,abk,abl,abm,abn,abo,abp,abq,", "abr,abs,abt,abu,abv,ac0,ac1,ac2,ac3,ac4,ac5,ac6,ac7,ac8,ac9,aca,acb,acc,acd,ace,", "acf,acg,ach,aci,acj,ack,acl,acm,acn,aco,acp,acq,acr,acs,act,acu,acv,ad0,ad1,ad2,", "ad3,ad4,ad5,ad6,ad7,ad8,ad9,ada,adb,adc,add,ade,adf,adg,adh,adi,adj,adk,adl,adm,", "adn,ado,adp,adq,adr,ads,adt,adu,adv,ae0,ae1,ae2,ae3,ae4,ae5,ae6,ae7,ae8,ae9,aea,", "aeb,aec,aed,aee,aef,aeg,aeh,aei,aej,aek,ael,aem,aen,aeo,aep,aeq,aer,aes,aet,aeu,", "aev,af0,af1,af2,af3,af4,af5,af6,af7,af8,af9,afa,afb,afc,afd,afe,aff,afg,afh,afi,", "afj,afk,afl,afm,afn,afo,afp,afq,afr,afs,aft,afu,afv,ag0,ag1,ag2,ag3,ag4,ag5,ag6,", "ag7,ag8,ag9,aga,agb,agc,agd,age,agf,agg,agh,agi,agj,agk,agl,agm,agn,ago,agp,agq,", "agr,ags,agt,agu,agv,ah0,ah1,ah2,ah3,ah4,ah5,ah6,ah7,ah8,ah9,aha,ahb,ahc,ahd,ahe,", "ahf,ahg,ahh,ahi,ahj,ahk,ahl,ahm,ahn,aho,ahp,ahq,ahr,ahs,aht,ahu,ahv,ai0,ai1,ai2,", "ai3,ai4,ai5,ai6,ai7,ai8,ai9,aia,aib,aic,aid,aie,aif,aig,aih,aii,aij,aik,ail,aim,", "ain,aio,aip,aiq,air,ais,ait,aiu,aiv,aj0,aj1,aj2,aj3,aj4,aj5,aj6,aj7,aj8,aj9,aja,", "ajb,ajc,ajd,aje,ajf,ajg,ajh,aji,ajj,ajk,ajl,ajm,ajn,ajo,ajp,ajq,ajr,ajs,ajt,aju,", "ajv,ak0,ak1,ak2,ak3,ak4,ak5,ak6,ak7,ak8,ak9,aka,akb,akc,akd,ake,akf,akg,akh,aki,", "akj,akk,akl,akm,akn,ako,akp,akq,akr,aks,akt,aku,akv,al0,al1,al2,al3,al4,al5,al6,", "al7,al8,al9,ala,alb,alc,ald,ale,alf,alg,alh,ali,alj,alk,all,alm,aln,alo,alp,alq,", "alr,als,alt,alu,alv,am0,am1,am2,am3,am4,am5,am6,am7,am8,am9,ama,amb,amc,amd,ame,", "amf,amg,amh,ami,amj,amk,aml,amm,amn,amo,amp,amq,amr,ams,amt,amu,amv,an0,an1,an2,", "an3,an4,an5,an6,an7,an8,an9,ana,anb,anc,and,ane,anf,ang,anh,ani,anj,ank,anl,anm,", "ann,ano,anp,anq,anr,ans,ant,anu,anv,ao0,ao1,ao2,ao3,ao4,ao5,ao6,ao7,ao8,ao9,aoa,", "aob,aoc,aod,aoe,aof,aog,aoh,aoi,aoj,b00,b01,b02,b03,b04,b05,b06,b07,b08,b09,b0a,", "b0b,b0c,b0d,b0e,b0f,b0g,b0h,b0i,b0j,b0k,b0l,b0m,b0n,b0o,b0p,b0q,b0r,b0s,b0t,b0u,", "b0v,b10,b11,b12,b13,b14,b15,b16,b17,b18,b19,b1a,b1b,b1c,b1d,b1e,b1g,b1h,b1i,b1j,", "b1k,b1l,b1m,b1n,b1o,b1p,b1q,b1r,b1s,b1t,b1u,b1v,b20,b21,b22,b23,b24,b25,b26,b27,", "b28,b29,b2a,b2b,b2c,b2d,b2e,b2f,b2g,b2h,b2i,b2j,b2k,b2l,b2m,b2n,b2o,b2p,b2q,b2r,", "b2s,b2t,b2u,b40,b41,b42,b43,b44,b45,b46,b47,b48,b49,b4a,b4b,b4c,b4d,b4e,b4f,b4g,", "b4h,b4i,b4j,b4k,b4l,b4m,b4n,b4o,b4p,b4q,b4r,b4s,b4t,b4u,b4v,b50,b51,b52,b53,b54,", "b55,b56,b57,b58,b59,b5a,b5b,b5c,b5d,b5e,b5f,b5g,b5h,b5i,b5j,b5k,b5l,b5m,b5n,b5o,", "b5p,b5q,b5r,b5s,b5t,b5u,b5v,b60,b61,b62,b63,b64,b65,b66,b67,b68,b69,b6a,b6b,b6c,", "b6d,b6e,b6f,b6g,b6h,b6i,b6j,b6k,b6l,b6m,b6n,b6o,b6p,b6q,b6r,b6s,b6t,b6u,b6v,b70,", "b71,b72,b73,b74,b75,b76,b77,b78,b79,b7a,b7p,b7q,b7r,b7s,b7t,b7u,b7v,b80,b81,b82,", "b83,b84,b85,b86,b87,b88,b89,b8a,b8b,b8c,b8d,b8e,b8f,b8g,b8h,b8i,b8j,b8k,b8l,b8m,", "b8n,b8o,b8p,b8q,b8r,b8s,b8t,b8u,b8v,b90,b91,b92,b93,b94,b95,b9g,b9h,b9i,b9j,b9k,", "b9l,b9m,b9n,b9o,b9p,b9q,b9r,b9s,b9t,b9u,b9v,ba0,ba1,ba2,ba3,ba4,ba5,ba6,ba7,ba8,", "ba9,baa,bab,bac,bad,bae,baf,bag,bah,bai,baj,bak,bal,bam,ban,bao,bap,baq,bar,bas,", "bat,bau,bav,bb0,bb1,bb2,bb3,bb4,bb5,bbf,bc0,bc1,bc2,bc3,bc4,bc5,bc6,bc7,bc8,bc9,", "bca,bcb,bcc,bcd,bce,bcf,bcg,bch,bci,bcj,bck,bcl,bcm,bd0,bd1,bd2,bd3,bd4,bd5,bd6,", "bd8,bd9,bda,bdb,bdc,bdd,bde,bdg,bdh,bdi,bdj,bdk,bdl,bdm,bdo,bdp,bdq,bdr,bds,bdt,", "bdu,be0,be1,be2,be3,be4,be5,be6,be8,be9,bea,beb,bec,bed,bee,beg,beh,bei,bej,bek,", "bel,bem,beo,bep,beq,ber,bes,bet,beu,bg0,bg1,bg2,bg3,bg4,bg5,bg6,bg7,bg8,bg9,bga,", "bgb,bgc,bgd,bge,bgf,bgg,bgh,bgi,bgj,bgk,bgl,bgm,bgn,bgs,bgt,bk0,bk1,bk2,bk3,bk4,", "bk5,bk6,bk7,bk8,bk9,bka,bkb,bkc,bkd,bke,bkf,bkg,bkh,bki,bkj,bkk,bkl,bkm,bkn,bko,", "bkp,bkr,bks,bkt,bku,bkv,bl0,bl1,bl2,bl3,bl4,bl5,bl6,bl7,bl8,bl9,bla,blb,blc,bld,", "ble,blf,blg,blh,bli,blj,blk,bll,blm,bln,blo,blp,blq,blr,bls,blt,blu,blv,bm0,bm1,", "bm2,bm3,bm4,bm5,bm6,bm7,bm8,bm9,bma,bmb,bmc,bmd,bme,bmf,bmg,bmh,bmi,bmj,bmk,bml,", "bmm,bmn,bmo,bmp,bmq,bmr,bms,bmt,bmu,bmv,bn0,bn1,bn2,bn3,bn4,bn5,bn6,bn7,bn8,bn9,", "bna,bnb,bnc,bnd,bne,bnf,bng,bnh,bni,bnj,bo0,bo1,bo2,bo3,bo4,bo5,bo6,bo7,bo8,bo9,", "boa,bob,boc,bod,boe,bof,bog,boh,boi,boj,bok,bol,bom,bon,boo,bop,boq,bor,bos,bot,", "bou,bov,bp0,bp1,bp2,bp3,bp4,bp5,bp6,bp7,bp8,bp9,bpa,bpb,bpc,bpd,bpe,bpf,bpg,bph,", "bpi,bpj,bpk,bpl,bpm,bpn,bpo,bpp,bpq,bpr,bps,bpt,bpu,bpv,bq0,bq1,bq2,bq3,bq4,bq5,", "bq6,bq7,bq8,bq9,bqa,bqb,bqc,bqd,bqe,bqf,bqg,bqh,bqi,bqj,bqk,bql,bqm,bqn,bqo,bqp,", "bqq,bqr,bqs,bqt,bqu,bqv,br0,br1,br2,br3,br4,br5,br6,br7,br8,br9,bra,brb,brc,brd,", "bre,brf,brg,brh,bri,brj,brk,brl,brm,brn,bro,brp,brq,brr,brs,brt,bru,brv,bs0,bs1,", "bs2,bs3,bs4,bs5,bs6,bs7,bs8,bs9,bsa,bsb,bsc,bsd,bse,bsf,bsg,bsh,bsi,bsj,bsk,bsl,", "bsm,bsn,bso,bsp,bsq,bsr,bss,bst,bsu,bsv,bt0,bt1,bt2,bt3,bt4,bt5,bt6,bt7,bt8,bt9,", "bta,btb,btc,btd,bte,btf,btg,bth,bti,btj,btk,btl,btm,btn,bto,btp,btq,btr,bts,btt,", "btu,btv,bu0,bu1,bu2,bu3,bu4,bu5,bu6,bu7,bu8,bu9,bua,bub,buc,bud,bue,buf,bug,buh,", "bui,buj,buk,bul,bvg,bvh,bvi,bvj,bvk,bvl,bvm,bvn,bvo,bvp,bvq,bvr,c00,c01,c02,c03,", "c04,c05,c06,c07,c08,c09,c0a,c0b,c0c,c0d,c0e,c0f,c0g,c0h,c0i,c0j,c0k,c0l,c0m,c0n,", "c0o,c0p,c0q,c0r,c0s,c0t,c0u,c0v,c10,c11,c12,c13,c14,c15,c16,c17,c18,c19,c1a,c1b,", "c1c,c1d,c1e,c1f,c1g,c1h,c1i,c1j,c1k,c1l,c1m,c1n,c1o,c1p,c1q,c1r,c1s,c1t,c1u,c1v,", "c21,c22,c23,c24,c25,c26,c27,c28,c29,c2a,c2b,c2c,c2d,c2e,c2f,c2g,c2h,c2i,c2j,c2k,", "c2l,c2m,c2n,c2o,c2p,c2q,c2r,c2s,c2t,c2u,c2v,c30,c31,c32,c33,c34,c35,c36,c37,c38,", "c39,c3a,c3b,c3c,c3d,c3e,c3f,c3g,c3h,c3i,c3j,c3k,c3l,c3m,c3n,c3o,c3p,c3q,c3r,c3s,", "c3t,c3u,c3v,c40,c41,c42,c43,c44,c45,c46,c47,c48,c49,c4a,c4b,c4c,c4d,c4e,c4f,c4g,", "c4h,c4i,c4j,c4k,c4l,c4m,c4p,c4q,c4r,c4s,c4t,c4u,c4v,c50,c51,c52,c53,c54,c55,c56,", "c57,c58,c59,c5a,c5b,c5c,c5d,c5e,c5f,c5g,c5h,c5i,c5j,c5k,c5l,c5m,c5n,c5o,c5p,c5q,", "c5r,c5s,c5t,c5u,c5v,c60,c61,c62,c63,c64,c65,c66,c67,c68,c69,c6a,c6b,c6c,c6d,c6e,", "c6f,c6g,c6h,c6i,c6j,c6k,c6l,c6m,c6n,c6o,c6p,c6q,c6r,c6s,c6t,c6u,c6v,c70,c71,c72,", "c73,c74,c75,c76,c77,c78,c79,c7a,c7b,c7c,c7d,c7e,c7f,c7g,c7h,c7i,c7j,c7k,c7l,c7m,", "c7n,c7o,c7p,c7q,c7r,c7s,c7t,c7u,c7v,c85,c86,c87,c88,c89,c8a,c8b,c8c,c8d,c8e,c8f,", "c8g,c8h,c8i,c8j,c8k,c8l,c8m,c8n,c8o,c8p,c8q,c8r,c8s,c8t,c8u,c8v,c90,c91,c92,c93,", "c94,c95,c96,c97,c98,c99,c9a,c9b,c9c,c9h,c9i,c9j,c9k,c9l,c9m,c9n,c9o,c9p,c9q,c9r,", "c9s,c9t,c9u,c9v,ca0,ca1,ca2,ca3,ca4,ca5,ca6,ca7,ca8,ca9,caa,cab,cac,cad,cae,caf,", "cag,cah,cai,caj,cak,cal,cam,can,cao,cap,caq,car,cas,cat,cau,cav,cb0,cb1,cb2,cb3,", "cb4,cb5,cb6,cb7,cb8,cb9,cba,cbb,cbc,cbd,cbe,cbf,cbg,cbh,cbi,cbj,cbk,cbl,cbm,cbn,", "cbo,cbp,cbq,cbr,cbs,cbt,cbu,cbv,cc0,cc1,cc2,cc3,cc4,cc5,cc6,cc7,cc8,cc9,cca,ccb,", "ccc,ccd,cce,ccg,cch,cci,ccj,cck,ccl,ccm,ccn,cco,ccp,ccq,ccr,ccs,cct,ccu,ccv,cd0,", "cd1,cd2,cd3,cd4,cd5,cd6,cd7,cd8,cd9,cda,cdb,cdc,cdd,cde,cdf,cdg,cdh,cdi,cdj,cdk,", "cdl,cdm,cdn,ce0,ce1,ce2,ce3,ce4,ce5,ce6,ce7,ce8,ce9,cea,ceb,cec,ced,cee,cef,cfg,", "cfh,cfi,cfj,cfk,cfl,cfm,cfn,cfo,cfp,cfq,cfr,cfs,cft,cfu,cfv,cg0,cg1,cg2,cg3,cg4,", "cg5,cg6,cg7,cg8,cg9,cga,cgb,cgc,cgd,cge,cgf,cgg,cgh,cgi,cgj,cgk,cgl,cgm,cgn,cgo,", "cgp,cgq,cgr,cgs,cgt,cgu,ch0,ch1,ch2,ch3,ch4,ch5,ch6,ch7,ch8,ch9,cha,chb,chc,chd,", "che,chf,chg,chh,chi,chj,chk,chl,chm,chn,cho,chp,chq,chr,chs,cht,chu,chv,ci0,ci1,", "ci2,ci3,cig,cih,cii,cij,cik,cil,cim,cin,cio,cip,ciq,cir,cis,cit,ciu,civ,cj0,cj1,", "cj2,cj3,cj4,cj5,cj6,cj7,cj8,cj9,cja,cjb,cjc,cjd,cje,cjf,cjg,cjh,cji,cjj,cjk,cjl,", "cjm,cjn,cjo,cjp,cjq,cjr,cjs,cjt,cju,cjv,ck0,ck1,ck2,ck3,ck4,ck5,ck6,ck7,ck8,ck9,", "cka,ckb,ckc,ckd,cke,ckf,ckg,ckh,cki,ckj,ckk,ckl,ckm,ckn,cko,ckp,ckq,ckr,cks,ckt,", "cku,ckv,cl0,cl1,cl2,cl3,cl4,cl5,cl6,cl7,cl8,cl9,cla,clb,clc,cld,cle,clf,clg,clh,", "cli,clj,clk,cll,clm,cln,clo,clp,clq,clr,cls,clt,clu,clv,cm0,cm1,cm2,cm3,cm4,cm5,", "cm6,cm7,cm8,cm9,cma,cmb,cmc,cmd,cme,cmf,cmg,cmh,cmi,cmj,cmk,cml,cmm,cmn,cmo,cmp,", "cmq,cmr,cms,cmt,cmu,cmv,cn0,cn1,cn2,cn3,cn4,cn5,cn6,cn7,cn8,cn9,cna,cnb,cnc,cnd,", "cne,cnf,cng,cnh,cni,cnj,cnk,cnl,cnm,cnn,cno,cnp,cnq,cnr,cns,cnt,cnu,co0,co1,co2,", "co3,co4,co5,co6,co7,co8,co9,coa,cob,coc,cod,coe,cof,cog,coh,coi,coj,cok,col,com,", "con,coo,cop,coq,cor,cos,cot,cou,cov,cp0,cp1,cp2,cp3,cp4,cp5,cp6,cp7,cp8,cp9,cpa,", "cpb,cpc,cpd,cpe,cpf,cpg,cph,cpi,cpj,cpk,cpl,cpm,cpn,cpo,cpp,cpq,cpr,cps,cpt,cpu,", "cpv,cq0,cq1,cq2,cq3,cq4,cq5,cq6,cq7,cq8,cq9,cqa,cqb,cqc,cqd,cqe,cqf,cqg,cqh,cqi,", "cqj,cqk,cql,cqm,cqn,cqo,cqp,cqq,cqr,cqs,cqt,cqu,cqv,cr0,cr1,cr2,cr3,cr4,cr5,cr6,", "cr7,cr8,cr9,cra,crb,crc,crd,cre,crf,crg,crh,cri,crj,crk,crl,crm,crn,cro,crp,crq,", "crr,crs,crt,cru,crv,cs0,cs1,cs2,cs3,cs4,cs5,cs6,cs7,cs8,cs9,csa,csb,csc,csd,cse,", "csf,csg,csh,csi,csj,csk,csl,csm,csn,cso,csp,csq,csr,css,cst,csu,csv,ct0,ct1,ct2,", "ct3,ct4,ct5,ct6,ct7,ct8,ct9,cta,ctb,ctc,ctd,cte,ctf,ctg,cth,cti,ctj,ctk,ctl,ctm,", "ctn,cto,ctp,ctq,ctr,cts,ctt,ctu,ctv,cu0,cu1,cu2,cu3,cu4,cu5,cu6,cu7,cu8,cu9,cua,", "cub,cuc,cud,cue,cuf,cug,cuh,cui,cuj,cuk,cul,cum,cun,cuo,cup,cuq,cur,cus,cut,cuu,", "cuv,cv0,cv1,cv2,cv3,cv4,cv5,cv6,cv7,cv8,cv9,cva,cvb,cvc,cvd,cve,cvf,cvg,cvh,cvi,", "cvj,cvk,cvl,cvm,cvn,cvo,cvp,cvq,cvr,cvs,cvt,cvu,cvv,d00,jdl,je0,je1,je2,je3,je4,", "je5,je6,je7,je8,je9,jea,jeb,jec,jed,jee,jef,jeg,jeh,jei,jej,jek,jel,jem,jen,jeo,", "jep,jeq,jer,jes,jet,jeu,jev,jf0,jf1,jf2,jf3,jf4,jf5,jf6,jf7,jf8,jf9,jfa,jfb,jfc,", "jfd,jfe,jff,jfg,jfh,jfi,jfj,jfk,jfl,jfm,jfn,jfo,jfp,jfq,jfr,jfs,jft,jfu,jfv,jg0,", "17tr,1800,1801,1802,1803,1804,1805,1806,1807,1808,1809,180a,180b,180c,180d,180e,180f,180g,180h,180i,", "180j,180k,180l,180m,180n,180o,180p,180q,180r,180s,180t,180u,180v,1810,1811,1812,1813,1814,1815,1816,", "1817,1818,1819,181a,181b,181c,181d,181e,181f,181g,181h,181i,181j,181k,181l,181m,181n,181o,181p,181q,", "181r,181s,181t,181u,181v,1820,1821,1822,1823,1824,1825,1826,1827,1828,1829,182a,182b,182c,182d,182e,", "182f,182g,182h,182i,182j,182k,182l,182m,182n,182o,182p,182q,182r,182s,182t,182u,182v,1830,1831,1832,", "1833,1834,1835,1836,1837,1838,1839,183a,183b,183c,183d,183e,183f,183g,183h,183i,183j,183k,183l,183m,", "183n,183o,183p,183q,183r,183s,183t,183u,183v,1840,1841,1842,1843,1844,1845,1846,1847,1848,1849,184a,", "184b,184c,184d,184e,184f,184g,184h,184i,184j,184k,184l,184m,184n,184o,184p,184q,184r,184s,184t,184u,", "184v,1850,1851,1852,1853,1854,1855,1856,1857,1858,1859,185a,185b,185c,185d,185e,185f,185g,185h,185i,", "185j,185k,185l,185m,185n,185o,185p,185q,185r,185s,185t,185u,185v,1860,1861,1862,1863,1864,1865,1866,", "1867,1868,1869,186a,186b,186c,186d,186e,186f,186g,186h,186i,186j,186k,186l,186m,186n,186o,186p,186q,", "186r,186s,186t,186u,186v,1870,1871,1872,1873,1874,1875,1876,1877,1878,1879,187a,187b,187c,187d,187e,", "187f,187g,187h,187i,187j,187k,187l,187m,187n,187o,187p,187q,187r,187s,187t,187u,187v,1880,1881,1882,", "1883,1884,1885,1886,1887,1888,1889,188a,188b,188c,188d,188e,188f,188g,188h,188i,188j,188k,188l,188m,", "188n,188o,188p,188q,188r,188s,188t,188u,188v,1890,1891,1892,1893,1894,1895,1896,1897,1898,1899,189a,", "189b,189c,189d,189e,189f,189g,189h,189i,189j,189k,189l,189m,189n,189o,189p,189q,189r,189s,189t,189u,", "189v,18a0,18a1,18a2,18a3,18a4,18a5,18a6,18a7,18a8,18a9,18aa,18ab,18ac,18ad,18ae,18af,18ag,18ah,18ai,", "18aj,18ak,18al,18am,18an,18ao,18ap,18aq,18ar,18as,18at,18au,18av,18b0,18b1,18b2,18b3,18b4,18b5,18b6,", "18b7,18b8,18b9,18ba,18bb,18bc,18bd,18be,18bf,18bg,18bh,18bi,18bj,18bk,18bl,18bm,18bn,18bo,18bp,18bq,", "18br,18bs,18bt,18bu,18bv,18c0,18c1,18c2,18c3,18c4,18c5,18c6,18c7,18c8,18c9,18ca,18cb,18cc,18cd,18ce,", "18cf,18cg,18ch,18ci,18cj,18ck,18cl,18cm,18cn,18co,18cp,18cq,18cr,18cs,18ct,18cu,18cv,18d0,18d1,18d2,", "18d3,18d4,18d5,18d6,18d7,18d8,18d9,18da,18db,18dc,18dd,18de,18df,18dg,18dh,18di,18dj,18dk,18dl,18dm,", "18dn,18do,18dp,18dq,18dr,18ds,18dt,18du,18dv,18e0,18e1,18e2,18e3,18e4,18e5,18e6,18e7,18e8,18e9,18ea,", "18eb,18ec,18ed,18ee,18ef,18eg,18eh,18ei,18ej,18ek,18el,18em,18en,18eo,18ep,18eq,18er,18es,18et,18eu,", "18ev,18f0,18f1,18f2,18f3,18f4,18f5,18f6,18f7,18f8,18f9,18fa,18fb,18fc,18fd,18fe,18ff,18fg,18fh,18fi,", "18fj,18fk,18fl,18fm,18fn,18fo,18fp,18fq,18fr,18fs,18ft,18fu,18fv,18g0,18g1,18g2,18g3,18g4,18g5,18g6,", "18g7,18g8,18g9,18ga,18gb,18gc,18gd,18ge,18gf,18gg,18gh,18gi,18gj,18gk,18gl,18gm,18gn,18go,18gp,18gq,", "18gr,18gs,18gt,18gu,18gv,18h0,18h1,18h2,18h3,18h4,18h5,18h6,18h7,18h8,18h9,18ha,18hb,18hc,18hd,18he,", "18hf,18hg,18hh,18hi,18hj,18hk,18hl,18hm,18hn,18ho,18hp,18hq,18hr,18hs,18ht,18hu,18hv,18i0,18i1,18i2,", "18i3,18i4,18i5,18i6,18i7,18i8,18i9,18ia,18ib,18ic,18id,18ie,18if,18ig,18ih,18ii,18ij,18ik,18il,18im,", "18in,18io,18ip,18iq,18ir,18is,18it,18iu,18iv,18j0,18j1,18j2,18j3,18j4,18j5,18j6,18j7,18j8,18j9,18ja,", "18jb,18jc,18jd,18je,18jf,18jg,18jh,18ji,18jj,18jk,18jl,18jm,18jn,18jo,18jp,18jq,18jr,18js,18jt,18ju,", "18jv,18k0,18k1,18k2,18k3,18k4,18k5,18k6,18k7,18k8,18k9,18ka,18kb,18kc,18kd,18ke,18kf,18kg,18kh,18ki,", "18kj,18kk,18kl,18km,18kn,18ko,18kp,18kq,18kr,18ks,18kt,18ku,18kv,18l0,18l1,18l2,18l3,18l4,18l5,18l6,", "18l7,18l8,18l9,18la,18lb,18lc,18ld,18le,18lf,18lg,18lh,18li,18lj,18lk,18ll,18lm,18ln,18lo,18lp,18lq,", "18lr,18ls,18lt,18lu,18lv,18m0,18m1,18m2,18m3,18m4,18m5,18m6,18m7,18m8,18m9,18ma,18mb,18mc,18md,18me,", "18mf,18mg,18mh,18mi,18mj,18mk,18ml,18mm,18mn,18mo,18mp,18mq,18mr,18ms,18mt,18mu,18mv,18n0,18n1,18n2,", "18n3,18n4,18n5,18n6,18n7,18n8,18n9,18na,18nb,18nc,18nd,18ne,18nf,18ng,18nh,18ni,18nj,18nk,18nl,18nm,", "18nn,18no,18np,18nq,18nr,18ns,18nt,18nu,18nv,18o0,18o1,18o2,18o3,18o4,18o5,18o6,18o7,18o8,18o9,18oa,", "18ob,18oc,18od,18oe,18of,18og,18oh,18oi,18oj,18ok,18ol,18om,18on,18oo,18op,18oq,18or,18os,18ot,18ou,", "18ov,18p0,18p1,18p2,18p3,18p4,18p5,18p6,18p7,18p8,18p9,18pa,18pb,18pc,18pd,18pe,18pf,18pg,18ph,18pi,", "18pj,18pk,18pl,18pm,18pn,18po,18pp,18pq,18pr,18ps,18pt,18pu,18pv,18q0,18q1,18q2,18q3,18q4,18q5,18q6,", "18q7,18q8,18q9,18qa,18qb,18qc,18qd,18qe,18qf,18qg,18qh,18qi,18qj,18qk,18ql,18qm,18qn,18qo,18qp,18qq,", "18qr,18qs,18qt,18qu,18qv,18r0,18r1,18r2,18r3,18r4,18r5,18r6,18r7,18r8,18r9,18ra,18rb,18rc,18rd,18re,", "18rf,18rg,18rh,18ri,18rj,18rk,18rl,18rm,18rn,18ro,18rp,18rq,18rr,18rs,18rt,18ru,18rv,18s0,18s1,18s2,", "18s3,18s4,18s5,18s6,18s7,18s8,18s9,18sa,18sb,18sc,18sd,18se,18sf,18sg,18sh,18si,18sj,18sk,18sl,18sm,", "18sn,18so,18sp,18sq,18sr,18ss,18st,18su,18sv,18t0,18t1,18t2,18t3,18t4,18t5,18t6,18t7,18t8,18t9,18ta,", "18tb,18tc,18td,18te,18tf,18tg,18th,18ti,18tj,18tk,18tl,18tm,18tn,18to,18tp,18tq,18tr,18ts,18tt,18tu,", "18tv,18u0,18u1,18u2,18u3,18u4,18u5,18u6,18u7,18u8,18u9,18ua,18ub,18uc,18ud,18ue,18uf,18ug,18uh,18ui,", "18uj,18uk,18ul,18um,18un,18uo,18up,18uq,18ur,18us,18ut,18uu,18uv,18v0,18v1,18v2,18v3,18v4,18v5,18v6,", "18v7,18v8,18v9,18va,18vb,18vc,18vd,18ve,18vf,18vg,18vh,18vi,18vj,18vk,18vl,18vm,18vn,18vo,18vp,18vq,", "18vr,18vs,18vt,18vu,18vv,1900,1901,1902,1903,1904,1905,1906,1907,1908,1909,190a,190b,190c,190d,190e,", "190f,190g,190h,190i,190j,190k,190l,190m,190n,190o,190p,190q,190r,190s,190t,190u,190v,1910,1911,1912,", "1913,1914,1915,1916,1917,1918,1919,191a,191b,191c,191d,191e,191f,191g,191h,191i,191j,191k,191l,191m,", "191n,191o,191p,191q,191r,191s,191t,191u,191v,1920,1921,1922,1923,1924,1925,1926,1927,1928,1929,192a,", "192b,192c,192d,192e,192f,192g,192h,192i,192j,192k,192l,192m,192n,192o,192p,192q,192r,192s,192t,192u,", "192v,1930,1931,1932,1933,1934,1935,1936,1937,1938,1939,193a,193b,193c,193d,193e,193f,193g,193h,193i,", "193j,193k,193l,193m,193n,193o,193p,193q,193r,193s,193t,193u,193v,1940,1941,1942,1943,1944,1945,1946,", "1947,1948,1949,194a,194b,194c,194g,194h,194i,194j,194k,194l,194m,194n,194o,194p,194q,194r,194s,194t,", "194u,194v,1950,1951,1952,1953,1954,1955,1956,1957,1958,1959,195a,195b,195c,195d,195e,195f,195g,195h,", "195i,195j,195k,195l,195m,195n,195o,195p,195q,195r,195s,195t,195u,195v,1960,1961,1962,1963,1964,1965,", "1966,19o0,19o1,19o2,19o3,19o4,19o5,19o6,19o7,19o8,19o9,19oa,19ob,19oc,19od,19oe,19of,19og,19oh,19oi,", "19oj,19ok,19ol,19om,1a00,1a01,1a02,1a03,1a04,1a05,1a06,1a07,1a08,1a09,1a0a,1a0b,1a0c,1a0d,1a0e,1a0f,", "1a0g,1a0h,1a0i,1a0j,1a0k,1a0l,1a0m,1a0n,1a0o,1a0p,1a0q,1a0r,1a0s,1a0t,1a0u,1a0v,1a10,1a11,1a12,1a13,", "1a14,1a15,1a16,1a17,1a18,1a19,1a1a,1a1b,1b00,1lt3,1m00,1mrv,1ms0,1mvv,1n00,1nvv,1o00,1u7v,1u80,1u81,", "1u82,1u83,1u84,1u85,1u86,1u87,1u88,1u89,1u8a,1u8b,1u8c,1u8d,1u8e,1u8f,1u8g,1u8h,1u8i,1u8j,1u8k,1u8l,", "1u8m,1u8n,1u8o,1u8p,1u8q,1u8r,1u8s,1u8t,1u8u,1u8v,1u90,1u91,1u92,1u93,1u94,1u95,1u96,1u97,1u98,1u99,", "1u9a,1u9b,1u9c,1u9d,1u9e,1u9f,1u9g,1u9h,1u9i,1u9j,1u9k,1u9l,1u9m,1u9n,1u9o,1u9p,1u9q,1u9r,1u9s,1u9t,", "1u9u,1u9v,1ua0,1ua1,1ua2,1ua3,1ua4,1ua5,1ua6,1ua7,1ua8,1ua9,1uaa,1uab,1uac,1uad,1uae,1uaf,1uag,1uah,", "1uai,1uaj,1uak,1ual,1uam,1uan,1uao,1uap,1uaq,1uar,1uas,1uat,1uau,1uav,1ub0,1ub1,1ub2,1ub3,1ub4,1ub5,", "1ub6,1ub7,1ub8,1ub9,1uba,1ubb,1ubc,1ubd,1ube,1ubf,1ubg,1ubh,1ubi,1ubj,1ubk,1ubl,1ubm,1ubn,1ubo,1ubp,", "1ubq,1ubr,1ubs,1ubt,1ubu,1ubv,1uc0,1uc1,1uc2,1uc3,1uc4,1uc5,1uc6,1uc7,1uc8,1uc9,1uca,1ucb,1ucc,1ucd,", "1uce,1ucf,1ucg,1uch,1uci,1ucj,1uck,1ucl,1ucm,1ucn,1uco,1ucp,1ucq,1ucr,1ucs,1uct,1ucu,1ucv,1ud0,1ud1,", "1ud2,1ud3,1ud4,1ud5,1ud6,1ud7,1ud8,1ud9,1uda,1udb,1udc,1udd,1ude,1udf,1udg,1udh,1udi,1udj,1udk,1udl,", "1udm,1udn,1udo,1udp,1udq,1udr,1uds,1udt,1udu,1udv,1ue0,1ue1,1ue2,1ue3,1ue4,1ue5,1ue6,1ue7,1ue8,1ue9,", "1uea,1ueb,1uec,1ued,1uee,1uef,1ueg,1ueh,1uei,1uej,1uek,1uel,1uem,1uen,1ueo,1uep,1ueq,1uer,1ues,1uet,", "1ueu,1uev,1uf0,1uf1,1uf2,1uf3,1uf4,1uf5,1uf6,1uf7,1uf8,1uf9,1ufa,1ufb,1ufc,1ufd,1ufe,1uff,1ufg,1ufh,", "1ufi,1ufj,1ufk,1ufl,1ufm,1ufn,1ufo,1ufp,1ufq,1ufr,1ufs,1uft,1ufu,1ufv,1ug0,1ug1,1ug2,1ug3,1ug4,1ug5,", "1ug6,1ug7,1ug8,1ug9,1uga,1ugb,1ugc,1ugd,1uge,1ugf,1ugg,1ugh,1ugi,1ugj,1ugk,1ugl,1ugm,1ugn,1ugo,1ugp,", "1ugq,1ugr,1ugs,1ugt,1ugu,1ugv,1uh0,1uh1,1uh2,1uh3,1uh4,1uh5,1uh6,1uh7,1uh8,1uh9,1uha,1uhb,1uhc,1uhd,", "1uhg,1uhh,1uhi,1uhj,1uhk,1uhl,1uhm,1uhn,1uho,1uhp,1uhq,1uhr,1uhs,1uht,1uhu,1uhv,1ui0,1ui1,1ui2,1ui3,", "1ui4,1ui5,1ui6,1ui7,1ui8,1ui9,1uia,1uib,1uic,1uid,1uie,1uif,1uig,1uih,1uii,1uij,1uik,1uil,1uim,1uin,", "1uio,1uip,1uiq,1uir,1uis,1uit,1uiu,1uiv,1uj0,1uj1,1uj2,1uj3,1uj4,1uj5,1uj6,1uj7,1uj8,1uj9,1uja,1ujg,", "1ujh,1uji,1ujj,1ujk,1ujl,1ujm,1ujn,1ujo,1ujp,1ujq,1ujr,1ujs,1ujt,1uju,1ujv,1uk0,1uk1,1uk2,1uk3,1uk4,", "1uk5,1uk6,1uk7,1uk8,1uk9,1uka,1ukb,1ukc,1ukd,1uke,1ukf,1ukg,1ukh,1uki,1ukj,1ukk,1ukl,1ukm,1ukn,1uko,", "1ukp,1ukq,1ukr,1uks,1ukt,1uku,1ukv,1ul0,1ul1,1ul2,1ul3,1ul4,1ul5,1ul6,1ul7,1ul8,1ul9,1ula,1ulb,1ulc,", "1uld,1ule,1ulf,1ulg,1ulh,1uli,1ulj,1ulk,1ull,1ulm,1uln,1ulo,1ulp,1ulq,1ulr,1uls,1ult,1ulu,1ulv,1um0,", "1um1,1um2,1um3,1um4,1um5,1um6,1um7,1um8,1um9,1uma,1umb,1umc,1umd,1ume,1umf,1umg,1umh,1umi,1umj,1umk,", "1uml,1umm,1umn,1umo,1ump,1uo0,1uo1,1uo2,1uo3,1uo4,1uo5,1uo6,1uoj,1uok,1uol,1uom,1uon,1uot,1uou,1uov,", "1up0,1up1,1up2,1up3,1up4,1up5,1up6,1up7,1up8,1up9,1upa,1upb,1upc,1upd,1upe,1upf,1upg,1uph,1upi,1upj,", "1upk,1upl,1upm,1upo,1upp,1upq,1upr,1ups,1upu,1uq0,1uq1,1uq3,1uq4,1uq6,1uq7,1uq8,1uq9,1uqa,1uqb,1uqc,", "1uqd,1uqe,1uqf,1uqg,1uqh,1uqi,1uqj,1uqk,1uql,1uqm,1uqn,1uqo,1uqp,1uqq,1uqr,1uqs,1uqt,1uqu,1uqv,1ur0,", "1ur1,1ur2,1ur3,1ur4,1ur5,1ur6,1ur7,1ur8,1ur9,1ura,1urb,1urc,1urd,1ure,1urf,1urg,1urh,1uri,1urj,1urk,", "1url,1urm,1urn,1uro,1urp,1urq,1urr,1urs,1urt,1uru,1urv,1us0,1us1,1us2,1us3,1us4,1us5,1us6,1us7,1us8,", "1us9,1usa,1usb,1usc,1usd,1use,1usf,1usg,1ush,1usi,1usj,1usk,1usl,1usm,1usn,1uso,1usp,1usq,1usr,1uss,", "1ust,1usu,1usv,1ut0,1ut1,1ut2,1ut3,1ut4,1ut5,1ut6,1ut7,1ut8,1ut9,1uta,1utb,1utc,1utd,1ute,1utf,1utg,", "1uth,1uuj,1uuk,1uul,1uum,1uun,1uuo,1uup,1uuq,1uur,1uus,1uut,1uuu,1uuv,1uv0,1uv1,1uv2,1uv3,1uv4,1uv5,", "1uv6,1uv7,1uv8,1uv9,1uva,1uvb,1uvc,1uvd,1uve,1uvf,1uvg,1uvh,1uvi,1uvj,1uvk,1uvl,1uvm,1uvn,1uvo,1uvp,", "1uvq,1uvr,1uvs,1uvt,1uvu,1uvv,1v00,1v01,1v02,1v03,1v04,1v05,1v06,1v07,1v08,1v09,1v0a,1v0b,1v0c,1v0d,", "1v0e,1v0f,1v0g,1v0h,1v0i,1v0j,1v0k,1v0l,1v0m,1v0n,1v0o,1v0p,1v0q,1v0r,1v0s,1v0t,1v0u,1v0v,1v10,1v11,", "1v12,1v13,1v14,1v15,1v16,1v17,1v18,1v19,1v1a,1v1b,1v1c,1v1d,1v1e,1v1f,1v1g,1v1h,1v1i,1v1j,1v1k,1v1l,", "1v1m,1v1n,1v1o,1v1p,1v1q,1v1r,1v1s,1v1t,1v1u,1v1v,1v20,1v21,1v22,1v23,1v24,1v25,1v26,1v27,1v28,1v29,", "1v2a,1v2b,1v2c,1v2d,1v2e,1v2f,1v2g,1v2h,1v2i,1v2j,1v2k,1v2l,1v2m,1v2n,1v2o,1v2p,1v2q,1v2r,1v2s,1v2t,", "1v2u,1v2v,1v30,1v31,1v32,1v33,1v34,1v35,1v36,1v37,1v38,1v39,1v3a,1v3b,1v3c,1v3d,1v3e,1v3f,1v3g,1v3h,", "1v3i,1v3j,1v3k,1v3l,1v3m,1v3n,1v3o,1v3p,1v3q,1v3r,1v3s,1v3t,1v3u,1v3v,1v40,1v41,1v42,1v43,1v44,1v45,", "1v46,1v47,1v48,1v49,1v4a,1v4b,1v4c,1v4d,1v4e,1v4f,1v4g,1v4h,1v4i,1v4j,1v4k,1v4l,1v4m,1v4n,1v4o,1v4p,", "1v4q,1v4r,1v4s,1v4t,1v4u,1v4v,1v50,1v51,1v52,1v53,1v54,1v55,1v56,1v57,1v58,1v59,1v5a,1v5b,1v5c,1v5d,", "1v5e,1v5f,1v5g,1v5h,1v5i,1v5j,1v5k,1v5l,1v5m,1v5n,1v5o,1v5p,1v5q,1v5r,1v5s,1v5t,1v5u,1v5v,1v60,1v61,", "1v62,1v63,1v64,1v65,1v66,1v67,1v68,1v69,1v6a,1v6b,1v6c,1v6d,1v6e,1v6f,1v6g,1v6h,1v6i,1v6j,1v6k,1v6l,", "1v6m,1v6n,1v6o,1v6p,1v6q,1v6r,1v6s,1v6t,1v6u,1v6v,1v70,1v71,1v72,1v73,1v74,1v75,1v76,1v77,1v78,1v79,", "1v7a,1v7b,1v7c,1v7d,1v7e,1v7f,1v7g,1v7h,1v7i,1v7j,1v7k,1v7l,1v7m,1v7n,1v7o,1v7p,1v7q,1v7r,1v7s,1v7t,", "1v7u,1v7v,1v80,1v81,1v82,1v83,1v84,1v85,1v86,1v87,1v88,1v89,1v8a,1v8b,1v8c,1v8d,1v8e,1v8f,1v8g,1v8h,", "1v8i,1v8j,1v8k,1v8l,1v8m,1v8n,1v8o,1v8p,1v8q,1v8r,1v8s,1v8t,1v8u,1v8v,1v90,1v91,1v92,1v93,1v94,1v95,", "1v96,1v97,1v98,1v99,1v9a,1v9b,1v9c,1v9d,1v9e,1v9f,1v9g,1v9h,1v9i,1v9j,1v9k,1v9l,1v9m,1v9n,1v9o,1v9p,", "1v9q,1v9r,1v9s,1v9t,1v9u,1v9v,1vag,1vah,1vai,1vaj,1vak,1val,1vam,1van,1vao,1vap,1vaq,1var,1vas,1vat,", "1vau,1vav,1vb0,1vb1,1vb2,1vb3,1vb4,1vb5,1vb6,1vb7,1vb8,1vb9,1vba,1vbb,1vbc,1vbd,1vbe,1vbf,1vbg,1vbh,", "1vbi,1vbj,1vbk,1vbl,1vbm,1vbn,1vbo,1vbp,1vbq,1vbr,1vbs,1vbt,1vbu,1vbv,1vc0,1vc1,1vc2,1vc3,1vc4,1vc5,", "1vc6,1vc7,1vc8,1vc9,1vca,1vcb,1vcc,1vcd,1vce,1vcf,1vci,1vcj,1vck,1vcl,1vcm,1vcn,1vco,1vcp,1vcq,1vcr,", "1vcs,1vct,1vcu,1vcv,1vd0,1vd1,1vd2,1vd3,1vd4,1vd5,1vd6,1vd7,1vd8,1vd9,1vda,1vdb,1vdc,1vdd,1vde,1vdf,", "1vdg,1vdh,1vdi,1vdj,1vdk,1vdl,1vdm,1vdn,1vdo,1vdp,1vdq,1vdr,1vds,1vdt,1vdu,1vdv,1ve0,1ve1,1ve2,1ve3,", "1ve4,1ve5,1ve6,1ve7,1vfg,1vfh,1vfi,1vfj,1vfk,1vfl,1vfm,1vfn,1vfo,1vfp,1vfq,1vfr,1vfs,1vft,1vg0,1vg1,", "1vg2,1vg3,1vg4,1vg5,1vg6,1vg7,1vg8,1vg9,1vga,1vgb,1vgc,1vgd,1vge,1vgf,1vgg,1vgh,1vgi,1vgj,1vgk,1vgl,", "1vgm,1vgn,1vgo,1vgp,1vh0,1vh1,1vh2,1vh3,1vhg,1vhh,1vhi,1vhj,1vhk,1vhl,1vhm,1vhn,1vho,1vhp,1vhq,1vhr,", "1vhs,1vht,1vhu,1vhv,1vi0,1vi1,1vi2,1vi3,1vi4,1vi5,1vi6,1vi7,1vi8,1vi9,1via,1vib,1vic,1vid,1vie,1vif,", "1vig,1vih,1vii,1vik,1vil,1vim,1vin,1vio,1vip,1viq,1vir,1vis,1vit,1viu,1viv,1vj0,1vj1,1vj2,1vj3,1vj4,", "1vj5,1vj6,1vj8,1vj9,1vja,1vjb,1vjg,1vjh,1vji,1vjj,1vjk,1vjm,1vjn,1vjo,1vjp,1vjq,1vjr,1vjs,1vjt,1vju,", "1vjv,1vk0,1vk1,1vk2,1vk3,1vk4,1vk5,1vk6,1vk7,1vk8,1vk9,1vka,1vkb,1vkc,1vkd,1vke,1vkf,1vkg,1vkh,1vki,", "1vkj,1vkk,1vkl,1vkm,1vkn,1vko,1vkp,1vkq,1vkr,1vks,1vkt,1vku,1vkv,1vl0,1vl1,1vl2,1vl3,1vl4,1vl5,1vl6,", "1vl7,1vl8,1vl9,1vla,1vlb,1vlc,1vld,1vle,1vlf,1vlg,1vlh,1vli,1vlj,1vlk,1vll,1vlm,1vln,1vlo,1vlp,1vlq,", "1vlr,1vls,1vlt,1vlu,1vlv,1vm0,1vm1,1vm2,1vm3,1vm4,1vm5,1vm6,1vm7,1vm8,1vm9,1vma,1vmb,1vmc,1vmd,1vme,", "1vmf,1vmg,1vmh,1vmi,1vmj,1vmk,1vml,1vmm,1vmn,1vmo,1vmp,1vmq,1vmr,1vms,1vmt,1vmu,1vmv,1vn0,1vn1,1vn2,", "1vn3,1vn4,1vn5,1vn6,1vn7,1vn8,1vn9,1vna,1vnb,1vnc,1vnd,1vne,1vnf,1vng,1vnh,1vni,1vnj,1vnk,1vnl,1vnm,", "1vnn,1vno,1vnp,1vnq,1vnr,1vns,1vnv,1vo1,1vo2,1vo3,1vo4,1vo5,1vo6,1vo7,1vo8,1vo9,1voa,1vob,1voc,1vod,", "1voe,1vof,1vog,1voh,1voi,1voj,1vok,1vol,1vom,1von,1voo,1vop,1voq,1vor,1vos,1vot,1vou,1vov,1vp0,1vp1,", "1vp2,1vp3,1vp4,1vp5,1vp6,1vp7,1vp8,1vp9,1vpa,1vpb,1vpc,1vpd,1vpe,1vpf,1vpg,1vph,1vpi,1vpj,1vpk,1vpl,", "1vpm,1vpn,1vpo,1vpp,1vpq,1vpr,1vps,1vpt,1vpu,1vpv,1vq0,1vq1,1vq2,1vq3,1vq4,1vq5,1vq6,1vq7,1vq8,1vq9,", "1vqa,1vqb,1vqc,1vqd,1vqe,1vqf,1vqg,1vqh,1vqi,1vqj,1vqk,1vql,1vqm,1vqn,1vqo,1vqp,1vqq,1vqr,1vqs,1vqt,", "1vqu,1vqv,1vr0,1vr1,1vr2,1vr3,1vr4,1vr5,1vr6,1vr7,1vr8,1vr9,1vra,1vrb,1vrc,1vrd,1vre,1vrf,1vrg,1vrh,", "1vri,1vrj,1vrk,1vrl,1vrm,1vrn,1vro,1vrp,1vrq,1vrr,1vrs,1vrt,1vru,1vrv,1vs0,1vs1,1vs2,1vs3,1vs4,1vs5,", "1vs6,1vs7,1vs8,1vs9,1vsa,1vsb,1vsc,1vsd,1vse,1vsf,1vsg,1vsh,1vsi,1vsj,1vsk,1vsl,1vsm,1vsn,1vso,1vsp,", "1vsq,1vsr,1vss,1vst,1vsu,1vsv,1vt0,1vt1,1vt2,1vt3,1vt4,1vt5,1vt6,1vt7,1vt8,1vt9,1vta,1vtb,1vtc,1vtd,", "1vte,1vtf,1vtg,1vth,1vti,1vtj,1vtk,1vtl,1vtm,1vtn,1vto,1vtp,1vtq,1vtr,1vts,1vtt,1vtu,1vu2,1vu3,1vu4,", "1vu5,1vu6,1vu7,1vua,1vub,1vuc,1vud,1vue,1vuf,1vui,1vuj,1vuk,1vul,1vum,1vun,1vuq,1vur,1vus,1vv0,1vv1,", "1vv2,1vv3,1vv4,1vv5,1vv6,1vv8,1vv9,1vva,1vvb,1vvc,1vvd,1vve,1vvp,1vvq,1vvr,1vvs,1vvt,2000,2001,2002,", "2003,2004,2005,2006,2007,2008,2009,200a,200b,200d,200e,200f,200g,200h,200i,200j,200k,200l,200m,200n,", "200o,200p,200q,200r,200s,200t,200u,200v,2010,2011,2012,2013,2014,2015,2016,2018,2019,201a,201b,201c,", "201d,201e,201f,201g,201h,201i,201j,201k,201l,201m,201n,201o,201p,201q,201s,201t,201v,2020,2021,2022,", "2023,2024,2025,2026,2027,2028,2029,202a,202b,202c,202d,202g,202h,202i,202j,202k,202l,202m,202n,202o,", "202p,202q,202r,202s,202t,2040,2041,2042,2043,2044,2045,2046,2047,2048,2049,204a,204b,204c,204d,204e,", "204f,204g,204h,204i,204j,204k,204l,204m,204n,204o,204p,204q,204r,204s,204t,204u,204v,2050,2051,2052,", "2053,2054,2055,2056,2057,2058,2059,205a,205b,205c,205d,205e,205f,205g,205h,205i,205j,205k,205l,205m,", "205n,205o,205p,205q,205r,205s,205t,205u,205v,2060,2061,2062,2063,2064,2065,2066,2067,2068,2069,206a,", "206b,206c,206d,206e,206f,206g,206h,206i,206j,206k,206l,206m,206n,206o,206p,206q,206r,206s,206t,206u,", "206v,2070,2071,2072,2073,2074,2075,2076,2077,2078,2079,207a,207b,207c,207d,207e,207f,207g,207h,207i,", "207j,207k,207l,207m,207n,207o,207p,207q,2080,2081,2082,2087,2088,2089,208a,208b,208c,208d,208e,208f,", "208g,208h,208i,208j,208k,208l,208m,208n,208o,208p,208q,208r,208s,208t,208u,208v,2090,2091,2092,2093,", "2094,2095,2096,2097,2098,2099,209a,209b,209c,209d,209e,209f,209g,209h,209i,209j,209n,209o,209p,209q,", "209r,209s,209t,209u,209v,20a0,20a1,20a2,20a3,20a4,20a5,20a6,20a7,20a8,20a9,20aa,20ab,20ac,20ad,20ae,", "20af,20ag,20ah,20ai,20aj,20ak,20al,20am,20an,20ao,20ap,20aq,20ar,20as,20at,20au,20av,20b0,20b1,20b2,", "20b3,20b4,20b5,20b6,20b7,20b8,20b9,20ba,20bb,20bc,20bd,20be,20bf,20bg,20bh,20bi,20bj,20bk,20bl,20bm,", "20bn,20bo,20bp,20bq,20br,20bs,20bt,20bu,20bv,20c0,20c1,20c2,20c3,20c4,20c5,20c6,20c7,20c8,20c9,20ca,", "20o0,20o1,20o2,20o3,20o4,20o5,20o6,20o7,20o8,20o9,20oa,20ob,20oc,20od,20oe,20of,20og,20oh,20oi,20oj,", "20ok,20ol,20om,20on,20oo,20op,20oq,20or,20os,20ot,20ou,20p0,20p1,20p2,20p3,20pg,20ph,20pi,20pj,20pk,", "20pl,20pm,20pn,20po,20pp,20pq,20pr,20ps,20pt,20pu,20pv,20q0,20q1,20q2,20q3,20q4,20q5,20q6,20q7,20q8,", "20q9,20qa,20s0,20s1,20s2,20s3,20s4,20s5,20s6,20s7,20s8,20s9,20sa,20sb,20sc,20sd,20se,20sf,20sg,20sh,", "20si,20sj,20sk,20sl,20sm,20sn,20so,20sp,20sq,20sr,20ss,20st,20sv,20t0,20t1,20t2,20t3,20t4,20t5,20t6,", "20t7,20t8,20t9,20ta,20tb,20tc,20td,20te,20tf,20tg,20th,20ti,20tj,20tk,20tl,20tm,20tn,20to,20tp,20tq,", "20tr,20ts,20tt,20tu,20tv,20u0,20u1,20u2,20u3,20u8,20u9,20ua,20ub,20uc,20ud,20ue,20uf,20ug,20uh,20ui,", "20uj,20uk,20ul,2100,2101,2102,2103,2104,2105,2106,2107,2108,2109,210a,210b,210c,210d,210e,210f,210g,", "210h,210i,210j,210k,210l,210m,210n,210o,210p,210q,210r,210s,210t,210u,210v,2110,2111,2112,2113,2114,", "2115,2116,2117,2118,2119,211a,211b,211c,211d,211e,211f,211g,211h,211i,211j,211k,211l,211m,211n,211o,", "211p,211q,211r,211s,211t,211u,211v,2120,2121,2122,2123,2124,2125,2126,2127,2128,2129,212a,212b,212c,", "212d,212e,212f,212g,212h,212i,212j,212k,212l,212m,212n,212o,212p,212q,212r,212s,212t,212u,212v,2130,", "2131,2132,2133,2134,2135,2136,2137,2138,2139,213a,213b,213c,213d,213e,213f,213g,213h,213i,213j,213k,", "213l,213m,213n,213o,213p,213q,213r,213s,213t,213u,213v,2140,2141,2142,2143,2144,2145,2146,2147,2148,", "2149,214a,214b,214c,214d,214e,214f,214g,214h,214i,214j,214k,214l,214m,214n,214o,214p,214q,214r,214s,", "214t,2150,2151,2152,2153,2154,2155,2156,2157,2158,2159,2200,2201,2202,2203,2204,2205,2208,220a,220b,", "220c,220d,220e,220f,220g,220h,220i,220j,220k,220l,220m,220n,220o,220p,220q,220r,220s,220t,220u,220v,", "2210,2211,2212,2213,2214,2215,2216,2217,2218,2219,221a,221b,221c,221d,221e,221f,221g,221h,221i,221j,", "221k,221l,221n,221o,221s,221v,22g0,22g1,22g2,22g3,22g5,22g6,22gc,22gd,22ge,22gf,22gg,22gh,22gi,22gj,", "22gl,22gm,22gn,22gp,22gq,22gr,22gs,22gt,22gu,22gv,22h0,22h1,22h2,22h3,22h4,22h5,22h6,22h7,22h8,22h9,", "22ha,22hb,22hc,22hd,22he,22hf,22hg,22hh,22hi,22hj,22ho,22hp,22hq,22hv,22i0,22i1,22i2,22i3,22i4,22i5,", "22i6,22i7,22ig,22ih,22ii,22ij,22ik,22il,22im,22in,22io,3k00,3k01,3k02,3k03,3k04,3k05,3k06,3k07,3k08,", "3k09,3k0a,3k0b,3k0c,3k0d,3k0e,3k0f,3k0g,3k0h,3k0i,3k0j,3k0k,3k0l,3k0m,3k0n,3k0o,3k0p,3k0q,3k0r,3k0s,", "3k0t,3k0u,3k0v,3k10,3k11,3k12,3k13,3k14,3k15,3k16,3k17,3k18,3k19,3k1a,3k1b,3k1c,3k1d,3k1e,3k1f,3k1g,", "3k1h,3k1i,3k1j,3k1k,3k1l,3k1m,3k1n,3k1o,3k1p,3k1q,3k1r,3k1s,3k1t,3k1u,3k1v,3k20,3k21,3k22,3k23,3k24,", "3k25,3k26,3k27,3k28,3k29,3k2a,3k2b,3k2c,3k2d,3k2e,3k2f,3k2g,3k2h,3k2i,3k2j,3k2k,3k2l,3k2m,3k2n,3k2o,", "3k2p,3k2q,3k2r,3k2s,3k2t,3k2u,3k2v,3k30,3k31,3k32,3k33,3k34,3k35,3k36,3k37,3k38,3k39,3k3a,3k3b,3k3c,", "3k3d,3k3e,3k3f,3k3g,3k3h,3k3i,3k3j,3k3k,3k3l,3k3m,3k3n,3k3o,3k3p,3k3q,3k3r,3k3s,3k3t,3k3u,3k3v,3k40,", "3k41,3k42,3k43,3k44,3k45,3k46,3k47,3k48,3k49,3k4a,3k4b,3k4c,3k4d,3k4e,3k4f,3k4g,3k4h,3k4i,3k4j,3k4k,", "3k4l,3k4m,3k4n,3k4o,3k4p,3k4q,3k4r,3k4s,3k4t,3k4u,3k4v,3k50,3k51,3k52,3k53,3k54,3k55,3k56,3k57,3k58,", "3k59,3k5a,3k5b,3k5c,3k5d,3k5e,3k5f,3k5g,3k5h,3k5i,3k5j,3k5k,3k5l,3k5m,3k5n,3k5o,3k5p,3k5q,3k5r,3k5s,", "3k5t,3k5u,3k5v,3k60,3k61,3k62,3k63,3k64,3k65,3k66,3k67,3k68,3k69,3k6a,3k6b,3k6c,3k6d,3k6e,3k6f,3k6g,", "3k6h,3k6i,3k6j,3k6k,3k6l,3k6m,3k6n,3k6o,3k6p,3k6q,3k6r,3k6s,3k6t,3k6u,3k6v,3k70,3k71,3k72,3k73,3k74,", "3k75,3k76,3k77,3k78,3k79,3k7a,3k7b,3k7c,3k7d,3k7e,3k7f,3k7g,3k7h,3k7i,3k7j,3k7k,3k7l,3k80,3k81,3k82,", "3k83,3k84,3k85,3k86,3k87,3k88,3k89,3k8a,3k8b,3k8c,3k8d,3k8e,3k8f,3k8g,3k8h,3k8i,3k8j,3k8k,3k8l,3k8m,", "3k8n,3k8o,3k8p,3k8q,3k8r,3k8s,3k8t,3k8u,3k8v,3k90,3k91,3k92,3k93,3k94,3k95,3k96,3k9a,3k9b,3k9c,3k9d,", "3k9e,3k9f,3k9g,3k9h,3k9i,3k9j,3k9k,3k9l,3k9m,3k9n,3k9o,3k9p,3k9q,3k9r,3k9s,3k9t,3k9u,3k9v,3ka0,3ka1,", "3ka2,3ka3,3ka4,3ka5,3ka6,3ka7,3ka8,3ka9,3kaa,3kab,3kac,3kad,3kae,3kaf,3kag,3kah,3kai,3kaj,3kak,3kal,", "3kam,3kan,3kao,3kap,3kaq,3kar,3kas,3kat,3kau,3kav,3kb0,3kb1,3kb2,3kb3,3kb4,3kb5,3kb6,3kb7,3kb8,3kb9,", "3kba,3kbb,3kbc,3kbd,3kbe,3kbf,3kbg,3kbh,3kbi,3kbj,3kbk,3kbl,3kbm,3kbn,3kbo,3kbp,3kbq,3kbr,3kbs,3kbt,", "3kbu,3kbv,3kc0,3kc1,3kc2,3kc3,3kc4,3kc5,3kc6,3kc7,3kc8,3kc9,3kca,3kcb,3kcc,3kcd,3kce,3kcf,3kcg,3kch,", "3kci,3kcj,3kck,3kcl,3kcm,3kcn,3kco,3kcp,3kcq,3kcr,3kcs,3kct,3kcu,3kcv,3kd0,3kd1,3kd2,3kd3,3kd4,3kd5,", "3kd6,3kd7,3kd8,3kd9,3kda,3kdb,3kdc,3kdd,3kde,3kdf,3kdg,3kdh,3kdi,3kdj,3kdk,3kdl,3kdm,3kdn,3kdo,3kdp,", "3kdq,3kdr,3kds,3kdt,3kdu,3kdv,3ke0,3ke1,3ke2,3ke3,3ke4,3ke5,3ke6,3ke7,3ke8,3ke9,3kea,3keb,3kec,3ked,", "3kee,3kef,3keg,3keh,3kei,3kej,3kek,3kel,3kem,3ken,3keo,3kep,3keq,3ker,3kes,3ket,3kg0,3kg1,3kg2,3kg3,", "3kg4,3kg5,3kg6,3kg7,3kg8,3kg9,3kga,3kgb,3kgc,3kgd,3kge,3kgf,3kgg,3kgh,3kgi,3kgj,3kgk,3kgl,3kgm,3kgn,", "3kgo,3kgp,3kgq,3kgr,3kgs,3kgt,3kgu,3kgv,3kh0,3kh1,3kh2,3kh3,3kh4,3kh5,3kh6,3kh7,3kh8,3kh9,3kha,3khb,", "3khc,3khd,3khe,3khf,3khg,3khh,3khi,3khj,3khk,3khl,3khm,3khn,3kho,3khp,3khq,3khr,3khs,3kht,3khu,3khv,", "3ki0,3ki1,3ki2,3ki3,3ki4,3ki5,3ko0,3ko1,3ko2,3ko3,3ko4,3ko5,3ko6,3ko7,3ko8,3ko9,3koa,3kob,3koc,3kod,", "3koe,3kof,3kog,3koh,3koi,3koj,3kok,3kol,3kom,3kon,3koo,3kop,3koq,3kor,3kos,3kot,3kou,3kov,3kp0,3kp1,", "3kp2,3kp3,3kp4,3kp5,3kp6,3kp7,3kp8,3kp9,3kpa,3kpb,3kpc,3kpd,3kpe,3kpf,3kpg,3kph,3kpi,3kpj,3kpk,3kpl,", "3kpm,3kpn,3kpo,3kpp,3kpq,3kpr,3kps,3kpt,3kpu,3kpv,3kq0,3kq1,3kq2,3kq3,3kq4,3kq5,3kq6,3kq7,3kq8,3kq9,", "3kqa,3kqb,3kqc,3kqd,3kqe,3kqf,3kqg,3kqh,3kqi,3kqj,3kqk,3kql,3kqm,3l00,3l01,3l02,3l03,3l04,3l05,3l06,", "3l07,3l08,3l09,3l0a,3l0b,3l0c,3l0d,3l0e,3l0f,3l0g,3l0h,3l0i,3l0j,3l0k,3l0l,3l0m,3l0n,3l0o,3l0p,3l0q,", "3l0r,3l0s,3l0t,3l0u,3l0v,3l10,3l11,3l12,3l13,3l14,3l15,3l16,3l17,3l18,3l19,3l1a,3l1b,3l1c,3l1d,3l1e,", "3l1f,3l1g,3l1h,3l1i,3l1j,3l1k,3l1l,3l1m,3l1n,3l1o,3l1p,3l1q,3l1r,3l1s,3l1t,3l1u,3l1v,3l20,3l21,3l22,", "3l23,3l24,3l25,3l26,3l27,3l28,3l29,3l2a,3l2b,3l2c,3l2d,3l2e,3l2f,3l2g,3l2h,3l2i,3l2j,3l2k,3l2m,3l2n,", "3l2o,3l2p,3l2q,3l2r,3l2s,3l2t,3l2u,3l2v,3l30,3l31,3l32,3l33,3l34,3l35,3l36,3l37,3l38,3l39,3l3a,3l3b,", "3l3c,3l3d,3l3e,3l3f,3l3g,3l3h,3l3i,3l3j,3l3k,3l3l,3l3m,3l3n,3l3o,3l3p,3l3q,3l3r,3l3s,3l3t,3l3u,3l3v,", "3l40,3l41,3l42,3l43,3l44,3l45,3l46,3l47,3l48,3l49,3l4a,3l4b,3l4c,3l4d,3l4e,3l4f,3l4g,3l4h,3l4i,3l4j,", "3l4k,3l4l,3l4m,3l4n,3l4o,3l4p,3l4q,3l4r,3l4s,3l4u,3l4v,3l52,3l55,3l56,3l59,3l5a,3l5b,3l5c,3l5e,3l5f,", "3l5g,3l5h,3l5i,3l5j,3l5k,3l5l,3l5m,3l5n,3l5o,3l5p,3l5r,3l5t,3l5u,3l5v,3l60,3l61,3l62,3l63,3l65,3l66,", "3l67,3l68,3l69,3l6a,3l6b,3l6c,3l6d,3l6e,3l6f,3l6g,3l6h,3l6i,3l6j,3l6k,3l6l,3l6m,3l6n,3l6o,3l6p,3l6q,", "3l6r,3l6s,3l6t,3l6u,3l6v,3l70,3l71,3l72,3l73,3l74,3l75,3l76,3l77,3l78,3l79,3l7a,3l7b,3l7c,3l7d,3l7e,", "3l7f,3l7g,3l7h,3l7i,3l7j,3l7k,3l7l,3l7m,3l7n,3l7o,3l7p,3l7q,3l7r,3l7s,3l7t,3l7u,3l7v,3l80,3l81,3l82,", "3l83,3l84,3l85,3l87,3l88,3l89,3l8a,3l8d,3l8e,3l8f,3l8g,3l8h,3l8i,3l8j,3l8k,3l8m,3l8n,3l8o,3l8p,3l8q,", "3l8r,3l8s,3l8u,3l8v,3l90,3l91,3l92,3l93,3l94,3l95,3l96,3l97,3l98,3l99,3l9a,3l9b,3l9c,3l9d,3l9e,3l9f,", "3l9g,3l9h,3l9i,3l9j,3l9k,3l9l,3l9m,3l9n,3l9o,3l9p,3l9r,3l9s,3l9t,3l9u,3la0,3la1,3la2,3la3,3la4,3la6,", "3laa,3lab,3lac,3lad,3lae,3laf,3lag,3lai,3laj,3lak,3lal,3lam,3lan,3lao,3lap,3laq,3lar,3las,3lat,3lau,", "3lav,3lb0,3lb1,3lb2,3lb3,3lb4,3lb5,3lb6,3lb7,3lb8,3lb9,3lba,3lbb,3lbc,3lbd,3lbe,3lbf,3lbg,3lbh,3lbi,", "3lbj,3lbk,3lbl,3lbm,3lbn,3lbo,3lbp,3lbq,3lbr,3lbs,3lbt,3lbu,3lbv,3lc0,3lc1,3lc2,3lc3,3lc4,3lc5,3lc6,", "3lc7,3lc8,3lc9,3lca,3lcb,3lcc,3lcd,3lce,3lcf,3lcg,3lch,3lci,3lcj,3lck,3lcl,3lcm,3lcn,3lco,3lcp,3lcq,", "3lcr,3lcs,3lct,3lcu,3lcv,3ld0,3ld1,3ld2,3ld3,3ld4,3ld5,3ld6,3ld7,3ld8,3ld9,3lda,3ldb,3ldc,3ldd,3lde,", "3ldf,3ldg,3ldh,3ldi,3ldj,3ldk,3ldl,3ldm,3ldn,3ldo,3ldp,3ldq,3ldr,3lds,3ldt,3ldu,3ldv,3le0,3le1,3le2,", "3le3,3le4,3le5,3le6,3le7,3le8,3le9,3lea,3leb,3lec,3led,3lee,3lef,3leg,3leh,3lei,3lej,3lek,3lel,3lem,", "3len,3leo,3lep,3leq,3ler,3les,3let,3leu,3lev,3lf0,3lf1,3lf2,3lf3,3lf4,3lf5,3lf6,3lf7,3lf8,3lf9,3lfa,", "3lfb,3lfc,3lfd,3lfe,3lff,3lfg,3lfh,3lfi,3lfj,3lfk,3lfl,3lfm,3lfn,3lfo,3lfp,3lfq,3lfr,3lfs,3lft,3lfu,", "3lfv,3lg0,3lg1,3lg2,3lg3,3lg4,3lg5,3lg6,3lg7,3lg8,3lg9,3lga,3lgb,3lgc,3lgd,3lge,3lgf,3lgg,3lgh,3lgi,", "3lgj,3lgk,3lgl,3lgm,3lgn,3lgo,3lgp,3lgq,3lgr,3lgs,3lgt,3lgu,3lgv,3lh0,3lh1,3lh2,3lh3,3lh4,3lh5,3lh6,", "3lh7,3lh8,3lh9,3lha,3lhb,3lhc,3lhd,3lhe,3lhf,3lhg,3lhh,3lhi,3lhj,3lhk,3lhl,3lhm,3lhn,3lho,3lhp,3lhq,", "3lhr,3lhs,3lht,3lhu,3lhv,3li0,3li1,3li2,3li3,3li4,3li5,3li6,3li7,3li8,3li9,3lia,3lib,3lic,3lid,3lie,", "3lif,3lig,3lih,3lii,3lij,3lik,3lil,3lim,3lin,3lio,3lip,3liq,3lir,3lis,3lit,3liu,3liv,3lj0,3lj1,3lj2,", "3lj3,3lj4,3lj5,3lj6,3lj7,3lj8,3lj9,3lja,3ljb,3ljc,3ljd,3lje,3ljf,3ljg,3ljh,3lji,3ljj,3ljk,3ljl,3ljm,", "3ljn,3ljo,3ljp,3ljq,3ljr,3ljs,3ljt,3lju,3ljv,3lk0,3lk1,3lk2,3lk3,3lk4,3lk5,3lk6,3lk7,3lk8,3lk9,3lka,", "3lkb,3lkc,3lkd,3lke,3lkf,3lkg,3lkh,3lki,3lkj,3lkk,3lkl,3lkm,3lkn,3lko,3lkp,3lkq,3lkr,3lks,3lkt,3lku,", "3lkv,3ll0,3ll1,3ll2,3ll3,3ll4,3ll5,3ll8,3ll9,3lla,3llb,3llc,3lld,3lle,3llf,3llg,3llh,3lli,3llj,3llk,", "3lll,3llm,3lln,3llo,3llp,3llq,3llr,3lls,3llt,3llu,3llv,3lm0,3lm1,3lm2,3lm3,3lm4,3lm5,3lm6,3lm7,3lm8,", "3lm9,3lma,3lmb,3lmc,3lmd,3lme,3lmf,3lmg,3lmh,3lmi,3lmj,3lmk,3lml,3lmm,3lmn,3lmo,3lmp,3lmq,3lmr,3lms,", "3lmt,3lmu,3lmv,3ln0,3ln1,3ln2,3ln3,3ln4,3ln5,3ln6,3ln7,3ln8,3ln9,3lna,3lnb,3lnc,3lnd,3lne,3lnf,3lng,", "3lnh,3lni,3lnj,3lnk,3lnl,3lnm,3lnn,3lno,3lnp,3lnq,3lnr,3lns,3lnt,3lnu,3lnv,3lo0,3lo1,3lo2,3lo3,3lo4,", "3lo5,3lo6,3lo7,3lo8,3lo9,3loa,3lob,3loc,3lod,3loe,3lof,3log,3loh,3loi,3loj,3lok,3lol,3lom,3lon,3loo,", "3lop,3loq,3lor,3los,3lot,3lou,3lov,3lp0,3lp1,3lp2,3lp3,3lp4,3lp5,3lp6,3lp7,3lp8,3lp9,3lpa,3lpb,3lpc,", "3lpd,3lpe,3lpf,3lpg,3lph,3lpi,3lpj,3lpk,3lpl,3lpm,3lpn,3lpo,3lpp,3lpq,3lpr,3lps,3lpt,3lpu,3lpv,3lq0,", "3lq1,3lq2,3lq3,3lq4,3lq5,3lq6,3lq7,3lq8,3lq9,3lqa,3lqb,3lqc,3lqd,3lqe,3lqf,3lqg,3lqh,3lqi,3lqj,3lqk,", "3lql,3lqm,3lqn,3lqo,3lqp,3lqq,3lqr,3lqs,3lqt,3lqu,3lqv,3lr0,3lr1,3lr2,3lr3,3lr4,3lr5,3lr6,3lr7,3lr8,", "3lr9,3lra,3lrb,3lrc,3lrd,3lre,3lrf,3lrg,3lrh,3lri,3lrj,3lrk,3lrl,3lrm,3lrn,3lro,3lrp,3lrq,3lrr,3lrs,", "3lrt,3lru,3lrv,3ls0,3ls1,3ls2,3ls3,3ls4,3ls5,3ls6,3ls7,3ls8,3ls9,3lsa,3lsb,3lsc,3lsd,3lse,3lsf,3lsg,", "3lsh,3lsi,3lsj,3lsk,3lsl,3lsm,3lsn,3lso,3lsp,3lsq,3lsr,3lss,3lst,3lsu,3lsv,3lt0,3lt1,3lt2,3lt3,3lt4,", "3lt5,3lt6,3lt7,3lt8,3lt9,3lta,3ltb,3ltc,3ltd,3lte,3ltf,3ltg,3lth,3lti,3ltj,3ltk,3ltl,3ltm,3ltn,3lto,", "3ltp,3ltq,3ltr,3lts,3ltt,3ltu,3ltv,3lu0,3lu1,3lu2,3lu3,3lu4,3lu5,3lu6,3lu7,3lu8,3lu9,3lue,3luf,3lug,", "3luh,3lui,3luj,3luk,3lul,3lum,3lun,3luo,3lup,3luq,3lur,3lus,3lut,3luu,3luv,3lv0,3lv1,3lv2,3lv3,3lv4,", "3lv5,3lv6,3lv7,3lv8,3lv9,3lva,3lvb,3lvc,3lvd,3lve,3lvf,3lvg,3lvh,3lvi,3lvj,3lvk,3lvl,3lvm,3lvn,3lvo,", "3lvp,3lvq,3lvr,3lvs,3lvt,3lvu,3lvv,4000,59mm,5u00,5u01,5u02,5u03,5u04,5u05,5u06,5u07,5u08,5u09,5u0a,", "5u0b,5u0c,5u0d,5u0e,5u0f,5u0g,5u0h,5u0i,5u0j,5u0k,5u0l,5u0m,5u0n,5u0o,5u0p,5u0q,5u0r,5u0s,5u0t,5u0u,", "5u0v,5u10,5u11,5u12,5u13,5u14,5u15,5u16,5u17,5u18,5u19,5u1a,5u1b,5u1c,5u1d,5u1e,5u1f,5u1g,5u1h,5u1i,", "5u1j,5u1k,5u1l,5u1m,5u1n,5u1o,5u1p,5u1q,5u1r,5u1s,5u1t,5u1u,5u1v,5u20,5u21,5u22,5u23,5u24,5u25,5u26,", "5u27,5u28,5u29,5u2a,5u2b,5u2c,5u2d,5u2e,5u2f,5u2g,5u2h,5u2i,5u2j,5u2k,5u2l,5u2m,5u2n,5u2o,5u2p,5u2q,", "5u2r,5u2s,5u2t,5u2u,5u2v,5u30,5u31,5u32,5u33,5u34,5u35,5u36,5u37,5u38,5u39,5u3a,5u3b,5u3c,5u3d,5u3e,", "5u3f,5u3g,5u3h,5u3i,5u3j,5u3k,5u3l,5u3m,5u3n,5u3o,5u3p,5u3q,5u3r,5u3s,5u3t,5u3u,5u3v,5u40,5u41,5u42,", "5u43,5u44,5u45,5u46,5u47,5u48,5u49,5u4a,5u4b,5u4c,5u4d,5u4e,5u4f,5u4g,5u4h,5u4i,5u4j,5u4k,5u4l,5u4m,", "5u4n,5u4o,5u4p,5u4q,5u4r,5u4s,5u4t,5u4u,5u4v,5u50,5u51,5u52,5u53,5u54,5u55,5u56,5u57,5u58,5u59,5u5a,", "5u5b,5u5c,5u5d,5u5e,5u5f,5u5g,5u5h,5u5i,5u5j,5u5k,5u5l,5u5m,5u5n,5u5o,5u5p,5u5q,5u5r,5u5s,5u5t,5u5u,", "5u5v,5u60,5u61,5u62,5u63,5u64,5u65,5u66,5u67,5u68,5u69,5u6a,5u6b,5u6c,5u6d,5u6e,5u6f,5u6g,5u6h,5u6i,", "5u6j,5u6k,5u6l,5u6m,5u6n,5u6o,5u6p,5u6q,5u6r,5u6s,5u6t,5u6u,5u6v,5u70,5u71,5u72,5u73,5u74,5u75,5u76,", "5u77,5u78,5u79,5u7a,5u7b,5u7c,5u7d,5u7e,5u7f,5u7g,5u7h,5u7i,5u7j,5u7k,5u7l,5u7m,5u7n,5u7o,5u7p,5u7q,", "5u7r,5u7s,5u7t,5u7u,5u7v,5u80,5u81,5u82,5u83,5u84,5u85,5u86,5u87,5u88,5u89,5u8a,5u8b,5u8c,5u8d,5u8e,", "5u8f,5u8g,5u8h,5u8i,5u8j,5u8k,5u8l,5u8m,5u8n,5u8o,5u8p,5u8q,5u8r,5u8s,5u8t,5u8u,5u8v,5u90,5u91,5u92,", "5u93,5u94,5u95,5u96,5u97,5u98,5u99,5u9a,5u9b,5u9c,5u9d,5u9e,5u9f,5u9g,5u9h,5u9i,5u9j,5u9k,5u9l,5u9m,", "5u9n,5u9o,5u9p,5u9q,5u9r,5u9s,5u9t,5u9u,5u9v,5ua0,5ua1,5ua2,5ua3,5ua4,5ua5,5ua6,5ua7,5ua8,5ua9,5uaa,", "5uab,5uac,5uad,5uae,5uaf,5uag,5uah,5uai,5uaj,5uak,5ual,5uam,5uan,5uao,5uap,5uaq,5uar,5uas,5uat,5uau,", "5uav,5ub0,5ub1,5ub2,5ub3,5ub4,5ub5,5ub6,5ub7,5ub8,5ub9,5uba,5ubb,5ubc,5ubd,5ube,5ubf,5ubg,5ubh,5ubi,", "5ubj,5ubk,5ubl,5ubm,5ubn,5ubo,5ubp,5ubq,5ubr,5ubs,5ubt,5ubu,5ubv,5uc0,5uc1,5uc2,5uc3,5uc4,5uc5,5uc6,", "5uc7,5uc8,5uc9,5uca,5ucb,5ucc,5ucd,5uce,5ucf,5ucg,5uch,5uci,5ucj,5uck,5ucl,5ucm,5ucn,5uco,5ucp,5ucq,", "5ucr,5ucs,5uct,5ucu,5ucv,5ud0,5ud1,5ud2,5ud3,5ud4,5ud5,5ud6,5ud7,5ud8,5ud9,5uda,5udb,5udc,5udd,5ude,", "5udf,5udg,5udh,5udi,5udj,5udk,5udl,5udm,5udn,5udo,5udp,5udq,5udr,5uds,5udt,5udu,5udv,5ue0,5ue1,5ue2,", "5ue3,5ue4,5ue5,5ue6,5ue7,5ue8,5ue9,5uea,5ueb,5uec,5ued,5uee,5uef,5ueg,5ueh,5uei,5uej,5uek,5uel,5uem,", "5uen,5ueo,5uep,5ueq,5uer,5ues,5uet,5ueu,5uev,5uf0,5uf1,5uf2,5uf3,5uf4,5uf5,5uf6,5uf7,5uf8,5uf9,5ufa,", "5ufb,5ufc,5ufd,5ufe,5uff,5ufg,5ufh,5ufi,5ufj,5ufk,5ufl,5ufm,5ufn,5ufo,5ufp,5ufq,5ufr,5ufs,5uft,5ufu,", "5ufv,5ug0,5ug1,5ug2,5ug3,5ug4,5ug5,5ug6,5ug7,5ug8,5ug9,5uga,5ugb,5ugc,5ugd,5uge,5ugf,5ugg,5ugh,5ugi,", "5ugj,5ugk,5ugl,5ugm,5ugn,5ugo,5ugp,5ugq,5ugr,5ugs,5ugt,s001,s010,s011,s012,s013,s014,s015,s016,s017,", "s018,s019,s01a,s01b,s01c,s01d,s01e,s01f,s01g,s01h,s01i,s01j,s01k,s01l,s01m,s01n,s01o,s01p,s01q,s01r,", "s01s,s01t,s01u,s01v,s020,s021,s022,s023,s024,s025,s026,s027,s028,s029,s02a,s02b,s02c,s02d,s02e,s02f,", "s02g,s02h,s02i,s02j,s02k,s02l,s02m,s02n,s02o,s02p,s02q,s02r,s02s,s02t,s02u,s02v,s030,s031,s032,s033,", "s034,s035,s036,s037,s038,s039,s03a,s03b,s03c,s03d,s03e,s03f,s03g,s03h,s03i,s03j,s03k,s03l,s03m,s03n,", "s03o,s03p,s03q,s03r,s03s,s03t,s03u,s03v,s080,s081,s082,s083,s084,s085,s086,s087,s088,s089,s08a,s08b,", "s08c,s08d,s08e,s08f,s08g,s08h,s08i,s08j,s08k,s08l,s08m,s08n,s08o,s08p,s08q,s08r,s08s,s08t,s08u,s08v,", "s090,s091,s092,s093,s094,s095,s096,s097,s098,s099,s09a,s09b,s09c,s09d,s09e,s09f,s09g,s09h,s09i,s09j,", "s09k,s09l,s09m,s09n,s09o,s09p,s09q,s09r,s09s,s09t,s09u,s09v,s0a0,s0a1,s0a2,s0a3,s0a4,s0a5,s0a6,s0a7,", "s0a8,s0a9,s0aa,s0ab,s0ac,s0ad,s0ae,s0af,s0ag,s0ah,s0ai,s0aj,s0ak,s0al,s0am,s0an,s0ao,s0ap,s0aq,s0ar,", "s0as,s0at,s0au,s0av,s0b0,s0b1,s0b2,s0b3,s0b4,s0b5,s0b6,s0b7,s0b8,s0b9,s0ba,s0bb,s0bc,s0bd,s0be,s0bf,", "s0bg,s0bh,s0bi,s0bj,s0bk,s0bl,s0bm,s0bn,s0bo,s0bp,s0bq,s0br,s0bs,s0bt,s0bu,s0bv,s0c0,s0c1,s0c2,s0c3,", "s0c4,s0c5,s0c6,s0c7,s0c8,s0c9,s0ca,s0cb,s0cc,s0cd,s0ce,s0cf,s0cg,s0ch,s0ci,s0cj,s0ck,s0cl,s0cm,s0cn,", "s0co,s0cp,s0cq,s0cr,s0cs,s0ct,s0cu,s0cv,s0d0,s0d1,s0d2,s0d3,s0d4,s0d5,s0d6,s0d7,s0d8,s0d9,s0da,s0db,", "s0dc,s0dd,s0de,s0df,s0dg,s0dh,s0di,s0dj,s0dk,s0dl,s0dm,s0dn,s0do,s0dp,s0dq,s0dr,s0ds,s0dt,s0du,s0dv,", "s0e0,s0e1,s0e2,s0e3,s0e4,s0e5,s0e6,s0e7,s0e8,s0e9,s0ea,s0eb,s0ec,s0ed,s0ee,s0ef,s0eg,s0eh,s0ei,s0ej,", "s0ek,s0el,s0em,s0en,s0eo,s0ep,s0eq,s0er,s0es,s0et,s0eu,s0ev,s0f0,s0f1,s0f2,s0f3,s0f4,s0f5,s0f6,s0f7,", "s0f8,s0f9,s0fa,s0fb,s0fc,s0fd,s0fe,s0ff,u000,vvvt,10000,11vvt" }; public static final String[] canonicalClassValues = { "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,76,76,76,76,76,", "76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,78,6s,6s,6s,", "6s,78,6o,6s,6s,6s,6s,6s,6a,6a,6s,6s,6s,6s,6a,6a,6s,6s,6s,6s,", "6s,6s,6s,6s,6s,6s,6s,1,1,1,1,1,6s,6s,6s,6s,76,76,76,76,", "76,76,76,76,7g,76,6s,6s,6s,76,76,76,6s,6s,0,76,76,76,6s,6s,", "6s,6s,76,78,6s,6s,76,79,7a,7a,79,7a,7a,79,76,76,76,76,76,76,", "76,76,76,76,76,76,76,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,76,76,76,76,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,6s,76,76,76,76,6s,76,76,76,6u,6s,76,76,76,76,76,76,6s,6s,", "6s,6s,6s,6s,76,76,6s,76,76,6u,74,76,a,b,c,d,e,f,g,h,", "i,j,k,l,m,0,n,0,o,p,0,76,6s,0,i,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,76,76,76,76,", "76,76,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,r,s,t,u,v,10,11,12,76,76,6s,6s,76,76,76,76,76,6s,", "76,76,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "76,76,76,76,76,76,76,0,0,76,76,76,76,6s,76,0,0,76,76,0,", "6s,76,76,6s,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,76,6s,76,76,6s,76,76,6s,6s,6s,76,", "6s,6s,76,6s,76,76,76,6s,76,6s,76,6s,76,6s,76,76,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,76,6s,76,76,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,", "0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,7,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,9,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,9,2k,2r,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,37,37,9,0,0,0,0,0,0,0,0,0,3b,3b,3b,3b,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,3m,3m,0,0,0,0,0,0,0,", "0,0,3q,3q,3q,3q,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,6s,6s,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,6s,0,6s,0,6o,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,41,42,0,44,0,0,0,0,0,42,42,42,42,0,", "0,42,0,76,76,9,0,76,76,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,6s,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,7,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,76,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,76,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,74,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,6u,76,6s,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,76,6s,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,76,76,6s,76,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,76,76,1,1,76,76,76,", "76,1,1,1,76,76,0,0,0,0,76,0,0,0,1,1,76,6s,76,1,", "1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6q,74,", "78,6u,70,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,8,8,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,q,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,76,76,76,76,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,6s,0,76,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,76,1,6s,9,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6o,6o,1,1,1,", "0,0,0,72,6o,6o,6o,6o,6o,0,0,0,0,0,0,0,0,6s,6s,6s,", "6s,6s,6s,6s,6s,0,0,76,76,76,76,76,6s,6s,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,76,76,76,76,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,76,76,76,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,", "0,0,0,0,0,0,0,0,0,0,0,0" }; public static final String[] decompositionKeys = { "50,58,5a,5f,5i,5j,5k,5l,5o,5p,5q,5s,5t,5u,60,61,62,63,64,", "65,67,68,69,6a,6b,6c,6d,6e,6f,6h,6i,6j,6k,6l,6m,6p,6q,6r,6s,", "6t,70,71,72,73,74,75,77,78,79,7a,7b,7c,7d,7e,7f,7h,7i,7j,7k,", "7l,7m,7p,7q,7r,7s,7t,7v,80,81,82,83,84,85,86,87,88,89,8a,8b,", "8c,8d,8e,8f,8i,8j,8k,8l,8m,8n,8o,8p,8q,8r,8s,8t,8u,8v,90,91,", "92,93,94,95,98,99,9a,9b,9c,9d,9e,9f,9g,9i,9j,9k,9l,9m,9n,9p,", "9q,9r,9s,9t,9u,9v,a0,a3,a4,a5,a6,a7,a8,a9,ac,ad,ae,af,ag,ah,", "ak,al,am,an,ao,ap,aq,ar,as,at,au,av,b0,b1,b2,b3,b4,b5,b8,b9,", "ba,bb,bc,bd,be,bf,bg,bh,bi,bj,bk,bl,bm,bn,bo,bp,bq,br,bs,bt,", "bu,bv,d0,d1,df,dg,e4,e5,e6,e7,e8,e9,ea,eb,ec,ed,ee,ef,eg,eh,", "ei,ej,ek,el,em,en,eo,ep,eq,er,es,eu,ev,f0,f1,f2,f3,f6,f7,f8,", "f9,fa,fb,fc,fd,fe,ff,fg,fh,fi,fj,fk,fl,fo,fp,fq,fr,fs,ft,fu,", "fv,g0,g1,g2,g3,g4,g5,g6,g7,g8,g9,ga,gb,gc,gd,ge,gf,gg,gh,gi,", "gj,gk,gl,gm,gn,go,gp,gq,gr,gu,gv,h6,h7,h8,h9,ha,hb,hc,hd,he,", "hf,hg,hh,hi,hj,lg,lh,li,lj,lk,ll,lm,ln,lo,mo,mp,mq,mr,ms,mt,", "n0,n1,n2,n3,n4,q0,q1,q3,q4,rk,rq,ru,s4,s5,s6,s7,s8,s9,sa,sc,", "se,sf,sg,ta,tb,tc,td,te,tf,tg,ua,ub,uc,ud,ue,ug,uh,ui,uj,uk,", "ul,um,vg,vh,vi,vk,vl,vp,100,101,103,107,10c,10d,10e,10p,11p,12g,12h,12j,", "12n,12s,12t,12u,13m,13n,161,162,16g,16h,16i,16j,16m,16n,16q,16r,16s,16t,16u,16v,", "172,173,174,175,176,177,17a,17b,17c,17d,17e,17f,17g,17h,17i,17j,17k,17l,17o,17p,", "1c7,1h2,1h3,1h4,1h5,1h6,1jl,1jm,1jn,1jo,1m0,1m2,1mj,299,29h,29k,2ao,2ap,2aq,2ar,", "2as,2at,2au,2av,2eb,2ec,2es,2et,2ev,2hj,2hm,2ip,2iq,2ir,2iu,2q8,2qb,2qc,2qs,2qt,", "2sk,2ua,2ub,2uc,328,360,367,368,36a,36b,3aa,3ab,3ac,3eq,3es,3et,3eu,3hj,3lj,3ms,", "3mt,3oc,3q3,3qd,3qi,3qn,3qs,3r9,3rj,3rl,3rm,3rn,3ro,3rp,3s1,3sj,3st,3t2,3t7,3tc,", "3tp,416,47s,79c,79d,79e,79g,79h,79i,79j,79k,79l,79m,79n,79o,79p,79q,79s,79t,79u,", "79v,7a0,7a1,7a2,7a3,7a4,7a5,7a6,7a7,7a8,7a9,7aa,7ab,7ac,7ad,7af,7ag,7ah,7ai,7aj,", "7ak,7al,7am,7an,7ao,7ap,7aq,7ar,7as,7at,7au,7av,7b0,7b1,7b2,7b3,7b4,7b5,7b6,7b7,", "7b8,7b9,7ba,7bo,7cr,7cs,7ct,7cu,7cv,7d0,7d1,7d2,7d3,7d4,7d5,7d6,7d7,7d8,7d9,7da,", "7db,7dc,7dd,7de,7df,7dg,7dh,7di,7dj,7dk,7dl,7dm,7dn,7do,7dp,7dq,7dr,7ds,7dt,7du,", "7dv,7g0,7g1,7g2,7g3,7g4,7g5,7g6,7g7,7g8,7g9,7ga,7gb,7gc,7gd,7ge,7gf,7gg,7gh,7gi,", "7gj,7gk,7gl,7gm,7gn,7go,7gp,7gq,7gr,7gs,7gt,7gu,7gv,7h0,7h1,7h2,7h3,7h4,7h5,7h6,", "7h7,7h8,7h9,7ha,7hb,7hc,7hd,7he,7hf,7hg,7hh,7hi,7hj,7hk,7hl,7hm,7hn,7ho,7hp,7hq,", "7hr,7hs,7ht,7hu,7hv,7i0,7i1,7i2,7i3,7i4,7i5,7i6,7i7,7i8,7i9,7ia,7ib,7ic,7id,7ie,", "7if,7ig,7ih,7ii,7ij,7ik,7il,7im,7in,7io,7ip,7iq,7ir,7is,7it,7iu,7iv,7j0,7j1,7j2,", "7j3,7j4,7j5,7j6,7j7,7j8,7j9,7ja,7jb,7jc,7jd,7je,7jf,7jg,7jh,7ji,7jj,7jk,7jl,7jm,", "7jn,7jo,7jp,7jq,7jr,7js,7jt,7ju,7jv,7k0,7k1,7k2,7k3,7k4,7k5,7k6,7k7,7k8,7k9,7ka,", "7kb,7kc,7kd,7ke,7kf,7kg,7kh,7ki,7kj,7kk,7kl,7km,7kn,7ko,7kp,7kq,7kr,7l0,7l1,7l2,", "7l3,7l4,7l5,7l6,7l7,7l8,7l9,7la,7lb,7lc,7ld,7le,7lf,7lg,7lh,7li,7lj,7lk,7ll,7lm,", "7ln,7lo,7lp,7lq,7lr,7ls,7lt,7lu,7lv,7m0,7m1,7m2,7m3,7m4,7m5,7m6,7m7,7m8,7m9,7ma,", "7mb,7mc,7md,7me,7mf,7mg,7mh,7mi,7mj,7mk,7ml,7mm,7mn,7mo,7mp,7mq,7mr,7ms,7mt,7mu,", "7mv,7n0,7n1,7n2,7n3,7n4,7n5,7n6,7n7,7n8,7n9,7na,7nb,7nc,7nd,7ne,7nf,7ng,7nh,7ni,", "7nj,7nk,7nl,7nm,7nn,7no,7np,7o0,7o1,7o2,7o3,7o4,7o5,7o6,7o7,7o8,7o9,7oa,7ob,7oc,", "7od,7oe,7of,7og,7oh,7oi,7oj,7ok,7ol,7oo,7op,7oq,7or,7os,7ot,7p0,7p1,7p2,7p3,7p4,", "7p5,7p6,7p7,7p8,7p9,7pa,7pb,7pc,7pd,7pe,7pf,7pg,7ph,7pi,7pj,7pk,7pl,7pm,7pn,7po,", "7pp,7pq,7pr,7ps,7pt,7pu,7pv,7q0,7q1,7q2,7q3,7q4,7q5,7q8,7q9,7qa,7qb,7qc,7qd,7qg,", "7qh,7qi,7qj,7qk,7ql,7qm,7qn,7qp,7qr,7qt,7qv,7r0,7r1,7r2,7r3,7r4,7r5,7r6,7r7,7r8,", "7r9,7ra,7rb,7rc,7rd,7re,7rf,7rg,7rh,7ri,7rj,7rk,7rl,7rm,7rn,7ro,7rp,7rq,7rr,7rs,", "7rt,7s0,7s1,7s2,7s3,7s4,7s5,7s6,7s7,7s8,7s9,7sa,7sb,7sc,7sd,7se,7sf,7sg,7sh,7si,", "7sj,7sk,7sl,7sm,7sn,7so,7sp,7sq,7sr,7ss,7st,7su,7sv,7t0,7t1,7t2,7t3,7t4,7t5,7t6,", "7t7,7t8,7t9,7ta,7tb,7tc,7td,7te,7tf,7tg,7th,7ti,7tj,7tk,7tm,7tn,7to,7tp,7tq,7tr,", "7ts,7tt,7tu,7tv,7u0,7u1,7u2,7u3,7u4,7u6,7u7,7u8,7u9,7ua,7ub,7uc,7ud,7ue,7uf,7ug,", "7uh,7ui,7uj,7um,7un,7uo,7up,7uq,7ur,7ut,7uu,7uv,7v0,7v1,7v2,7v3,7v4,7v5,7v6,7v7,", "7v8,7v9,7va,7vb,7vc,7vd,7ve,7vf,7vi,7vj,7vk,7vm,7vn,7vo,7vp,7vq,7vr,7vs,7vt,7vu,", "800,801,802,803,804,805,806,807,808,809,80a,80h,80n,814,815,816,81f,81j,81k,81m,", "81n,81s,81u,827,828,829,82n,82v,83g,83h,83k,83l,83m,83n,83o,83p,83q,83r,83s,83t,", "83u,83v,840,841,842,843,844,845,846,847,848,849,84a,84b,84c,84d,84e,84g,84h,84i,", "84j,84k,858,880,881,882,883,885,886,887,889,88a,88b,88c,88d,88e,88f,88g,88h,88i,", "88j,88l,88m,88p,88q,88r,88s,88t,890,891,892,894,896,898,89a,89b,89c,89d,89f,89g,", "89h,89j,89k,89l,89m,89n,89o,89p,89r,89s,89t,89u,89v,8a0,8a5,8a6,8a7,8a8,8a9,8aj,", "8ak,8al,8am,8an,8ao,8ap,8aq,8ar,8as,8at,8au,8av,8b0,8b1,8b2,8b3,8b4,8b5,8b6,8b7,", "8b8,8b9,8ba,8bb,8bc,8bd,8be,8bf,8bg,8bh,8bi,8bj,8bk,8bl,8bm,8bn,8bo,8bp,8bq,8br,", "8bs,8bt,8bu,8bv,8cq,8cr,8de,8ed,8ee,8ef,8g4,8g9,8gc,8h4,8h6,8hc,8hd,8hf,8hg,8i1,", "8i4,8i7,8i9,8j0,8j2,8jd,8je,8jf,8jg,8jh,8jk,8jl,8jo,8jp,8k0,8k1,8k4,8k5,8k8,8k9,", "8lc,8ld,8le,8lf,8n0,8n1,8n2,8n3,8na,8nb,8nc,8nd,8p9,8pa,930,931,932,933,934,935,", "936,937,938,939,93a,93b,93c,93d,93e,93f,93g,93h,93i,93j,93k,93l,93m,93n,93o,93p,", "93q,93r,93s,93t,93u,93v,940,941,942,943,944,945,946,947,948,949,94a,94b,94c,94d,", "94e,94f,94g,94h,94i,94j,94k,94l,94m,94n,94o,94p,94q,94r,94s,94t,94u,94v,950,951,", "952,953,954,955,956,957,958,959,95a,95b,95c,95d,95e,95f,95g,95h,95i,95j,95k,95l,", "95m,95n,95o,95p,95q,95r,95s,95t,95u,95v,960,961,962,963,964,965,966,967,968,969,", "96a,96b,96c,96d,96e,96f,96g,96h,96i,96j,96k,96l,96m,96n,96o,96p,96q,96r,96s,96t,", "96u,96v,970,971,972,973,974,975,976,977,978,979,97a,agc,ajk,ajl,ajm,ams,bbf,bkv,", "bnj,bo0,bo1,bo2,bo3,bo4,bo5,bo6,bo7,bo8,bo9,boa,bob,boc,bod,boe,bof,bog,boh,boi,", "boj,bok,bol,bom,bon,boo,bop,boq,bor,bos,bot,bou,bov,bp0,bp1,bp2,bp3,bp4,bp5,bp6,", "bp7,bp8,bp9,bpa,bpb,bpc,bpd,bpe,bpf,bpg,bph,bpi,bpj,bpk,bpl,bpm,bpn,bpo,bpp,bpq,", "bpr,bps,bpt,bpu,bpv,bq0,bq1,bq2,bq3,bq4,bq5,bq6,bq7,bq8,bq9,bqa,bqb,bqc,bqd,bqe,", "bqf,bqg,bqh,bqi,bqj,bqk,bql,bqm,bqn,bqo,bqp,bqq,bqr,bqs,bqt,bqu,bqv,br0,br1,br2,", "br3,br4,br5,br6,br7,br8,br9,bra,brb,brc,brd,bre,brf,brg,brh,bri,brj,brk,brl,brm,", "brn,bro,brp,brq,brr,brs,brt,bru,brv,bs0,bs1,bs2,bs3,bs4,bs5,bs6,bs7,bs8,bs9,bsa,", "bsb,bsc,bsd,bse,bsf,bsg,bsh,bsi,bsj,bsk,bsl,bsm,bsn,bso,bsp,bsq,bsr,bss,bst,bsu,", "bsv,bt0,bt1,bt2,bt3,bt4,bt5,bt6,bt7,bt8,bt9,bta,btb,btc,btd,bte,btf,btg,bth,bti,", "btj,btk,btl,btm,btn,bto,btp,btq,btr,bts,btt,btu,btv,bu0,bu1,bu2,bu3,bu4,bu5,bu6,", "bu7,bu8,bu9,bua,bub,buc,bud,bue,buf,bug,buh,bui,buj,buk,bul,c00,c1m,c1o,c1p,c1q,", "c2c,c2e,c2g,c2i,c2k,c2m,c2o,c2q,c2s,c2u,c30,c32,c35,c37,c39,c3g,c3h,c3j,c3k,c3m,", "c3n,c3p,c3q,c3s,c3t,c4k,c4r,c4s,c4u,c4v,c5c,c5e,c5g,c5i,c5k,c5m,c5o,c5q,c5s,c5u,", "c60,c62,c65,c67,c69,c6g,c6h,c6j,c6k,c6m,c6n,c6p,c6q,c6s,c6t,c7k,c7n,c7o,c7p,c7q,", "c7u,c7v,c9h,c9i,c9j,c9k,c9l,c9m,c9n,c9o,c9p,c9q,c9r,c9s,c9t,c9u,c9v,ca0,ca1,ca2,", "ca3,ca4,ca5,ca6,ca7,ca8,ca9,caa,cab,cac,cad,cae,caf,cag,cah,cai,caj,cak,cal,cam,", "can,cao,cap,caq,car,cas,cat,cau,cav,cb0,cb1,cb2,cb3,cb4,cb5,cb6,cb7,cb8,cb9,cba,", "cbb,cbc,cbd,cbe,cbf,cbg,cbh,cbi,cbj,cbk,cbl,cbm,cbn,cbo,cbp,cbq,cbr,cbs,cbt,cbu,", "cbv,cc0,cc1,cc2,cc3,cc4,cc5,cc6,cc7,cc8,cc9,cca,ccb,ccc,ccd,cce,cci,ccj,cck,ccl,", "ccm,ccn,cco,ccp,ccq,ccr,ccs,cct,ccu,ccv,cg0,cg1,cg2,cg3,cg4,cg5,cg6,cg7,cg8,cg9,", "cga,cgb,cgc,cgd,cge,cgf,cgg,cgh,cgi,cgj,cgk,cgl,cgm,cgn,cgo,cgp,cgq,cgr,cgs,cgt,", "cgu,ch0,ch1,ch2,ch3,ch4,ch5,ch6,ch7,ch8,ch9,cha,chb,chc,chd,che,chf,chg,chh,chi,", "chj,chk,chl,chm,chn,cho,chp,chq,chr,chs,cht,chu,chv,ci0,ci1,ci2,ci3,cig,cih,cii,", "cij,cik,cil,cim,cin,cio,cip,ciq,cir,cis,cit,ciu,civ,cj0,cj1,cj2,cj3,cj4,cj5,cj6,", "cj7,cj8,cj9,cja,cjb,cjc,cjd,cje,cjf,cjg,cjh,cji,cjj,cjk,cjl,cjm,cjn,cjo,cjp,cjq,", "cjr,cjs,cjt,cju,ck0,ck1,ck2,ck3,ck4,ck5,ck6,ck7,ck8,ck9,cka,ckb,ckc,ckd,cke,ckf,", "ckg,ckh,cki,ckj,ckk,ckl,ckm,ckn,cko,ckp,ckq,ckr,cks,ckt,cku,ckv,cl0,cl1,cl2,cl3,", "cl4,cl5,cl6,cl7,cl8,cl9,cla,clb,clc,cld,cle,clf,clg,clh,cli,clj,clk,cll,clm,cln,", "clo,clp,clq,clr,cls,clt,clu,clv,cm0,cm1,cm2,cm3,cm4,cm5,cm6,cm7,cm8,cm9,cma,cmb,", "cmc,cmd,cme,cmf,cmg,cmh,cmi,cmj,cmk,cml,cmm,cmn,cmo,cmp,cmq,cmr,cms,cmt,cmu,cmv,", "cn0,cn1,cn2,cn3,cn4,cn5,cn6,cn7,cn8,cn9,cna,cnb,cnc,cnd,cne,cnf,cng,cnh,cni,cnj,", "cnk,cnl,cnm,cnn,cno,cnp,cnq,cnr,cns,cnt,cnu,co0,co1,co2,co3,co4,co5,co6,co7,co8,", "co9,coa,cob,coc,cod,coe,cof,cog,coh,coi,coj,cok,col,com,con,coo,cop,coq,cor,cos,", "cot,cou,cov,cp0,cp1,cp2,cp3,cp4,cp5,cp6,cp7,cp8,cp9,cpa,cpb,cpc,cpd,cpe,cpf,cpg,", "cph,cpi,cpj,cpk,cpl,cpm,cpn,cpo,cpp,cpq,cpr,cps,cpt,cpu,cpv,cq0,cq1,cq2,cq3,cq4,", "cq5,cq6,cq7,cq8,cq9,cqa,cqb,cqc,cqd,cqe,cqf,cqg,cqh,cqi,cqj,cqk,cql,cqm,cqn,cqo,", "cqp,cqq,cqr,cqs,cqt,cqu,cqv,cr0,cr1,cr2,cr3,cr4,cr5,cr6,cr7,cr8,cr9,cra,crb,crc,", "crd,cre,crf,crg,crh,cri,crj,crk,crl,crm,crn,cro,crp,crq,crr,crs,crt,cru,crv,cs0,", "cs1,cs2,cs3,cs4,cs5,cs6,cs7,cs8,cs9,csa,csb,csc,csd,cse,csf,csg,csh,csi,csj,csk,", "csl,csm,csn,cso,csp,csq,csr,css,cst,csu,csv,ct0,ct1,ct2,ct3,ct4,ct5,ct6,ct7,ct8,", "ct9,cta,ctb,ctc,ctd,cte,ctf,ctg,cth,cti,ctj,ctk,ctl,ctm,ctn,cto,ctp,ctq,ctr,cts,", "ctt,ctu,ctv,cu0,cu1,cu2,cu3,cu4,cu5,cu6,cu7,cu8,cu9,cua,cub,cuc,cud,cue,cuf,cug,", "cuh,cui,cuj,cuk,cul,cum,cun,cuo,cup,cuq,cur,cus,cut,cuu,cuv,cv0,cv1,cv2,cv3,cv4,", "cv5,cv6,cv7,cv8,cv9,cva,cvb,cvc,cvd,cve,cvf,cvg,cvh,cvi,cvj,cvk,cvl,cvm,cvn,cvo,", "cvp,cvq,cvr,cvs,cvt,cvu,cvv,1u80,1u81,1u82,1u83,1u84,1u85,1u86,1u87,1u88,1u89,1u8a,1u8b,1u8c,", "1u8d,1u8e,1u8f,1u8g,1u8h,1u8i,1u8j,1u8k,1u8l,1u8m,1u8n,1u8o,1u8p,1u8q,1u8r,1u8s,1u8t,1u8u,1u8v,1u90,", "1u91,1u92,1u93,1u94,1u95,1u96,1u97,1u98,1u99,1u9a,1u9b,1u9c,1u9d,1u9e,1u9f,1u9g,1u9h,1u9i,1u9j,1u9k,", "1u9l,1u9m,1u9n,1u9o,1u9p,1u9q,1u9r,1u9s,1u9t,1u9u,1u9v,1ua0,1ua1,1ua2,1ua3,1ua4,1ua5,1ua6,1ua7,1ua8,", "1ua9,1uaa,1uab,1uac,1uad,1uae,1uaf,1uag,1uah,1uai,1uaj,1uak,1ual,1uam,1uan,1uao,1uap,1uaq,1uar,1uas,", "1uat,1uau,1uav,1ub0,1ub1,1ub2,1ub3,1ub4,1ub5,1ub6,1ub7,1ub8,1ub9,1uba,1ubb,1ubc,1ubd,1ube,1ubf,1ubg,", "1ubh,1ubi,1ubj,1ubk,1ubl,1ubm,1ubn,1ubo,1ubp,1ubq,1ubr,1ubs,1ubt,1ubu,1ubv,1uc0,1uc1,1uc2,1uc3,1uc4,", "1uc5,1uc6,1uc7,1uc8,1uc9,1uca,1ucb,1ucc,1ucd,1uce,1ucf,1ucg,1uch,1uci,1ucj,1uck,1ucl,1ucm,1ucn,1uco,", "1ucp,1ucq,1ucr,1ucs,1uct,1ucu,1ucv,1ud0,1ud1,1ud2,1ud3,1ud4,1ud5,1ud6,1ud7,1ud8,1ud9,1uda,1udb,1udc,", "1udd,1ude,1udf,1udg,1udh,1udi,1udj,1udk,1udl,1udm,1udn,1udo,1udp,1udq,1udr,1uds,1udt,1udu,1udv,1ue0,", "1ue1,1ue2,1ue3,1ue4,1ue5,1ue6,1ue7,1ue8,1ue9,1uea,1ueb,1uec,1ued,1uee,1uef,1ueg,1ueh,1uei,1uej,1uek,", "1uel,1uem,1uen,1ueo,1uep,1ueq,1uer,1ues,1uet,1ueu,1uev,1uf0,1uf1,1uf2,1uf3,1uf4,1uf5,1uf6,1uf7,1uf8,", "1uf9,1ufa,1ufb,1ufc,1ufd,1ufe,1uff,1ufg,1ufh,1ufi,1ufj,1ufk,1ufl,1ufm,1ufn,1ufo,1ufp,1ufq,1ufr,1ufs,", "1uft,1ufu,1ufv,1ug0,1ug1,1ug2,1ug3,1ug4,1ug5,1ug6,1ug7,1ug8,1ug9,1uga,1ugb,1ugc,1ugd,1ugg,1ugi,1ugl,", "1ugm,1ugn,1ugo,1ugp,1ugq,1ugr,1ugs,1ugt,1ugu,1uh0,1uh2,1uh5,1uh6,1uha,1uhb,1uhc,1uhd,1uhg,1uhh,1uhi,", "1uhj,1uhk,1uhl,1uhm,1uhn,1uho,1uhp,1uhq,1uhr,1uhs,1uht,1uhu,1uhv,1ui0,1ui1,1ui2,1ui3,1ui4,1ui5,1ui6,", "1ui7,1ui8,1ui9,1uia,1uib,1uic,1uid,1uie,1uif,1uig,1uih,1uii,1uij,1uik,1uil,1uim,1uin,1uio,1uip,1uiq,", "1uir,1uis,1uit,1uiu,1uiv,1uj0,1uj1,1uj2,1uj3,1uj4,1uj5,1uj6,1uj7,1uj8,1uj9,1uja,1ujg,1ujh,1uji,1ujj,", "1ujk,1ujl,1ujm,1ujn,1ujo,1ujp,1ujq,1ujr,1ujs,1ujt,1uju,1ujv,1uk0,1uk1,1uk2,1uk3,1uk4,1uk5,1uk6,1uk7,", "1uk8,1uk9,1uka,1ukb,1ukc,1ukd,1uke,1ukf,1ukg,1ukh,1uki,1ukj,1ukk,1ukl,1ukm,1ukn,1uko,1ukp,1ukq,1ukr,", "1uks,1ukt,1uku,1ukv,1ul0,1ul1,1ul2,1ul3,1ul4,1ul5,1ul6,1ul7,1ul8,1ul9,1ula,1ulb,1ulc,1uld,1ule,1ulf,", "1ulg,1ulh,1uli,1ulj,1ulk,1ull,1ulm,1uln,1ulo,1ulp,1ulq,1ulr,1uls,1ult,1ulu,1ulv,1um0,1um1,1um2,1um3,", "1um4,1um5,1um6,1um7,1um8,1um9,1uma,1umb,1umc,1umd,1ume,1umf,1umg,1umh,1umi,1umj,1umk,1uml,1umm,1umn,", "1umo,1ump,1uo0,1uo1,1uo2,1uo3,1uo4,1uo5,1uo6,1uoj,1uok,1uol,1uom,1uon,1uot,1uov,1up0,1up1,1up2,1up3,", "1up4,1up5,1up6,1up7,1up8,1up9,1upa,1upb,1upc,1upd,1upe,1upf,1upg,1uph,1upi,1upj,1upk,1upl,1upm,1upo,", "1upp,1upq,1upr,1ups,1upu,1uq0,1uq1,1uq3,1uq4,1uq6,1uq7,1uq8,1uq9,1uqa,1uqb,1uqc,1uqd,1uqe,1uqf,1uqg,", "1uqh,1uqi,1uqj,1uqk,1uql,1uqm,1uqn,1uqo,1uqp,1uqq,1uqr,1uqs,1uqt,1uqu,1uqv,1ur0,1ur1,1ur2,1ur3,1ur4,", "1ur5,1ur6,1ur7,1ur8,1ur9,1ura,1urb,1urc,1urd,1ure,1urf,1urg,1urh,1uri,1urj,1urk,1url,1urm,1urn,1uro,", "1urp,1urq,1urr,1urs,1urt,1uru,1urv,1us0,1us1,1us2,1us3,1us4,1us5,1us6,1us7,1us8,1us9,1usa,1usb,1usc,", "1usd,1use,1usf,1usg,1ush,1usi,1usj,1usk,1usl,1usm,1usn,1uso,1usp,1usq,1usr,1uss,1ust,1usu,1usv,1ut0,", "1ut1,1ut2,1ut3,1ut4,1ut5,1ut6,1ut7,1ut8,1ut9,1uta,1utb,1utc,1utd,1ute,1utf,1utg,1uth,1uuj,1uuk,1uul,", "1uum,1uun,1uuo,1uup,1uuq,1uur,1uus,1uut,1uuu,1uuv,1uv0,1uv1,1uv2,1uv3,1uv4,1uv5,1uv6,1uv7,1uv8,1uv9,", "1uva,1uvb,1uvc,1uvd,1uve,1uvf,1uvg,1uvh,1uvi,1uvj,1uvk,1uvl,1uvm,1uvn,1uvo,1uvp,1uvq,1uvr,1uvs,1uvt,", "1uvu,1uvv,1v00,1v01,1v02,1v03,1v04,1v05,1v06,1v07,1v08,1v09,1v0a,1v0b,1v0c,1v0d,1v0e,1v0f,1v0g,1v0h,", "1v0i,1v0j,1v0k,1v0l,1v0m,1v0n,1v0o,1v0p,1v0q,1v0r,1v0s,1v0t,1v0u,1v0v,1v10,1v11,1v12,1v13,1v14,1v15,", "1v16,1v17,1v18,1v19,1v1a,1v1b,1v1c,1v1d,1v1e,1v1f,1v1g,1v1h,1v1i,1v1j,1v1k,1v1l,1v1m,1v1n,1v1o,1v1p,", "1v1q,1v1r,1v1s,1v1t,1v1u,1v1v,1v20,1v21,1v22,1v23,1v24,1v25,1v26,1v27,1v28,1v29,1v2a,1v2b,1v2c,1v2d,", "1v2e,1v2f,1v2g,1v2h,1v2i,1v2j,1v2k,1v2l,1v2m,1v2n,1v2o,1v2p,1v2q,1v2r,1v2s,1v2t,1v2u,1v2v,1v30,1v31,", "1v32,1v33,1v34,1v35,1v36,1v37,1v38,1v39,1v3a,1v3b,1v3c,1v3d,1v3e,1v3f,1v3g,1v3h,1v3i,1v3j,1v3k,1v3l,", "1v3m,1v3n,1v3o,1v3p,1v3q,1v3r,1v3s,1v3t,1v3u,1v3v,1v40,1v41,1v42,1v43,1v44,1v45,1v46,1v47,1v48,1v49,", "1v4a,1v4b,1v4c,1v4d,1v4e,1v4f,1v4g,1v4h,1v4i,1v4j,1v4k,1v4l,1v4m,1v4n,1v4o,1v4p,1v4q,1v4r,1v4s,1v4t,", "1v4u,1v4v,1v50,1v51,1v52,1v53,1v54,1v55,1v56,1v57,1v58,1v59,1v5a,1v5b,1v5c,1v5d,1v5e,1v5f,1v5g,1v5h,", "1v5i,1v5j,1v5k,1v5l,1v5m,1v5n,1v5o,1v5p,1v5q,1v5r,1v5s,1v5t,1v5u,1v5v,1v60,1v61,1v62,1v63,1v64,1v65,", "1v66,1v67,1v68,1v69,1v6a,1v6b,1v6c,1v6d,1v6e,1v6f,1v6g,1v6h,1v6i,1v6j,1v6k,1v6l,1v6m,1v6n,1v6o,1v6p,", "1v6q,1v6r,1v6s,1v6t,1v6u,1v6v,1v70,1v71,1v72,1v73,1v74,1v75,1v76,1v77,1v78,1v79,1v7a,1v7b,1v7c,1v7d,", "1v7e,1v7f,1v7g,1v7h,1v7i,1v7j,1v7k,1v7l,1v7m,1v7n,1v7o,1v7p,1v7q,1v7r,1v7s,1v7t,1v7u,1v7v,1v80,1v81,", "1v82,1v83,1v84,1v85,1v86,1v87,1v88,1v89,1v8a,1v8b,1v8c,1v8d,1v8e,1v8f,1v8g,1v8h,1v8i,1v8j,1v8k,1v8l,", "1v8m,1v8n,1v8o,1v8p,1v8q,1v8r,1v8s,1v8t,1v8u,1v8v,1v90,1v91,1v92,1v93,1v94,1v95,1v96,1v97,1v98,1v99,", "1v9a,1v9b,1v9c,1v9d,1v9e,1v9f,1v9g,1v9h,1v9i,1v9j,1v9k,1v9l,1v9m,1v9n,1v9o,1v9p,1v9q,1v9r,1v9s,1v9t,", "1vag,1vah,1vai,1vaj,1vak,1val,1vam,1van,1vao,1vap,1vaq,1var,1vas,1vat,1vau,1vav,1vb0,1vb1,1vb2,1vb3,", "1vb4,1vb5,1vb6,1vb7,1vb8,1vb9,1vba,1vbb,1vbc,1vbd,1vbe,1vbf,1vbg,1vbh,1vbi,1vbj,1vbk,1vbl,1vbm,1vbn,", "1vbo,1vbp,1vbq,1vbr,1vbs,1vbt,1vbu,1vbv,1vc0,1vc1,1vc2,1vc3,1vc4,1vc5,1vc6,1vc7,1vc8,1vc9,1vca,1vcb,", "1vcc,1vcd,1vce,1vcf,1vci,1vcj,1vck,1vcl,1vcm,1vcn,1vco,1vcp,1vcq,1vcr,1vcs,1vct,1vcu,1vcv,1vd0,1vd1,", "1vd2,1vd3,1vd4,1vd5,1vd6,1vd7,1vd8,1vd9,1vda,1vdb,1vdc,1vdd,1vde,1vdf,1vdg,1vdh,1vdi,1vdj,1vdk,1vdl,", "1vdm,1vdn,1vdo,1vdp,1vdq,1vdr,1vds,1vdt,1vdu,1vdv,1ve0,1ve1,1ve2,1ve3,1ve4,1ve5,1ve6,1ve7,1vfg,1vfh,", "1vfi,1vfj,1vfk,1vfl,1vfm,1vfn,1vfo,1vfp,1vfq,1vfr,1vfs,1vgg,1vgh,1vgi,1vgj,1vgk,1vgl,1vgm,1vgn,1vgo,", "1vgp,1vhg,1vhh,1vhi,1vhj,1vhk,1vhl,1vhm,1vhn,1vho,1vhp,1vhq,1vhr,1vhs,1vht,1vhu,1vhv,1vi0,1vi1,1vi2,", "1vi3,1vi4,1vi7,1vi8,1vi9,1via,1vib,1vic,1vid,1vie,1vif,1vig,1vih,1vii,1vik,1vil,1vim,1vin,1vio,1vip,", "1viq,1vir,1vis,1vit,1viu,1viv,1vj0,1vj1,1vj2,1vj3,1vj4,1vj5,1vj6,1vj8,1vj9,1vja,1vjb,1vjg,1vjh,1vji,", "1vjk,1vjm,1vjn,1vjo,1vjp,1vjq,1vjr,1vjs,1vjt,1vju,1vjv,1vk0,1vk1,1vk2,1vk3,1vk4,1vk5,1vk6,1vk7,1vk8,", "1vk9,1vka,1vkb,1vkc,1vkd,1vke,1vkf,1vkg,1vkh,1vki,1vkj,1vkk,1vkl,1vkm,1vkn,1vko,1vkp,1vkq,1vkr,1vks,", "1vkt,1vku,1vkv,1vl0,1vl1,1vl2,1vl3,1vl4,1vl5,1vl6,1vl7,1vl8,1vl9,1vla,1vlb,1vlc,1vld,1vle,1vlf,1vlg,", "1vlh,1vli,1vlj,1vlk,1vll,1vlm,1vln,1vlo,1vlp,1vlq,1vlr,1vls,1vlt,1vlu,1vlv,1vm0,1vm1,1vm2,1vm3,1vm4,", "1vm5,1vm6,1vm7,1vm8,1vm9,1vma,1vmb,1vmc,1vmd,1vme,1vmf,1vmg,1vmh,1vmi,1vmj,1vmk,1vml,1vmm,1vmn,1vmo,", "1vmp,1vmq,1vmr,1vms,1vmt,1vmu,1vmv,1vn0,1vn1,1vn2,1vn3,1vn4,1vn5,1vn6,1vn7,1vn8,1vn9,1vna,1vnb,1vnc,", "1vnd,1vne,1vnf,1vng,1vnh,1vni,1vnj,1vnk,1vnl,1vnm,1vnn,1vno,1vnp,1vnq,1vnr,1vns,1vo1,1vo2,1vo3,1vo4,", "1vo5,1vo6,1vo7,1vo8,1vo9,1voa,1vob,1voc,1vod,1voe,1vof,1vog,1voh,1voi,1voj,1vok,1vol,1vom,1von,1voo,", "1vop,1voq,1vor,1vos,1vot,1vou,1vov,1vp0,1vp1,1vp2,1vp3,1vp4,1vp5,1vp6,1vp7,1vp8,1vp9,1vpa,1vpb,1vpc,", "1vpd,1vpe,1vpf,1vpg,1vph,1vpi,1vpj,1vpk,1vpl,1vpm,1vpn,1vpo,1vpp,1vpq,1vpr,1vps,1vpt,1vpu,1vpv,1vq0,", "1vq1,1vq2,1vq3,1vq4,1vq5,1vq6,1vq7,1vq8,1vq9,1vqa,1vqb,1vqc,1vqd,1vqe,1vqf,1vqg,1vqh,1vqi,1vqj,1vqk,", "1vql,1vqm,1vqn,1vqo,1vqp,1vqq,1vqr,1vqs,1vqt,1vqu,1vqv,1vr0,1vr1,1vr2,1vr3,1vr4,1vr5,1vr6,1vr7,1vr8,", "1vr9,1vra,1vrb,1vrc,1vrd,1vre,1vrf,1vrg,1vrh,1vri,1vrj,1vrk,1vrl,1vrm,1vrn,1vro,1vrp,1vrq,1vrr,1vrs,", "1vrt,1vru,1vrv,1vs0,1vs1,1vs2,1vs3,1vs4,1vs5,1vs6,1vs7,1vs8,1vs9,1vsa,1vsb,1vsc,1vsd,1vse,1vsf,1vsg,", "1vsh,1vsi,1vsj,1vsk,1vsl,1vsm,1vsn,1vso,1vsp,1vsq,1vsr,1vss,1vst,1vsu,1vsv,1vt0,1vt1,1vt2,1vt3,1vt4,", "1vt5,1vt6,1vt7,1vt8,1vt9,1vta,1vtb,1vtc,1vtd,1vte,1vtf,1vtg,1vth,1vti,1vtj,1vtk,1vtl,1vtm,1vtn,1vto,", "1vtp,1vtq,1vtr,1vts,1vtt,1vtu,1vu2,1vu3,1vu4,1vu5,1vu6,1vu7,1vua,1vub,1vuc,1vud,1vue,1vuf,1vui,1vuj,", "1vuk,1vul,1vum,1vun,1vuq,1vur,1vus,1vv0,1vv1,1vv2,1vv3,1vv4,1vv5,1vv6,1vv8,1vv9,1vva,1vvb,1vvc,1vvd,", "1vve,3kau,3kav,3kb0,3kb1,3kb2,3kb3,3kb4,3kdr,3kds,3kdt,3kdu,3kdv,3ke0,3l00,3l01,3l02,3l03,3l04,3l05,", "3l06,3l07,3l08,3l09,3l0a,3l0b,3l0c,3l0d,3l0e,3l0f,3l0g,3l0h,3l0i,3l0j,3l0k,3l0l,3l0m,3l0n,3l0o,3l0p,", "3l0q,3l0r,3l0s,3l0t,3l0u,3l0v,3l10,3l11,3l12,3l13,3l14,3l15,3l16,3l17,3l18,3l19,3l1a,3l1b,3l1c,3l1d,", "3l1e,3l1f,3l1g,3l1h,3l1i,3l1j,3l1k,3l1l,3l1m,3l1n,3l1o,3l1p,3l1q,3l1r,3l1s,3l1t,3l1u,3l1v,3l20,3l21,", "3l22,3l23,3l24,3l25,3l26,3l27,3l28,3l29,3l2a,3l2b,3l2c,3l2d,3l2e,3l2f,3l2g,3l2h,3l2i,3l2j,3l2k,3l2m,", "3l2n,3l2o,3l2p,3l2q,3l2r,3l2s,3l2t,3l2u,3l2v,3l30,3l31,3l32,3l33,3l34,3l35,3l36,3l37,3l38,3l39,3l3a,", "3l3b,3l3c,3l3d,3l3e,3l3f,3l3g,3l3h,3l3i,3l3j,3l3k,3l3l,3l3m,3l3n,3l3o,3l3p,3l3q,3l3r,3l3s,3l3t,3l3u,", "3l3v,3l40,3l41,3l42,3l43,3l44,3l45,3l46,3l47,3l48,3l49,3l4a,3l4b,3l4c,3l4d,3l4e,3l4f,3l4g,3l4h,3l4i,", "3l4j,3l4k,3l4l,3l4m,3l4n,3l4o,3l4p,3l4q,3l4r,3l4s,3l4u,3l4v,3l52,3l55,3l56,3l59,3l5a,3l5b,3l5c,3l5e,", "3l5f,3l5g,3l5h,3l5i,3l5j,3l5k,3l5l,3l5m,3l5n,3l5o,3l5p,3l5r,3l5t,3l5u,3l5v,3l60,3l61,3l62,3l63,3l65,", "3l66,3l67,3l68,3l69,3l6a,3l6b,3l6c,3l6d,3l6e,3l6f,3l6g,3l6h,3l6i,3l6j,3l6k,3l6l,3l6m,3l6n,3l6o,3l6p,", "3l6q,3l6r,3l6s,3l6t,3l6u,3l6v,3l70,3l71,3l72,3l73,3l74,3l75,3l76,3l77,3l78,3l79,3l7a,3l7b,3l7c,3l7d,", "3l7e,3l7f,3l7g,3l7h,3l7i,3l7j,3l7k,3l7l,3l7m,3l7n,3l7o,3l7p,3l7q,3l7r,3l7s,3l7t,3l7u,3l7v,3l80,3l81,", "3l82,3l83,3l84,3l85,3l87,3l88,3l89,3l8a,3l8d,3l8e,3l8f,3l8g,3l8h,3l8i,3l8j,3l8k,3l8m,3l8n,3l8o,3l8p,", "3l8q,3l8r,3l8s,3l8u,3l8v,3l90,3l91,3l92,3l93,3l94,3l95,3l96,3l97,3l98,3l99,3l9a,3l9b,3l9c,3l9d,3l9e,", "3l9f,3l9g,3l9h,3l9i,3l9j,3l9k,3l9l,3l9m,3l9n,3l9o,3l9p,3l9r,3l9s,3l9t,3l9u,3la0,3la1,3la2,3la3,3la4,", "3la6,3laa,3lab,3lac,3lad,3lae,3laf,3lag,3lai,3laj,3lak,3lal,3lam,3lan,3lao,3lap,3laq,3lar,3las,3lat,", "3lau,3lav,3lb0,3lb1,3lb2,3lb3,3lb4,3lb5,3lb6,3lb7,3lb8,3lb9,3lba,3lbb,3lbc,3lbd,3lbe,3lbf,3lbg,3lbh,", "3lbi,3lbj,3lbk,3lbl,3lbm,3lbn,3lbo,3lbp,3lbq,3lbr,3lbs,3lbt,3lbu,3lbv,3lc0,3lc1,3lc2,3lc3,3lc4,3lc5,", "3lc6,3lc7,3lc8,3lc9,3lca,3lcb,3lcc,3lcd,3lce,3lcf,3lcg,3lch,3lci,3lcj,3lck,3lcl,3lcm,3lcn,3lco,3lcp,", "3lcq,3lcr,3lcs,3lct,3lcu,3lcv,3ld0,3ld1,3ld2,3ld3,3ld4,3ld5,3ld6,3ld7,3ld8,3ld9,3lda,3ldb,3ldc,3ldd,", "3lde,3ldf,3ldg,3ldh,3ldi,3ldj,3ldk,3ldl,3ldm,3ldn,3ldo,3ldp,3ldq,3ldr,3lds,3ldt,3ldu,3ldv,3le0,3le1,", "3le2,3le3,3le4,3le5,3le6,3le7,3le8,3le9,3lea,3leb,3lec,3led,3lee,3lef,3leg,3leh,3lei,3lej,3lek,3lel,", "3lem,3len,3leo,3lep,3leq,3ler,3les,3let,3leu,3lev,3lf0,3lf1,3lf2,3lf3,3lf4,3lf5,3lf6,3lf7,3lf8,3lf9,", "3lfa,3lfb,3lfc,3lfd,3lfe,3lff,3lfg,3lfh,3lfi,3lfj,3lfk,3lfl,3lfm,3lfn,3lfo,3lfp,3lfq,3lfr,3lfs,3lft,", "3lfu,3lfv,3lg0,3lg1,3lg2,3lg3,3lg4,3lg5,3lg6,3lg7,3lg8,3lg9,3lga,3lgb,3lgc,3lgd,3lge,3lgf,3lgg,3lgh,", "3lgi,3lgj,3lgk,3lgl,3lgm,3lgn,3lgo,3lgp,3lgq,3lgr,3lgs,3lgt,3lgu,3lgv,3lh0,3lh1,3lh2,3lh3,3lh4,3lh5,", "3lh6,3lh7,3lh8,3lh9,3lha,3lhb,3lhc,3lhd,3lhe,3lhf,3lhg,3lhh,3lhi,3lhj,3lhk,3lhl,3lhm,3lhn,3lho,3lhp,", "3lhq,3lhr,3lhs,3lht,3lhu,3lhv,3li0,3li1,3li2,3li3,3li4,3li5,3li6,3li7,3li8,3li9,3lia,3lib,3lic,3lid,", "3lie,3lif,3lig,3lih,3lii,3lij,3lik,3lil,3lim,3lin,3lio,3lip,3liq,3lir,3lis,3lit,3liu,3liv,3lj0,3lj1,", "3lj2,3lj3,3lj4,3lj5,3lj6,3lj7,3lj8,3lj9,3lja,3ljb,3ljc,3ljd,3lje,3ljf,3ljg,3ljh,3lji,3ljj,3ljk,3ljl,", "3ljm,3ljn,3ljo,3ljp,3ljq,3ljr,3ljs,3ljt,3lju,3ljv,3lk0,3lk1,3lk2,3lk3,3lk4,3lk5,3lk6,3lk7,3lk8,3lk9,", "3lka,3lkb,3lkc,3lkd,3lke,3lkf,3lkg,3lkh,3lki,3lkj,3lkk,3lkl,3lkm,3lkn,3lko,3lkp,3lkq,3lkr,3lks,3lkt,", "3lku,3lkv,3ll0,3ll1,3ll2,3ll3,3ll4,3ll5,3ll8,3ll9,3lla,3llb,3llc,3lld,3lle,3llf,3llg,3llh,3lli,3llj,", "3llk,3lll,3llm,3lln,3llo,3llp,3llq,3llr,3lls,3llt,3llu,3llv,3lm0,3lm1,3lm2,3lm3,3lm4,3lm5,3lm6,3lm7,", "3lm8,3lm9,3lma,3lmb,3lmc,3lmd,3lme,3lmf,3lmg,3lmh,3lmi,3lmj,3lmk,3lml,3lmm,3lmn,3lmo,3lmp,3lmq,3lmr,", "3lms,3lmt,3lmu,3lmv,3ln0,3ln1,3ln2,3ln3,3ln4,3ln5,3ln6,3ln7,3ln8,3ln9,3lna,3lnb,3lnc,3lnd,3lne,3lnf,", "3lng,3lnh,3lni,3lnj,3lnk,3lnl,3lnm,3lnn,3lno,3lnp,3lnq,3lnr,3lns,3lnt,3lnu,3lnv,3lo0,3lo1,3lo2,3lo3,", "3lo4,3lo5,3lo6,3lo7,3lo8,3lo9,3loa,3lob,3loc,3lod,3loe,3lof,3log,3loh,3loi,3loj,3lok,3lol,3lom,3lon,", "3loo,3lop,3loq,3lor,3los,3lot,3lou,3lov,3lp0,3lp1,3lp2,3lp3,3lp4,3lp5,3lp6,3lp7,3lp8,3lp9,3lpa,3lpb,", "3lpc,3lpd,3lpe,3lpf,3lpg,3lph,3lpi,3lpj,3lpk,3lpl,3lpm,3lpn,3lpo,3lpp,3lpq,3lpr,3lps,3lpt,3lpu,3lpv,", "3lq0,3lq1,3lq2,3lq3,3lq4,3lq5,3lq6,3lq7,3lq8,3lq9,3lqa,3lqb,3lqc,3lqd,3lqe,3lqf,3lqg,3lqh,3lqi,3lqj,", "3lqk,3lql,3lqm,3lqn,3lqo,3lqp,3lqq,3lqr,3lqs,3lqt,3lqu,3lqv,3lr0,3lr1,3lr2,3lr3,3lr4,3lr5,3lr6,3lr7,", "3lr8,3lr9,3lra,3lrb,3lrc,3lrd,3lre,3lrf,3lrg,3lrh,3lri,3lrj,3lrk,3lrl,3lrm,3lrn,3lro,3lrp,3lrq,3lrr,", "3lrs,3lrt,3lru,3lrv,3ls0,3ls1,3ls2,3ls3,3ls4,3ls5,3ls6,3ls7,3ls8,3ls9,3lsa,3lsb,3lsc,3lsd,3lse,3lsf,", "3lsg,3lsh,3lsi,3lsj,3lsk,3lsl,3lsm,3lsn,3lso,3lsp,3lsq,3lsr,3lss,3lst,3lsu,3lsv,3lt0,3lt1,3lt2,3lt3,", "3lt4,3lt5,3lt6,3lt7,3lt8,3lt9,3lta,3ltb,3ltc,3ltd,3lte,3ltf,3ltg,3lth,3lti,3ltj,3ltk,3ltl,3ltm,3ltn,", "3lto,3ltp,3ltq,3ltr,3lts,3ltt,3ltu,3ltv,3lu0,3lu1,3lu2,3lu3,3lu4,3lu5,3lu6,3lu7,3lu8,3lu9,3lue,3luf,", "3lug,3luh,3lui,3luj,3luk,3lul,3lum,3lun,3luo,3lup,3luq,3lur,3lus,3lut,3luu,3luv,3lv0,3lv1,3lv2,3lv3,", "3lv4,3lv5,3lv6,3lv7,3lv8,3lv9,3lva,3lvb,3lvc,3lvd,3lve,3lvf,3lvg,3lvh,3lvi,3lvj,3lvk,3lvl,3lvm,3lvn,", "3lvo,3lvp,3lvq,3lvr,3lvs,3lvt,3lvu,3lvv,5u00,5u01,5u02,5u03,5u04,5u05,5u06,5u07,5u08,5u09,5u0a,5u0b,", "5u0c,5u0d,5u0e,5u0f,5u0g,5u0h,5u0i,5u0j,5u0k,5u0l,5u0m,5u0n,5u0o,5u0p,5u0q,5u0r,5u0s,5u0t,5u0u,5u0v,", "5u10,5u11,5u12,5u13,5u14,5u15,5u16,5u17,5u18,5u19,5u1a,5u1b,5u1c,5u1d,5u1e,5u1f,5u1g,5u1h,5u1i,5u1j,", "5u1k,5u1l,5u1m,5u1n,5u1o,5u1p,5u1q,5u1r,5u1s,5u1t,5u1u,5u1v,5u20,5u21,5u22,5u23,5u24,5u25,5u26,5u27,", "5u28,5u29,5u2a,5u2b,5u2c,5u2d,5u2e,5u2f,5u2g,5u2h,5u2i,5u2j,5u2k,5u2l,5u2m,5u2n,5u2o,5u2p,5u2q,5u2r,", "5u2s,5u2t,5u2u,5u2v,5u30,5u31,5u32,5u33,5u34,5u35,5u36,5u37,5u38,5u39,5u3a,5u3b,5u3c,5u3d,5u3e,5u3f,", "5u3g,5u3h,5u3i,5u3j,5u3k,5u3l,5u3m,5u3n,5u3o,5u3p,5u3q,5u3r,5u3s,5u3t,5u3u,5u3v,5u40,5u41,5u42,5u43,", "5u44,5u45,5u46,5u47,5u48,5u49,5u4a,5u4b,5u4c,5u4d,5u4e,5u4f,5u4g,5u4h,5u4i,5u4j,5u4k,5u4l,5u4m,5u4n,", "5u4o,5u4p,5u4q,5u4r,5u4s,5u4t,5u4u,5u4v,5u50,5u51,5u52,5u53,5u54,5u55,5u56,5u57,5u58,5u59,5u5a,5u5b,", "5u5c,5u5d,5u5e,5u5f,5u5g,5u5h,5u5i,5u5j,5u5k,5u5l,5u5m,5u5n,5u5o,5u5p,5u5q,5u5r,5u5s,5u5t,5u5u,5u5v,", "5u60,5u61,5u62,5u63,5u64,5u65,5u66,5u67,5u68,5u69,5u6a,5u6b,5u6c,5u6d,5u6e,5u6f,5u6g,5u6h,5u6i,5u6j,", "5u6k,5u6l,5u6m,5u6n,5u6o,5u6p,5u6q,5u6r,5u6s,5u6t,5u6u,5u6v,5u70,5u71,5u72,5u73,5u74,5u75,5u76,5u77,", "5u78,5u79,5u7a,5u7b,5u7c,5u7d,5u7e,5u7f,5u7g,5u7h,5u7i,5u7j,5u7k,5u7l,5u7m,5u7n,5u7o,5u7p,5u7q,5u7r,", "5u7s,5u7t,5u7u,5u7v,5u80,5u81,5u82,5u83,5u84,5u85,5u86,5u87,5u88,5u89,5u8a,5u8b,5u8c,5u8d,5u8e,5u8f,", "5u8g,5u8h,5u8i,5u8j,5u8k,5u8l,5u8m,5u8n,5u8o,5u8p,5u8q,5u8r,5u8s,5u8t,5u8u,5u8v,5u90,5u91,5u92,5u93,", "5u94,5u95,5u96,5u97,5u98,5u99,5u9a,5u9b,5u9c,5u9d,5u9e,5u9f,5u9g,5u9h,5u9i,5u9j,5u9k,5u9l,5u9m,5u9n,", "5u9o,5u9p,5u9q,5u9r,5u9s,5u9t,5u9u,5u9v,5ua0,5ua1,5ua2,5ua3,5ua4,5ua5,5ua6,5ua7,5ua8,5ua9,5uaa,5uab,", "5uac,5uad,5uae,5uaf,5uag,5uah,5uai,5uaj,5uak,5ual,5uam,5uan,5uao,5uap,5uaq,5uar,5uas,5uat,5uau,5uav,", "5ub0,5ub1,5ub2,5ub3,5ub4,5ub5,5ub6,5ub7,5ub8,5ub9,5uba,5ubb,5ubc,5ubd,5ube,5ubf,5ubg,5ubh,5ubi,5ubj,", "5ubk,5ubl,5ubm,5ubn,5ubo,5ubp,5ubq,5ubr,5ubs,5ubt,5ubu,5ubv,5uc0,5uc1,5uc2,5uc3,5uc4,5uc5,5uc6,5uc7,", "5uc8,5uc9,5uca,5ucb,5ucc,5ucd,5uce,5ucf,5ucg,5uch,5uci,5ucj,5uck,5ucl,5ucm,5ucn,5uco,5ucp,5ucq,5ucr,", "5ucs,5uct,5ucu,5ucv,5ud0,5ud1,5ud2,5ud3,5ud4,5ud5,5ud6,5ud7,5ud8,5ud9,5uda,5udb,5udc,5udd,5ude,5udf,", "5udg,5udh,5udi,5udj,5udk,5udl,5udm,5udn,5udo,5udp,5udq,5udr,5uds,5udt,5udu,5udv,5ue0,5ue1,5ue2,5ue3,", "5ue4,5ue5,5ue6,5ue7,5ue8,5ue9,5uea,5ueb,5uec,5ued,5uee,5uef,5ueg,5ueh,5uei,5uej,5uek,5uel,5uem,5uen,", "5ueo,5uep,5ueq,5uer,5ues,5uet,5ueu,5uev,5uf0,5uf1,5uf2,5uf3,5uf4,5uf5,5uf6,5uf7,5uf8,5uf9,5ufa,5ufb,", "5ufc,5ufd,5ufe,5uff,5ufg,5ufh,5ufi,5ufj,5ufk,5ufl,5ufm,5ufn,5ufo,5ufp,5ufq,5ufr,5ufs,5uft,5ufu,5ufv,", "5ug0,5ug1,5ug2,5ug3,5ug4,5ug5,5ug6,5ug7,5ug8,5ug9,5uga,5ugb,5ugc,5ugd,5uge,5ugf,5ugg,5ugh,5ugi,5ugj,", "5ugk,5ugl,5ugm,5ugn,5ugo,5ugp,5ugq,5ugr,5ugs,5ugt" }; public static final String[] decompositionValues = { "\u0020", "\u0020\u0308", "a", "\u0020\u0304", "2", "3", "\u0020\u0301", "\u03bc", "\u0020\u0327", "1", "o", "1\u20444", "1\u20442", "3\u20444", "A\u0300", "A\u0301", "A\u0302", "A\u0303", "A\u0308", "A\u030a", "C\u0327", "E\u0300", "E\u0301", "E\u0302", "E\u0308", "I\u0300", "I\u0301", "I\u0302", "I\u0308", "N\u0303", "O\u0300", "O\u0301", "O\u0302", "O\u0303", "O\u0308", "U\u0300", "U\u0301", "U\u0302", "U\u0308", "Y\u0301", "a\u0300", "a\u0301", "a\u0302", "a\u0303", "a\u0308", "a\u030a", "c\u0327", "e\u0300", "e\u0301", "e\u0302", "e\u0308", "i\u0300", "i\u0301", "i\u0302", "i\u0308", "n\u0303", "o\u0300", "o\u0301", "o\u0302", "o\u0303", "o\u0308", "u\u0300", "u\u0301", "u\u0302", "u\u0308", "y\u0301", "y\u0308", "A\u0304", "a\u0304", "A\u0306", "a\u0306", "A\u0328", "a\u0328", "C\u0301", "c\u0301", "C\u0302", "c\u0302", "C\u0307", "c\u0307", "C\u030c", "c\u030c", "D\u030c", "d\u030c", "E\u0304", "e\u0304", "E\u0306", "e\u0306", "E\u0307", "e\u0307", "E\u0328", "e\u0328", "E\u030c", "e\u030c", "G\u0302", "g\u0302", "G\u0306", "g\u0306", "G\u0307", "g\u0307", "G\u0327", "g\u0327", "H\u0302", "h\u0302", "I\u0303", "i\u0303", "I\u0304", "i\u0304", "I\u0306", "i\u0306", "I\u0328", "i\u0328", "I\u0307", "IJ", "ij", "J\u0302", "j\u0302", "K\u0327", "k\u0327", "L\u0301", "l\u0301", "L\u0327", "l\u0327", "L\u030c", "l\u030c", "L\u00b7", "l\u00b7", "N\u0301", "n\u0301", "N\u0327", "n\u0327", "N\u030c", "n\u030c", "\u02bcn", "O\u0304", "o\u0304", "O\u0306", "o\u0306", "O\u030b", "o\u030b", "R\u0301", "r\u0301", "R\u0327", "r\u0327", "R\u030c", "r\u030c", "S\u0301", "s\u0301", "S\u0302", "s\u0302", "S\u0327", "s\u0327", "S\u030c", "s\u030c", "T\u0327", "t\u0327", "T\u030c", "t\u030c", "U\u0303", "u\u0303", "U\u0304", "u\u0304", "U\u0306", "u\u0306", "U\u030a", "u\u030a", "U\u030b", "u\u030b", "U\u0328", "u\u0328", "W\u0302", "w\u0302", "Y\u0302", "y\u0302", "Y\u0308", "Z\u0301", "z\u0301", "Z\u0307", "z\u0307", "Z\u030c", "z\u030c", "s", "O\u031b", "o\u031b", "U\u031b", "u\u031b", "D\u017d", "D\u017e", "d\u017e", "LJ", "Lj", "lj", "NJ", "Nj", "nj", "A\u030c", "a\u030c", "I\u030c", "i\u030c", "O\u030c", "o\u030c", "U\u030c", "u\u030c", "\u00dc\u0304", "\u00fc\u0304", "\u00dc\u0301", "\u00fc\u0301", "\u00dc\u030c", "\u00fc\u030c", "\u00dc\u0300", "\u00fc\u0300", "\u00c4\u0304", "\u00e4\u0304", "\u0226\u0304", "\u0227\u0304", "\u00c6\u0304", "\u00e6\u0304", "G\u030c", "g\u030c", "K\u030c", "k\u030c", "O\u0328", "o\u0328", "\u01ea\u0304", "\u01eb\u0304", "\u01b7\u030c", "\u0292\u030c", "j\u030c", "DZ", "Dz", "dz", "G\u0301", "g\u0301", "N\u0300", "n\u0300", "\u00c5\u0301", "\u00e5\u0301", "\u00c6\u0301", "\u00e6\u0301", "\u00d8\u0301", "\u00f8\u0301", "A\u030f", "a\u030f", "A\u0311", "a\u0311", "E\u030f", "e\u030f", "E\u0311", "e\u0311", "I\u030f", "i\u030f", "I\u0311", "i\u0311", "O\u030f", "o\u030f", "O\u0311", "o\u0311", "R\u030f", "r\u030f", "R\u0311", "r\u0311", "U\u030f", "u\u030f", "U\u0311", "u\u0311", "S\u0326", "s\u0326", "T\u0326", "t\u0326", "H\u030c", "h\u030c", "A\u0307", "a\u0307", "E\u0327", "e\u0327", "\u00d6\u0304", "\u00f6\u0304", "\u00d5\u0304", "\u00f5\u0304", "O\u0307", "o\u0307", "\u022e\u0304", "\u022f\u0304", "Y\u0304", "y\u0304", "h", "\u0266", "j", "r", "\u0279", "\u027b", "\u0281", "w", "y", "\u0020\u0306", "\u0020\u0307", "\u0020\u030a", "\u0020\u0328", "\u0020\u0303", "\u0020\u030b", "\u0263", "l", "s", "x", "\u0295", "\u0300", "\u0301", "\u0313", "\u0308\u0301", "\u02b9", "\u0020\u0345", ";", "\u0020\u0301", "\u00a8\u0301", "\u0391\u0301", "\u00b7", "\u0395\u0301", "\u0397\u0301", "\u0399\u0301", "\u039f\u0301", "\u03a5\u0301", "\u03a9\u0301", "\u03ca\u0301", "\u0399\u0308", "\u03a5\u0308", "\u03b1\u0301", "\u03b5\u0301", "\u03b7\u0301", "\u03b9\u0301", "\u03cb\u0301", "\u03b9\u0308", "\u03c5\u0308", "\u03bf\u0301", "\u03c5\u0301", "\u03c9\u0301", "\u03b2", "\u03b8", "\u03a5", "\u03d2\u0301", "\u03d2\u0308", "\u03c6", "\u03c0", "\u03ba", "\u03c1", "\u03c2", "\u0398", "\u03b5", "\u03a3", "\u0415\u0300", "\u0415\u0308", "\u0413\u0301", "\u0406\u0308", "\u041a\u0301", "\u0418\u0300", "\u0423\u0306", "\u0418\u0306", "\u0438\u0306", "\u0435\u0300", "\u0435\u0308", "\u0433\u0301", "\u0456\u0308", "\u043a\u0301", "\u0438\u0300", "\u0443\u0306", "\u0474\u030f", "\u0475\u030f", "\u0416\u0306", "\u0436\u0306", "\u0410\u0306", "\u0430\u0306", "\u0410\u0308", "\u0430\u0308", "\u0415\u0306", "\u0435\u0306", "\u04d8\u0308", "\u04d9\u0308", "\u0416\u0308", "\u0436\u0308", "\u0417\u0308", "\u0437\u0308", "\u0418\u0304", "\u0438\u0304", "\u0418\u0308", "\u0438\u0308", "\u041e\u0308", "\u043e\u0308", "\u04e8\u0308", "\u04e9\u0308", "\u042d\u0308", "\u044d\u0308", "\u0423\u0304", "\u0443\u0304", "\u0423\u0308", "\u0443\u0308", "\u0423\u030b", "\u0443\u030b", "\u0427\u0308", "\u0447\u0308", "\u042b\u0308", "\u044b\u0308", "\u0565\u0582", "\u0627\u0653", "\u0627\u0654", "\u0648\u0654", "\u0627\u0655", "\u064a\u0654", "\u0627\u0674", "\u0648\u0674", "\u06c7\u0674", "\u064a\u0674", "\u06d5\u0654", "\u06c1\u0654", "\u06d2\u0654", "\u0928\u093c", "\u0930\u093c", "\u0933\u093c", "\u0915\u093c", "\u0916\u093c", "\u0917\u093c", "\u091c\u093c", "\u0921\u093c", "\u0922\u093c", "\u092b\u093c", "\u092f\u093c", "\u09c7\u09be", "\u09c7\u09d7", "\u09a1\u09bc", "\u09a2\u09bc", "\u09af\u09bc", "\u0a32\u0a3c", "\u0a38\u0a3c", "\u0a16\u0a3c", "\u0a17\u0a3c", "\u0a1c\u0a3c", "\u0a2b\u0a3c", "\u0b47\u0b56", "\u0b47\u0b3e", "\u0b47\u0b57", "\u0b21\u0b3c", "\u0b22\u0b3c", "\u0b92\u0bd7", "\u0bc6\u0bbe", "\u0bc7\u0bbe", "\u0bc6\u0bd7", "\u0c46\u0c56", "\u0cbf\u0cd5", "\u0cc6\u0cd5", "\u0cc6\u0cd6", "\u0cc6\u0cc2", "\u0cca\u0cd5", "\u0d46\u0d3e", "\u0d47\u0d3e", "\u0d46\u0d57", "\u0dd9\u0dca", "\u0dd9\u0dcf", "\u0ddc\u0dca", "\u0dd9\u0ddf", "\u0e4d\u0e32", "\u0ecd\u0eb2", "\u0eab\u0e99", "\u0eab\u0ea1", "\u0f0b", "\u0f42\u0fb7", "\u0f4c\u0fb7", "\u0f51\u0fb7", "\u0f56\u0fb7", "\u0f5b\u0fb7", "\u0f40\u0fb5", "\u0f71\u0f72", "\u0f71\u0f74", "\u0fb2\u0f80", "\u0fb2\u0f81", "\u0fb3\u0f80", "\u0fb3\u0f81", "\u0f71\u0f80", "\u0f92\u0fb7", "\u0f9c\u0fb7", "\u0fa1\u0fb7", "\u0fa6\u0fb7", "\u0fab\u0fb7", "\u0f90\u0fb5", "\u1025\u102e", "\u10dc", "A", "\u00c6", "B", "D", "E", "\u018e", "G", "H", "I", "J", "K", "L", "M", "N", "O", "\u0222", "P", "R", "T", "U", "W", "a", "\u0250", "\u0251", "\u1d02", "b", "d", "e", "\u0259", "\u025b", "\u025c", "g", "k", "m", "\u014b", "o", "\u0254", "\u1d16", "\u1d17", "p", "t", "u", "\u1d1d", "\u026f", "v", "\u1d25", "\u03b2", "\u03b3", "\u03b4", "\u03c6", "\u03c7", "i", "r", "u", "v", "\u03b2", "\u03b3", "\u03c1", "\u03c6", "\u03c7", "\u043d", "\u0252", "c", "\u0255", "\u00f0", "\u025c", "f", "\u025f", "\u0261", "\u0265", "\u0268", "\u0269", "\u026a", "\u1d7b", "\u029d", "\u026d", "\u1d85", "\u029f", "\u0271", "\u0270", "\u0272", "\u0273", "\u0274", "\u0275", "\u0278", "\u0282", "\u0283", "\u01ab", "\u0289", "\u028a", "\u1d1c", "\u028b", "\u028c", "z", "\u0290", "\u0291", "\u0292", "\u03b8", "A\u0325", "a\u0325", "B\u0307", "b\u0307", "B\u0323", "b\u0323", "B\u0331", "b\u0331", "\u00c7\u0301", "\u00e7\u0301", "D\u0307", "d\u0307", "D\u0323", "d\u0323", "D\u0331", "d\u0331", "D\u0327", "d\u0327", "D\u032d", "d\u032d", "\u0112\u0300", "\u0113\u0300", "\u0112\u0301", "\u0113\u0301", "E\u032d", "e\u032d", "E\u0330", "e\u0330", "\u0228\u0306", "\u0229\u0306", "F\u0307", "f\u0307", "G\u0304", "g\u0304", "H\u0307", "h\u0307", "H\u0323", "h\u0323", "H\u0308", "h\u0308", "H\u0327", "h\u0327", "H\u032e", "h\u032e", "I\u0330", "i\u0330", "\u00cf\u0301", "\u00ef\u0301", "K\u0301", "k\u0301", "K\u0323", "k\u0323", "K\u0331", "k\u0331", "L\u0323", "l\u0323", "\u1e36\u0304", "\u1e37\u0304", "L\u0331", "l\u0331", "L\u032d", "l\u032d", "M\u0301", "m\u0301", "M\u0307", "m\u0307", "M\u0323", "m\u0323", "N\u0307", "n\u0307", "N\u0323", "n\u0323", "N\u0331", "n\u0331", "N\u032d", "n\u032d", "\u00d5\u0301", "\u00f5\u0301", "\u00d5\u0308", "\u00f5\u0308", "\u014c\u0300", "\u014d\u0300", "\u014c\u0301", "\u014d\u0301", "P\u0301", "p\u0301", "P\u0307", "p\u0307", "R\u0307", "r\u0307", "R\u0323", "r\u0323", "\u1e5a\u0304", "\u1e5b\u0304", "R\u0331", "r\u0331", "S\u0307", "s\u0307", "S\u0323", "s\u0323", "\u015a\u0307", "\u015b\u0307", "\u0160\u0307", "\u0161\u0307", "\u1e62\u0307", "\u1e63\u0307", "T\u0307", "t\u0307", "T\u0323", "t\u0323", "T\u0331", "t\u0331", "T\u032d", "t\u032d", "U\u0324", "u\u0324", "U\u0330", "u\u0330", "U\u032d", "u\u032d", "\u0168\u0301", "\u0169\u0301", "\u016a\u0308", "\u016b\u0308", "V\u0303", "v\u0303", "V\u0323", "v\u0323", "W\u0300", "w\u0300", "W\u0301", "w\u0301", "W\u0308", "w\u0308", "W\u0307", "w\u0307", "W\u0323", "w\u0323", "X\u0307", "x\u0307", "X\u0308", "x\u0308", "Y\u0307", "y\u0307", "Z\u0302", "z\u0302", "Z\u0323", "z\u0323", "Z\u0331", "z\u0331", "h\u0331", "t\u0308", "w\u030a", "y\u030a", "a\u02be", "\u017f\u0307", "A\u0323", "a\u0323", "A\u0309", "a\u0309", "\u00c2\u0301", "\u00e2\u0301", "\u00c2\u0300", "\u00e2\u0300", "\u00c2\u0309", "\u00e2\u0309", "\u00c2\u0303", "\u00e2\u0303", "\u1ea0\u0302", "\u1ea1\u0302", "\u0102\u0301", "\u0103\u0301", "\u0102\u0300", "\u0103\u0300", "\u0102\u0309", "\u0103\u0309", "\u0102\u0303", "\u0103\u0303", "\u1ea0\u0306", "\u1ea1\u0306", "E\u0323", "e\u0323", "E\u0309", "e\u0309", "E\u0303", "e\u0303", "\u00ca\u0301", "\u00ea\u0301", "\u00ca\u0300", "\u00ea\u0300", "\u00ca\u0309", "\u00ea\u0309", "\u00ca\u0303", "\u00ea\u0303", "\u1eb8\u0302", "\u1eb9\u0302", "I\u0309", "i\u0309", "I\u0323", "i\u0323", "O\u0323", "o\u0323", "O\u0309", "o\u0309", "\u00d4\u0301", "\u00f4\u0301", "\u00d4\u0300", "\u00f4\u0300", "\u00d4\u0309", "\u00f4\u0309", "\u00d4\u0303", "\u00f4\u0303", "\u1ecc\u0302", "\u1ecd\u0302", "\u01a0\u0301", "\u01a1\u0301", "\u01a0\u0300", "\u01a1\u0300", "\u01a0\u0309", "\u01a1\u0309", "\u01a0\u0303", "\u01a1\u0303", "\u01a0\u0323", "\u01a1\u0323", "U\u0323", "u\u0323", "U\u0309", "u\u0309", "\u01af\u0301", "\u01b0\u0301", "\u01af\u0300", "\u01b0\u0300", "\u01af\u0309", "\u01b0\u0309", "\u01af\u0303", "\u01b0\u0303", "\u01af\u0323", "\u01b0\u0323", "Y\u0300", "y\u0300", "Y\u0323", "y\u0323", "Y\u0309", "y\u0309", "Y\u0303", "y\u0303", "\u03b1\u0313", "\u03b1\u0314", "\u1f00\u0300", "\u1f01\u0300", "\u1f00\u0301", "\u1f01\u0301", "\u1f00\u0342", "\u1f01\u0342", "\u0391\u0313", "\u0391\u0314", "\u1f08\u0300", "\u1f09\u0300", "\u1f08\u0301", "\u1f09\u0301", "\u1f08\u0342", "\u1f09\u0342", "\u03b5\u0313", "\u03b5\u0314", "\u1f10\u0300", "\u1f11\u0300", "\u1f10\u0301", "\u1f11\u0301", "\u0395\u0313", "\u0395\u0314", "\u1f18\u0300", "\u1f19\u0300", "\u1f18\u0301", "\u1f19\u0301", "\u03b7\u0313", "\u03b7\u0314", "\u1f20\u0300", "\u1f21\u0300", "\u1f20\u0301", "\u1f21\u0301", "\u1f20\u0342", "\u1f21\u0342", "\u0397\u0313", "\u0397\u0314", "\u1f28\u0300", "\u1f29\u0300", "\u1f28\u0301", "\u1f29\u0301", "\u1f28\u0342", "\u1f29\u0342", "\u03b9\u0313", "\u03b9\u0314", "\u1f30\u0300", "\u1f31\u0300", "\u1f30\u0301", "\u1f31\u0301", "\u1f30\u0342", "\u1f31\u0342", "\u0399\u0313", "\u0399\u0314", "\u1f38\u0300", "\u1f39\u0300", "\u1f38\u0301", "\u1f39\u0301", "\u1f38\u0342", "\u1f39\u0342", "\u03bf\u0313", "\u03bf\u0314", "\u1f40\u0300", "\u1f41\u0300", "\u1f40\u0301", "\u1f41\u0301", "\u039f\u0313", "\u039f\u0314", "\u1f48\u0300", "\u1f49\u0300", "\u1f48\u0301", "\u1f49\u0301", "\u03c5\u0313", "\u03c5\u0314", "\u1f50\u0300", "\u1f51\u0300", "\u1f50\u0301", "\u1f51\u0301", "\u1f50\u0342", "\u1f51\u0342", "\u03a5\u0314", "\u1f59\u0300", "\u1f59\u0301", "\u1f59\u0342", "\u03c9\u0313", "\u03c9\u0314", "\u1f60\u0300", "\u1f61\u0300", "\u1f60\u0301", "\u1f61\u0301", "\u1f60\u0342", "\u1f61\u0342", "\u03a9\u0313", "\u03a9\u0314", "\u1f68\u0300", "\u1f69\u0300", "\u1f68\u0301", "\u1f69\u0301", "\u1f68\u0342", "\u1f69\u0342", "\u03b1\u0300", "\u03ac", "\u03b5\u0300", "\u03ad", "\u03b7\u0300", "\u03ae", "\u03b9\u0300", "\u03af", "\u03bf\u0300", "\u03cc", "\u03c5\u0300", "\u03cd", "\u03c9\u0300", "\u03ce", "\u1f00\u0345", "\u1f01\u0345", "\u1f02\u0345", "\u1f03\u0345", "\u1f04\u0345", "\u1f05\u0345", "\u1f06\u0345", "\u1f07\u0345", "\u1f08\u0345", "\u1f09\u0345", "\u1f0a\u0345", "\u1f0b\u0345", "\u1f0c\u0345", "\u1f0d\u0345", "\u1f0e\u0345", "\u1f0f\u0345", "\u1f20\u0345", "\u1f21\u0345", "\u1f22\u0345", "\u1f23\u0345", "\u1f24\u0345", "\u1f25\u0345", "\u1f26\u0345", "\u1f27\u0345", "\u1f28\u0345", "\u1f29\u0345", "\u1f2a\u0345", "\u1f2b\u0345", "\u1f2c\u0345", "\u1f2d\u0345", "\u1f2e\u0345", "\u1f2f\u0345", "\u1f60\u0345", "\u1f61\u0345", "\u1f62\u0345", "\u1f63\u0345", "\u1f64\u0345", "\u1f65\u0345", "\u1f66\u0345", "\u1f67\u0345", "\u1f68\u0345", "\u1f69\u0345", "\u1f6a\u0345", "\u1f6b\u0345", "\u1f6c\u0345", "\u1f6d\u0345", "\u1f6e\u0345", "\u1f6f\u0345", "\u03b1\u0306", "\u03b1\u0304", "\u1f70\u0345", "\u03b1\u0345", "\u03ac\u0345", "\u03b1\u0342", "\u1fb6\u0345", "\u0391\u0306", "\u0391\u0304", "\u0391\u0300", "\u0386", "\u0391\u0345", "\u0020\u0313", "\u03b9", "\u0020\u0313", "\u0020\u0342", "\u00a8\u0342", "\u1f74\u0345", "\u03b7\u0345", "\u03ae\u0345", "\u03b7\u0342", "\u1fc6\u0345", "\u0395\u0300", "\u0388", "\u0397\u0300", "\u0389", "\u0397\u0345", "\u1fbf\u0300", "\u1fbf\u0301", "\u1fbf\u0342", "\u03b9\u0306", "\u03b9\u0304", "\u03ca\u0300", "\u0390", "\u03b9\u0342", "\u03ca\u0342", "\u0399\u0306", "\u0399\u0304", "\u0399\u0300", "\u038a", "\u1ffe\u0300", "\u1ffe\u0301", "\u1ffe\u0342", "\u03c5\u0306", "\u03c5\u0304", "\u03cb\u0300", "\u03b0", "\u03c1\u0313", "\u03c1\u0314", "\u03c5\u0342", "\u03cb\u0342", "\u03a5\u0306", "\u03a5\u0304", "\u03a5\u0300", "\u038e", "\u03a1\u0314", "\u00a8\u0300", "\u0385", "`", "\u1f7c\u0345", "\u03c9\u0345", "\u03ce\u0345", "\u03c9\u0342", "\u1ff6\u0345", "\u039f\u0300", "\u038c", "\u03a9\u0300", "\u038f", "\u03a9\u0345", "\u00b4", "\u0020\u0314", "\u2002", "\u2003", "\u0020", "\u0020", "\u0020", "\u0020", "\u0020", "\u0020", "\u0020", "\u0020", "\u0020", "\u2010", "\u0020\u0333", ".", "..", "...", "\u0020", "\u2032\u2032", "\u2032\u2032\u2032", "\u2035\u2035", "\u2035\u2035\u2035", "!!", "\u0020\u0305", "??", "?!", "!?", "\u2032\u2032\u2032\u2032", "\u0020", "0", "i", "4", "5", "6", "7", "8", "9", "+", "\u2212", "=", "(", ")", "n", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "+", "\u2212", "=", "(", ")", "a", "e", "o", "x", "\u0259", "Rs", "a/c", "a/s", "C", "\u00b0C", "c/o", "c/u", "\u0190", "\u00b0F", "g", "H", "H", "H", "h", "\u0127", "I", "I", "L", "l", "N", "No", "P", "Q", "R", "R", "R", "SM", "TEL", "TM", "Z", "\u03a9", "Z", "K", "\u00c5", "B", "C", "e", "E", "F", "M", "o", "\u05d0", "\u05d1", "\u05d2", "\u05d3", "i", "FAX", "\u03c0", "\u03b3", "\u0393", "\u03a0", "\u2211", "D", "d", "e", "i", "j", "1\u20443", "2\u20443", "1\u20445", "2\u20445", "3\u20445", "4\u20445", "1\u20446", "5\u20446", "1\u20448", "3\u20448", "5\u20448", "7\u20448", "1\u2044", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X", "XI", "XII", "L", "C", "D", "M", "i", "ii", "iii", "iv", "v", "vi", "vii", "viii", "ix", "x", "xi", "xii", "l", "c", "d", "m", "\u2190\u0338", "\u2192\u0338", "\u2194\u0338", "\u21d0\u0338", "\u21d4\u0338", "\u21d2\u0338", "\u2203\u0338", "\u2208\u0338", "\u220b\u0338", "\u2223\u0338", "\u2225\u0338", "\u222b\u222b", "\u222b\u222b\u222b", "\u222e\u222e", "\u222e\u222e\u222e", "\u223c\u0338", "\u2243\u0338", "\u2245\u0338", "\u2248\u0338", "=\u0338", "\u2261\u0338", "\u224d\u0338", "<\u0338", ">\u0338", "\u2264\u0338", "\u2265\u0338", "\u2272\u0338", "\u2273\u0338", "\u2276\u0338", "\u2277\u0338", "\u227a\u0338", "\u227b\u0338", "\u2282\u0338", "\u2283\u0338", "\u2286\u0338", "\u2287\u0338", "\u22a2\u0338", "\u22a8\u0338", "\u22a9\u0338", "\u22ab\u0338", "\u227c\u0338", "\u227d\u0338", "\u2291\u0338", "\u2292\u0338", "\u22b2\u0338", "\u22b3\u0338", "\u22b4\u0338", "\u22b5\u0338", "\u3008", "\u3009", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "(1)", "(2)", "(3)", "(4)", "(5)", "(6)", "(7)", "(8)", "(9)", "(10)", "(11)", "(12)", "(13)", "(14)", "(15)", "(16)", "(17)", "(18)", "(19)", "(20)", "1.", "2.", "3.", "4.", "5.", "6.", "7.", "8.", "9.", "10.", "11.", "12.", "13.", "14.", "15.", "16.", "17.", "18.", "19.", "20.", "(a)", "(b)", "(c)", "(d)", "(e)", "(f)", "(g)", "(h)", "(i)", "(j)", "(k)", "(l)", "(m)", "(n)", "(o)", "(p)", "(q)", "(r)", "(s)", "(t)", "(u)", "(v)", "(w)", "(x)", "(y)", "(z)", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "0", "\u222b\u222b\u222b\u222b", "::=", "==", "===", "\u2add\u0338", "\u2d61", "\u6bcd", "\u9f9f", "\u4e00", "\u4e28", "\u4e36", "\u4e3f", "\u4e59", "\u4e85", "\u4e8c", "\u4ea0", "\u4eba", "\u513f", "\u5165", "\u516b", "\u5182", "\u5196", "\u51ab", "\u51e0", "\u51f5", "\u5200", "\u529b", "\u52f9", "\u5315", "\u531a", "\u5338", "\u5341", "\u535c", "\u5369", "\u5382", "\u53b6", "\u53c8", "\u53e3", "\u56d7", "\u571f", "\u58eb", "\u5902", "\u590a", "\u5915", "\u5927", "\u5973", "\u5b50", "\u5b80", "\u5bf8", "\u5c0f", "\u5c22", "\u5c38", "\u5c6e", "\u5c71", "\u5ddb", "\u5de5", "\u5df1", "\u5dfe", "\u5e72", "\u5e7a", "\u5e7f", "\u5ef4", "\u5efe", "\u5f0b", "\u5f13", "\u5f50", "\u5f61", "\u5f73", "\u5fc3", "\u6208", "\u6236", "\u624b", "\u652f", "\u6534", "\u6587", "\u6597", "\u65a4", "\u65b9", "\u65e0", "\u65e5", "\u66f0", "\u6708", "\u6728", "\u6b20", "\u6b62", "\u6b79", "\u6bb3", "\u6bcb", "\u6bd4", "\u6bdb", "\u6c0f", "\u6c14", "\u6c34", "\u706b", "\u722a", "\u7236", "\u723b", "\u723f", "\u7247", "\u7259", "\u725b", "\u72ac", "\u7384", "\u7389", "\u74dc", "\u74e6", "\u7518", "\u751f", "\u7528", "\u7530", "\u758b", "\u7592", "\u7676", "\u767d", "\u76ae", "\u76bf", "\u76ee", "\u77db", "\u77e2", "\u77f3", "\u793a", "\u79b8", "\u79be", "\u7a74", "\u7acb", "\u7af9", "\u7c73", "\u7cf8", "\u7f36", "\u7f51", "\u7f8a", "\u7fbd", "\u8001", "\u800c", "\u8012", "\u8033", "\u807f", "\u8089", "\u81e3", "\u81ea", "\u81f3", "\u81fc", "\u820c", "\u821b", "\u821f", "\u826e", "\u8272", "\u8278", "\u864d", "\u866b", "\u8840", "\u884c", "\u8863", "\u897e", "\u898b", "\u89d2", "\u8a00", "\u8c37", "\u8c46", "\u8c55", "\u8c78", "\u8c9d", "\u8d64", "\u8d70", "\u8db3", "\u8eab", "\u8eca", "\u8f9b", "\u8fb0", "\u8fb5", "\u9091", "\u9149", "\u91c6", "\u91cc", "\u91d1", "\u9577", "\u9580", "\u961c", "\u96b6", "\u96b9", "\u96e8", "\u9751", "\u975e", "\u9762", "\u9769", "\u97cb", "\u97ed", "\u97f3", "\u9801", "\u98a8", "\u98db", "\u98df", "\u9996", "\u9999", "\u99ac", "\u9aa8", "\u9ad8", "\u9adf", "\u9b25", "\u9b2f", "\u9b32", "\u9b3c", "\u9b5a", "\u9ce5", "\u9e75", "\u9e7f", "\u9ea5", "\u9ebb", "\u9ec3", "\u9ecd", "\u9ed1", "\u9ef9", "\u9efd", "\u9f0e", "\u9f13", "\u9f20", "\u9f3b", "\u9f4a", "\u9f52", "\u9f8d", "\u9f9c", "\u9fa0", "\u0020", "\u3012", "\u5341", "\u5344", "\u5345", "\u304b\u3099", "\u304d\u3099", "\u304f\u3099", "\u3051\u3099", "\u3053\u3099", "\u3055\u3099", "\u3057\u3099", "\u3059\u3099", "\u305b\u3099", "\u305d\u3099", "\u305f\u3099", "\u3061\u3099", "\u3064\u3099", "\u3066\u3099", "\u3068\u3099", "\u306f\u3099", "\u306f\u309a", "\u3072\u3099", "\u3072\u309a", "\u3075\u3099", "\u3075\u309a", "\u3078\u3099", "\u3078\u309a", "\u307b\u3099", "\u307b\u309a", "\u3046\u3099", "\u0020\u3099", "\u0020\u309a", "\u309d\u3099", "\u3088\u308a", "\u30ab\u3099", "\u30ad\u3099", "\u30af\u3099", "\u30b1\u3099", "\u30b3\u3099", "\u30b5\u3099", "\u30b7\u3099", "\u30b9\u3099", "\u30bb\u3099", "\u30bd\u3099", "\u30bf\u3099", "\u30c1\u3099", "\u30c4\u3099", "\u30c6\u3099", "\u30c8\u3099", "\u30cf\u3099", "\u30cf\u309a", "\u30d2\u3099", "\u30d2\u309a", "\u30d5\u3099", "\u30d5\u309a", "\u30d8\u3099", "\u30d8\u309a", "\u30db\u3099", "\u30db\u309a", "\u30a6\u3099", "\u30ef\u3099", "\u30f0\u3099", "\u30f1\u3099", "\u30f2\u3099", "\u30fd\u3099", "\u30b3\u30c8", "\u1100", "\u1101", "\u11aa", "\u1102", "\u11ac", "\u11ad", "\u1103", "\u1104", "\u1105", "\u11b0", "\u11b1", "\u11b2", "\u11b3", "\u11b4", "\u11b5", "\u111a", "\u1106", "\u1107", "\u1108", "\u1121", "\u1109", "\u110a", "\u110b", "\u110c", "\u110d", "\u110e", "\u110f", "\u1110", "\u1111", "\u1112", "\u1161", "\u1162", "\u1163", "\u1164", "\u1165", "\u1166", "\u1167", "\u1168", "\u1169", "\u116a", "\u116b", "\u116c", "\u116d", "\u116e", "\u116f", "\u1170", "\u1171", "\u1172", "\u1173", "\u1174", "\u1175", "\u1160", "\u1114", "\u1115", "\u11c7", "\u11c8", "\u11cc", "\u11ce", "\u11d3", "\u11d7", "\u11d9", "\u111c", "\u11dd", "\u11df", "\u111d", "\u111e", "\u1120", "\u1122", "\u1123", "\u1127", "\u1129", "\u112b", "\u112c", "\u112d", "\u112e", "\u112f", "\u1132", "\u1136", "\u1140", "\u1147", "\u114c", "\u11f1", "\u11f2", "\u1157", "\u1158", "\u1159", "\u1184", "\u1185", "\u1188", "\u1191", "\u1192", "\u1194", "\u119e", "\u11a1", "\u4e00", "\u4e8c", "\u4e09", "\u56db", "\u4e0a", "\u4e2d", "\u4e0b", "\u7532", "\u4e59", "\u4e19", "\u4e01", "\u5929", "\u5730", "\u4eba", "(\u1100)", "(\u1102)", "(\u1103)", "(\u1105)", "(\u1106)", "(\u1107)", "(\u1109)", "(\u110b)", "(\u110c)", "(\u110e)", "(\u110f)", "(\u1110)", "(\u1111)", "(\u1112)", "(\u1100\u1161)", "(\u1102\u1161)", "(\u1103\u1161)", "(\u1105\u1161)", "(\u1106\u1161)", "(\u1107\u1161)", "(\u1109\u1161)", "(\u110b\u1161)", "(\u110c\u1161)", "(\u110e\u1161)", "(\u110f\u1161)", "(\u1110\u1161)", "(\u1111\u1161)", "(\u1112\u1161)", "(\u110c\u116e)", "(\u110b\u1169\u110c\u1165\u11ab)", "(\u110b\u1169\u1112\u116e)", "(\u4e00)", "(\u4e8c)", "(\u4e09)", "(\u56db)", "(\u4e94)", "(\u516d)", "(\u4e03)", "(\u516b)", "(\u4e5d)", "(\u5341)", "(\u6708)", "(\u706b)", "(\u6c34)", "(\u6728)", "(\u91d1)", "(\u571f)", "(\u65e5)", "(\u682a)", "(\u6709)", "(\u793e)", "(\u540d)", "(\u7279)", "(\u8ca1)", "(\u795d)", "(\u52b4)", "(\u4ee3)", "(\u547c)", "(\u5b66)", "(\u76e3)", "(\u4f01)", "(\u8cc7)", "(\u5354)", "(\u796d)", "(\u4f11)", "(\u81ea)", "(\u81f3)", "PTE", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32", "33", "34", "35", "\u1100", "\u1102", "\u1103", "\u1105", "\u1106", "\u1107", "\u1109", "\u110b", "\u110c", "\u110e", "\u110f", "\u1110", "\u1111", "\u1112", "\u1100\u1161", "\u1102\u1161", "\u1103\u1161", "\u1105\u1161", "\u1106\u1161", "\u1107\u1161", "\u1109\u1161", "\u110b\u1161", "\u110c\u1161", "\u110e\u1161", "\u110f\u1161", "\u1110\u1161", "\u1111\u1161", "\u1112\u1161", "\u110e\u1161\u11b7\u1100\u1169", "\u110c\u116e\u110b\u1174", "\u110b\u116e", "\u4e00", "\u4e8c", "\u4e09", "\u56db", "\u4e94", "\u516d", "\u4e03", "\u516b", "\u4e5d", "\u5341", "\u6708", "\u706b", "\u6c34", "\u6728", "\u91d1", "\u571f", "\u65e5", "\u682a", "\u6709", "\u793e", "\u540d", "\u7279", "\u8ca1", "\u795d", "\u52b4", "\u79d8", "\u7537", "\u5973", "\u9069", "\u512a", "\u5370", "\u6ce8", "\u9805", "\u4f11", "\u5199", "\u6b63", "\u4e0a", "\u4e2d", "\u4e0b", "\u5de6", "\u53f3", "\u533b", "\u5b97", "\u5b66", "\u76e3", "\u4f01", "\u8cc7", "\u5354", "\u591c", "36", "37", "38", "39", "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "50", "1\u6708", "2\u6708", "3\u6708", "4\u6708", "5\u6708", "6\u6708", "7\u6708", "8\u6708", "9\u6708", "10\u6708", "11\u6708", "12\u6708", "Hg", "erg", "eV", "LTD", "\u30a2", "\u30a4", "\u30a6", "\u30a8", "\u30aa", "\u30ab", "\u30ad", "\u30af", "\u30b1", "\u30b3", "\u30b5", "\u30b7", "\u30b9", "\u30bb", "\u30bd", "\u30bf", "\u30c1", "\u30c4", "\u30c6", "\u30c8", "\u30ca", "\u30cb", "\u30cc", "\u30cd", "\u30ce", "\u30cf", "\u30d2", "\u30d5", "\u30d8", "\u30db", "\u30de", "\u30df", "\u30e0", "\u30e1", "\u30e2", "\u30e4", "\u30e6", "\u30e8", "\u30e9", "\u30ea", "\u30eb", "\u30ec", "\u30ed", "\u30ef", "\u30f0", "\u30f1", "\u30f2", "\u30a2\u30d1\u30fc\u30c8", "\u30a2\u30eb\u30d5\u30a1", "\u30a2\u30f3\u30da\u30a2", "\u30a2\u30fc\u30eb", "\u30a4\u30cb\u30f3\u30b0", "\u30a4\u30f3\u30c1", "\u30a6\u30a9\u30f3", "\u30a8\u30b9\u30af\u30fc\u30c9", "\u30a8\u30fc\u30ab\u30fc", "\u30aa\u30f3\u30b9", "\u30aa\u30fc\u30e0", "\u30ab\u30a4\u30ea", "\u30ab\u30e9\u30c3\u30c8", "\u30ab\u30ed\u30ea\u30fc", "\u30ac\u30ed\u30f3", "\u30ac\u30f3\u30de", "\u30ae\u30ac", "\u30ae\u30cb\u30fc", "\u30ad\u30e5\u30ea\u30fc", "\u30ae\u30eb\u30c0\u30fc", "\u30ad\u30ed", "\u30ad\u30ed\u30b0\u30e9\u30e0", "\u30ad\u30ed\u30e1\u30fc\u30c8\u30eb", "\u30ad\u30ed\u30ef\u30c3\u30c8", "\u30b0\u30e9\u30e0", "\u30b0\u30e9\u30e0\u30c8\u30f3", "\u30af\u30eb\u30bc\u30a4\u30ed", "\u30af\u30ed\u30fc\u30cd", "\u30b1\u30fc\u30b9", "\u30b3\u30eb\u30ca", "\u30b3\u30fc\u30dd", "\u30b5\u30a4\u30af\u30eb", "\u30b5\u30f3\u30c1\u30fc\u30e0", "\u30b7\u30ea\u30f3\u30b0", "\u30bb\u30f3\u30c1", "\u30bb\u30f3\u30c8", "\u30c0\u30fc\u30b9", "\u30c7\u30b7", "\u30c9\u30eb", "\u30c8\u30f3", "\u30ca\u30ce", "\u30ce\u30c3\u30c8", "\u30cf\u30a4\u30c4", "\u30d1\u30fc\u30bb\u30f3\u30c8", "\u30d1\u30fc\u30c4", "\u30d0\u30fc\u30ec\u30eb", "\u30d4\u30a2\u30b9\u30c8\u30eb", "\u30d4\u30af\u30eb", "\u30d4\u30b3", "\u30d3\u30eb", "\u30d5\u30a1\u30e9\u30c3\u30c9", "\u30d5\u30a3\u30fc\u30c8", "\u30d6\u30c3\u30b7\u30a7\u30eb", "\u30d5\u30e9\u30f3", "\u30d8\u30af\u30bf\u30fc\u30eb", "\u30da\u30bd", "\u30da\u30cb\u30d2", "\u30d8\u30eb\u30c4", "\u30da\u30f3\u30b9", "\u30da\u30fc\u30b8", "\u30d9\u30fc\u30bf", "\u30dd\u30a4\u30f3\u30c8", "\u30dc\u30eb\u30c8", "\u30db\u30f3", "\u30dd\u30f3\u30c9", "\u30db\u30fc\u30eb", "\u30db\u30fc\u30f3", "\u30de\u30a4\u30af\u30ed", "\u30de\u30a4\u30eb", "\u30de\u30c3\u30cf", "\u30de\u30eb\u30af", "\u30de\u30f3\u30b7\u30e7\u30f3", "\u30df\u30af\u30ed\u30f3", "\u30df\u30ea", "\u30df\u30ea\u30d0\u30fc\u30eb", "\u30e1\u30ac", "\u30e1\u30ac\u30c8\u30f3", "\u30e1\u30fc\u30c8\u30eb", "\u30e4\u30fc\u30c9", "\u30e4\u30fc\u30eb", "\u30e6\u30a2\u30f3", "\u30ea\u30c3\u30c8\u30eb", "\u30ea\u30e9", "\u30eb\u30d4\u30fc", "\u30eb\u30fc\u30d6\u30eb", "\u30ec\u30e0", "\u30ec\u30f3\u30c8\u30b2\u30f3", "\u30ef\u30c3\u30c8", "0\u70b9", "1\u70b9", "2\u70b9", "3\u70b9", "4\u70b9", "5\u70b9", "6\u70b9", "7\u70b9", "8\u70b9", "9\u70b9", "10\u70b9", "11\u70b9", "12\u70b9", "13\u70b9", "14\u70b9", "15\u70b9", "16\u70b9", "17\u70b9", "18\u70b9", "19\u70b9", "20\u70b9", "21\u70b9", "22\u70b9", "23\u70b9", "24\u70b9", "hPa", "da", "AU", "bar", "oV", "pc", "dm", "dm\u00b2", "dm\u00b3", "IU", "\u5e73\u6210", "\u662d\u548c", "\u5927\u6b63", "\u660e\u6cbb", "\u682a\u5f0f\u4f1a\u793e", "pA", "nA", "\u03bcA", "mA", "kA", "KB", "MB", "GB", "cal", "kcal", "pF", "nF", "\u03bcF", "\u03bcg", "mg", "kg", "Hz", "kHz", "MHz", "GHz", "THz", "\u03bc\u2113", "m\u2113", "d\u2113", "k\u2113", "fm", "nm", "\u03bcm", "mm", "cm", "km", "mm\u00b2", "cm\u00b2", "m\u00b2", "km\u00b2", "mm\u00b3", "cm\u00b3", "m\u00b3", "km\u00b3", "m\u2215s", "m\u2215s\u00b2", "Pa", "kPa", "MPa", "GPa", "rad", "rad\u2215s", "rad\u2215s\u00b2", "ps", "ns", "\u03bcs", "ms", "pV", "nV", "\u03bcV", "mV", "kV", "MV", "pW", "nW", "\u03bcW", "mW", "kW", "MW", "k\u03a9", "M\u03a9", "a.m.", "Bq", "cc", "cd", "C\u2215kg", "Co.", "dB", "Gy", "ha", "HP", "in", "KK", "KM", "kt", "lm", "ln", "log", "lx", "mb", "mil", "mol", "PH", "p.m.", "PPM", "PR", "sr", "Sv", "Wb", "V\u2215m", "A\u2215m", "1\u65e5", "2\u65e5", "3\u65e5", "4\u65e5", "5\u65e5", "6\u65e5", "7\u65e5", "8\u65e5", "9\u65e5", "10\u65e5", "11\u65e5", "12\u65e5", "13\u65e5", "14\u65e5", "15\u65e5", "16\u65e5", "17\u65e5", "18\u65e5", "19\u65e5", "20\u65e5", "21\u65e5", "22\u65e5", "23\u65e5", "24\u65e5", "25\u65e5", "26\u65e5", "27\u65e5", "28\u65e5", "29\u65e5", "30\u65e5", "31\u65e5", "gal", "\u8c48", "\u66f4", "\u8eca", "\u8cc8", "\u6ed1", "\u4e32", "\u53e5", "\u9f9c", "\u9f9c", "\u5951", "\u91d1", "\u5587", "\u5948", "\u61f6", "\u7669", "\u7f85", "\u863f", "\u87ba", "\u88f8", "\u908f", "\u6a02", "\u6d1b", "\u70d9", "\u73de", "\u843d", "\u916a", "\u99f1", "\u4e82", "\u5375", "\u6b04", "\u721b", "\u862d", "\u9e1e", "\u5d50", "\u6feb", "\u85cd", "\u8964", "\u62c9", "\u81d8", "\u881f", "\u5eca", "\u6717", "\u6d6a", "\u72fc", "\u90ce", "\u4f86", "\u51b7", "\u52de", "\u64c4", "\u6ad3", "\u7210", "\u76e7", "\u8001", "\u8606", "\u865c", "\u8def", "\u9732", "\u9b6f", "\u9dfa", "\u788c", "\u797f", "\u7da0", "\u83c9", "\u9304", "\u9e7f", "\u8ad6", "\u58df", "\u5f04", "\u7c60", "\u807e", "\u7262", "\u78ca", "\u8cc2", "\u96f7", "\u58d8", "\u5c62", "\u6a13", "\u6dda", "\u6f0f", "\u7d2f", "\u7e37", "\u964b", "\u52d2", "\u808b", "\u51dc", "\u51cc", "\u7a1c", "\u7dbe", "\u83f1", "\u9675", "\u8b80", "\u62cf", "\u6a02", "\u8afe", "\u4e39", "\u5be7", "\u6012", "\u7387", "\u7570", "\u5317", "\u78fb", "\u4fbf", "\u5fa9", "\u4e0d", "\u6ccc", "\u6578", "\u7d22", "\u53c3", "\u585e", "\u7701", "\u8449", "\u8aaa", "\u6bba", "\u8fb0", "\u6c88", "\u62fe", "\u82e5", "\u63a0", "\u7565", "\u4eae", "\u5169", "\u51c9", "\u6881", "\u7ce7", "\u826f", "\u8ad2", "\u91cf", "\u52f5", "\u5442", "\u5973", "\u5eec", "\u65c5", "\u6ffe", "\u792a", "\u95ad", "\u9a6a", "\u9e97", "\u9ece", "\u529b", "\u66c6", "\u6b77", "\u8f62", "\u5e74", "\u6190", "\u6200", "\u649a", "\u6f23", "\u7149", "\u7489", "\u79ca", "\u7df4", "\u806f", "\u8f26", "\u84ee", "\u9023", "\u934a", "\u5217", "\u52a3", "\u54bd", "\u70c8", "\u88c2", "\u8aaa", "\u5ec9", "\u5ff5", "\u637b", "\u6bae", "\u7c3e", "\u7375", "\u4ee4", "\u56f9", "\u5be7", "\u5dba", "\u601c", "\u73b2", "\u7469", "\u7f9a", "\u8046", "\u9234", "\u96f6", "\u9748", "\u9818", "\u4f8b", "\u79ae", "\u91b4", "\u96b8", "\u60e1", "\u4e86", "\u50da", "\u5bee", "\u5c3f", "\u6599", "\u6a02", "\u71ce", "\u7642", "\u84fc", "\u907c", "\u9f8d", "\u6688", "\u962e", "\u5289", "\u677b", "\u67f3", "\u6d41", "\u6e9c", "\u7409", "\u7559", "\u786b", "\u7d10", "\u985e", "\u516d", "\u622e", "\u9678", "\u502b", "\u5d19", "\u6dea", "\u8f2a", "\u5f8b", "\u6144", "\u6817", "\u7387", "\u9686", "\u5229", "\u540f", "\u5c65", "\u6613", "\u674e", "\u68a8", "\u6ce5", "\u7406", "\u75e2", "\u7f79", "\u88cf", "\u88e1", "\u91cc", "\u96e2", "\u533f", "\u6eba", "\u541d", "\u71d0", "\u7498", "\u85fa", "\u96a3", "\u9c57", "\u9e9f", "\u6797", "\u6dcb", "\u81e8", "\u7acb", "\u7b20", "\u7c92", "\u72c0", "\u7099", "\u8b58", "\u4ec0", "\u8336", "\u523a", "\u5207", "\u5ea6", "\u62d3", "\u7cd6", "\u5b85", "\u6d1e", "\u66b4", "\u8f3b", "\u884c", "\u964d", "\u898b", "\u5ed3", "\u5140", "\u55c0", "\u585a", "\u6674", "\u51de", "\u732a", "\u76ca", "\u793c", "\u795e", "\u7965", "\u798f", "\u9756", "\u7cbe", "\u7fbd", "\u8612", "\u8af8", "\u9038", "\u90fd", "\u98ef", "\u98fc", "\u9928", "\u9db4", "\u4fae", "\u50e7", "\u514d", "\u52c9", "\u52e4", "\u5351", "\u559d", "\u5606", "\u5668", "\u5840", "\u58a8", "\u5c64", "\u5c6e", "\u6094", "\u6168", "\u618e", "\u61f2", "\u654f", "\u65e2", "\u6691", "\u6885", "\u6d77", "\u6e1a", "\u6f22", "\u716e", "\u722b", "\u7422", "\u7891", "\u793e", "\u7949", "\u7948", "\u7950", "\u7956", "\u795d", "\u798d", "\u798e", "\u7a40", "\u7a81", "\u7bc0", "\u7df4", "\u7e09", "\u7e41", "\u7f72", "\u8005", "\u81ed", "\u8279", "\u8279", "\u8457", "\u8910", "\u8996", "\u8b01", "\u8b39", "\u8cd3", "\u8d08", "\u8fb6", "\u9038", "\u96e3", "\u97ff", "\u983b", "\u4e26", "\u51b5", "\u5168", "\u4f80", "\u5145", "\u5180", "\u52c7", "\u52fa", "\u559d", "\u5555", "\u5599", "\u55e2", "\u585a", "\u58b3", "\u5944", "\u5954", "\u5a62", "\u5b28", "\u5ed2", "\u5ed9", "\u5f69", "\u5fad", "\u60d8", "\u614e", "\u6108", "\u618e", "\u6160", "\u61f2", "\u6234", "\u63c4", "\u641c", "\u6452", "\u6556", "\u6674", "\u6717", "\u671b", "\u6756", "\u6b79", "\u6bba", "\u6d41", "\u6edb", "\u6ecb", "\u6f22", "\u701e", "\u716e", "\u77a7", "\u7235", "\u72af", "\u732a", "\u7471", "\u7506", "\u753b", "\u761d", "\u761f", "\u76ca", "\u76db", "\u76f4", "\u774a", "\u7740", "\u78cc", "\u7ab1", "\u7bc0", "\u7c7b", "\u7d5b", "\u7df4", "\u7f3e", "\u8005", "\u8352", "\u83ef", "\u8779", "\u8941", "\u8986", "\u8996", "\u8abf", "\u8af8", "\u8acb", "\u8b01", "\u8afe", "\u8aed", "\u8b39", "\u8b8a", "\u8d08", "\u8f38", "\u9072", "\u9199", "\u9276", "\u967c", "\u96e3", "\u9756", "\u97db", "\u97ff", "\u980b", "\u983b", "\u9b12", "\u9f9c", "\u284a", "\u2844", "\u33d5", "\u3b9d", "\u4018", "\u4039", "\u5249", "\u5cd0", "\u7ed3", "\u9f43", "\u9f8e", "ff", "fi", "fl", "ffi", "ffl", "\u017ft", "st", "\u0574\u0576", "\u0574\u0565", "\u0574\u056b", "\u057e\u0576", "\u0574\u056d", "\u05d9\u05b4", "\u05f2\u05b7", "\u05e2", "\u05d0", "\u05d3", "\u05d4", "\u05db", "\u05dc", "\u05dd", "\u05e8", "\u05ea", "+", "\u05e9\u05c1", "\u05e9\u05c2", "\ufb49\u05c1", "\ufb49\u05c2", "\u05d0\u05b7", "\u05d0\u05b8", "\u05d0\u05bc", "\u05d1\u05bc", "\u05d2\u05bc", "\u05d3\u05bc", "\u05d4\u05bc", "\u05d5\u05bc", "\u05d6\u05bc", "\u05d8\u05bc", "\u05d9\u05bc", "\u05da\u05bc", "\u05db\u05bc", "\u05dc\u05bc", "\u05de\u05bc", "\u05e0\u05bc", "\u05e1\u05bc", "\u05e3\u05bc", "\u05e4\u05bc", "\u05e6\u05bc", "\u05e7\u05bc", "\u05e8\u05bc", "\u05e9\u05bc", "\u05ea\u05bc", "\u05d5\u05b9", "\u05d1\u05bf", "\u05db\u05bf", "\u05e4\u05bf", "\u05d0\u05dc", "\u0671", "\u0671", "\u067b", "\u067b", "\u067b", "\u067b", "\u067e", "\u067e", "\u067e", "\u067e", "\u0680", "\u0680", "\u0680", "\u0680", "\u067a", "\u067a", "\u067a", "\u067a", "\u067f", "\u067f", "\u067f", "\u067f", "\u0679", "\u0679", "\u0679", "\u0679", "\u06a4", "\u06a4", "\u06a4", "\u06a4", "\u06a6", "\u06a6", "\u06a6", "\u06a6", "\u0684", "\u0684", "\u0684", "\u0684", "\u0683", "\u0683", "\u0683", "\u0683", "\u0686", "\u0686", "\u0686", "\u0686", "\u0687", "\u0687", "\u0687", "\u0687", "\u068d", "\u068d", "\u068c", "\u068c", "\u068e", "\u068e", "\u0688", "\u0688", "\u0698", "\u0698", "\u0691", "\u0691", "\u06a9", "\u06a9", "\u06a9", "\u06a9", "\u06af", "\u06af", "\u06af", "\u06af", "\u06b3", "\u06b3", "\u06b3", "\u06b3", "\u06b1", "\u06b1", "\u06b1", "\u06b1", "\u06ba", "\u06ba", "\u06bb", "\u06bb", "\u06bb", "\u06bb", "\u06c0", "\u06c0", "\u06c1", "\u06c1", "\u06c1", "\u06c1", "\u06be", "\u06be", "\u06be", "\u06be", "\u06d2", "\u06d2", "\u06d3", "\u06d3", "\u06ad", "\u06ad", "\u06ad", "\u06ad", "\u06c7", "\u06c7", "\u06c6", "\u06c6", "\u06c8", "\u06c8", "\u0677", "\u06cb", "\u06cb", "\u06c5", "\u06c5", "\u06c9", "\u06c9", "\u06d0", "\u06d0", "\u06d0", "\u06d0", "\u0649", "\u0649", "\u0626\u0627", "\u0626\u0627", "\u0626\u06d5", "\u0626\u06d5", "\u0626\u0648", "\u0626\u0648", "\u0626\u06c7", "\u0626\u06c7", "\u0626\u06c6", "\u0626\u06c6", "\u0626\u06c8", "\u0626\u06c8", "\u0626\u06d0", "\u0626\u06d0", "\u0626\u06d0", "\u0626\u0649", "\u0626\u0649", "\u0626\u0649", "\u06cc", "\u06cc", "\u06cc", "\u06cc", "\u0626\u062c", "\u0626\u062d", "\u0626\u0645", "\u0626\u0649", "\u0626\u064a", "\u0628\u062c", "\u0628\u062d", "\u0628\u062e", "\u0628\u0645", "\u0628\u0649", "\u0628\u064a", "\u062a\u062c", "\u062a\u062d", "\u062a\u062e", "\u062a\u0645", "\u062a\u0649", "\u062a\u064a", "\u062b\u062c", "\u062b\u0645", "\u062b\u0649", "\u062b\u064a", "\u062c\u062d", "\u062c\u0645", "\u062d\u062c", "\u062d\u0645", "\u062e\u062c", "\u062e\u062d", "\u062e\u0645", "\u0633\u062c", "\u0633\u062d", "\u0633\u062e", "\u0633\u0645", "\u0635\u062d", "\u0635\u0645", "\u0636\u062c", "\u0636\u062d", "\u0636\u062e", "\u0636\u0645", "\u0637\u062d", "\u0637\u0645", "\u0638\u0645", "\u0639\u062c", "\u0639\u0645", "\u063a\u062c", "\u063a\u0645", "\u0641\u062c", "\u0641\u062d", "\u0641\u062e", "\u0641\u0645", "\u0641\u0649", "\u0641\u064a", "\u0642\u062d", "\u0642\u0645", "\u0642\u0649", "\u0642\u064a", "\u0643\u0627", "\u0643\u062c", "\u0643\u062d", "\u0643\u062e", "\u0643\u0644", "\u0643\u0645", "\u0643\u0649", "\u0643\u064a", "\u0644\u062c", "\u0644\u062d", "\u0644\u062e", "\u0644\u0645", "\u0644\u0649", "\u0644\u064a", "\u0645\u062c", "\u0645\u062d", "\u0645\u062e", "\u0645\u0645", "\u0645\u0649", "\u0645\u064a", "\u0646\u062c", "\u0646\u062d", "\u0646\u062e", "\u0646\u0645", "\u0646\u0649", "\u0646\u064a", "\u0647\u062c", "\u0647\u0645", "\u0647\u0649", "\u0647\u064a", "\u064a\u062c", "\u064a\u062d", "\u064a\u062e", "\u064a\u0645", "\u064a\u0649", "\u064a\u064a", "\u0630\u0670", "\u0631\u0670", "\u0649\u0670", "\u0020\u064c\u0651", "\u0020\u064d\u0651", "\u0020\u064e\u0651", "\u0020\u064f\u0651", "\u0020\u0650\u0651", "\u0020\u0651\u0670", "\u0626\u0631", "\u0626\u0632", "\u0626\u0645", "\u0626\u0646", "\u0626\u0649", "\u0626\u064a", "\u0628\u0631", "\u0628\u0632", "\u0628\u0645", "\u0628\u0646", "\u0628\u0649", "\u0628\u064a", "\u062a\u0631", "\u062a\u0632", "\u062a\u0645", "\u062a\u0646", "\u062a\u0649", "\u062a\u064a", "\u062b\u0631", "\u062b\u0632", "\u062b\u0645", "\u062b\u0646", "\u062b\u0649", "\u062b\u064a", "\u0641\u0649", "\u0641\u064a", "\u0642\u0649", "\u0642\u064a", "\u0643\u0627", "\u0643\u0644", "\u0643\u0645", "\u0643\u0649", "\u0643\u064a", "\u0644\u0645", "\u0644\u0649", "\u0644\u064a", "\u0645\u0627", "\u0645\u0645", "\u0646\u0631", "\u0646\u0632", "\u0646\u0645", "\u0646\u0646", "\u0646\u0649", "\u0646\u064a", "\u0649\u0670", "\u064a\u0631", "\u064a\u0632", "\u064a\u0645", "\u064a\u0646", "\u064a\u0649", "\u064a\u064a", "\u0626\u062c", "\u0626\u062d", "\u0626\u062e", "\u0626\u0645", "\u0626\u0647", "\u0628\u062c", "\u0628\u062d", "\u0628\u062e", "\u0628\u0645", "\u0628\u0647", "\u062a\u062c", "\u062a\u062d", "\u062a\u062e", "\u062a\u0645", "\u062a\u0647", "\u062b\u0645", "\u062c\u062d", "\u062c\u0645", "\u062d\u062c", "\u062d\u0645", "\u062e\u062c", "\u062e\u0645", "\u0633\u062c", "\u0633\u062d", "\u0633\u062e", "\u0633\u0645", "\u0635\u062d", "\u0635\u062e", "\u0635\u0645", "\u0636\u062c", "\u0636\u062d", "\u0636\u062e", "\u0636\u0645", "\u0637\u062d", "\u0638\u0645", "\u0639\u062c", "\u0639\u0645", "\u063a\u062c", "\u063a\u0645", "\u0641\u062c", "\u0641\u062d", "\u0641\u062e", "\u0641\u0645", "\u0642\u062d", "\u0642\u0645", "\u0643\u062c", "\u0643\u062d", "\u0643\u062e", "\u0643\u0644", "\u0643\u0645", "\u0644\u062c", "\u0644\u062d", "\u0644\u062e", "\u0644\u0645", "\u0644\u0647", "\u0645\u062c", "\u0645\u062d", "\u0645\u062e", "\u0645\u0645", "\u0646\u062c", "\u0646\u062d", "\u0646\u062e", "\u0646\u0645", "\u0646\u0647", "\u0647\u062c", "\u0647\u0645", "\u0647\u0670", "\u064a\u062c", "\u064a\u062d", "\u064a\u062e", "\u064a\u0645", "\u064a\u0647", "\u0626\u0645", "\u0626\u0647", "\u0628\u0645", "\u0628\u0647", "\u062a\u0645", "\u062a\u0647", "\u062b\u0645", "\u062b\u0647", "\u0633\u0645", "\u0633\u0647", "\u0634\u0645", "\u0634\u0647", "\u0643\u0644", "\u0643\u0645", "\u0644\u0645", "\u0646\u0645", "\u0646\u0647", "\u064a\u0645", "\u064a\u0647", "\u0640\u064e\u0651", "\u0640\u064f\u0651", "\u0640\u0650\u0651", "\u0637\u0649", "\u0637\u064a", "\u0639\u0649", "\u0639\u064a", "\u063a\u0649", "\u063a\u064a", "\u0633\u0649", "\u0633\u064a", "\u0634\u0649", "\u0634\u064a", "\u062d\u0649", "\u062d\u064a", "\u062c\u0649", "\u062c\u064a", "\u062e\u0649", "\u062e\u064a", "\u0635\u0649", "\u0635\u064a", "\u0636\u0649", "\u0636\u064a", "\u0634\u062c", "\u0634\u062d", "\u0634\u062e", "\u0634\u0645", "\u0634\u0631", "\u0633\u0631", "\u0635\u0631", "\u0636\u0631", "\u0637\u0649", "\u0637\u064a", "\u0639\u0649", "\u0639\u064a", "\u063a\u0649", "\u063a\u064a", "\u0633\u0649", "\u0633\u064a", "\u0634\u0649", "\u0634\u064a", "\u062d\u0649", "\u062d\u064a", "\u062c\u0649", "\u062c\u064a", "\u062e\u0649", "\u062e\u064a", "\u0635\u0649", "\u0635\u064a", "\u0636\u0649", "\u0636\u064a", "\u0634\u062c", "\u0634\u062d", "\u0634\u062e", "\u0634\u0645", "\u0634\u0631", "\u0633\u0631", "\u0635\u0631", "\u0636\u0631", "\u0634\u062c", "\u0634\u062d", "\u0634\u062e", "\u0634\u0645", "\u0633\u0647", "\u0634\u0647", "\u0637\u0645", "\u0633\u062c", "\u0633\u062d", "\u0633\u062e", "\u0634\u062c", "\u0634\u062d", "\u0634\u062e", "\u0637\u0645", "\u0638\u0645", "\u0627\u064b", "\u0627\u064b", "\u062a\u062c\u0645", "\u062a\u062d\u062c", "\u062a\u062d\u062c", "\u062a\u062d\u0645", "\u062a\u062e\u0645", "\u062a\u0645\u062c", "\u062a\u0645\u062d", "\u062a\u0645\u062e", "\u062c\u0645\u062d", "\u062c\u0645\u062d", "\u062d\u0645\u064a", "\u062d\u0645\u0649", "\u0633\u062d\u062c", "\u0633\u062c\u062d", "\u0633\u062c\u0649", "\u0633\u0645\u062d", "\u0633\u0645\u062d", "\u0633\u0645\u062c", "\u0633\u0645\u0645", "\u0633\u0645\u0645", "\u0635\u062d\u062d", "\u0635\u062d\u062d", "\u0635\u0645\u0645", "\u0634\u062d\u0645", "\u0634\u062d\u0645", "\u0634\u062c\u064a", "\u0634\u0645\u062e", "\u0634\u0645\u062e", "\u0634\u0645\u0645", "\u0634\u0645\u0645", "\u0636\u062d\u0649", "\u0636\u062e\u0645", "\u0636\u062e\u0645", "\u0637\u0645\u062d", "\u0637\u0645\u062d", "\u0637\u0645\u0645", "\u0637\u0645\u064a", "\u0639\u062c\u0645", "\u0639\u0645\u0645", "\u0639\u0645\u0645", "\u0639\u0645\u0649", "\u063a\u0645\u0645", "\u063a\u0645\u064a", "\u063a\u0645\u0649", "\u0641\u062e\u0645", "\u0641\u062e\u0645", "\u0642\u0645\u062d", "\u0642\u0645\u0645", "\u0644\u062d\u0645", "\u0644\u062d\u064a", "\u0644\u062d\u0649", "\u0644\u062c\u062c", "\u0644\u062c\u062c", "\u0644\u062e\u0645", "\u0644\u062e\u0645", "\u0644\u0645\u062d", "\u0644\u0645\u062d", "\u0645\u062d\u062c", "\u0645\u062d\u0645", "\u0645\u062d\u064a", "\u0645\u062c\u062d", "\u0645\u062c\u0645", "\u0645\u062e\u062c", "\u0645\u062e\u0645", "\u0645\u062c\u062e", "\u0647\u0645\u062c", "\u0647\u0645\u0645", "\u0646\u062d\u0645", "\u0646\u062d\u0649", "\u0646\u062c\u0645", "\u0646\u062c\u0645", "\u0646\u062c\u0649", "\u0646\u0645\u064a", "\u0646\u0645\u0649", "\u064a\u0645\u0645", "\u064a\u0645\u0645", "\u0628\u062e\u064a", "\u062a\u062c\u064a", "\u062a\u062c\u0649", "\u062a\u062e\u064a", "\u062a\u062e\u0649", "\u062a\u0645\u064a", "\u062a\u0645\u0649", "\u062c\u0645\u064a", "\u062c\u062d\u0649", "\u062c\u0645\u0649", "\u0633\u062e\u0649", "\u0635\u062d\u064a", "\u0634\u062d\u064a", "\u0636\u062d\u064a", "\u0644\u062c\u064a", "\u0644\u0645\u064a", "\u064a\u062d\u064a", "\u064a\u062c\u064a", "\u064a\u0645\u064a", "\u0645\u0645\u064a", "\u0642\u0645\u064a", "\u0646\u062d\u064a", "\u0642\u0645\u062d", "\u0644\u062d\u0645", "\u0639\u0645\u064a", "\u0643\u0645\u064a", "\u0646\u062c\u062d", "\u0645\u062e\u064a", "\u0644\u062c\u0645", "\u0643\u0645\u0645", "\u0644\u062c\u0645", "\u0646\u062c\u062d", "\u062c\u062d\u064a", "\u062d\u062c\u064a", "\u0645\u062c\u064a", "\u0641\u0645\u064a", "\u0628\u062d\u064a", "\u0643\u0645\u0645", "\u0639\u062c\u0645", "\u0635\u0645\u0645", "\u0633\u062e\u064a", "\u0646\u062c\u064a", "\u0635\u0644\u06d2", "\u0642\u0644\u06d2", "\u0627\u0644\u0644\u0647", "\u0627\u0643\u0628\u0631", "\u0645\u062d\u0645\u062f", "\u0635\u0644\u0639\u0645", "\u0631\u0633\u0648\u0644", "\u0639\u0644\u064a\u0647", "\u0648\u0633\u0644\u0645", "\u0635\u0644\u0649", "\u0635\u0644\u0649\u0020\u0627\u0644\u0644\u0647\u0020\u0639\u0644\u064a\u0647\u0020\u0648\u0633\u0644\u0645", "\u062c\u0644\u0020\u062c\u0644\u0627\u0644\u0647", "\u0631\u06cc\u0627\u0644", ",", "\u3001", "\u3002", ":", ";", "!", "?", "\u3016", "\u3017", "\u2026", "\u2025", "\u2014", "\u2013", "_", "_", "(", ")", "{", "}", "\u3014", "\u3015", "\u3010", "\u3011", "\u300a", "\u300b", "\u3008", "\u3009", "\u300c", "\u300d", "\u300e", "\u300f", "[", "]", "\u203e", "\u203e", "\u203e", "\u203e", "_", "_", "_", ",", "\u3001", ".", ";", ":", "?", "!", "\u2014", "(", ")", "{", "}", "\u3014", "\u3015", "#", "&", "*", "+", "-", "<", ">", "=", "\\", "$", "%", "@", "\u0020\u064b", "\u0640\u064b", "\u0020\u064c", "\u0020\u064d", "\u0020\u064e", "\u0640\u064e", "\u0020\u064f", "\u0640\u064f", "\u0020\u0650", "\u0640\u0650", "\u0020\u0651", "\u0640\u0651", "\u0020\u0652", "\u0640\u0652", "\u0621", "\u0622", "\u0622", "\u0623", "\u0623", "\u0624", "\u0624", "\u0625", "\u0625", "\u0626", "\u0626", "\u0626", "\u0626", "\u0627", "\u0627", "\u0628", "\u0628", "\u0628", "\u0628", "\u0629", "\u0629", "\u062a", "\u062a", "\u062a", "\u062a", "\u062b", "\u062b", "\u062b", "\u062b", "\u062c", "\u062c", "\u062c", "\u062c", "\u062d", "\u062d", "\u062d", "\u062d", "\u062e", "\u062e", "\u062e", "\u062e", "\u062f", "\u062f", "\u0630", "\u0630", "\u0631", "\u0631", "\u0632", "\u0632", "\u0633", "\u0633", "\u0633", "\u0633", "\u0634", "\u0634", "\u0634", "\u0634", "\u0635", "\u0635", "\u0635", "\u0635", "\u0636", "\u0636", "\u0636", "\u0636", "\u0637", "\u0637", "\u0637", "\u0637", "\u0638", "\u0638", "\u0638", "\u0638", "\u0639", "\u0639", "\u0639", "\u0639", "\u063a", "\u063a", "\u063a", "\u063a", "\u0641", "\u0641", "\u0641", "\u0641", "\u0642", "\u0642", "\u0642", "\u0642", "\u0643", "\u0643", "\u0643", "\u0643", "\u0644", "\u0644", "\u0644", "\u0644", "\u0645", "\u0645", "\u0645", "\u0645", "\u0646", "\u0646", "\u0646", "\u0646", "\u0647", "\u0647", "\u0647", "\u0647", "\u0648", "\u0648", "\u0649", "\u0649", "\u064a", "\u064a", "\u064a", "\u064a", "\u0644\u0622", "\u0644\u0622", "\u0644\u0623", "\u0644\u0623", "\u0644\u0625", "\u0644\u0625", "\u0644\u0627", "\u0644\u0627", "!", "\"", "#", "$", "%", "&", "'", "(", ")", "*", "+", ",", "-", ".", "/", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ":", ";", "<", "=", ">", "?", "@", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "[", "\\", "]", "^", "_", "`", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "{", "|", "}", "~", "\u2985", "\u2986", "\u3002", "\u300c", "\u300d", "\u3001", "\u30fb", "\u30f2", "\u30a1", "\u30a3", "\u30a5", "\u30a7", "\u30a9", "\u30e3", "\u30e5", "\u30e7", "\u30c3", "\u30fc", "\u30a2", "\u30a4", "\u30a6", "\u30a8", "\u30aa", "\u30ab", "\u30ad", "\u30af", "\u30b1", "\u30b3", "\u30b5", "\u30b7", "\u30b9", "\u30bb", "\u30bd", "\u30bf", "\u30c1", "\u30c4", "\u30c6", "\u30c8", "\u30ca", "\u30cb", "\u30cc", "\u30cd", "\u30ce", "\u30cf", "\u30d2", "\u30d5", "\u30d8", "\u30db", "\u30de", "\u30df", "\u30e0", "\u30e1", "\u30e2", "\u30e4", "\u30e6", "\u30e8", "\u30e9", "\u30ea", "\u30eb", "\u30ec", "\u30ed", "\u30ef", "\u30f3", "\u3099", "\u309a", "\u3164", "\u3131", "\u3132", "\u3133", "\u3134", "\u3135", "\u3136", "\u3137", "\u3138", "\u3139", "\u313a", "\u313b", "\u313c", "\u313d", "\u313e", "\u313f", "\u3140", "\u3141", "\u3142", "\u3143", "\u3144", "\u3145", "\u3146", "\u3147", "\u3148", "\u3149", "\u314a", "\u314b", "\u314c", "\u314d", "\u314e", "\u314f", "\u3150", "\u3151", "\u3152", "\u3153", "\u3154", "\u3155", "\u3156", "\u3157", "\u3158", "\u3159", "\u315a", "\u315b", "\u315c", "\u315d", "\u315e", "\u315f", "\u3160", "\u3161", "\u3162", "\u3163", "\u00a2", "\u00a3", "\u00ac", "\u00af", "\u00a6", "\u00a5", "\u20a9", "\u2502", "\u2190", "\u2191", "\u2192", "\u2193", "\u25a0", "\u25cb", "\ud157\ud165", "\ud158\ud165", "\ud15f\ud16e", "\ud15f\ud16f", "\ud15f\ud170", "\ud15f\ud171", "\ud15f\ud172", "\ud1b9\ud165", "\ud1ba\ud165", "\ud1bb\ud16e", "\ud1bc\ud16e", "\ud1bb\ud16f", "\ud1bc\ud16f", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", "g", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "A", "C", "D", "G", "J", "K", "N", "O", "P", "Q", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "f", "h", "i", "j", "k", "l", "m", "n", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "A", "B", "D", "E", "F", "G", "J", "K", "L", "M", "N", "O", "P", "Q", "S", "T", "U", "V", "W", "X", "Y", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "A", "B", "D", "E", "F", "G", "I", "J", "K", "L", "M", "O", "S", "T", "U", "V", "W", "X", "Y", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "\u0131", "\u0237", "\u0391", "\u0392", "\u0393", "\u0394", "\u0395", "\u0396", "\u0397", "\u0398", "\u0399", "\u039a", "\u039b", "\u039c", "\u039d", "\u039e", "\u039f", "\u03a0", "\u03a1", "\u03f4", "\u03a3", "\u03a4", "\u03a5", "\u03a6", "\u03a7", "\u03a8", "\u03a9", "\u2207", "\u03b1", "\u03b2", "\u03b3", "\u03b4", "\u03b5", "\u03b6", "\u03b7", "\u03b8", "\u03b9", "\u03ba", "\u03bb", "\u03bc", "\u03bd", "\u03be", "\u03bf", "\u03c0", "\u03c1", "\u03c2", "\u03c3", "\u03c4", "\u03c5", "\u03c6", "\u03c7", "\u03c8", "\u03c9", "\u2202", "\u03f5", "\u03d1", "\u03f0", "\u03d5", "\u03f1", "\u03d6", "\u0391", "\u0392", "\u0393", "\u0394", "\u0395", "\u0396", "\u0397", "\u0398", "\u0399", "\u039a", "\u039b", "\u039c", "\u039d", "\u039e", "\u039f", "\u03a0", "\u03a1", "\u03f4", "\u03a3", "\u03a4", "\u03a5", "\u03a6", "\u03a7", "\u03a8", "\u03a9", "\u2207", "\u03b1", "\u03b2", "\u03b3", "\u03b4", "\u03b5", "\u03b6", "\u03b7", "\u03b8", "\u03b9", "\u03ba", "\u03bb", "\u03bc", "\u03bd", "\u03be", "\u03bf", "\u03c0", "\u03c1", "\u03c2", "\u03c3", "\u03c4", "\u03c5", "\u03c6", "\u03c7", "\u03c8", "\u03c9", "\u2202", "\u03f5", "\u03d1", "\u03f0", "\u03d5", "\u03f1", "\u03d6", "\u0391", "\u0392", "\u0393", "\u0394", "\u0395", "\u0396", "\u0397", "\u0398", "\u0399", "\u039a", "\u039b", "\u039c", "\u039d", "\u039e", "\u039f", "\u03a0", "\u03a1", "\u03f4", "\u03a3", "\u03a4", "\u03a5", "\u03a6", "\u03a7", "\u03a8", "\u03a9", "\u2207", "\u03b1", "\u03b2", "\u03b3", "\u03b4", "\u03b5", "\u03b6", "\u03b7", "\u03b8", "\u03b9", "\u03ba", "\u03bb", "\u03bc", "\u03bd", "\u03be", "\u03bf", "\u03c0", "\u03c1", "\u03c2", "\u03c3", "\u03c4", "\u03c5", "\u03c6", "\u03c7", "\u03c8", "\u03c9", "\u2202", "\u03f5", "\u03d1", "\u03f0", "\u03d5", "\u03f1", "\u03d6", "\u0391", "\u0392", "\u0393", "\u0394", "\u0395", "\u0396", "\u0397", "\u0398", "\u0399", "\u039a", "\u039b", "\u039c", "\u039d", "\u039e", "\u039f", "\u03a0", "\u03a1", "\u03f4", "\u03a3", "\u03a4", "\u03a5", "\u03a6", "\u03a7", "\u03a8", "\u03a9", "\u2207", "\u03b1", "\u03b2", "\u03b3", "\u03b4", "\u03b5", "\u03b6", "\u03b7", "\u03b8", "\u03b9", "\u03ba", "\u03bb", "\u03bc", "\u03bd", "\u03be", "\u03bf", "\u03c0", "\u03c1", "\u03c2", "\u03c3", "\u03c4", "\u03c5", "\u03c6", "\u03c7", "\u03c8", "\u03c9", "\u2202", "\u03f5", "\u03d1", "\u03f0", "\u03d5", "\u03f1", "\u03d6", "\u0391", "\u0392", "\u0393", "\u0394", "\u0395", "\u0396", "\u0397", "\u0398", "\u0399", "\u039a", "\u039b", "\u039c", "\u039d", "\u039e", "\u039f", "\u03a0", "\u03a1", "\u03f4", "\u03a3", "\u03a4", "\u03a5", "\u03a6", "\u03a7", "\u03a8", "\u03a9", "\u2207", "\u03b1", "\u03b2", "\u03b3", "\u03b4", "\u03b5", "\u03b6", "\u03b7", "\u03b8", "\u03b9", "\u03ba", "\u03bb", "\u03bc", "\u03bd", "\u03be", "\u03bf", "\u03c0", "\u03c1", "\u03c2", "\u03c3", "\u03c4", "\u03c5", "\u03c6", "\u03c7", "\u03c8", "\u03c9", "\u2202", "\u03f5", "\u03d1", "\u03f0", "\u03d5", "\u03f1", "\u03d6", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "\u4e3d", "\u4e38", "\u4e41", "\u0122", "\u4f60", "\u4fae", "\u4fbb", "\u5002", "\u507a", "\u5099", "\u50e7", "\u50cf", "\u349e", "\u063a", "\u514d", "\u5154", "\u5164", "\u5177", "\u051c", "\u34b9", "\u5167", "\u518d", "\u054b", "\u5197", "\u51a4", "\u4ecc", "\u51ac", "\u51b5", "\u91df", "\u51f5", "\u5203", "\u34df", "\u523b", "\u5246", "\u5272", "\u5277", "\u3515", "\u52c7", "\u52c9", "\u52e4", "\u52fa", "\u5305", "\u5306", "\u5317", "\u5349", "\u5351", "\u535a", "\u5373", "\u537d", "\u537f", "\u537f", "\u537f", "\u0a2c", "\u7070", "\u53ca", "\u53df", "\u0b63", "\u53eb", "\u53f1", "\u5406", "\u549e", "\u5438", "\u5448", "\u5468", "\u54a2", "\u54f6", "\u5510", "\u5553", "\u5563", "\u5584", "\u5584", "\u5599", "\u55ab", "\u55b3", "\u55c2", "\u5716", "\u5606", "\u5717", "\u5651", "\u5674", "\u5207", "\u58ee", "\u57ce", "\u57f4", "\u580d", "\u578b", "\u5832", "\u5831", "\u58ac", "\u14e4", "\u58f2", "\u58f7", "\u5906", "\u591a", "\u5922", "\u5962", "\u16a8", "\u16ea", "\u59ec", "\u5a1b", "\u5a27", "\u59d8", "\u5a66", "\u36ee", "\u36fc", "\u5b08", "\u5b3e", "\u5b3e", "\u19c8", "\u5bc3", "\u5bd8", "\u5be7", "\u5bf3", "\u1b18", "\u5bff", "\u5c06", "\u5f53", "\u5c22", "\u3781", "\u5c60", "\u5c6e", "\u5cc0", "\u5c8d", "\u1de4", "\u5d43", "\u1de6", "\u5d6e", "\u5d6b", "\u5d7c", "\u5de1", "\u5de2", "\u382f", "\u5dfd", "\u5e28", "\u5e3d", "\u5e69", "\u3862", "\u2183", "\u387c", "\u5eb0", "\u5eb3", "\u5eb6", "\u5eca", "\ua392", "\u5efe", "\u2331", "\u2331", "\u8201", "\u5f22", "\u5f22", "\u38c7", "\u32b8", "\u61da", "\u5f62", "\u5f6b", "\u38e3", "\u5f9a", "\u5fcd", "\u5fd7", "\u5ff9", "\u6081", "\u393a", "\u391c", "\u6094", "\u26d4", "\u60c7", "\u6148", "\u614c", "\u614e", "\u614c", "\u617a", "\u618e", "\u61b2", "\u61a4", "\u61af", "\u61de", "\u61f2", "\u61f6", "\u6210", "\u621b", "\u625d", "\u62b1", "\u62d4", "\u6350", "\u2b0c", "\u633d", "\u62fc", "\u6368", "\u6383", "\u63e4", "\u2bf1", "\u6422", "\u63c5", "\u63a9", "\u3a2e", "\u6469", "\u647e", "\u649d", "\u6477", "\u3a6c", "\u654f", "\u656c", "\u300a", "\u65e3", "\u66f8", "\u6649", "\u3b19", "\u6691", "\u3b08", "\u3ae4", "\u5192", "\u5195", "\u6700", "\u669c", "\u80ad", "\u43d9", "\u6717", "\u671b", "\u6721", "\u675e", "\u6753", "\u33c3", "\u3b49", "\u67fa", "\u6785", "\u6852", "\u6885", "\u346d", "\u688e", "\u681f", "\u6914", "\u3b9d", "\u6942", "\u69a3", "\u69ea", "\u6aa8", "\u36a3", "\u6adb", "\u3c18", "\u6b21", "\u38a7", "\u6b54", "\u3c4e", "\u6b72", "\u6b9f", "\u6bba", "\u6bbb", "\u3a8d", "\u1d0b", "\u3afa", "\u6c4e", "\u3cbc", "\u6cbf", "\u6ccd", "\u6c67", "\u6d16", "\u6d3e", "\u6d77", "\u6d41", "\u6d69", "\u6d78", "\u6d85", "\u3d1e", "\u6d34", "\u6e2f", "\u6e6e", "\u3d33", "\u6ecb", "\u6ec7", "\u3ed1", "\u6df9", "\u6f6e", "\u3f5e", "\u3f8e", "\u6fc6", "\u7039", "\u701e", "\u701b", "\u3d96", "\u704a", "\u707d", "\u7077", "\u70ad", "\u0525", "\u7145", "\u4263", "\u719c", "\u43ab", "\u7228", "\u7235", "\u7250", "\u4608", "\u7280", "\u7295", "\u4735", "\u4814", "\u737a", "\u738b", "\u3eac", "\u73a5", "\u3eb8", "\u3eb8", "\u7447", "\u745c", "\u7471", "\u7485", "\u74ca", "\u3f1b", "\u7524", "\u4c36", "\u753e", "\u4c92", "\u7570", "\u219f", "\u7610", "\u4fa1", "\u4fb8", "\u5044", "\u3ffc", "\u4008", "\u76f4", "\u50f3", "\u50f2", "\u5119", "\u5133", "\u771e", "\u771f", "\u771f", "\u774a", "\u4039", "\u778b", "\u4046", "\u4096", "\u541d", "\u784e", "\u788c", "\u78cc", "\u40e3", "\u5626", "\u7956", "\u569a", "\u56c5", "\u798f", "\u79eb", "\u412f", "\u7a40", "\u7a4a", "\u7a4f", "\u597c", "\u5aa7", "\u5aa7", "\u7aee", "\u4202", "\u5bab", "\u7bc6", "\u7bc9", "\u4227", "\u5c80", "\u7cd2", "\u42a0", "\u7ce8", "\u7ce3", "\u7d00", "\u5f86", "\u7d63", "\u4301", "\u7dc7", "\u7e02", "\u7e45", "\u4334", "\u6228", "\u6247", "\u4359", "\u62d9", "\u7f7a", "\u633e", "\u7f95", "\u7ffa", "\u8005", "\u64da", "\u6523", "\u8060", "\u65a8", "\u8070", "\u335f", "\u43d5", "\u80b2", "\u8103", "\u440b", "\u813e", "\u5ab5", "\u67a7", "\u67b5", "\u3393", "\u339c", "\u8201", "\u8204", "\u8f9e", "\u446b", "\u8291", "\u828b", "\u829d", "\u52b3", "\u82b1", "\u82b3", "\u82bd", "\u82e6", "\u6b3c", "\u82e5", "\u831d", "\u8363", "\u83ad", "\u8323", "\u83bd", "\u83e7", "\u8457", "\u8353", "\u83ca", "\u83cc", "\u83dc", "\u6c36", "\u6d6b", "\u6cd5", "\u452b", "\u84f1", "\u84f3", "\u8516", "\u73ca", "\u8564", "\u6f2c", "\u455d", "\u4561", "\u6fb1", "\u70d2", "\u456b", "\u8650", "\u865c", "\u8667", "\u8669", "\u86a9", "\u8688", "\u870e", "\u86e2", "\u8779", "\u8728", "\u876b", "\u8786", "\u45d7", "\u87e1", "\u8801", "\u45f9", "\u8860", "\u8863", "\u7667", "\u88d7", "\u88de", "\u4635", "\u88fa", "\u34bb", "\u78ae", "\u7966", "\u46be", "\u46c7", "\u8aa0", "\u8aed", "\u8b8a", "\u8c55", "\u7ca8", "\u8cab", "\u8cc1", "\u8d1b", "\u8d77", "\u7f2f", "\u0804", "\u8dcb", "\u8dbc", "\u8df0", "\u08de", "\u8ed4", "\u8f38", "\u85d2", "\u85ed", "\u9094", "\u90f1", "\u9111", "\u872e", "\u911b", "\u9238", "\u92d7", "\u92d8", "\u927c", "\u93f9", "\u9415", "\u8bfa", "\u958b", "\u4995", "\u95b7", "\u8d77", "\u49e6", "\u96c3", "\u5db2", "\u9723", "\u9145", "\u921a", "\u4a6e", "\u4a76", "\u97e0", "\u940a", "\u4ab2", "\u9496", "\u980b", "\u980b", "\u9829", "\u95b6", "\u98e2", "\u4b33", "\u9929", "\u99a7", "\u99c2", "\u99fe", "\u4bce", "\u9b30", "\u9b12", "\u9c40", "\u9cfd", "\u4cce", "\u4ced", "\u9d67", "\ua0ce", "\u4cf8", "\ua105", "\ua20e", "\ua291", "\u9ebb", "\u4d56", "\u9ef9", "\u9efe", "\u9f05", "\u9f0f", "\u9f16", "\u9f3b", "\ua600" }; public static final String[] exclusionList = { "2ao,2ap,2aq,2ar,2as,2at,2au,2av,2es,2et,2ev,2hj,2hm,2ip,2iq,2ir,2iu,2qs,2qt,", "3q3,3qd,3qi,3qn,3qs,3r9,3rm,3ro,3sj,3st,3t2,3t7,3tc,3tp,1uot,1uov,1upa,1upb,1upc,1upd,", "1upe,1upf,1upg,1uph,1upi,1upj,1upk,1upl,1upm,1upo,1upp,1upq,1upr,1ups,1upu,1uq0,1uq1,1uq3,1uq4,1uq6,", "1uq7,1uq8,1uq9,1uqa,1uqb,1uqc,1uqd,1uqe,ams,3kau,3kav,3kb0,3kb1,3kb2,3kb3,3kb4,3kdr,3kds,3kdt,3kdu,", "3kdv,3ke0" }; public static final String[] compatibilityList = { "50,58,5a,5f,5i,5j,5k,5l,5o,5p,5q,5s,5t,5u,9i,9j,9v,a0,a9,", "bv,e4,e5,e6,e7,e8,e9,ea,eb,ec,fh,fi,fj,lg,lh,li,lj,lk,ll,lm,", "ln,lo,mo,mp,mq,mr,ms,mt,n0,n1,n2,n3,n4,rq,s4,ug,uh,ui,ul,um,", "vg,vh,vi,vk,vl,vp,1c7,1jl,1jm,1jn,1jo,3hj,3lj,3ms,3mt,3oc,3rn,3rp,47s,79c,", "79d,79e,79g,79h,79i,79j,79k,79l,79m,79n,79o,79p,79q,79s,79t,79u,79v,7a0,7a1,7a2,", "7a3,7a4,7a5,7a6,7a7,7a8,7a9,7aa,7ab,7ac,7ad,7af,7ag,7ah,7ai,7aj,7ak,7al,7am,7an,", "7ao,7ap,7aq,7ar,7as,7at,7au,7av,7b0,7b1,7b2,7b3,7b4,7b5,7b6,7b7,7b8,7b9,7ba,7bo,", "7cr,7cs,7ct,7cu,7cv,7d0,7d1,7d2,7d3,7d4,7d5,7d6,7d7,7d8,7d9,7da,7db,7dc,7dd,7de,", "7df,7dg,7dh,7di,7dj,7dk,7dl,7dm,7dn,7do,7dp,7dq,7dr,7ds,7dt,7du,7dv,7kq,7tt,7tv,", "7u0,7vu,802,803,804,805,806,807,808,809,80a,80h,80n,814,815,816,81f,81j,81k,81m,", "81n,81s,81u,827,828,829,82n,82v,83g,83h,83k,83l,83m,83n,83o,83p,83q,83r,83s,83t,", "83u,83v,840,841,842,843,844,845,846,847,848,849,84a,84b,84c,84d,84e,84g,84h,84i,", "84j,84k,858,880,881,882,883,885,886,887,889,88a,88b,88c,88d,88e,88f,88g,88h,88i,", "88j,88l,88m,88p,88q,88r,88s,88t,890,891,892,894,898,89c,89d,89f,89g,89h,89j,89k,", "89l,89m,89n,89o,89p,89r,89s,89t,89u,89v,8a0,8a5,8a6,8a7,8a8,8a9,8aj,8ak,8al,8am,", "8an,8ao,8ap,8aq,8ar,8as,8at,8au,8av,8b0,8b1,8b2,8b3,8b4,8b5,8b6,8b7,8b8,8b9,8ba,", "8bb,8bc,8bd,8be,8bf,8bg,8bh,8bi,8bj,8bk,8bl,8bm,8bn,8bo,8bp,8bq,8br,8bs,8bt,8bu,", "8bv,8hc,8hd,8hf,8hg,930,931,932,933,934,935,936,937,938,939,93a,93b,93c,93d,93e,", "93f,93g,93h,93i,93j,93k,93l,93m,93n,93o,93p,93q,93r,93s,93t,93u,93v,940,941,942,", "943,944,945,946,947,948,949,94a,94b,94c,94d,94e,94f,94g,94h,94i,94j,94k,94l,94m,", "94n,94o,94p,94q,94r,94s,94t,94u,94v,950,951,952,953,954,955,956,957,958,959,95a,", "95b,95c,95d,95e,95f,95g,95h,95i,95j,95k,95l,95m,95n,95o,95p,95q,95r,95s,95t,95u,", "95v,960,961,962,963,964,965,966,967,968,969,96a,96b,96c,96d,96e,96f,96g,96h,96i,", "96j,96k,96l,96m,96n,96o,96p,96q,96r,96s,96t,96u,96v,970,971,972,973,974,975,976,", "977,978,979,97a,agc,ajk,ajl,ajm,bbf,bkv,bnj,bo0,bo1,bo2,bo3,bo4,bo5,bo6,bo7,bo8,", "bo9,boa,bob,boc,bod,boe,bof,bog,boh,boi,boj,bok,bol,bom,bon,boo,bop,boq,bor,bos,", "bot,bou,bov,bp0,bp1,bp2,bp3,bp4,bp5,bp6,bp7,bp8,bp9,bpa,bpb,bpc,bpd,bpe,bpf,bpg,", "bph,bpi,bpj,bpk,bpl,bpm,bpn,bpo,bpp,bpq,bpr,bps,bpt,bpu,bpv,bq0,bq1,bq2,bq3,bq4,", "bq5,bq6,bq7,bq8,bq9,bqa,bqb,bqc,bqd,bqe,bqf,bqg,bqh,bqi,bqj,bqk,bql,bqm,bqn,bqo,", "bqp,bqq,bqr,bqs,bqt,bqu,bqv,br0,br1,br2,br3,br4,br5,br6,br7,br8,br9,bra,brb,brc,", "brd,bre,brf,brg,brh,bri,brj,brk,brl,brm,brn,bro,brp,brq,brr,brs,brt,bru,brv,bs0,", "bs1,bs2,bs3,bs4,bs5,bs6,bs7,bs8,bs9,bsa,bsb,bsc,bsd,bse,bsf,bsg,bsh,bsi,bsj,bsk,", "bsl,bsm,bsn,bso,bsp,bsq,bsr,bss,bst,bsu,bsv,bt0,bt1,bt2,bt3,bt4,bt5,bt6,bt7,bt8,", "bt9,bta,btb,btc,btd,bte,btf,btg,bth,bti,btj,btk,btl,btm,btn,bto,btp,btq,btr,bts,", "btt,btu,btv,bu0,bu1,bu2,bu3,bu4,bu5,bu6,bu7,bu8,bu9,bua,bub,buc,bud,bue,buf,bug,", "buh,bui,buj,buk,bul,c00,c1m,c1o,c1p,c1q,c4r,c4s,c4v,c7v,c9h,c9i,c9j,c9k,c9l,c9m,", "c9n,c9o,c9p,c9q,c9r,c9s,c9t,c9u,c9v,ca0,ca1,ca2,ca3,ca4,ca5,ca6,ca7,ca8,ca9,caa,", "cab,cac,cad,cae,caf,cag,cah,cai,caj,cak,cal,cam,can,cao,cap,caq,car,cas,cat,cau,", "cav,cb0,cb1,cb2,cb3,cb4,cb5,cb6,cb7,cb8,cb9,cba,cbb,cbc,cbd,cbe,cbf,cbg,cbh,cbi,", "cbj,cbk,cbl,cbm,cbn,cbo,cbp,cbq,cbr,cbs,cbt,cbu,cbv,cc0,cc1,cc2,cc3,cc4,cc5,cc6,", "cc7,cc8,cc9,cca,ccb,ccc,ccd,cce,cci,ccj,cck,ccl,ccm,ccn,cco,ccp,ccq,ccr,ccs,cct,", "ccu,ccv,cg0,cg1,cg2,cg3,cg4,cg5,cg6,cg7,cg8,cg9,cga,cgb,cgc,cgd,cge,cgf,cgg,cgh,", "cgi,cgj,cgk,cgl,cgm,cgn,cgo,cgp,cgq,cgr,cgs,cgt,cgu,ch0,ch1,ch2,ch3,ch4,ch5,ch6,", "ch7,ch8,ch9,cha,chb,chc,chd,che,chf,chg,chh,chi,chj,chk,chl,chm,chn,cho,chp,chq,", "chr,chs,cht,chu,chv,ci0,ci1,ci2,ci3,cig,cih,cii,cij,cik,cil,cim,cin,cio,cip,ciq,", "cir,cis,cit,ciu,civ,cj0,cj1,cj2,cj3,cj4,cj5,cj6,cj7,cj8,cj9,cja,cjb,cjc,cjd,cje,", "cjf,cjg,cjh,cji,cjj,cjk,cjl,cjm,cjn,cjo,cjp,cjq,cjr,cjs,cjt,cju,ck0,ck1,ck2,ck3,", "ck4,ck5,ck6,ck7,ck8,ck9,cka,ckb,ckc,ckd,cke,ckf,ckg,ckh,cki,ckj,ckk,ckl,ckm,ckn,", "cko,ckp,ckq,ckr,cks,ckt,cku,ckv,cl0,cl1,cl2,cl3,cl4,cl5,cl6,cl7,cl8,cl9,cla,clb,", "clc,cld,cle,clf,clg,clh,cli,clj,clk,cll,clm,cln,clo,clp,clq,clr,cls,clt,clu,clv,", "cm0,cm1,cm2,cm3,cm4,cm5,cm6,cm7,cm8,cm9,cma,cmb,cmc,cmd,cme,cmf,cmg,cmh,cmi,cmj,", "cmk,cml,cmm,cmn,cmo,cmp,cmq,cmr,cms,cmt,cmu,cmv,cn0,cn1,cn2,cn3,cn4,cn5,cn6,cn7,", "cn8,cn9,cna,cnb,cnc,cnd,cne,cnf,cng,cnh,cni,cnj,cnk,cnl,cnm,cnn,cno,cnp,cnq,cnr,", "cns,cnt,cnu,co0,co1,co2,co3,co4,co5,co6,co7,co8,co9,coa,cob,coc,cod,coe,cof,cog,", "coh,coi,coj,cok,col,com,con,coo,cop,coq,cor,cos,cot,cou,cov,cp0,cp1,cp2,cp3,cp4,", "cp5,cp6,cp7,cp8,cp9,cpa,cpb,cpc,cpd,cpe,cpf,cpg,cph,cpi,cpj,cpk,cpl,cpm,cpn,cpo,", "cpp,cpq,cpr,cps,cpt,cpu,cpv,cq0,cq1,cq2,cq3,cq4,cq5,cq6,cq7,cq8,cq9,cqa,cqb,cqc,", "cqd,cqe,cqf,cqg,cqh,cqi,cqj,cqk,cql,cqm,cqn,cqo,cqp,cqq,cqr,cqs,cqt,cqu,cqv,cr0,", "cr1,cr2,cr3,cr4,cr5,cr6,cr7,cr8,cr9,cra,crb,crc,crd,cre,crf,crg,crh,cri,crj,crk,", "crl,crm,crn,cro,crp,crq,crr,crs,crt,cru,crv,cs0,cs1,cs2,cs3,cs4,cs5,cs6,cs7,cs8,", "cs9,csa,csb,csc,csd,cse,csf,csg,csh,csi,csj,csk,csl,csm,csn,cso,csp,csq,csr,css,", "cst,csu,csv,ct0,ct1,ct2,ct3,ct4,ct5,ct6,ct7,ct8,ct9,cta,ctb,ctc,ctd,cte,ctf,ctg,", "cth,cti,ctj,ctk,ctl,ctm,ctn,cto,ctp,ctq,ctr,cts,ctt,ctu,ctv,cu0,cu1,cu2,cu3,cu4,", "cu5,cu6,cu7,cu8,cu9,cua,cub,cuc,cud,cue,cuf,cug,cuh,cui,cuj,cuk,cul,cum,cun,cuo,", "cup,cuq,cur,cus,cut,cuu,cuv,cv0,cv1,cv2,cv3,cv4,cv5,cv6,cv7,cv8,cv9,cva,cvb,cvc,", "cvd,cve,cvf,cvg,cvh,cvi,cvj,cvk,cvl,cvm,cvn,cvo,cvp,cvq,cvr,cvs,cvt,cvu,cvv,1uo0,", "1uo1,1uo2,1uo3,1uo4,1uo5,1uo6,1uoj,1uok,1uol,1uom,1uon,1up0,1up1,1up2,1up3,1up4,1up5,1up6,1up7,1up8,", "1up9,1uqf,1uqg,1uqh,1uqi,1uqj,1uqk,1uql,1uqm,1uqn,1uqo,1uqp,1uqq,1uqr,1uqs,1uqt,1uqu,1uqv,1ur0,1ur1,", "1ur2,1ur3,1ur4,1ur5,1ur6,1ur7,1ur8,1ur9,1ura,1urb,1urc,1urd,1ure,1urf,1urg,1urh,1uri,1urj,1urk,1url,", "1urm,1urn,1uro,1urp,1urq,1urr,1urs,1urt,1uru,1urv,1us0,1us1,1us2,1us3,1us4,1us5,1us6,1us7,1us8,1us9,", "1usa,1usb,1usc,1usd,1use,1usf,1usg,1ush,1usi,1usj,1usk,1usl,1usm,1usn,1uso,1usp,1usq,1usr,1uss,1ust,", "1usu,1usv,1ut0,1ut1,1ut2,1ut3,1ut4,1ut5,1ut6,1ut7,1ut8,1ut9,1uta,1utb,1utc,1utd,1ute,1utf,1utg,1uth,", "1uuj,1uuk,1uul,1uum,1uun,1uuo,1uup,1uuq,1uur,1uus,1uut,1uuu,1uuv,1uv0,1uv1,1uv2,1uv3,1uv4,1uv5,1uv6,", "1uv7,1uv8,1uv9,1uva,1uvb,1uvc,1uvd,1uve,1uvf,1uvg,1uvh,1uvi,1uvj,1uvk,1uvl,1uvm,1uvn,1uvo,1uvp,1uvq,", "1uvr,1uvs,1uvt,1uvu,1uvv,1v00,1v01,1v02,1v03,1v04,1v05,1v06,1v07,1v08,1v09,1v0a,1v0b,1v0c,1v0d,1v0e,", "1v0f,1v0g,1v0h,1v0i,1v0j,1v0k,1v0l,1v0m,1v0n,1v0o,1v0p,1v0q,1v0r,1v0s,1v0t,1v0u,1v0v,1v10,1v11,1v12,", "1v13,1v14,1v15,1v16,1v17,1v18,1v19,1v1a,1v1b,1v1c,1v1d,1v1e,1v1f,1v1g,1v1h,1v1i,1v1j,1v1k,1v1l,1v1m,", "1v1n,1v1o,1v1p,1v1q,1v1r,1v1s,1v1t,1v1u,1v1v,1v20,1v21,1v22,1v23,1v24,1v25,1v26,1v27,1v28,1v29,1v2a,", "1v2b,1v2c,1v2d,1v2e,1v2f,1v2g,1v2h,1v2i,1v2j,1v2k,1v2l,1v2m,1v2n,1v2o,1v2p,1v2q,1v2r,1v2s,1v2t,1v2u,", "1v2v,1v30,1v31,1v32,1v33,1v34,1v35,1v36,1v37,1v38,1v39,1v3a,1v3b,1v3c,1v3d,1v3e,1v3f,1v3g,1v3h,1v3i,", "1v3j,1v3k,1v3l,1v3m,1v3n,1v3o,1v3p,1v3q,1v3r,1v3s,1v3t,1v3u,1v3v,1v40,1v41,1v42,1v43,1v44,1v45,1v46,", "1v47,1v48,1v49,1v4a,1v4b,1v4c,1v4d,1v4e,1v4f,1v4g,1v4h,1v4i,1v4j,1v4k,1v4l,1v4m,1v4n,1v4o,1v4p,1v4q,", "1v4r,1v4s,1v4t,1v4u,1v4v,1v50,1v51,1v52,1v53,1v54,1v55,1v56,1v57,1v58,1v59,1v5a,1v5b,1v5c,1v5d,1v5e,", "1v5f,1v5g,1v5h,1v5i,1v5j,1v5k,1v5l,1v5m,1v5n,1v5o,1v5p,1v5q,1v5r,1v5s,1v5t,1v5u,1v5v,1v60,1v61,1v62,", "1v63,1v64,1v65,1v66,1v67,1v68,1v69,1v6a,1v6b,1v6c,1v6d,1v6e,1v6f,1v6g,1v6h,1v6i,1v6j,1v6k,1v6l,1v6m,", "1v6n,1v6o,1v6p,1v6q,1v6r,1v6s,1v6t,1v6u,1v6v,1v70,1v71,1v72,1v73,1v74,1v75,1v76,1v77,1v78,1v79,1v7a,", "1v7b,1v7c,1v7d,1v7e,1v7f,1v7g,1v7h,1v7i,1v7j,1v7k,1v7l,1v7m,1v7n,1v7o,1v7p,1v7q,1v7r,1v7s,1v7t,1v7u,", "1v7v,1v80,1v81,1v82,1v83,1v84,1v85,1v86,1v87,1v88,1v89,1v8a,1v8b,1v8c,1v8d,1v8e,1v8f,1v8g,1v8h,1v8i,", "1v8j,1v8k,1v8l,1v8m,1v8n,1v8o,1v8p,1v8q,1v8r,1v8s,1v8t,1v8u,1v8v,1v90,1v91,1v92,1v93,1v94,1v95,1v96,", "1v97,1v98,1v99,1v9a,1v9b,1v9c,1v9d,1v9e,1v9f,1v9g,1v9h,1v9i,1v9j,1v9k,1v9l,1v9m,1v9n,1v9o,1v9p,1v9q,", "1v9r,1v9s,1v9t,1vag,1vah,1vai,1vaj,1vak,1val,1vam,1van,1vao,1vap,1vaq,1var,1vas,1vat,1vau,1vav,1vb0,", "1vb1,1vb2,1vb3,1vb4,1vb5,1vb6,1vb7,1vb8,1vb9,1vba,1vbb,1vbc,1vbd,1vbe,1vbf,1vbg,1vbh,1vbi,1vbj,1vbk,", "1vbl,1vbm,1vbn,1vbo,1vbp,1vbq,1vbr,1vbs,1vbt,1vbu,1vbv,1vc0,1vc1,1vc2,1vc3,1vc4,1vc5,1vc6,1vc7,1vc8,", "1vc9,1vca,1vcb,1vcc,1vcd,1vce,1vcf,1vci,1vcj,1vck,1vcl,1vcm,1vcn,1vco,1vcp,1vcq,1vcr,1vcs,1vct,1vcu,", "1vcv,1vd0,1vd1,1vd2,1vd3,1vd4,1vd5,1vd6,1vd7,1vd8,1vd9,1vda,1vdb,1vdc,1vdd,1vde,1vdf,1vdg,1vdh,1vdi,", "1vdj,1vdk,1vdl,1vdm,1vdn,1vdo,1vdp,1vdq,1vdr,1vds,1vdt,1vdu,1vdv,1ve0,1ve1,1ve2,1ve3,1ve4,1ve5,1ve6,", "1ve7,1vfg,1vfh,1vfi,1vfj,1vfk,1vfl,1vfm,1vfn,1vfo,1vfp,1vfq,1vfr,1vfs,1vgg,1vgh,1vgi,1vgj,1vgk,1vgl,", "1vgm,1vgn,1vgo,1vgp,1vhg,1vhh,1vhi,1vhj,1vhk,1vhl,1vhm,1vhn,1vho,1vhp,1vhq,1vhr,1vhs,1vht,1vhu,1vhv,", "1vi0,1vi1,1vi2,1vi3,1vi4,1vi7,1vi8,1vi9,1via,1vib,1vic,1vid,1vie,1vif,1vig,1vih,1vii,1vik,1vil,1vim,", "1vin,1vio,1vip,1viq,1vir,1vis,1vit,1viu,1viv,1vj0,1vj1,1vj2,1vj3,1vj4,1vj5,1vj6,1vj8,1vj9,1vja,1vjb,", "1vjg,1vjh,1vji,1vjk,1vjm,1vjn,1vjo,1vjp,1vjq,1vjr,1vjs,1vjt,1vju,1vjv,1vk0,1vk1,1vk2,1vk3,1vk4,1vk5,", "1vk6,1vk7,1vk8,1vk9,1vka,1vkb,1vkc,1vkd,1vke,1vkf,1vkg,1vkh,1vki,1vkj,1vkk,1vkl,1vkm,1vkn,1vko,1vkp,", "1vkq,1vkr,1vks,1vkt,1vku,1vkv,1vl0,1vl1,1vl2,1vl3,1vl4,1vl5,1vl6,1vl7,1vl8,1vl9,1vla,1vlb,1vlc,1vld,", "1vle,1vlf,1vlg,1vlh,1vli,1vlj,1vlk,1vll,1vlm,1vln,1vlo,1vlp,1vlq,1vlr,1vls,1vlt,1vlu,1vlv,1vm0,1vm1,", "1vm2,1vm3,1vm4,1vm5,1vm6,1vm7,1vm8,1vm9,1vma,1vmb,1vmc,1vmd,1vme,1vmf,1vmg,1vmh,1vmi,1vmj,1vmk,1vml,", "1vmm,1vmn,1vmo,1vmp,1vmq,1vmr,1vms,1vmt,1vmu,1vmv,1vn0,1vn1,1vn2,1vn3,1vn4,1vn5,1vn6,1vn7,1vn8,1vn9,", "1vna,1vnb,1vnc,1vnd,1vne,1vnf,1vng,1vnh,1vni,1vnj,1vnk,1vnl,1vnm,1vnn,1vno,1vnp,1vnq,1vnr,1vns,1vo1,", "1vo2,1vo3,1vo4,1vo5,1vo6,1vo7,1vo8,1vo9,1voa,1vob,1voc,1vod,1voe,1vof,1vog,1voh,1voi,1voj,1vok,1vol,", "1vom,1von,1voo,1vop,1voq,1vor,1vos,1vot,1vou,1vov,1vp0,1vp1,1vp2,1vp3,1vp4,1vp5,1vp6,1vp7,1vp8,1vp9,", "1vpa,1vpb,1vpc,1vpd,1vpe,1vpf,1vpg,1vph,1vpi,1vpj,1vpk,1vpl,1vpm,1vpn,1vpo,1vpp,1vpq,1vpr,1vps,1vpt,", "1vpu,1vpv,1vq0,1vq1,1vq2,1vq3,1vq4,1vq5,1vq6,1vq7,1vq8,1vq9,1vqa,1vqb,1vqc,1vqd,1vqe,1vqf,1vqg,1vqh,", "1vqi,1vqj,1vqk,1vql,1vqm,1vqn,1vqo,1vqp,1vqq,1vqr,1vqs,1vqt,1vqu,1vqv,1vr0,1vr1,1vr2,1vr3,1vr4,1vr5,", "1vr6,1vr7,1vr8,1vr9,1vra,1vrb,1vrc,1vrd,1vre,1vrf,1vrg,1vrh,1vri,1vrj,1vrk,1vrl,1vrm,1vrn,1vro,1vrp,", "1vrq,1vrr,1vrs,1vrt,1vru,1vrv,1vs0,1vs1,1vs2,1vs3,1vs4,1vs5,1vs6,1vs7,1vs8,1vs9,1vsa,1vsb,1vsc,1vsd,", "1vse,1vsf,1vsg,1vsh,1vsi,1vsj,1vsk,1vsl,1vsm,1vsn,1vso,1vsp,1vsq,1vsr,1vss,1vst,1vsu,1vsv,1vt0,1vt1,", "1vt2,1vt3,1vt4,1vt5,1vt6,1vt7,1vt8,1vt9,1vta,1vtb,1vtc,1vtd,1vte,1vtf,1vtg,1vth,1vti,1vtj,1vtk,1vtl,", "1vtm,1vtn,1vto,1vtp,1vtq,1vtr,1vts,1vtt,1vtu,1vu2,1vu3,1vu4,1vu5,1vu6,1vu7,1vua,1vub,1vuc,1vud,1vue,", "1vuf,1vui,1vuj,1vuk,1vul,1vum,1vun,1vuq,1vur,1vus,1vv0,1vv1,1vv2,1vv3,1vv4,1vv5,1vv6,1vv8,1vv9,1vva,", "1vvb,1vvc,1vvd,1vve,3l00,3l01,3l02,3l03,3l04,3l05,3l06,3l07,3l08,3l09,3l0a,3l0b,3l0c,3l0d,3l0e,3l0f,", "3l0g,3l0h,3l0i,3l0j,3l0k,3l0l,3l0m,3l0n,3l0o,3l0p,3l0q,3l0r,3l0s,3l0t,3l0u,3l0v,3l10,3l11,3l12,3l13,", "3l14,3l15,3l16,3l17,3l18,3l19,3l1a,3l1b,3l1c,3l1d,3l1e,3l1f,3l1g,3l1h,3l1i,3l1j,3l1k,3l1l,3l1m,3l1n,", "3l1o,3l1p,3l1q,3l1r,3l1s,3l1t,3l1u,3l1v,3l20,3l21,3l22,3l23,3l24,3l25,3l26,3l27,3l28,3l29,3l2a,3l2b,", "3l2c,3l2d,3l2e,3l2f,3l2g,3l2h,3l2i,3l2j,3l2k,3l2m,3l2n,3l2o,3l2p,3l2q,3l2r,3l2s,3l2t,3l2u,3l2v,3l30,", "3l31,3l32,3l33,3l34,3l35,3l36,3l37,3l38,3l39,3l3a,3l3b,3l3c,3l3d,3l3e,3l3f,3l3g,3l3h,3l3i,3l3j,3l3k,", "3l3l,3l3m,3l3n,3l3o,3l3p,3l3q,3l3r,3l3s,3l3t,3l3u,3l3v,3l40,3l41,3l42,3l43,3l44,3l45,3l46,3l47,3l48,", "3l49,3l4a,3l4b,3l4c,3l4d,3l4e,3l4f,3l4g,3l4h,3l4i,3l4j,3l4k,3l4l,3l4m,3l4n,3l4o,3l4p,3l4q,3l4r,3l4s,", "3l4u,3l4v,3l52,3l55,3l56,3l59,3l5a,3l5b,3l5c,3l5e,3l5f,3l5g,3l5h,3l5i,3l5j,3l5k,3l5l,3l5m,3l5n,3l5o,", "3l5p,3l5r,3l5t,3l5u,3l5v,3l60,3l61,3l62,3l63,3l65,3l66,3l67,3l68,3l69,3l6a,3l6b,3l6c,3l6d,3l6e,3l6f,", "3l6g,3l6h,3l6i,3l6j,3l6k,3l6l,3l6m,3l6n,3l6o,3l6p,3l6q,3l6r,3l6s,3l6t,3l6u,3l6v,3l70,3l71,3l72,3l73,", "3l74,3l75,3l76,3l77,3l78,3l79,3l7a,3l7b,3l7c,3l7d,3l7e,3l7f,3l7g,3l7h,3l7i,3l7j,3l7k,3l7l,3l7m,3l7n,", "3l7o,3l7p,3l7q,3l7r,3l7s,3l7t,3l7u,3l7v,3l80,3l81,3l82,3l83,3l84,3l85,3l87,3l88,3l89,3l8a,3l8d,3l8e,", "3l8f,3l8g,3l8h,3l8i,3l8j,3l8k,3l8m,3l8n,3l8o,3l8p,3l8q,3l8r,3l8s,3l8u,3l8v,3l90,3l91,3l92,3l93,3l94,", "3l95,3l96,3l97,3l98,3l99,3l9a,3l9b,3l9c,3l9d,3l9e,3l9f,3l9g,3l9h,3l9i,3l9j,3l9k,3l9l,3l9m,3l9n,3l9o,", "3l9p,3l9r,3l9s,3l9t,3l9u,3la0,3la1,3la2,3la3,3la4,3la6,3laa,3lab,3lac,3lad,3lae,3laf,3lag,3lai,3laj,", "3lak,3lal,3lam,3lan,3lao,3lap,3laq,3lar,3las,3lat,3lau,3lav,3lb0,3lb1,3lb2,3lb3,3lb4,3lb5,3lb6,3lb7,", "3lb8,3lb9,3lba,3lbb,3lbc,3lbd,3lbe,3lbf,3lbg,3lbh,3lbi,3lbj,3lbk,3lbl,3lbm,3lbn,3lbo,3lbp,3lbq,3lbr,", "3lbs,3lbt,3lbu,3lbv,3lc0,3lc1,3lc2,3lc3,3lc4,3lc5,3lc6,3lc7,3lc8,3lc9,3lca,3lcb,3lcc,3lcd,3lce,3lcf,", "3lcg,3lch,3lci,3lcj,3lck,3lcl,3lcm,3lcn,3lco,3lcp,3lcq,3lcr,3lcs,3lct,3lcu,3lcv,3ld0,3ld1,3ld2,3ld3,", "3ld4,3ld5,3ld6,3ld7,3ld8,3ld9,3lda,3ldb,3ldc,3ldd,3lde,3ldf,3ldg,3ldh,3ldi,3ldj,3ldk,3ldl,3ldm,3ldn,", "3ldo,3ldp,3ldq,3ldr,3lds,3ldt,3ldu,3ldv,3le0,3le1,3le2,3le3,3le4,3le5,3le6,3le7,3le8,3le9,3lea,3leb,", "3lec,3led,3lee,3lef,3leg,3leh,3lei,3lej,3lek,3lel,3lem,3len,3leo,3lep,3leq,3ler,3les,3let,3leu,3lev,", "3lf0,3lf1,3lf2,3lf3,3lf4,3lf5,3lf6,3lf7,3lf8,3lf9,3lfa,3lfb,3lfc,3lfd,3lfe,3lff,3lfg,3lfh,3lfi,3lfj,", "3lfk,3lfl,3lfm,3lfn,3lfo,3lfp,3lfq,3lfr,3lfs,3lft,3lfu,3lfv,3lg0,3lg1,3lg2,3lg3,3lg4,3lg5,3lg6,3lg7,", "3lg8,3lg9,3lga,3lgb,3lgc,3lgd,3lge,3lgf,3lgg,3lgh,3lgi,3lgj,3lgk,3lgl,3lgm,3lgn,3lgo,3lgp,3lgq,3lgr,", "3lgs,3lgt,3lgu,3lgv,3lh0,3lh1,3lh2,3lh3,3lh4,3lh5,3lh6,3lh7,3lh8,3lh9,3lha,3lhb,3lhc,3lhd,3lhe,3lhf,", "3lhg,3lhh,3lhi,3lhj,3lhk,3lhl,3lhm,3lhn,3lho,3lhp,3lhq,3lhr,3lhs,3lht,3lhu,3lhv,3li0,3li1,3li2,3li3,", "3li4,3li5,3li6,3li7,3li8,3li9,3lia,3lib,3lic,3lid,3lie,3lif,3lig,3lih,3lii,3lij,3lik,3lil,3lim,3lin,", "3lio,3lip,3liq,3lir,3lis,3lit,3liu,3liv,3lj0,3lj1,3lj2,3lj3,3lj4,3lj5,3lj6,3lj7,3lj8,3lj9,3lja,3ljb,", "3ljc,3ljd,3lje,3ljf,3ljg,3ljh,3lji,3ljj,3ljk,3ljl,3ljm,3ljn,3ljo,3ljp,3ljq,3ljr,3ljs,3ljt,3lju,3ljv,", "3lk0,3lk1,3lk2,3lk3,3lk4,3lk5,3lk6,3lk7,3lk8,3lk9,3lka,3lkb,3lkc,3lkd,3lke,3lkf,3lkg,3lkh,3lki,3lkj,", "3lkk,3lkl,3lkm,3lkn,3lko,3lkp,3lkq,3lkr,3lks,3lkt,3lku,3lkv,3ll0,3ll1,3ll2,3ll3,3ll4,3ll5,3ll8,3ll9,", "3lla,3llb,3llc,3lld,3lle,3llf,3llg,3llh,3lli,3llj,3llk,3lll,3llm,3lln,3llo,3llp,3llq,3llr,3lls,3llt,", "3llu,3llv,3lm0,3lm1,3lm2,3lm3,3lm4,3lm5,3lm6,3lm7,3lm8,3lm9,3lma,3lmb,3lmc,3lmd,3lme,3lmf,3lmg,3lmh,", "3lmi,3lmj,3lmk,3lml,3lmm,3lmn,3lmo,3lmp,3lmq,3lmr,3lms,3lmt,3lmu,3lmv,3ln0,3ln1,3ln2,3ln3,3ln4,3ln5,", "3ln6,3ln7,3ln8,3ln9,3lna,3lnb,3lnc,3lnd,3lne,3lnf,3lng,3lnh,3lni,3lnj,3lnk,3lnl,3lnm,3lnn,3lno,3lnp,", "3lnq,3lnr,3lns,3lnt,3lnu,3lnv,3lo0,3lo1,3lo2,3lo3,3lo4,3lo5,3lo6,3lo7,3lo8,3lo9,3loa,3lob,3loc,3lod,", "3loe,3lof,3log,3loh,3loi,3loj,3lok,3lol,3lom,3lon,3loo,3lop,3loq,3lor,3los,3lot,3lou,3lov,3lp0,3lp1,", "3lp2,3lp3,3lp4,3lp5,3lp6,3lp7,3lp8,3lp9,3lpa,3lpb,3lpc,3lpd,3lpe,3lpf,3lpg,3lph,3lpi,3lpj,3lpk,3lpl,", "3lpm,3lpn,3lpo,3lpp,3lpq,3lpr,3lps,3lpt,3lpu,3lpv,3lq0,3lq1,3lq2,3lq3,3lq4,3lq5,3lq6,3lq7,3lq8,3lq9,", "3lqa,3lqb,3lqc,3lqd,3lqe,3lqf,3lqg,3lqh,3lqi,3lqj,3lqk,3lql,3lqm,3lqn,3lqo,3lqp,3lqq,3lqr,3lqs,3lqt,", "3lqu,3lqv,3lr0,3lr1,3lr2,3lr3,3lr4,3lr5,3lr6,3lr7,3lr8,3lr9,3lra,3lrb,3lrc,3lrd,3lre,3lrf,3lrg,3lrh,", "3lri,3lrj,3lrk,3lrl,3lrm,3lrn,3lro,3lrp,3lrq,3lrr,3lrs,3lrt,3lru,3lrv,3ls0,3ls1,3ls2,3ls3,3ls4,3ls5,", "3ls6,3ls7,3ls8,3ls9,3lsa,3lsb,3lsc,3lsd,3lse,3lsf,3lsg,3lsh,3lsi,3lsj,3lsk,3lsl,3lsm,3lsn,3lso,3lsp,", "3lsq,3lsr,3lss,3lst,3lsu,3lsv,3lt0,3lt1,3lt2,3lt3,3lt4,3lt5,3lt6,3lt7,3lt8,3lt9,3lta,3ltb,3ltc,3ltd,", "3lte,3ltf,3ltg,3lth,3lti,3ltj,3ltk,3ltl,3ltm,3ltn,3lto,3ltp,3ltq,3ltr,3lts,3ltt,3ltu,3ltv,3lu0,3lu1,", "3lu2,3lu3,3lu4,3lu5,3lu6,3lu7,3lu8,3lu9,3lue,3luf,3lug,3luh,3lui,3luj,3luk,3lul,3lum,3lun,3luo,3lup,", "3luq,3lur,3lus,3lut,3luu,3luv,3lv0,3lv1,3lv2,3lv3,3lv4,3lv5,3lv6,3lv7,3lv8,3lv9,3lva,3lvb,3lvc,3lvd,", "3lve,3lvf,3lvg,3lvh,3lvi,3lvj,3lvk,3lvl,3lvm,3lvn,3lvo,3lvp,3lvq,3lvr,3lvs,3lvt,3lvu,3lvv" }; } saxonb-9.1.0.8/bj/net/sf/saxon/codenorm/package.html0000644000175000017500000000071511033112257021471 0ustar eugeneeugene Package overview: net.sf.saxon.ant

    This package contains the code to implement Unicode normalization.

    Much of the code is derived directly from the reference implementation published by the Unicode Consortium. However, the code for constructing the data tables used as input to the algorithm has been redesigned and rewritten for efficiency.

    saxonb-9.1.0.8/bj/net/sf/saxon/dom4j/0000755000175000017500000000000012216261746016430 5ustar eugeneeugenesaxonb-9.1.0.8/bj/net/sf/saxon/dom4j/DocumentWrapper.java0000644000175000017500000001066111033112257022402 0ustar eugeneeugenepackage net.sf.saxon.dom4j; import net.sf.saxon.Configuration; import net.sf.saxon.om.DocumentInfo; import net.sf.saxon.om.NamePool; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.type.Type; import org.dom4j.Document; import java.util.Iterator; import java.util.Collections; /** * The root node of an XPath tree. (Or equivalently, the tree itself).

    * This class should have been named Root; it is used not only for the root of a document, * but also for the root of a result tree fragment, which is not constrained to contain a * single top-level element. * @author * This is the implementation of the NodeInfo interface used as a wrapper for DOM4J nodes. * @author Michael H. Kay */ // History: this started life as the NodeWrapper for JDOM nodes; it was then modified by the // Orbeon team to act as a wrapper for DOM4J nodes, and was shipped with the Orbeon product; // it has now been absorbed back into Saxon. public class NodeWrapper implements NodeInfo, VirtualNode, SiblingCountingNode { protected Object node; protected short nodeKind; private NodeWrapper parent; // null means unknown protected DocumentWrapper docWrapper; // Beware: with dom4j, this is an index over the result of content(), which may contain Namespace nodes protected int index; // -1 means unknown /** * This constructor is protected: nodes should be created using the wrap * factory method on the DocumentWrapper class * @param node The DOM4J node to be wrapped * @param parent The NodeWrapper that wraps the parent of this node * @param index Position of this node among its siblings */ protected NodeWrapper(Object node, NodeWrapper parent, int index) { this.node = node; this.parent = parent; this.index = index; } /** * Factory method to wrap a DOM4J node with a wrapper that implements the Saxon * NodeInfo interface. * @param node The DOM4J node * @param docWrapper The wrapper for the Document containing this node * @return The new wrapper for the supplied node */ protected NodeWrapper makeWrapper(Object node, DocumentWrapper docWrapper) { return makeWrapper(node, docWrapper, null, -1); } /** * Factory method to wrap a DOM4J node with a wrapper that implements the Saxon * NodeInfo interface. * @param node The DOM4J node * @param docWrapper The wrapper for the Document containing this node * @param parent The wrapper for the parent of the DOM4J node * @param index The position of this node relative to its siblings * @return The new wrapper for the supplied node */ protected NodeWrapper makeWrapper(Object node, DocumentWrapper docWrapper, NodeWrapper parent, int index) { NodeWrapper wrapper; if (node instanceof Document) { return docWrapper; } else if (node instanceof Element) { wrapper = new NodeWrapper(node, parent, index); wrapper.nodeKind = Type.ELEMENT; } else if (node instanceof Attribute) { wrapper = new NodeWrapper(node, parent, index); wrapper.nodeKind = Type.ATTRIBUTE; } else if (node instanceof String || node instanceof Text || node instanceof CDATA) { wrapper = new NodeWrapper(node, parent, index); wrapper.nodeKind = Type.TEXT; } else if (node instanceof Comment) { wrapper = new NodeWrapper(node, parent, index); wrapper.nodeKind = Type.COMMENT; } else if (node instanceof ProcessingInstruction) { wrapper = new NodeWrapper(node, parent, index); wrapper.nodeKind = Type.PROCESSING_INSTRUCTION; } else if (node instanceof Namespace) { wrapper = new NodeWrapper(node, parent, index); wrapper.nodeKind = Type.NAMESPACE; } else { throw new IllegalArgumentException("Bad node type in dom4j! " + node.getClass() + " instance " + node.toString()); } wrapper.docWrapper = docWrapper; return wrapper; } /** * Get the underlying DOM node, to implement the VirtualNode interface */ public Object getUnderlyingNode() { return node; } /** * Get the name pool for this node * @return the NamePool */ public NamePool getNamePool() { return docWrapper.getNamePool(); } /** * Return the type of node. * @return one of the values Node.ELEMENT, Node.TEXT, Node.ATTRIBUTE, etc. */ public int getNodeKind() { return nodeKind; } /** * Get the typed value of the item */ public SequenceIterator getTypedValue() { return SingletonIterator.makeIterator((AtomicValue)atomize()); } public Value atomize() { switch (getNodeKind()) { case Type.COMMENT: case Type.PROCESSING_INSTRUCTION: return new StringValue(getStringValueCS()); default: return new UntypedAtomicValue(getStringValueCS()); } } /** * Get the type annotation * @return UNTYPED or UNTYPED_ATOMIC */ public int getTypeAnnotation() { if (getNodeKind() == Type.ATTRIBUTE) { return StandardNames.XS_UNTYPED_ATOMIC; } return StandardNames.XS_UNTYPED; } /** * Determine whether this is the same node as another node.
    * Note: a.isSameNode(b) if and only if generateId(a)==generateId(b) * @param other the node to be compared with * @return true if this Node object and the supplied Node object represent the * same node in the tree. */ public boolean isSameNode(NodeInfo other) { if (!(other instanceof NodeWrapper)) { return false; } NodeWrapper ow = (NodeWrapper)other; return node.equals(ow.node); } /** * Get the System ID for the node. * @return the System Identifier of the entity in the source document containing the node, * or null if not known. Note this is not the same as the base URI: the base URI can be * modified by xml:base, but the system ID cannot. */ public String getSystemId() { return docWrapper.baseURI; } public void setSystemId(String uri) { docWrapper.baseURI = uri; } /** * Get the Base URI for the node, that is, the URI used for resolving a relative URI contained * in the node. In the DOM4J model, base URIs are held only an the document level. We don't * currently take any account of xml:base attributes. */ public String getBaseURI() { if (getNodeKind() == Type.NAMESPACE) { return null; } NodeInfo n = this; if (getNodeKind() != Type.ELEMENT) { n = n.getParent(); } // Look for an xml:base attribute while (n != null) { String xmlbase = n.getAttributeValue(StandardNames.XML_BASE); if (xmlbase != null) { return xmlbase; } n = n.getParent(); } // if not found, return the base URI of the document node return docWrapper.baseURI; } /** * Get line number * @return the line number of the node in its original source document; or -1 if not available */ public int getLineNumber() { return -1; } /** * Get column number * @return the column number of the node in its original source document; or -1 if not available */ public int getColumnNumber() { return -1; } /** * Determine the relative position of this node and another node, in document order. * The other node will always be in the same document. * @param other The other node, whose position is to be compared with this node * @return -1 if this node precedes the other node, +1 if it follows the other * node, or 0 if they are the same node. (In this case, isSameNode() will always * return true, and the two nodes will produce the same result for generateId()) */ public int compareOrder(NodeInfo other) { return Navigator.compareOrder(this, (SiblingCountingNode)other); } /** * Return the string value of the node. The interpretation of this depends on the type * of node. For an element it is the accumulated character content of the element, * including descendant elements. * @return the string value of the node */ public String getStringValue() { return getStringValue(node); } public CharSequence getStringValueCS() { return getStringValue(node); } private static String getStringValue(Object node) { if (node instanceof Document) { return ((Document)node).getStringValue(); } else if (node instanceof Element) { return ((Element)node).getStringValue(); } else if (node instanceof Attribute) { return ((Attribute)node).getValue(); } else if (node instanceof Text) { return ((Text)node).getText(); } else if (node instanceof CDATA) { return ((CDATA)node).getText(); } else if (node instanceof String) { return (String)node; } else if (node instanceof Comment) { return ((Comment)node).getText(); } else if (node instanceof ProcessingInstruction) { return ((ProcessingInstruction)node).getStringValue(); } else if (node instanceof Namespace) { return ((Namespace)node).getURI(); } else { return ""; } } /** * Get name code. The name code is a coded form of the node name: two nodes * with the same name code have the same namespace URI, the same local name, * and the same prefix. By masking the name code with &0xfffff, you get a * fingerprint: two nodes with the same fingerprint have the same local name * and namespace URI. * @see net.sf.saxon.om.NamePool#allocate allocate */ public int getNameCode() { switch (nodeKind) { case Type.ELEMENT: case Type.ATTRIBUTE: case Type.PROCESSING_INSTRUCTION: case Type.NAMESPACE: return docWrapper.getNamePool().allocate(getPrefix(), getURI(), getLocalPart()); default: return -1; } } /** * Get fingerprint. The fingerprint is a coded form of the expanded name * of the node: two nodes * with the same name code have the same namespace URI and the same local name. * A fingerprint of -1 should be returned for a node with no name. */ public int getFingerprint() { return getNameCode()&0xfffff; } /** * Get the local part of the name of this node. This is the name after the ":" if any. * @return the local part of the name. For an unnamed node, returns "". */ public String getLocalPart() { switch (nodeKind) { case Type.ELEMENT: return ((Element)node).getName(); case Type.ATTRIBUTE: return ((Attribute)node).getName(); case Type.TEXT: case Type.COMMENT: case Type.DOCUMENT: return ""; case Type.PROCESSING_INSTRUCTION: return ((ProcessingInstruction)node).getTarget(); case Type.NAMESPACE: return ((Namespace)node).getPrefix(); default: return null; } } /** * Get the prefix part of the name of this node. This is the name before the ":" if any. * (Note, this method isn't required as part of the NodeInfo interface.) * @return the prefix part of the name. For an unnamed node, return an empty string. */ public String getPrefix() { switch (nodeKind) { case Type.ELEMENT: return ((Element)node).getNamespacePrefix(); case Type.ATTRIBUTE: return ((Attribute)node).getNamespacePrefix(); default: return ""; } } /** * Get the URI part of the name of this node. This is the URI corresponding to the * prefix, or the URI of the default namespace if appropriate. * @return The URI of the namespace of this node. For an unnamed node, return null. * For a node with an empty prefix, return an empty string. */ public String getURI() { switch (nodeKind) { case Type.ELEMENT: return ((Element)node).getNamespaceURI(); case Type.ATTRIBUTE: return ((Attribute)node).getNamespaceURI(); default: return ""; } } /** * Get the display name of this node. For elements and attributes this is [prefix:]localname. * For unnamed nodes, it is an empty string. * @return The display name of this node. * For a node with no name, return an empty string. */ public String getDisplayName() { switch (nodeKind) { case Type.ELEMENT: return ((Element)node).getQualifiedName(); case Type.ATTRIBUTE: return ((Attribute)node).getQualifiedName(); case Type.PROCESSING_INSTRUCTION: case Type.NAMESPACE: return getLocalPart(); default: return ""; } } /** * Get the NodeInfo object representing the parent of this node */ public NodeInfo getParent() { if (parent==null) { if (node instanceof Element) { if (((Element)node).isRootElement()) { parent = makeWrapper(((Element)node).getDocument(), docWrapper); } else { parent = makeWrapper(((Element)node).getParent(), docWrapper); } } else if (node instanceof Text) { parent = makeWrapper(((Text)node).getParent(), docWrapper); } else if (node instanceof CDATA) { parent = makeWrapper(((CDATA)node).getParent(), docWrapper); } else if (node instanceof Comment) { parent = makeWrapper(((Comment)node).getParent(), docWrapper); } else if (node instanceof ProcessingInstruction) { parent = makeWrapper(((ProcessingInstruction)node).getParent(), docWrapper); } else if (node instanceof Attribute) { parent = makeWrapper(((Attribute)node).getParent(), docWrapper); } else if (node instanceof Document) { parent = null; } else if (node instanceof Namespace) { throw new UnsupportedOperationException("Cannot find parent of DOM4J namespace node"); } else { throw new IllegalStateException("Unknown DOM4J node type " + node.getClass()); } } return parent; } /** * Get the index position of this node among its siblings (starting from 0) */ public int getSiblingPosition() { if (index == -1) { int ix = 0; getParent(); AxisIterator iter; switch (nodeKind) { case Type.ELEMENT: case Type.TEXT: case Type.COMMENT: case Type.PROCESSING_INSTRUCTION: // iter = parent.iterateAxis(Axis.ATTRIBUTE); // break; { final NodeWrapper parent = (NodeWrapper) getParent(); final List children; if (parent.getNodeKind()==Type.DOCUMENT) { children = ((Document) parent.node).content(); } else { // Beware: dom4j content() contains Namespace nodes (which is broken)! children = ((Element) parent.node).content(); } for (ListIterator iterator = children.listIterator(); iterator.hasNext();) { final Object n = iterator.next(); if (n == node) { index = ix; return index; } ix++; } throw new IllegalStateException("DOM4J node not linked to parent node"); } case Type.ATTRIBUTE: iter = parent.iterateAxis(Axis.ATTRIBUTE); break; case Type.NAMESPACE: iter = parent.iterateAxis(Axis.NAMESPACE); break; default: index = 0; return index; } while (true) { NodeInfo n = (NodeInfo)iter.next(); if (n == null) { break; } if (n.isSameNodeInfo(this)) { index = ix; return index; } ix++; } throw new IllegalStateException("DOM4J node not linked to parent node"); } return index; } /** * Return an iteration over the nodes reached by the given axis from this node * @param axisNumber the axis to be used * @return a SequenceIterator that scans the nodes reached by the axis in turn. */ public AxisIterator iterateAxis(byte axisNumber) { return iterateAxis(axisNumber, AnyNodeTest.getInstance()); } /** * Return an iteration over the nodes reached by the given axis from this node * @param axisNumber the axis to be used * @param nodeTest A pattern to be matched by the returned nodes * @return a SequenceIterator that scans the nodes reached by the axis in turn. */ public AxisIterator iterateAxis(byte axisNumber, NodeTest nodeTest) { switch (axisNumber) { case Axis.ANCESTOR: if (nodeKind==Type.DOCUMENT) { return EmptyIterator.getInstance(); } return new Navigator.AxisFilter( new Navigator.AncestorEnumeration(this, false), nodeTest); case Axis.ANCESTOR_OR_SELF: if (nodeKind==Type.DOCUMENT) { return Navigator.filteredSingleton(this, nodeTest); } return new Navigator.AxisFilter( new Navigator.AncestorEnumeration(this, true), nodeTest); case Axis.ATTRIBUTE: if (nodeKind!=Type.ELEMENT) return EmptyIterator.getInstance(); return new Navigator.AxisFilter( new AttributeEnumeration(this), nodeTest); case Axis.CHILD: if (hasChildNodes()) { return new Navigator.AxisFilter( new ChildEnumeration(this, true, true), nodeTest); } else { return EmptyIterator.getInstance(); } case Axis.DESCENDANT: if (hasChildNodes()) { return new Navigator.AxisFilter( new Navigator.DescendantEnumeration(this, false, true), nodeTest); } else { return EmptyIterator.getInstance(); } case Axis.DESCENDANT_OR_SELF: return new Navigator.AxisFilter( new Navigator.DescendantEnumeration(this, true, true), nodeTest); case Axis.FOLLOWING: return new Navigator.AxisFilter( new Navigator.FollowingEnumeration(this), nodeTest); case Axis.FOLLOWING_SIBLING: switch (nodeKind) { case Type.DOCUMENT: case Type.ATTRIBUTE: case Type.NAMESPACE: return EmptyIterator.getInstance(); default: return new Navigator.AxisFilter( new ChildEnumeration(this, false, true), nodeTest); } case Axis.NAMESPACE: if (nodeKind!=Type.ELEMENT) { return EmptyIterator.getInstance(); } return new Navigator.AxisFilter( new NamespaceEnumeration(this), nodeTest); case Axis.PARENT: getParent(); return Navigator.filteredSingleton(parent, nodeTest); case Axis.PRECEDING: return new Navigator.AxisFilter( new Navigator.PrecedingEnumeration(this, false), nodeTest); case Axis.PRECEDING_SIBLING: switch (nodeKind) { case Type.DOCUMENT: case Type.ATTRIBUTE: case Type.NAMESPACE: return EmptyIterator.getInstance(); default: return new Navigator.AxisFilter( new ChildEnumeration(this, false, false), nodeTest); } case Axis.SELF: return Navigator.filteredSingleton(this, nodeTest); case Axis.PRECEDING_OR_ANCESTOR: return new Navigator.AxisFilter( new Navigator.PrecedingEnumeration(this, true), nodeTest); default: throw new IllegalArgumentException("Unknown axis number " + axisNumber); } } /** * Find the value of a given attribute of this node.
    * This method is defined on all nodes to meet XSL requirements, but for nodes * other than elements it will always return null. * @param uri the namespace uri of an attribute ("" if no namespace) * @param localName the local name of the attribute * @return the value of the attribute, if it exists, otherwise null */ // public String getAttributeValue(String uri, String localName) { // if (nodeKind==Type.ELEMENT) { // Namespace ns = Namespace.getNamespace(uri); // return ((Element)node).getAttributeValue(localName, ns); // } else { // return ""; // } // } /** * Get the value of a given attribute of this node * @param fingerprint The fingerprint of the attribute name * @return the attribute value if it exists or null if not */ public String getAttributeValue(int fingerprint) { if (nodeKind==Type.ELEMENT) { Iterator list = ((Element)node).attributes().iterator(); NamePool pool = docWrapper.getNamePool(); while (list.hasNext()) { Attribute att = (Attribute)list.next(); int nameCode = pool.allocate(att.getNamespacePrefix(), att.getNamespaceURI(), att.getName()); if (fingerprint == (nameCode & 0xfffff)) { return att.getValue(); } } } return null; } /** * Get the root node - always a document node with this tree implementation * @return the NodeInfo representing the containing document */ public NodeInfo getRoot() { return docWrapper; } /** * Get the root (document) node * @return the DocumentInfo representing the containing document */ public DocumentInfo getDocumentRoot() { return docWrapper; } /** * Determine whether the node has any children.
    * Note: the result is equivalent to
    * getEnumeration(Axis.CHILD, AnyNodeTest.getInstance()).hasNext() */ public boolean hasChildNodes() { switch (nodeKind) { case Type.DOCUMENT: return true; case Type.ELEMENT: // Beware: dom4j content() contains Namespace nodes (which is broken)! List content = ((Element)node).content(); for (int i=0; i *

    For a node other than an element, the method returns null.

    */ public int[] getDeclaredNamespaces(int[] buffer) { if (node instanceof Element) { final Element elem = (Element) node; final List namespaces = elem.declaredNamespaces(); if (namespaces == null || namespaces.isEmpty()) { return EMPTY_NAMESPACE_LIST; } final int count = namespaces.size(); if (count == 0) { return EMPTY_NAMESPACE_LIST; } else { int[] result = (buffer == null || count > buffer.length ? new int[count] : buffer); NamePool pool = getNamePool(); int n = 0; for (Iterator i = namespaces.iterator(); i.hasNext();) { final Namespace namespace = (Namespace) i.next(); final String prefix = namespace.getPrefix(); final String uri = namespace.getURI(); result[n++] = pool.allocateNamespaceCode(prefix, uri); } if (count < result.length) { result[count] = -1; } return result; } } else { return null; } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/dom4j/DOM4JObjectModel.java0000644000175000017500000002573511033417647022233 0ustar eugeneeugenepackage net.sf.saxon.dom4j; import net.sf.saxon.Configuration; import net.sf.saxon.event.PipelineConfiguration; import net.sf.saxon.event.Receiver; import net.sf.saxon.expr.JPConverter; import net.sf.saxon.expr.PJConverter; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.*; import net.sf.saxon.pattern.AnyNodeTest; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ItemType; import net.sf.saxon.value.SingletonNode; import net.sf.saxon.value.Value; import org.dom4j.*; import javax.xml.transform.Result; import javax.xml.transform.Source; import java.io.Serializable; /** * This class is the DOM4J implementation of Saxon's ExternalObjectModel interface; it supports * the wrapping of DOM4J documents as instances of the Saxon NodeInfo interface. */ public class DOM4JObjectModel implements ExternalObjectModel, Serializable { public DOM4JObjectModel() {} /** * Get the URI of the external object model as used in the JAXP factory interfaces for obtaining * an XPath implementation */ public String getIdentifyingURI() { return NamespaceConstant.OBJECT_MODEL_DOM4J; } public PJConverter getPJConverter(Class targetClass) { if (isRecognizedNodeClass(targetClass)) { return new PJConverter() { public Object convert(ValueRepresentation value, Class targetClass, XPathContext context) throws XPathException { return convertXPathValueToObject(Value.asValue(value), targetClass, context); } }; } else { return null; } } public JPConverter getJPConverter(Class targetClass) { if (isRecognizedNodeClass(targetClass)) { return new JPConverter() { public ValueRepresentation convert(Object object, XPathContext context) throws XPathException { return convertObjectToXPathValue(object, context.getConfiguration()); } public ItemType getItemType() { return AnyNodeTest.getInstance(); } }; } else { return null; } } /** * Get a converter that converts a sequence of XPath nodes to this model's representation * of a node list. * @param node an example of the kind of node used in this model * @return if the model does not recognize this node as one of its own, return null. Otherwise * return a PJConverter that takes a list of XPath nodes (represented as NodeInfo objects) and * returns a collection of nodes in this object model */ public PJConverter getNodeListCreator(Object node) { return null; } /** * Test whether this object model recognizes a given node as one of its own */ public boolean isRecognizedNode(Object object) { return object instanceof Document || object instanceof Element || object instanceof Attribute || object instanceof Text || object instanceof CDATA || object instanceof Comment || object instanceof ProcessingInstruction || object instanceof Namespace; } /** * Test whether this object model recognizes a given class as representing a * node in that object model. This method will generally be called at compile time. * * @param nodeClass A class that possibly represents nodes * @return true if the class is used to represent nodes in this object model */ private boolean isRecognizedNodeClass(Class nodeClass) { return Document.class.isAssignableFrom(nodeClass) || Element.class.isAssignableFrom(nodeClass) || Attribute.class.isAssignableFrom(nodeClass) || Text.class.isAssignableFrom(nodeClass) || CDATA.class.isAssignableFrom(nodeClass) || Comment.class.isAssignableFrom(nodeClass) || ProcessingInstruction.class.isAssignableFrom(nodeClass) || Namespace.class.isAssignableFrom(nodeClass); } /** * Test whether this object model recognizes a given class as representing a * list of nodes in that object model. This method will generally be called at compile time. * * @param nodeClass A class that possibly represents nodes * @return true if the class is used to represent nodes in this object model */ public boolean isRecognizedNodeListClass(Class nodeClass) { return false; } /** * Test whether this object model recognizes a particular kind of JAXP Result object, * and if it does, return a Receiver that builds an instance of this data model from * a sequence of events. If the Result is not recognised, return null. */ public Receiver getDocumentBuilder(Result result) { return null; } /** * Test whether this object model recognizes a particular kind of JAXP Source object, * and if it does, send the contents of the document to a supplied Receiver, and return true. * Otherwise, return false. */ public boolean sendSource(Source source, Receiver receiver, PipelineConfiguration pipe) throws XPathException { return false; } /** * Wrap or unwrap a node using this object model to return the corresponding Saxon node. If the supplied * source does not belong to this object model, return null */ public NodeInfo unravel(Source source, Configuration config) { return null; } /** * Convert a Java object to an XPath value. If the supplied object is recognized as a representation * of a value using this object model, the object model should convert the value to an XPath value * and return this as the result. If not, it should return null. If the object is recognized but cannot * be converted, an exception should be thrown */ public ValueRepresentation convertObjectToXPathValue(Object object, Configuration config) throws XPathException { if (isRecognizedNode(object)) { if (object instanceof Document) { return wrapDocument(object, null, config); } else { Document root = getDocumentRoot(object); DocumentInfo docInfo = wrapDocument(root, null, config); return wrapNode(docInfo, object); } } else { return null; } } /** * Convert an XPath value to an object in this object model. If the supplied value can be converted * to an object in this model, of the specified class, then the conversion should be done and the * resulting object returned. If the value cannot be converted, the method should return null. Note * that the supplied class might be a List, in which case the method should inspect the contents of the * Value to see whether they belong to this object model. */ public Object convertXPathValueToObject(Value value, Object targetClass, XPathContext context) { if (value instanceof SingletonNode) { NodeInfo node = ((SingletonNode)value).getNode(); if (node instanceof VirtualNode) { Object u = ((VirtualNode)node).getUnderlyingNode(); if (((Class)targetClass).isAssignableFrom(u.getClass())) { return u; } } } return null; } /** * Wrap a document node in the external object model in a document wrapper that implements * the Saxon DocumentInfo interface * @param node a node (any node) in the third party document * @param baseURI the base URI of the node (supply "" if unknown) * @param config the Saxon configuration (which among other things provides access to the NamePool) * @return the wrapper, which must implement DocumentInfo */ public DocumentInfo wrapDocument(Object node, String baseURI, Configuration config) { Document documentNode = getDocumentRoot(node); return new net.sf.saxon.dom4j.DocumentWrapper(documentNode, baseURI, config); } /** * Wrap a node within the external object model in a node wrapper that implements the Saxon * VirtualNode interface (which is an extension of NodeInfo) * @param document the document wrapper, as a DocumentInfo object * @param node the node to be wrapped. This must be a node within the document wrapped by the * DocumentInfo provided in the first argument * @return the wrapper for the node, as an instance of VirtualNode */ public NodeInfo wrapNode(DocumentInfo document, Object node) { return ((DocumentWrapper)document).wrap(node); } /** * Get the document root */ private Document getDocumentRoot(Object node) { while (!(node instanceof Document)) { if (node instanceof Element) { if (((Element)node).isRootElement()) { return ((Element)node).getDocument(); } else { node = ((Element)node).getParent(); } } else if (node instanceof Text) { node = ((Text)node).getParent(); } else if (node instanceof Comment) { node = ((Comment)node).getParent(); } else if (node instanceof ProcessingInstruction) { node = ((ProcessingInstruction)node).getParent(); } else if (node instanceof Attribute) { node = ((Attribute)node).getParent(); } else if (node instanceof Document) { return (Document)node; } else if (node instanceof Namespace) { throw new UnsupportedOperationException("Cannot find parent of DOM4J namespace node"); } else { throw new IllegalStateException("Unknown DOM4J node type " + node.getClass()); } } return (Document)node; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): Gunther Schadow (changes to allow access to public fields; also wrapping // of extensions and mapping of null to empty sequence). // saxonb-9.1.0.8/bj/net/sf/saxon/dom4j/package.html0000644000175000017500000000130611033112257020675 0ustar eugeneeugene Package overview for net.sf.saxon.dom4j

    This package provides glue classes that enable Saxon to process a source document supplied as a DOM4J tree (see http://www.dom4j.org).

    These classes are not part of the core saxon.jar product, but are released as a separate saxon-dom4j.jar.

    The package provides implementations of the Saxon DocumentInfo and NodeInfo classes that act as wrappers to the relevant DOM4J classes


    Michael H. Kay
    Saxonica Limited
    9 February 2007

    saxonb-9.1.0.8/bj/net/sf/saxon/Compile.java0000644000175000017500000002774011033112257017644 0ustar eugeneeugenepackage net.sf.saxon; import net.sf.saxon.instruct.TerminationException; import net.sf.saxon.trans.XPathException; import org.xml.sax.InputSource; import javax.xml.transform.Source; import javax.xml.transform.Templates; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerFactoryConfigurationError; import javax.xml.transform.sax.SAXSource; import java.io.*; import java.util.Date; /** * This Compile class provides a command-line interface allowing a * stylesheet to be compiled.

    * * @author M.H.Kay */ public class Compile { private TransformerFactoryImpl factory = new TransformerFactoryImpl(); private boolean showTime = false; private boolean debug = false; /** * Main program, can be used directly from the command line. *

    The format is:

    *

    java net.sf.saxon.Compile [options] style-file output-file

    *

    This program compiles the XSL style sheet in style-file to the output-file.

    * * @param args Arguments supplied on the command line * @exception java.lang.Exception Any compilation error occurs */ public static void main (String args[]) throws java.lang.Exception { // the real work is delegated to another routine so that it can be used in a subclass (new Compile()).doMain(args); } /** * Support method for main program. This support method can also be invoked from subclasses * that support the same command line interface * * @param args the command-line arguments */ protected void doMain(String args[]) { String styleFileName; boolean useURLs = false; String outputFileName; // Check the command-line arguments. try { int i = 0; while (true) { if (i>=args.length) badUsage("No stylesheet file name"); if (args[i].charAt(0)=='-') { if (args[i].equals("-u")) { useURLs = true; i++; } else if (args[i].equals("-t")) { System.err.println(factory.getConfiguration().getProductTitle()); //System.err.println("Java version " + System.getProperty("java.version")); System.err.println(Configuration.getPlatform().getPlatformVersion()); factory.setAttribute( FeatureKeys.TIMING, Boolean.TRUE); //Loader.setTracing(true); showTime = true; i++; } else if (args[i].equals("-y")) { i++; if (args.length < i+2) badUsage("No style parser class"); String styleParserName = args[i++]; factory.setAttribute( FeatureKeys.STYLE_PARSER_CLASS, styleParserName); } else if (args[i].equals("-r")) { i++; if (args.length < i+2) badUsage("No URIResolver class"); String r = args[i++]; factory.setURIResolver(factory.getConfiguration().makeURIResolver(r)); } else if (args[i].equals("-debug")) { i++; debug = true; } else if (args[i].equals("-1.1")) { // XML 1.1 i++; factory.setAttribute(FeatureKeys.XML_VERSION, "1.1"); } else badUsage("Unknown option " + args[i]); } else break; } if (args.length < i+1 ) badUsage("No stylesheet file name"); styleFileName = args[i++]; if (args.length < i+1 ) badUsage("No output file name"); outputFileName = args[i++]; long startTime = (new Date()).getTime(); Source styleSource; if (useURLs || styleFileName.startsWith("http:") || styleFileName.startsWith("file:")) { styleSource = factory.getURIResolver().resolve(styleFileName, null); if (styleSource == null) { styleSource = factory.getConfiguration().getSystemURIResolver().resolve(styleFileName, null); } } else { File sheetFile = new File(styleFileName); if (!sheetFile.exists()) { quit("Stylesheet file " + sheetFile + " does not exist", 2); } InputSource eis = new InputSource(sheetFile.toURI().toString()); styleSource = new SAXSource(factory.getConfiguration().getStyleParser(), eis); } if (styleSource==null) { quit("URIResolver for stylesheet file must return a Source", 2); } Templates sheet = factory.newTemplates(styleSource); if (showTime) { long endTime = (new Date()).getTime(); System.err.println("Stylesheet compilation time: " + (endTime-startTime) + " milliseconds"); } try { String msg = ((PreparedStylesheet)sheet).getExecutable().getReasonUnableToCompile(); if (msg != null) { System.err.println(msg); quit("Unable to compile stylesheet", 2); } System.err.println("Serializing compiled stylesheet"); ((PreparedStylesheet)sheet).setTargetNamePool( ((PreparedStylesheet)sheet).getConfiguration().getNamePool()); OutputStream fos = new FileOutputStream(outputFileName); if (debug) { fos = new TracingObjectOutputStream(fos); } ObjectOutputStream oos = new ObjectOutputStream(fos); //noinspection RedundantCast oos.writeObject((PreparedStylesheet)sheet); oos.close(); System.err.println("Finished serializing stylesheet"); } catch (Exception err) { err.printStackTrace(); } } catch (TerminationException err) { quit(err.getMessage(), 1); } catch (XPathException err) { quit("Stylesheet compilation failed: " + err.getMessage(), 2); } catch (TransformerConfigurationException err) { quit("Stylesheet compilation failed: " + err.getMessage(), 2); } catch (TransformerFactoryConfigurationError err) { quit("Stylesheet compilation failed: " + err.getMessage(), 2); } catch (Exception err2) { err2.printStackTrace(); } } /** * Exit with a message * * @param message Message to be output * @param code Result code to be returned to the operating system */ protected static void quit(String message, int code) { System.err.println(message); System.exit(code); } /** Output error message when incorrect command line options/arguments are used * * @param message Error message to be displayed */ protected void badUsage(String message) { System.err.println(message); System.err.println(factory.getConfiguration().getProductTitle()); System.err.println("Usage: java net.sf.saxon.Compile [options] stylesheet-file output-file"); System.err.println("Options: "); System.err.println(" -r classname Use specified URIResolver class"); System.err.println(" -t Display version and timing information"); System.err.println(" -u Names are URLs not filenames"); System.err.println(" -y classname Use specified SAX parser for stylesheet"); System.err.println(" -debug Produce trace output to diagnose failures"); System.err.println(" -1.1 Allow XML 1.1 documents"); System.err.println(" -? Display this message "); System.exit(2); } /** * Tracing version of ObjectOutputStream for diagnostics */ private static class TracingObjectOutputStream extends FilterOutputStream { OutputStream oos; public TracingObjectOutputStream(OutputStream oos) { super(oos); this.oos = oos; } public void write(byte b[]) throws IOException { char[] chars = new char[b.length]; for (int i=0; i= 0) { System.err.println("write byte[]: " + s); } super.write(b); } /** * Writes len bytes from the specified * byte array starting at offset off to * this output stream. *

    * The write method of FilterOutputStream * calls the write method of one argument on each * byte to output. *

    * Note that this method does not call the write method * of its underlying input stream with the same arguments. Subclasses * of FilterOutputStream should provide a more efficient * implementation of this method. * * @param b the data. * @param off the start offset in the data. * @param len the number of bytes to write. * @throws java.io.IOException if an I/O error occurs. * @see java.io.FilterOutputStream#write(int) */ public void write(byte b[], int off, int len) throws IOException { char[] chars = new char[len]; for (int i=0; i= 0) { System.err.println("write byte[]: " + s); } super.write(b, off, len); } /** * Writes the specified byte to this output stream. *

    * The write method of FilterOutputStream * calls the write method of its underlying output stream, * that is, it performs out.write(b). *

    * Implements the abstract write method of OutputStream. * * @param b the byte. * @throws java.io.IOException if an I/O error occurs. */ // public void write(int b) throws IOException { // char c = (char)b; // System.err.println("write byte: " + c); // super.write(b); // } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/sql/0000755000175000017500000000000012216261746016212 5ustar eugeneeugenesaxonb-9.1.0.8/bj/net/sf/saxon/sql/SQLUpdate.java0000644000175000017500000002055411033112257020651 0ustar eugeneeugenepackage net.sf.saxon.sql; import net.sf.saxon.expr.*; import net.sf.saxon.instruct.Executable; import net.sf.saxon.om.*; import net.sf.saxon.style.ExtensionInstruction; import net.sf.saxon.trans.XPathException; import net.sf.saxon.trans.SaxonErrorCode; import net.sf.saxon.value.AtomicValue; import net.sf.saxon.value.ObjectValue; import net.sf.saxon.value.StringValue; import net.sf.saxon.value.Whitespace; import net.sf.saxon.type.Type; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; /** * An sql:update element in the stylesheet. * @author Mathias Payer * @author Michael Kay *

    * For example: *

    *   <sql:update connection="{$connection}" table="table-name" where="{$where}"
    *                 xsl:extension-element-prefixes="sql">
    *       <sql:column name="column-name" select="$new_value" />
    *   </sql:update>
    * 

    *

    */ public class SQLUpdate extends ExtensionInstruction { Expression connection; String table; Expression where; public void prepareAttributes() throws XPathException { table = getAttributeList().getValue("", "table"); if (table==null) { reportAbsence("table"); } table = SQLConnect.quoteSqlName(table); String dbWhere = getAttributeList().getValue("", "where"); if (dbWhere == null) { where = new StringLiteral(StringValue.EMPTY_STRING); } else { where = makeAttributeValueTemplate(dbWhere); } String connectAtt = getAttributeList().getValue("", "connection"); if (connectAtt==null) { reportAbsence("connection"); } else { connection = makeExpression(connectAtt); } } public void validate() throws XPathException { super.validate(); where = typeCheck("where", where); connection = typeCheck("connection", connection); AxisIterator kids = iterateAxis(Axis.CHILD); while(true) { NodeInfo curr = (NodeInfo)kids.next(); if (curr == null) { break; } if (curr instanceof SQLColumn) { // OK } else if (curr.getNodeKind() == Type.TEXT && Whitespace.isWhite(curr.getStringValueCS())) { // OK } else { compileError("Only sql:column is allowed as a child of sql:update", "XTSE0010"); } } } public Expression compile(Executable exec) throws XPathException { // Collect names of columns to be added FastStringBuffer statement = new FastStringBuffer(120); statement.append("UPDATE " + table + " SET "); AxisIterator kids = iterateAxis(Axis.CHILD); NodeInfo child; int cols = 0; while (true) { child = (NodeInfo)kids.next(); if (child == null) { break; } if (child instanceof SQLColumn) { if (cols++ > 0) statement.append(','); String colname = ((SQLColumn)child).getColumnName(); statement.append(colname); statement.append("=?"); } } return new UpdateInstruction(connection, statement.toString(), getColumnInstructions(exec), where); } public List getColumnInstructions(Executable exec) throws XPathException { List list = new ArrayList(10); AxisIterator kids = iterateAxis(Axis.CHILD); NodeInfo child; while (true) { child = (NodeInfo)kids.next(); if (child == null) { break; } if (child instanceof SQLColumn) { list.add(((SQLColumn)child).compile(exec)); } } return list; } private static class UpdateInstruction extends SimpleExpression { private static final long serialVersionUID = -4234440812734827279L; public static final int CONNECTION = 0; public static final int WHERE = 1; public static final int FIRST_COLUMN = 2; String statement; public UpdateInstruction(Expression connection, String statement, List columnInstructions, Expression where) { Expression[] sub = new Expression[columnInstructions.size() + 2]; sub[CONNECTION] = connection; sub[WHERE] = where; for (int i=0; isaxonb-9.1.0.8/bj/net/sf/saxon/sql/SQLElementFactory.java0000644000175000017500000000337711033112257022354 0ustar eugeneeugenepackage net.sf.saxon.sql; import net.sf.saxon.style.ExtensionElementFactory; /** * Class SQLElementFactory.
    * A "Factory" for SQL extension nodes in the stylesheet tree.
    */ public class SQLElementFactory implements ExtensionElementFactory { /** * Identify the class to be used for stylesheet elements with a given local name. * The returned class must extend net.sf.saxon.style.StyleElement * @return null if the local name is not a recognised element type in this * namespace. */ public Class getExtensionClass(String localname) { if (localname.equals("connect")) return SQLConnect.class; if (localname.equals("insert")) return SQLInsert.class; if (localname.equals("update")) return SQLUpdate.class; if (localname.equals("delete")) return SQLDelete.class; if (localname.equals("column")) return SQLColumn.class; if (localname.equals("close")) return SQLClose.class; if (localname.equals("query")) return SQLQuery.class; return null; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/sql/SQLInsert.java0000644000175000017500000002001511033112257020663 0ustar eugeneeugenepackage net.sf.saxon.sql; import net.sf.saxon.expr.Expression; import net.sf.saxon.expr.SimpleExpression; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.instruct.Executable; import net.sf.saxon.om.Axis; import net.sf.saxon.om.AxisIterator; import net.sf.saxon.om.Item; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.style.ExtensionInstruction; import net.sf.saxon.trans.SaxonErrorCode; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.Type; import net.sf.saxon.value.AtomicValue; import net.sf.saxon.value.ObjectValue; import net.sf.saxon.value.Whitespace; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; /** * An sql:insert element in the stylesheet. */ public class SQLInsert extends ExtensionInstruction { Expression connection; String table; public void prepareAttributes() throws XPathException { table = getAttributeList().getValue("", "table"); if (table==null) { reportAbsence("table"); } table = SQLConnect.quoteSqlName(table); String connectAtt = getAttributeList().getValue("", "connection"); if (connectAtt==null) { reportAbsence("connection"); } else { connection = makeExpression(connectAtt); } } public void validate() throws XPathException { super.validate(); connection = typeCheck("connection", connection); AxisIterator kids = iterateAxis(Axis.CHILD); while(true) { NodeInfo curr = (NodeInfo)kids.next(); if (curr == null) { break; } if (curr instanceof SQLColumn) { // OK } else if (curr.getNodeKind() == Type.TEXT && Whitespace.isWhite(curr.getStringValueCS())) { // OK } else { compileError("Only sql:column is allowed as a child of sql:insert", "XTSE0010"); } } } public Expression compile(Executable exec) throws XPathException { // Collect names of columns to be added StringBuffer statement = new StringBuffer(120); statement.append("INSERT INTO " + table + " ("); AxisIterator kids = iterateAxis(Axis.CHILD); NodeInfo child; int cols = 0; while (true) { child = (NodeInfo)kids.next(); if (child == null) { break; } if (child instanceof SQLColumn) { if (cols++ > 0) statement.append(','); String colname = ((SQLColumn)child).getColumnName(); statement.append(colname); } } statement.append(") VALUES ("); // Add "?" marks for the variable parameters for(int i=0; i9 && dbAtt.substring(0,9).equals("jdbc:odbc")) { dbDriver = "sun.jdbc.odbc.JdbcOdbcDriver"; } else { reportAbsence("driver"); } } driver = makeAttributeValueTemplate(dbDriver); // Get and expand user attribute, which defaults to empty string String userAtt = getAttributeValue("", "user"); if (userAtt==null) { user = new StringLiteral(StringValue.EMPTY_STRING); } else { user = makeAttributeValueTemplate(userAtt); } // Get and expand password attribute, which defaults to empty string String pwdAtt = getAttributeValue("", "password"); if (pwdAtt==null) { password = new StringLiteral(StringValue.EMPTY_STRING); } else { password = makeAttributeValueTemplate(pwdAtt); } } public void validate() throws XPathException { super.validate(); database = typeCheck("database", database); driver = typeCheck("driver", driver); user = typeCheck("user", user); password = typeCheck("password", password); } public Expression compile(Executable exec) throws XPathException { return new ConnectInstruction(database, driver, user, password); } private static class ConnectInstruction extends SimpleExpression { public static final int DATABASE = 0; public static final int DRIVER = 1; public static final int USER = 2; public static final int PASSWORD = 3; public ConnectInstruction(Expression database, Expression driver, Expression user, Expression password) { Expression[] subs = {database, driver, user, password}; setArguments(subs); } /** * A subclass must provide one of the methods evaluateItem(), iterate(), or process(). * This method indicates which of the three is provided. */ public int getImplementationMethod() { return Expression.EVALUATE_METHOD; } public int computeCardinality() { return StaticProperty.EXACTLY_ONE; } public String getExpressionType() { return "sql:connect"; } public Item evaluateItem(XPathContext context) throws XPathException { // Establish the JDBC connection Connection connection = null; // JDBC Database Connection String dbString = arguments[DATABASE].evaluateAsString(context).toString(); String dbDriverString = arguments[DRIVER].evaluateAsString(context).toString(); String userString = arguments[USER].evaluateAsString(context).toString(); String pwdString = arguments[PASSWORD].evaluateAsString(context).toString(); try { // the following hack is necessary to load JDBC drivers Class.forName(dbDriverString); connection = DriverManager.getConnection(dbString, userString, pwdString); } catch (Exception ex) { dynamicError("JDBC Connection Failure: " + ex.getMessage(), SaxonErrorCode.SXSQ0003, context); } return new ObjectValue(connection); } } /** * Utility method to quote a SQL table or column name if it needs quoting. * @param name the supplied name * @return the supplied name, enclosed in double quotes if it does not satisfy the pattern [A-Za-z_][A-Za-z0-9_]*, * with any double quotes replaced by two double quotes */ public static String quoteSqlName(String name) throws IllegalArgumentException { // TODO: allow an embedded double-quote to be escaped as two double-quotes if (namePattern.matcher(name).matches()) { return name; } return "\"" + name + "\""; } private static Pattern namePattern = Pattern.compile("\"[^\"]+\"|[A-Za-z_][A-Za-z0-9_]*"); } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Additional Contributor(s): Rick Bonnett [rbonnett@acadia.net] // saxonb-9.1.0.8/bj/net/sf/saxon/sql/SQLColumn.java0000644000175000017500000000653511033112257020667 0ustar eugeneeugenepackage net.sf.saxon.sql; import net.sf.saxon.expr.Expression; import net.sf.saxon.expr.RoleLocator; import net.sf.saxon.expr.TypeChecker; import net.sf.saxon.instruct.Executable; import net.sf.saxon.om.AttributeCollection; import net.sf.saxon.om.Navigator; import net.sf.saxon.style.StyleElement; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.SequenceType; import net.sf.saxon.value.Whitespace; /** * An sql:column element in the stylesheet. */ public class SQLColumn extends StyleElement { private String name; private Expression select; /** * Determine whether this node is an instruction. * @return false - it is not an instruction */ public boolean isInstruction() { return false; } /** * Determine whether this type of element is allowed to contain a template-body * @return false: no, it may not contain a template-body */ public boolean mayContainSequenceConstructor() { return false; } protected boolean mayContainFallback() { return false; } public void prepareAttributes() throws XPathException { AttributeCollection atts = getAttributeList(); String selectAtt = null; String nameAtt = null; for (int a=0; a * For example: *
     *   <sql:query column="{$column}" table="{$table}" where="{$where}"
     *                 xsl:extension-element-prefixes="sql"/ >
     * 

    *

    * (result with HTML-table-output)
    *
     *   <sql:query column="{$column}" table="{$table}" where="{$where}"
     *                 row-tag="TR" column-tag="TD"
     *                 separatorType="tag"
     *                 xsl:extension-element-prefixes="sql"/ >
     * 
    * * @author claudio.thomas@unix-ag.org (based on Michael Kay's SQLInsert.java) */ public class SQLQuery extends ExtensionInstruction { Expression connection; /** * selected column(s) to query */ Expression column; /** * the table(s) to query in */ Expression table; /** * conditions of query (can be omitted) */ Expression where; String rowTag; /** * name of element to hold the rows */ String colTag; /** * name of element to hold the columns */ boolean disable = false; // true means disable-output-escaping="yes" public void prepareAttributes() throws XPathException { // Attributes for SQL-statement String dbCol = getAttributeValue("", "column"); if (dbCol == null) { reportAbsence("column"); } column = makeAttributeValueTemplate(dbCol); String dbTab = getAttributeValue("", "table"); if (dbTab == null) { reportAbsence("table"); dbTab = "saxon-dummy-table"; } table = makeAttributeValueTemplate(dbTab); String dbWhere = getAttributeValue("", "where"); if (dbWhere == null) { where = new StringLiteral(StringValue.EMPTY_STRING); } else { where = makeAttributeValueTemplate(dbWhere); } String connectAtt = getAttributeValue("", "connection"); if (connectAtt == null) { reportAbsence("connection"); } else { connection = makeExpression(connectAtt); } // Atributes for row & column element names rowTag = getAttributeValue("", "row-tag"); if (rowTag == null) { rowTag = "row"; } if (rowTag.indexOf(':') >= 0) { compileError("rowTag must not contain a colon"); } colTag = getAttributeValue("", "column-tag"); if (colTag == null) { colTag = "col"; } if (colTag.indexOf(':') >= 0) { compileError("colTag must not contain a colon"); } // Attribute output-escaping String disableAtt = getAttributeValue("", "disable-output-escaping"); if (disableAtt != null) { if (disableAtt.equals("yes")) { disable = true; } else if (disableAtt.equals("no")) { disable = false; } else { compileError("disable-output-escaping attribute must be either yes or no"); } } } public void validate() throws XPathException { super.validate(); column = typeCheck("column", column); table = typeCheck("table", table); where = typeCheck("where", where); connection = typeCheck("connection", connection); } public Expression compile(Executable exec) throws XPathException { return new QueryInstruction(connection, column, table, where, rowTag, colTag, disable); } private static class QueryInstruction extends SimpleExpression { public static final int CONNECTION = 0; public static final int COLUMN = 1; public static final int TABLE = 2; public static final int WHERE = 3; String rowTag; String colTag; int options; public QueryInstruction(Expression connection, Expression column, Expression table, Expression where, String rowTag, String colTag, boolean disable) { Expression[] sub = {connection, column, table, where}; setArguments(sub); this.rowTag = rowTag; this.colTag = colTag; this.options = (disable ? ReceiverOptions.DISABLE_ESCAPING : 0); } /** * A subclass must provide one of the methods evaluateItem(), iterate(), or process(). * This method indicates which of the three is provided. */ public int getImplementationMethod() { return Expression.PROCESS_METHOD; } public String getExpressionType() { return "sql:query"; } public void process(XPathContext context) throws XPathException { // Prepare the SQL statement (only do this once) Controller controller = context.getController(); Item conn = arguments[CONNECTION].evaluateItem(context); if (!(conn instanceof ObjectValue && ((ObjectValue)conn).getObject() instanceof Connection)) { XPathException de = new XPathException("Value of connection expression is not a JDBC Connection"); de.setXPathContext(context); throw de; } Connection connection = (Connection)((ObjectValue)conn).getObject(); String dbCol = arguments[COLUMN].evaluateAsString(context).toString(); String dbTab = arguments[TABLE].evaluateAsString(context).toString(); String dbWhere = arguments[WHERE].evaluateAsString(context).toString(); NamePool pool = controller.getNamePool(); int rowCode = pool.allocate("", "", rowTag); int colCode = pool.allocate("", "", colTag); PreparedStatement ps = null; ResultSet rs = null; XPathException de = null; try { StringBuffer statement = new StringBuffer(); statement.append("SELECT " + dbCol + " FROM " + dbTab); if (!dbWhere.equals("")) { statement.append(" WHERE " + dbWhere); } //System.err.println("-> SQL: " + statement.toString()); // -- Prepare the SQL statement ps = connection.prepareStatement(statement.toString()); controller.setUserData(this, "sql:statement", ps); // -- Execute Statement rs = ps.executeQuery(); // -- Print out Result Receiver out = context.getReceiver(); String result = ""; int icol = rs.getMetaData().getColumnCount(); while (rs.next()) { // next row //System.out.print("<- SQL : "+ rowStart); out.startElement(rowCode, StandardNames.XS_UNTYPED, locationId, 0); for (int col = 1; col <= icol; col++) { // next column // Read result from RS only once, because // of JDBC-Specifications result = rs.getString(col); out.startElement(colCode, StandardNames.XS_UNTYPED, locationId, 0); if (result != null) { out.characters(result, locationId, options); } out.endElement(); } //System.out.println(rowEnd); out.endElement(); } //rs.close(); if (!connection.getAutoCommit()) { connection.commit(); } } catch (SQLException ex) { de = new XPathException("(SQL) " + ex.getMessage()); de.setXPathContext(context); throw de; } finally { boolean wasDEThrown = (de != null); if (rs != null) { try { rs.close(); } catch (SQLException ex) { de = new XPathException("(SQL) " + ex.getMessage()); de.setXPathContext(context); } } if (ps != null) { try { ps.close(); } catch (SQLException ex) { de = new XPathException("(SQL) " + ex.getMessage()); de.setXPathContext(context); } } if (!wasDEThrown && de != null) { throw de; // test so we don't lose the real exception } } } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // // Contributor(s): claudio.thomas@unix-ag.org (based on SQLInsert.java) // saxonb-9.1.0.8/bj/net/sf/saxon/sql/SQLClose.java0000644000175000017500000000667511033112257020504 0ustar eugeneeugenepackage net.sf.saxon.sql; import net.sf.saxon.expr.Expression; import net.sf.saxon.expr.SimpleExpression; import net.sf.saxon.expr.StaticProperty; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.instruct.Executable; import net.sf.saxon.om.Item; import net.sf.saxon.style.ExtensionInstruction; import net.sf.saxon.trans.XPathException; import net.sf.saxon.trans.SaxonErrorCode; import net.sf.saxon.value.ObjectValue; import java.sql.Connection; import java.sql.SQLException; /** * An sql:close element in the stylesheet. */ public class SQLClose extends ExtensionInstruction { Expression connection = null; public void prepareAttributes() throws XPathException { String connectAtt = getAttributeList().getValue("", "connection"); if (connectAtt==null) { reportAbsence("connection"); } else { connection = makeExpression(connectAtt); } } public void validate() throws XPathException { super.validate(); connection = typeCheck("connection", connection); } public Expression compile(Executable exec) throws XPathException { return new CloseInstruction(connection); } private static class CloseInstruction extends SimpleExpression { public static final int CONNECTION = 0; public CloseInstruction(Expression connect) { Expression[] sub = {connect}; setArguments(sub); } /** * A subclass must provide one of the methods evaluateItem(), iterate(), or process(). * This method indicates which of the three is provided. */ public int getImplementationMethod() { return Expression.EVALUATE_METHOD; } public String getExpressionType() { return "sql:close"; } public int computeCardinality() { return StaticProperty.ALLOWS_ZERO_OR_ONE; } public Item evaluateItem(XPathContext context) throws XPathException { Item conn = arguments[CONNECTION].evaluateItem(context); if (!(conn instanceof ObjectValue && ((ObjectValue)conn).getObject() instanceof Connection) ) { dynamicError("Value of connection expression is not a JDBC Connection", SaxonErrorCode.SXSQ0001, context); } Connection connection = (Connection)((ObjectValue)conn).getObject(); try { connection.close(); } catch (SQLException ex) { dynamicError("(SQL) Failed to close connection: " + ex.getMessage(), SaxonErrorCode.SXSQ0002, context); } return null; } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Additional Contributor(s): Rick Bonnett [rbonnett@acadia.net] // saxonb-9.1.0.8/bj/net/sf/saxon/sql/SQLDelete.java0000644000175000017500000001245511033112257020632 0ustar eugeneeugenepackage net.sf.saxon.sql; import net.sf.saxon.expr.Expression; import net.sf.saxon.expr.SimpleExpression; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.expr.StringLiteral; import net.sf.saxon.instruct.Executable; import net.sf.saxon.om.Item; import net.sf.saxon.style.ExtensionInstruction; import net.sf.saxon.trans.XPathException; import net.sf.saxon.trans.SaxonErrorCode; import net.sf.saxon.value.ObjectValue; import net.sf.saxon.value.StringValue; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; /** * An sql:delete element in the stylesheet. * @author Mathias Payer * @author Michael Kay *

    * For example: *

    *   <sql:delete connection="{$connection}" table="table-name" where="{$where}"
    *                 xsl:extension-element-prefixes="sql" />
    * 

    *

    */ public class SQLDelete extends ExtensionInstruction { Expression connection; String table; Expression where; public void prepareAttributes() throws XPathException { table = getAttributeList().getValue("", "table"); if (table==null) { reportAbsence("table"); table = "saxon-error-table"; } table = SQLConnect.quoteSqlName(table); String dbWhere = getAttributeList().getValue("", "where"); if (dbWhere == null) { where = new StringLiteral(StringValue.EMPTY_STRING); } else { where = makeAttributeValueTemplate(dbWhere); } String connectAtt = getAttributeList().getValue("", "connection"); if (connectAtt==null) { reportAbsence("connection"); } else { connection = makeExpression(connectAtt); } } public void validate() throws XPathException { super.validate(); where = typeCheck("where", where); connection = typeCheck("connection", connection); } public Expression compile(Executable exec) throws XPathException { return new DeleteInstruction(connection, "DELETE FROM " + table, where); } private static class DeleteInstruction extends SimpleExpression { private static final long serialVersionUID = -4234440812734827279L; public static final int CONNECTION = 0; public static final int WHERE = 1; String statement; public DeleteInstruction(Expression connection, String statement, Expression where) { Expression[] sub = new Expression[2]; sub[CONNECTION] = connection; sub[WHERE] = where; this.statement = statement; setArguments(sub); } /** * A subclass must provide one of the methods evaluateItem(), iterate(), or process(). * This method indicates which of the three is provided. */ public int getImplementationMethod() { return Expression.EVALUATE_METHOD; } public String getExpressionType() { return "sql:delete"; } public Item evaluateItem(XPathContext context) throws XPathException { // Prepare the SQL statement (only do this once) Item conn = arguments[CONNECTION].evaluateItem(context); if (!(conn instanceof ObjectValue && ((ObjectValue)conn).getObject() instanceof Connection) ) { dynamicError("Value of connection expression is not a JDBC Connection", SaxonErrorCode.SXSQ0001, context); } Connection connection = (Connection)((ObjectValue)conn).getObject(); PreparedStatement ps = null; String dbWhere = arguments[WHERE].evaluateAsString(context).toString(); String localstmt = statement; if (!dbWhere.equals("")) { localstmt += " WHERE " + dbWhere; } try { ps=connection.prepareStatement(localstmt); ps.executeUpdate(); if (!connection.getAutoCommit()) { connection.commit(); } } catch (SQLException ex) { dynamicError("SQL DELETE failed: " + ex.getMessage(), SaxonErrorCode.SXSQ0004, context); } finally { if (ps != null) { try { ps.close(); } catch (SQLException ignore) {} } } return null; } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // Original code in SQLInsert.java by Michael Kay // Adaption to SQLDelete.java by Mathias Payer saxonb-9.1.0.8/bj/net/sf/saxon/sql/package.html0000644000175000017500000000142411033112257020460 0ustar eugeneeugene Package overview for net.sf.saxon.sql

    This package provides some sample extension elements for loading data into an SQL database.

    These classes are not intended as a production-quality tool, rather as an illustration of what can be achieved using extension elements. The classes are not distributed in the main saxon8.jar file, but in a separate saxon8-sql.jar file, which must be added to the classpath when these extensions are used.

    These SQL extensions are documented in the file sql-extension.html in the main documentation directory.


    Michael H. Kay
    Saxonica Limited
    9 February 2005

    saxonb-9.1.0.8/bj/net/sf/saxon/StandardURIResolver.java0000644000175000017500000002463211033112257022113 0ustar eugeneeugenepackage net.sf.saxon; import net.sf.saxon.event.IDFilter; import net.sf.saxon.event.Stripper; import net.sf.saxon.functions.EscapeURI; import net.sf.saxon.functions.ResolveURI; import net.sf.saxon.functions.URIQueryParameters; import net.sf.saxon.om.AllElementStripper; import net.sf.saxon.trans.XPathException; import net.sf.saxon.trans.Err; import net.sf.saxon.value.Whitespace; import org.xml.sax.InputSource; import org.xml.sax.XMLReader; import javax.xml.parsers.SAXParserFactory; import javax.xml.transform.Source; import javax.xml.transform.sax.SAXSource; import java.io.Serializable; import java.net.URI; import java.net.URISyntaxException; /** * This class provides the service of converting a URI into an InputSource. * It is used to get stylesheet modules referenced by xsl:import and xsl:include, * and source documents referenced by the document() function. The standard version * handles anything that the java URL class will handle. * You can write a subclass to handle other kinds of URI, e.g. references to things in * a database. * @author Michael H. Kay */ public class StandardURIResolver implements NonDelegatingURIResolver, Serializable { // TODO: IDEA: support the data: URI scheme. (Requires unescaping of the URI, then parsing the content as XML) private Configuration config = null; protected boolean recognizeQueryParameters = false; /** * Create a StandardURIResolver, with no reference to a Configuration. * This constructor is not used internally by Saxon, but it may be used by user-written application code. * It is deprecated because the StandardURIResolver works best when the Configuration is known. * @deprecated since 8.7 */ public StandardURIResolver() { this(null); } /** * Create a StandardURIResolver, with a reference to a Configuration * @param config The Configuration object. * This is used to get a SAX Parser for a source XML document */ public StandardURIResolver(Configuration config) { this.config = config; } /** * Indicate that query parameters (such as validation=strict) are to be recognized * @param recognize Set to true if query parameters in the URI are to be recognized and acted upon. * The default (for compatibility and interoperability reasons) is false. */ public void setRecognizeQueryParameters(boolean recognize) { recognizeQueryParameters = recognize; } /** * Determine whether query parameters (such as validation=strict) are to be recognized * @return true if query parameters are recognized and interpreted by Saxon. */ public boolean queryParametersAreRecognized() { return recognizeQueryParameters; } /** * Get the relevant platform * @return the platform */ protected Platform getPlatform() { return Configuration.getPlatform(); } /** * Set the configuration * @param config the configuration */ public void setConfiguration(Configuration config) { this.config = config; } /** * Get the configuration if available * @return the configuration */ public Configuration getConfiguration() { return config; } /** * Resolve a URI * @param href The relative or absolute URI. May be an empty string. May contain * a fragment identifier starting with "#", which must be the value of an ID attribute * in the referenced XML document. * @param base The base URI that should be used. May be null if uri is absolute. * @return a Source object representing an XML document */ public Source resolve(String href, String base) throws XPathException { // System.err.println("StandardURIResolver, href=" + href + ", base=" + base); Platform platform = getPlatform(); String relativeURI = href; String id = null; // Extract any fragment identifier. Note, this code is no longer used to // resolve fragment identifiers in URI references passed to the document() // function: the code of the document() function handles these itself. int hash = href.indexOf('#'); if (hash>=0) { relativeURI = href.substring(0, hash); id = href.substring(hash+1); // System.err.println("StandardURIResolver, href=" + href + ", id=" + id); } URIQueryParameters params = null; URI uri; URI relative; try { relativeURI = ResolveURI.escapeSpaces(relativeURI); relative = new URI(relativeURI); } catch (URISyntaxException err) { throw new XPathException("Invalid relative URI " + Err.wrap(relativeURI), err); } String query = relative.getQuery(); if (query != null && recognizeQueryParameters) { params = new URIQueryParameters(query, config); int q = relativeURI.indexOf('?'); relativeURI = relativeURI.substring(0, q); } Source source = null; if (recognizeQueryParameters && relativeURI.endsWith(".ptree")) { source = getPTreeSource(relativeURI, base); } if (source == null) { try { uri = platform.makeAbsolute(relativeURI, base); } catch (URISyntaxException err) { // System.err.println("Recovering from " + err); // last resort: if the base URI is null, or is itself a relative URI, we // try to expand it relative to the current working directory String expandedBase = ResolveURI.tryToExpand(base); if (!expandedBase.equals(base)) { // prevent infinite recursion return resolve(href, expandedBase); } //err.printStackTrace(); throw new XPathException("Invalid URI " + Err.wrap(relativeURI) + " - base " + Err.wrap(base), err); } // Check that any "%" sign in the URI is part of a well-formed percent-encoded UTF-8 character. // Without this check, dereferencing the resulting URL can fail with arbitrary unchecked exceptions final String uriString = uri.toString(); EscapeURI.checkPercentEncoding(uriString); source = new SAXSource(); setSAXInputSource((SAXSource)source, uriString); if (params != null) { XMLReader parser = params.getXMLReader(); if (parser != null) { ((SAXSource)source).setXMLReader(parser); } } if (((SAXSource)source).getXMLReader() == null) { if (config==null) { try { ((SAXSource)source).setXMLReader(SAXParserFactory.newInstance().newSAXParser().getXMLReader()); } catch (Exception err) { throw new XPathException(err); } } else { //((SAXSource)source).setXMLReader(config.getSourceParser()); // Leave the Sender to allocate an XMLReader, so that it can be returned to the pool after use } } } if (params != null) { int stripSpace = params.getStripSpace(); switch (stripSpace) { case Whitespace.ALL: { Stripper stripper = AllElementStripper.getInstance(); stripper.setStripAll(); source = AugmentedSource.makeAugmentedSource(source); ((AugmentedSource)source).addFilter(stripper); break; } case Whitespace.IGNORABLE: case Whitespace.NONE: source = AugmentedSource.makeAugmentedSource(source); ((AugmentedSource)source).setStripSpace(stripSpace); } } if (id != null) { IDFilter filter = new IDFilter(id); source = AugmentedSource.makeAugmentedSource(source); ((AugmentedSource)source).addFilter(filter); } if (params != null) { Integer validation = params.getValidationMode(); if (validation != null) { source = AugmentedSource.makeAugmentedSource(source); ((AugmentedSource)source).setSchemaValidationMode(validation.intValue()); } } if (params != null) { Boolean xinclude = params.getXInclude(); if (xinclude != null) { source = AugmentedSource.makeAugmentedSource(source); ((AugmentedSource)source).setXIncludeAware(xinclude.booleanValue()); } } return source; } /** * Handle a PTree source file (Saxon-SA only) * @param href the relative URI * @param base the base URI * @return the new Source object */ protected Source getPTreeSource(String href, String base) throws XPathException { throw new XPathException("PTree files can only be read using a Saxon-SA configuration"); } /** * Set the InputSource part of the returned SAXSource. This is done in a separate * method to allow subclassing. The default implementation simply places the URI in the * InputSource, allowing the XML parser to take responsibility for the dereferencing. * A subclass may choose to dereference the URI at this point an place an InputStream * in the SAXSource. * @param source the SAXSource being initialized * @param uriString the absolute (resolved) URI to be used */ protected void setSAXInputSource(SAXSource source, String uriString) { source.setInputSource(new InputSource(uriString)); source.setSystemId(uriString); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/number/0000755000175000017500000000000012216261747016704 5ustar eugeneeugenesaxonb-9.1.0.8/bj/net/sf/saxon/number/Alphanumeric.java0000644000175000017500000002326711101571476022164 0ustar eugeneeugenepackage net.sf.saxon.number; import net.sf.saxon.sort.IntRangeSet; /** * This class contains static utility methods to test whether a character is alphanumeric, as defined * by the rules of xsl:number: that is, whether it is in one of the Unicode categories * Nd, Nl, No, Lu, Ll, Lt, Lm or Lo */ public class Alphanumeric { private static int[] zeroDigits = { 0x0030, 0x0660, 0x06f0, 0x0966, 0x09e6, 0x0a66, 0x0ae6, 0x0b66, 0x0be6, 0x0c66, 0x0ce6, 0x0d66, 0x0e50, 0x0ed0, 0x0f20, 0x1040, 0x17e0, 0x1810, 0x1946, 0x19d0, 0xff10, 0x104a0, 0x107ce, 0x107d8, 0x107e2, 0x107ec, 0x107f6 }; // These data sets were generated from the Unicode 4.0 database using a custom stylesheet. // Note that the characters in the CJK Extended Ideograph ranges A and B, 3400-4DB5 and // 20000-2A6D6 are not listed individually\\ in the database, and therefore need to be handled specially. private static int[] startPoints = new int[]{ 0x0030, 0x0041, 0x0061, 0x00AA, 0x00B2, 0x00B5, 0x00B9, 0x00BC, 0x00C0, 0x00D8, 0x00F8, 0x0250, 0x02C6, 0x02E0, 0x02EE, 0x037A, 0x0386, 0x0388, 0x038C, 0x038E, 0x03A3, 0x03D0, 0x03F7, 0x048A, 0x04D0, 0x0500, 0x0531, 0x0559, 0x0561, 0x05D0, 0x05F0, 0x0621, 0x0640, 0x0660, 0x066E, 0x0671, 0x06D5, 0x06E5, 0x06EE, 0x06FF, 0x0710, 0x0712, 0x074D, 0x0780, 0x07B1, 0x0904, 0x093D, 0x0950, 0x0958, 0x0966, 0x097D, 0x0985, 0x098F, 0x0993, 0x09AA, 0x09B2, 0x09B6, 0x09BD, 0x09CE, 0x09DC, 0x09DF, 0x09E6, 0x09F4, 0x0A05, 0x0A0F, 0x0A13, 0x0A2A, 0x0A32, 0x0A35, 0x0A38, 0x0A59, 0x0A5E, 0x0A66, 0x0A72, 0x0A85, 0x0A8F, 0x0A93, 0x0AAA, 0x0AB2, 0x0AB5, 0x0ABD, 0x0AD0, 0x0AE0, 0x0AE6, 0x0B05, 0x0B0F, 0x0B13, 0x0B2A, 0x0B32, 0x0B35, 0x0B3D, 0x0B5C, 0x0B5F, 0x0B66, 0x0B71, 0x0B83, 0x0B85, 0x0B8E, 0x0B92, 0x0B99, 0x0B9C, 0x0B9E, 0x0BA3, 0x0BA8, 0x0BAE, 0x0BE6, 0x0C05, 0x0C0E, 0x0C12, 0x0C2A, 0x0C35, 0x0C60, 0x0C66, 0x0C85, 0x0C8E, 0x0C92, 0x0CAA, 0x0CB5, 0x0CBD, 0x0CDE, 0x0CE0, 0x0CE6, 0x0D05, 0x0D0E, 0x0D12, 0x0D2A, 0x0D60, 0x0D66, 0x0D85, 0x0D9A, 0x0DB3, 0x0DBD, 0x0DC0, 0x0E01, 0x0E32, 0x0E40, 0x0E50, 0x0E81, 0x0E84, 0x0E87, 0x0E8A, 0x0E8D, 0x0E94, 0x0E99, 0x0EA1, 0x0EA5, 0x0EA7, 0x0EAA, 0x0EAD, 0x0EB2, 0x0EBD, 0x0EC0, 0x0EC6, 0x0ED0, 0x0EDC, 0x0F00, 0x0F20, 0x0F40, 0x0F49, 0x0F88, 0x1000, 0x1023, 0x1029, 0x1040, 0x1050, 0x10A0, 0x10D0, 0x10FC, 0x1100, 0x115F, 0x11A8, 0x1200, 0x124A, 0x1250, 0x1258, 0x125A, 0x1260, 0x128A, 0x1290, 0x12B2, 0x12B8, 0x12C0, 0x12C2, 0x12C8, 0x12D8, 0x1312, 0x1318, 0x1369, 0x1380, 0x13A0, 0x1401, 0x166F, 0x1681, 0x16A0, 0x16EE, 0x1700, 0x170E, 0x1720, 0x1740, 0x1760, 0x176E, 0x1780, 0x17D7, 0x17DC, 0x17E0, 0x17F0, 0x1810, 0x1820, 0x1880, 0x1900, 0x1946, 0x1970, 0x1980, 0x19C1, 0x19D0, 0x1A00, 0x1D00, 0x1E00, 0x1EA0, 0x1F00, 0x1F18, 0x1F20, 0x1F48, 0x1F50, 0x1F59, 0x1F5B, 0x1F5D, 0x1F5F, 0x1F80, 0x1FB6, 0x1FBE, 0x1FC2, 0x1FC6, 0x1FD0, 0x1FD6, 0x1FE0, 0x1FF2, 0x1FF6, 0x2070, 0x2074, 0x207F, 0x2090, 0x2102, 0x2107, 0x210A, 0x2115, 0x2119, 0x2124, 0x2126, 0x2128, 0x212A, 0x212F, 0x2133, 0x213C, 0x2145, 0x2153, 0x2460, 0x24EA, 0x2776, 0x2C00, 0x2C30, 0x2C80, 0x2CFD, 0x2D00, 0x2D30, 0x2D6F, 0x2D80, 0x2DA0, 0x2DA8, 0x2DB0, 0x2DB8, 0x2DC0, 0x2DC8, 0x2DD0, 0x2DD8, 0x3005, 0x3021, 0x3031, 0x3038, 0x3041, 0x309D, 0x30A1, 0x30FC, 0x3105, 0x3131, 0x3192, 0x31A0, 0x31F0, 0x3220, 0x3251, 0x3280, 0x32B1, 0x3400, 0x4E00, /*0x9FBB,*/ 0xA000, 0xA800, 0xA803, 0xA807, 0xA80C, 0xAC00, /*0xD7A3,*/ 0xF900, 0xFA30, 0xFA70, 0xFB00, 0xFB13, 0xFB1D, 0xFB1F, 0xFB2A, 0xFB38, 0xFB3E, 0xFB40, 0xFB43, 0xFB46, 0xFBD3, 0xFD50, 0xFD92, 0xFDF0, 0xFE70, 0xFE76, 0xFF10, 0xFF21, 0xFF41, 0xFF66, 0xFFC2, 0xFFCA, 0xFFD2, 0xFFDA, 0x10000, 0x1000D, 0x10028, 0x1003C, 0x1003F, 0x10050, 0x10080, 0x10107, 0x10140, 0x1018A, 0x10300, 0x10320, 0x10330, 0x10380, 0x103A0, 0x103C8, 0x103D1, 0x10400, 0x104A0, 0x10800, 0x10808, 0x1080A, 0x10837, 0x1083C, 0x1083F, 0x10A00, 0x10A10, 0x10A15, 0x10A19, 0x10A40, 0x1D400, 0x1D456, 0x1D49E, 0x1D4A2, 0x1D4A5, 0x1D4A9, 0x1D4AE, 0x1D4BB, 0x1D4BD, 0x1D4C5, 0x1D507, 0x1D50D, 0x1D516, 0x1D51E, 0x1D53B, 0x1D540, 0x1D546, 0x1D54A, 0x1D552, 0x1D6A8, 0x1D6C2, 0x1D6DC, 0x1D6FC, 0x1D716, 0x1D736, 0x1D750, 0x1D770, 0x1D78A, 0x1D7AA, 0x1D7C4, 0x1D7CE, 0x20000, 0x2F800 }; private static int[] endPoints = new int[]{ 0x0039, 0x005A, 0x007A, 0x00AA, 0x00B3, 0x00B5, 0x00BA, 0x00BE, 0x00D6, 0x00F6, 0x0241, 0x02C1, 0x02D1, 0x02E4, 0x02EE, 0x037A, 0x0386, 0x038A, 0x038C, 0x03A1, 0x03CE, 0x03F5, 0x0481, 0x04CE, 0x04F9, 0x050F, 0x0556, 0x0559, 0x0587, 0x05EA, 0x05F2, 0x063A, 0x064A, 0x0669, 0x066F, 0x06D3, 0x06D5, 0x06E6, 0x06FC, 0x06FF, 0x0710, 0x072F, 0x076D, 0x07A5, 0x07B1, 0x0939, 0x093D, 0x0950, 0x0961, 0x096F, 0x097D, 0x098C, 0x0990, 0x09A8, 0x09B0, 0x09B2, 0x09B9, 0x09BD, 0x09CE, 0x09DD, 0x09E1, 0x09F1, 0x09F9, 0x0A0A, 0x0A10, 0x0A28, 0x0A30, 0x0A33, 0x0A36, 0x0A39, 0x0A5C, 0x0A5E, 0x0A6F, 0x0A74, 0x0A8D, 0x0A91, 0x0AA8, 0x0AB0, 0x0AB3, 0x0AB9, 0x0ABD, 0x0AD0, 0x0AE1, 0x0AEF, 0x0B0C, 0x0B10, 0x0B28, 0x0B30, 0x0B33, 0x0B39, 0x0B3D, 0x0B5D, 0x0B61, 0x0B6F, 0x0B71, 0x0B83, 0x0B8A, 0x0B90, 0x0B95, 0x0B9A, 0x0B9C, 0x0B9F, 0x0BA4, 0x0BAA, 0x0BB9, 0x0BF2, 0x0C0C, 0x0C10, 0x0C28, 0x0C33, 0x0C39, 0x0C61, 0x0C6F, 0x0C8C, 0x0C90, 0x0CA8, 0x0CB3, 0x0CB9, 0x0CBD, 0x0CDE, 0x0CE1, 0x0CEF, 0x0D0C, 0x0D10, 0x0D28, 0x0D39, 0x0D61, 0x0D6F, 0x0D96, 0x0DB1, 0x0DBB, 0x0DBD, 0x0DC6, 0x0E30, 0x0E33, 0x0E46, 0x0E59, 0x0E82, 0x0E84, 0x0E88, 0x0E8A, 0x0E8D, 0x0E97, 0x0E9F, 0x0EA3, 0x0EA5, 0x0EA7, 0x0EAB, 0x0EB0, 0x0EB3, 0x0EBD, 0x0EC4, 0x0EC6, 0x0ED9, 0x0EDD, 0x0F00, 0x0F33, 0x0F47, 0x0F6A, 0x0F8B, 0x1021, 0x1027, 0x102A, 0x1049, 0x1055, 0x10C5, 0x10FA, 0x10FC, 0x1159, 0x11A2, 0x11F9, 0x1248, 0x124D, 0x1256, 0x1258, 0x125D, 0x1288, 0x128D, 0x12B0, 0x12B5, 0x12BE, 0x12C0, 0x12C5, 0x12D6, 0x1310, 0x1315, 0x135A, 0x137C, 0x138F, 0x13F4, 0x166C, 0x1676, 0x169A, 0x16EA, 0x16F0, 0x170C, 0x1711, 0x1731, 0x1751, 0x176C, 0x1770, 0x17B3, 0x17D7, 0x17DC, 0x17E9, 0x17F9, 0x1819, 0x1877, 0x18A8, 0x191C, 0x196D, 0x1974, 0x19A9, 0x19C7, 0x19D9, 0x1A16, 0x1DBF, 0x1E9B, 0x1EF9, 0x1F15, 0x1F1D, 0x1F45, 0x1F4D, 0x1F57, 0x1F59, 0x1F5B, 0x1F5D, 0x1F7D, 0x1FB4, 0x1FBC, 0x1FBE, 0x1FC4, 0x1FCC, 0x1FD3, 0x1FDB, 0x1FEC, 0x1FF4, 0x1FFC, 0x2071, 0x2079, 0x2089, 0x2094, 0x2102, 0x2107, 0x2113, 0x2115, 0x211D, 0x2124, 0x2126, 0x2128, 0x212D, 0x2131, 0x2139, 0x213F, 0x2149, 0x2183, 0x249B, 0x24FF, 0x2793, 0x2C2E, 0x2C5E, 0x2CE4, 0x2CFD, 0x2D25, 0x2D65, 0x2D6F, 0x2D96, 0x2DA6, 0x2DAE, 0x2DB6, 0x2DBE, 0x2DC6, 0x2DCE, 0x2DD6, 0x2DDE, 0x3007, 0x3029, 0x3035, 0x303C, 0x3096, 0x309F, 0x30FA, 0x30FF, 0x312C, 0x318E, 0x3195, 0x31B7, 0x31FF, 0x3229, 0x325F, 0x3289, 0x32BF, 0x4DB5, /*0x4E00,*/ 0x9FBB, 0xA48C, 0xA801, 0xA805, 0xA80A, 0xA822, /*0xAC00,*/ 0xD7A3, 0xFA2D, 0xFA6A, 0xFAD9, 0xFB06, 0xFB17, 0xFB1D, 0xFB28, 0xFB36, 0xFB3C, 0xFB3E, 0xFB41, 0xFB44, 0xFBB1, 0xFD3D, 0xFD8F, 0xFDC7, 0xFDFB, 0xFE74, 0xFEFC, 0xFF19, 0xFF3A, 0xFF5A, 0xFFBE, 0xFFC7, 0xFFCF, 0xFFD7, 0xFFDC, 0x1000B, 0x10026, 0x1003A, 0x1003D, 0x1004D, 0x1005D, 0x100FA, 0x10133, 0x10178, 0x1018A, 0x1031E, 0x10323, 0x1034A, 0x1039D, 0x103C3, 0x103CF, 0x103D5, 0x1049D, 0x104A9, 0x10805, 0x10808, 0x10835, 0x10838, 0x1083C, 0x1083F, 0x10A00, 0x10A13, 0x10A17, 0x10A33, 0x10A47, 0x1D454, 0x1D49C, 0x1D49F, 0x1D4A2, 0x1D4A6, 0x1D4AC, 0x1D4B9, 0x1D4BB, 0x1D4C3, 0x1D505, 0x1D50A, 0x1D514, 0x1D51C, 0x1D539, 0x1D53E, 0x1D544, 0x1D546, 0x1D550, 0x1D6A5, 0x1D6C0, 0x1D6DA, 0x1D6FA, 0x1D714, 0x1D734, 0x1D74E, 0x1D76E, 0x1D788, 0x1D7A8, 0x1D7C2, 0x1D7C9, 0x1D7FF, 0x2A6D6, 0x2FA1D }; private static IntRangeSet alphanumerics = new IntRangeSet(startPoints, endPoints); /** * Determine whether a Unicode codepoint is alphanumeric, that is, whether it is in one of the * categories Nd, Nl, No, Lu, Ll, Lt, Lm or Lo * @param codepoint the codepoint to be tested * @return true if the codepoint is in one of these categories */ public static boolean isAlphanumeric(int codepoint) { return alphanumerics.contains(codepoint); } /** * Determine whether a character represents a decimal digit and if so, which digit. * @param in the Unicode character being tested. * @return -1 if it's not a decimal digit, otherwise the digit value. */ public static int getDigitValue(int in) { for (int z=0; z= zeroDigits[z]) { return in - zeroDigits[z]; } else { return -1; } } } return -1; } private Alphanumeric(){} } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/number/Numberer_frBE.java0000644000175000017500000002105011033112257022205 0ustar eugeneeugenepackage net.sf.saxon.number; /** * Class Numberer_frBE is a number formatter for French as used in Belgium. This one will be * activated for language="frBE" * * @author Luc Rochefort. Modified for fr-BE by Karel Goossens * @version 1.0 * */ public class Numberer_frBE extends AbstractNumberer { /** * Automatically generated serialVersionUID number */ private static final long serialVersionUID = -222104830008011842L; private static String[] frenchUnits = { "", "Un", "Deux", "Trois", "Quatre", "Cinq", "Six", "Sept", "Huit", "Neuf", "Dix", "Onze", "Douze", "Treize", "Quatorze", "Quinze", "Seize", "Dix-sept", "Dix-huit", "Dix-neuf" }; private static String[] frenchTens = { "", "Dix", "Vingt", "Trente", "Quarante", "Cinquante", "Soixante", "Soixante", "Quatre-vingt", "Quatre-vingt" }; private static String[] frenchOrdinalUnits = { "", "Premier", "Deuxième", "Troisième", "Quatrième", "Cinquième", "Sixième", "Septième", "Huitième", "Neuvième", "Dixième", "Onzième", "Douzième", "Treizième", "Quatorzième", "Quinzième", "Seizième", "Dix-septième", "Dix-huitième", "Dix-neuvième" }; private static String[] frenchOrdinalTens = { "", "Dixième", "Vingtième", "Trentième", "Quarantième", "Cinquantième", "Soixantième", "Soixante", "Quatre-vingtième", "Quatre-vingt" }; private static String[] frenchDays = { "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi", "Dimanche" }; private static String[] frenchMonths = { "Janvier", "Février", "Mars", "Avril", "Mai", "Juin", "Juillet", "Août", "Septembre", "Octobre", "Novembre", "Décembre" }; /* * (non-Javadoc) * * @see net.sf.saxon.number.Numberer_en#ordinalSuffix(java.lang.String, * long) */ protected String ordinalSuffix(String ordinalParam, long number) { if (number != 1) { return "e"; } else { return "er"; } } /* * (non-Javadoc) * * @see net.sf.saxon.number.Numberer_en#toWords(long) */ public String toWords(long number) { return toWords(number, true); } /* * (non-Javadoc) * * @see net.sf.saxon.number.Numberer_en#toWords(long, int) */ public String toWords(long number, int wordCase) { String s = toWords(number); if (wordCase == UPPER_CASE) { return s.toUpperCase(); } else if (wordCase == LOWER_CASE) { return s.toLowerCase(); } else { return s; } } private String toWords(long number, boolean terminal) { if (number == 0) { return "Zéro"; } else if (number >= 1000000000000000000l) { long rem = number % 1000000000000000000l; long n = number / 1000000000000000000l; String s = (n == 1 ? "Un" : toWords(n, true)); return s + " quintillion" + (n > 1 ? "s" : "") + (rem == 0 ? "" : " " + toWords(rem, LOWER_CASE, terminal)); } else if (number >= 1000000000000000l) { long rem = number % 1000000000000000l; long n = number / 1000000000000000l; String s = (n == 1 ? "Un" : toWords(n, true)); return s + " quatrillion" + (n > 1 ? "s" : "") + (rem == 0 ? "" : " " + toWords(rem, LOWER_CASE, terminal)); } else if (number >= 1000000000000l) { long rem = number % 1000000000000l; long n = number / 1000000000000l; String s = (n == 1 ? "Un" : toWords(n, true)); return s + " trillion" + (n > 1 ? "s" : "") + (rem == 0 ? "" : " " + toWords(rem, LOWER_CASE, terminal)); } else if (number >= 1000000000) { long rem = number % 1000000000; long n = number / 1000000000; String s = (n == 1 ? "Un" : toWords(n, true)); return s + " milliard" + (n > 1 ? "s" : "") + (rem == 0 ? "" : " " + toWords(rem, LOWER_CASE, terminal)); } else if (number >= 1000000) { long rem = number % 1000000; long n = number / 1000000; String s = (n == 1 ? "Un" : toWords(n, true)); return s + " million" + (n > 1 ? "s" : "") + (rem == 0 ? "" : " " + toWords(rem, LOWER_CASE, terminal)); } else if (number >= 1000) { long rem = number % 1000; long n = number / 1000; String s = (n == 1 ? "" : toWords(n, false)); return s + (n == 1 ? "Mille" : " mille") + (rem == 0 ? "" : " " + toWords(rem, LOWER_CASE, terminal)); } else if (number >= 100) { long rem = number % 100; long n = number / 100; String s = (n == 1 ? "" : toWords(n, false)); return s + (n == 1 ? "Cent" : " cent") + (rem == 0 && n > 1 && terminal ? "s" : ((rem != 0) ? " " + toWords(rem, LOWER_CASE, terminal) : "")); } else { if (number < 20) return frenchUnits[(int) number]; int rem = (int) (number % 10); int tens = (int) number / 10; if (tens == 7 || tens == 9) { rem += 10; } String link = (rem == 1 || rem == 11) ? ((tens == 8 || tens == 9) ? "-" : " et ") : "-"; return frenchTens[tens] + (rem == 0 ? ((tens == 8 && terminal) ? "s" : "") : link) + (tens == 0 ? frenchUnits[rem] : frenchUnits[rem].toLowerCase()); } } private String toWords(long number, int wordCase, boolean terminal) { String s = toWords(number, terminal); if (wordCase == UPPER_CASE) { return s.toUpperCase(); } else if (wordCase == LOWER_CASE) { return s.toLowerCase(); } else { return s; } } /* * (non-Javadoc) * * @see net.sf.saxon.number.Numberer_en#toOrdinalWords(java.lang.String, * long, int) */ public String toOrdinalWords(String ordinalParam, long number, int wordCase) { String ord; if (number < 20) { if (number == 0) { ord = "Zéroième"; } else { ord = frenchOrdinalUnits[(int) number]; } } else if (number < 100) { long mod10 = number % 10; long int10 = number / 10; if (int10 == 7 || int10 == 9) { int10 -= 1; mod10 += 10; } if (mod10 == 0) { ord = frenchOrdinalTens[(int) int10]; } else { String link = (mod10 == 1 || mod10 == 11) ? ((int10 == 8) ? "-" : " et ") : "-"; String prefix = toWords(int10 * 10); if (int10 == 8) { prefix = prefix.substring(0, prefix.length() - 1); } String result = prefix + link; ord = result + ((mod10 == 1) ? "unième" : toOrdinalWords("", mod10, LOWER_CASE)); } } else { String suffix = "ième"; long mod100 = number % 100; long int100 = number / 100; if (int100 == 70 || int100 == 90) { int100 -= 10; mod100 += 100; } String prefix = toWords(int100 * 100, false); if (int100 % 10000 == 0) { prefix = prefix.replaceFirst("Un ", ""); } /* strip prefix, if needed */ if ((prefix.endsWith("mille") || prefix.endsWith("Mille")) && mod100 == 0) { prefix = prefix.substring(0, prefix.length() - 1); } else if (prefix.endsWith("illions") || prefix.endsWith("illiards")) { prefix = prefix.substring(0, prefix.length() - 1); } ord = prefix + ((mod100 == 0) ? suffix : " " + ((mod100 == 1) ? "unième" : toOrdinalWords("", mod100, LOWER_CASE))); } if (wordCase == UPPER_CASE) { return ord.toUpperCase(); } else if (wordCase == LOWER_CASE) { return ord.toLowerCase(); } else { return ord; } } /* * (non-Javadoc) * * @see net.sf.saxon.number.Numberer#monthName(int, int, int) */ public String monthName(int month, int minWidth, int maxWidth) { String name = frenchMonths[month - 1]; if (maxWidth < 3) { maxWidth = 3; } if (name.length() > maxWidth) { name = name.substring(0, maxWidth); } while (name.length() < minWidth) { name = name + " "; } return name; } /* * (non-Javadoc) * * @see net.sf.saxon.number.Numberer#dayName(int, int, int) */ public String dayName(int day, int minWidth, int maxWidth) { String name = frenchDays[day - 1]; if (maxWidth < 3) { maxWidth = 3; } if (name.length() > maxWidth) { name = name.substring(0, maxWidth); } while (name.length() < minWidth) { name = name + " "; } return name; } } // // The contents of this file are subject to the Mozilla Public License Version // 1.0 (the "License"); // you may not use this file except in compliance with the License. You may // obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations // under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by Luc Rochefort are Copyright (C) Luc Rochefort. All // Rights Reserved. // // Contributor(s): Laurent Bourbeau, for the elaboration of JUnit tests // and Jean-Grégoire Djénandji, for acceptance testing. //saxonb-9.1.0.8/bj/net/sf/saxon/number/Numberer_nl.java0000644000175000017500000002106711033112257022010 0ustar eugeneeugenepackage net.sf.saxon.number; /** * @author Karel Goossens * BTR-Services Belgium. * Numberer class for the Dutch language. * * @see http://woordenlijst.org/leidraad/6/9/#r6n * @see http://taaladvies.net/taal/advies/popup.php?id=88 * @see http://www.vlaanderen.be/servlet/Satellite?c=Page&cid=1120536021990&pagename=taaltelefoon%2FPage%2FHomePageMIN */ public class Numberer_nl extends AbstractNumberer { private static final long serialVersionUID = 1L; private static String[] dutchOrdinalUnits = { "", "eenste", "tweede", "derde", "vierde", "vijfde", "zesde", "zevende", "achtste", "negende", "tiende", "elfde ", "twaalfde", "dertiende" , "veertiende", "vijftiende", "zestiende", "zeventiende", "achtiende", "negentiende"}; private static String[] dutchOrdinalTens = { "", "tiende", "twintigste", "dertigste", "veertigste", "vijftigste", "zestigste", "zeventigste", "tachtigste", "negentigste"}; private static String[] dutchUnits = { "", "een", "twee", "drie", "vier", "vijf", "zes", "zeven", "acht", "negen", "tien", "elf", "twaalf", "dertien", "veertien", "vijftien", "zestien", "zeventien", "achtien", "negentien"}; private static String[] dutchTens = { "", "tien", "twintig", "dertig", "veertig", "vijftig", "zestig", "zeventig", "tachtig", "negentig"}; /** * Show an ordinal number as dutch words in a requested case (for example, Twentyfirst) */ public String toOrdinalWords(String ordinalParam, long number, int wordCase) { String s; if(number==1000000000){ s="miljardste"; } else if(number==1000000){ s="miljoenste"; } else if(number==1000){ s="duizendste"; } else if(number==100){ s="honderste"; } else if (number >= 1000000000) { long rem = number % 1000000000; s = toWords(number / 1000000000) + " miljard" + (rem==0 ? "" : (rem < 100 ? " en " : " ") + toOrdinalWords(ordinalParam, rem, wordCase)); } else if (number >= 1000000) { long rem = number % 1000000; s = toWords(number / 1000000) + " miljoen" + (rem==0 ? "" : (rem < 100 ? " en " : " ") + toOrdinalWords(ordinalParam, rem, wordCase)); } else if (number >= 1000) { long rem = number % 1000; s = (number/1000==1?"":toWords(number / 1000)) + "duizend" +" "+ toOrdinalWords(ordinalParam, rem, wordCase); } else if (number >= 100) { long rem = number % 100; s = (number/100==1?"":toWords(number / 100)) + "honderd" + toOrdinalWords(ordinalParam, rem, wordCase); } else { if (number < 20) { s = dutchOrdinalUnits[(int)number]; } else { int rem = (int)(number % 10); if (rem==0) { s = dutchOrdinalTens[(int)number / 10]; } else { s = dutchUnits[rem]+(rem==2?"ën":"en")+dutchTens[(int)number / 10]+"ste"; } } } if (wordCase == UPPER_CASE) { return s.toUpperCase(); } else if (wordCase == LOWER_CASE) { return s.toLowerCase(); } else { return s; } } public String toWords(long number) { if (number >= 1000000000) { long rem = number % 1000000000; return toWords(number / 1000000000) + " miljard" + (rem==0 ? "" : (rem < 100 ? "en" : " ") + toWords(rem)); } else if (number >= 1000000) { long rem = number % 1000000; return toWords(number / 1000000) + " miljoen" + (rem==0 ? "" : (rem < 100 ? "en" : " ") + toWords(rem)); } else if (number >= 1000) { long rem = number % 1000; return (number/1000==1?"":toWords(number / 1000)) + "duizend" + (rem==0 ? "" : (rem < 100 ? "en" : " ") + toWords(rem)); } else if (number >= 100) { long rem = number % 100; return (number/100==1?"":toWords(number / 100)) + "honderd" + toWords(rem); } else { if (number < 20) return dutchUnits[(int)number]; int rem = (int)(number % 10); return (rem==0 ? "" : dutchUnits[rem])+(rem==2?"ën":"en")+dutchTens[(int)number / 10] ; } } public String toWords(long number, int wordCase) { String s; if (number == 0) { s = "nul"; } else { s = toWords(number); } if (wordCase == UPPER_CASE) { return s.toUpperCase(); } else if (wordCase == LOWER_CASE) { return s.toLowerCase(); } else { return s; } } private static String[] dutchMonths = { "januari", "februari", "maart", "april", "mei", "juni", "juli", "augustus", "september", "oktober", "november", "december" }; /** * Get a month name or abbreviation * @param month The month number (1=January, 12=December) * @param minWidth The minimum number of characters * @param maxWidth The maximum number of characters */ //@Override public String monthName(int month, int minWidth, int maxWidth) { String name = dutchMonths[month-1]; if (maxWidth < 3) { maxWidth = 3; } if (name.length() > maxWidth) { name = name.substring(0, maxWidth); } while (name.length() < minWidth) { name = name + ' '; } return name; } /** * Get a day name or abbreviation * @param day The day of the week (1=Monday, 7=Sunday) * @param minWidth The minimum number of characters * @param maxWidth The maximum number of characters */ public String dayName(int day, int minWidth, int maxWidth) { String name = dutchDays[day-1]; if (maxWidth < 2) { maxWidth = 2; } if (name.length() > maxWidth) { name = dutchDayAbbreviations[day-1]; if (name.length() > maxWidth) { name = name.substring(0, maxWidth); } } while (name.length() < minWidth) { name = name + ' '; } if (minWidth==1 && maxWidth==2) { // special case name = name.substring(0, minUniqueDayLength[day-1]); } return name; } private static String[] dutchDays = { "maandag", "dinsdag", "woensdag", "donderdag", "vrijdag", "zaterdag", "zondag" }; private static String[] dutchDayAbbreviations = { "ma", "di", "woe", "do", "vrij", "zat", "zon" }; private static int[] minUniqueDayLength = { 1, 2, 1, 2, 1, 2, 2 }; /** * Get an am/pm indicator * @param minutes the minutes within the day * @param minWidth minimum width of output * @param maxWidth maximum width of output * @return the AM or PM indicator */ public String halfDayName(int minutes, int minWidth, int maxWidth) { String s; if (minutes < 12*60) { switch (maxWidth) { case 1: s = "v"; break; case 2: case 3: s = "vm"; break; default: s = "v.m."; } } else { switch (maxWidth) { case 1: s = "n"; break; case 2: case 3: s = "nm"; break; default: s = "n.m."; } } return s; } /** * Get the name for an era (e.g. "BC" or "AD") * * @param year the proleptic gregorian year, using "0" for the year before 1AD */ public String getEraName(int year) { return (year > 0 ? "n.C." : "v.C."); } } saxonb-9.1.0.8/bj/net/sf/saxon/number/Numberer_sv.java0000644000175000017500000001630711033112257022030 0ustar eugeneeugenepackage net.sf.saxon.number; /** * @author Karel Goossens * BTR-Services Belgium. * * Numberer class for the Swedish language. * * @see http://en.wikipedia.org/wiki/Swedish_grammar * @see http://www2.hhs.se/isa/swedish/chap4.htm */ public class Numberer_sv extends AbstractNumberer { private static final long serialVersionUID = 1L; private static String[] swedishOrdinalUnits = { "", "första", "andra", "tredje", "fjärde", "femte", "sjätte", "sjunde", "åttonde", "nionde", "tionde", "elfte", "tolfte", "trettonde" , "fjortonde", "femtonde", "sextonde", "sjuttonde", "artonde", "níttonde"}; private static String[] swedishOrdinalTens = { "", "tionde", "tjugonde", "trettionde", "fyrtionde", "femtionde", "sextionde", "sjuttionde", "åttionde", "níttionde"}; private static String[] swedishUnits = { "", "ett", "två", "tre", "fyra", "fem", "sex", "sju", "åtta", "nio", "tio", "elva", "tolv", "tretton", "fjorton", "femton", "sexton", "sjutton", "arton", "nitton"}; private static String[] swedishTens = { "", "tio", "tjugo", "trettio", "fyrtio", "femtio", "sextio", "sjuttio", "åttio", "nittio"}; /** * Show an ordinal number as swedish words in a requested case (for example, Twentyfirst) * * @param ordinalParam not used. * @param number the number to be converted to a word. * @param wordCase UPPER_CASE or LOWER_CASE. * * @return String representing the number in words. */ public String toOrdinalWords(String ordinalParam, long number, int wordCase) { String s; if(number==1000000000){ s="miljardte"; } else if(number==1000000){ s="miljonte"; } else if(number==1000){ s="tusende"; } else if(number==100){ s="hundrade"; } else if (number >= 1000000000) { long rem = number % 1000000000; s = (number / 1000000000==1?"en":toWords(number / 1000000000)) + " miljard " + toOrdinalWords(ordinalParam, rem, wordCase); } else if (number >= 1000000) { long rem = number % 1000000; s = (number / 1000000==1?"en":toWords(number / 1000000)) + " miljon " + toOrdinalWords(ordinalParam, rem, wordCase); } else if (number >= 1000) { long rem = number % 1000; s = (number/1000==1?"et":toWords(number / 1000)) + "tusen" +" "+ toOrdinalWords(ordinalParam, rem, wordCase); } else if (number >= 100) { long rem = number % 100; s = (number/100==1?"":toWords(number / 100)) + "hundra" + (rem==0||rem > 19 ? "" : "en") + toOrdinalWords(ordinalParam, rem, wordCase); } else { if (number < 20) { s = swedishOrdinalUnits[(int)number]; } else { int rem = (int)(number % 10); if (rem==0) { s = swedishOrdinalTens[(int)number / 10]; } else { s = swedishTens[(int)number / 10]+swedishOrdinalUnits[rem]; } } } if (wordCase == UPPER_CASE) { return s.toUpperCase(); } else if (wordCase == LOWER_CASE) { return s.toLowerCase(); } else { return s; } } public String toWords(long number) { if (number >= 1000000000) { long rem = number % 1000000000; return (number / 1000000000==1?"en ":toWords(number / 1000000000)) + "miljard" + (rem==0 ? "" : " ") + toWords(rem); } else if (number >= 1000000) { long rem = number % 1000000; return (number/1000000==1?"en ":toWords(number / 1000000)) + "miljon" + (rem==0 ? "" :" ") + toWords(rem); } else if (number >= 1000) { long rem = number % 1000; return (number/1000==1?"et":toWords(number / 1000)) + "tusen" + (rem==0 ? "" : (rem < 100 ? "en" : " ") + toWords(rem)); } else if (number >= 100) { long rem = number % 100; return (number/100==1?"":toWords(number / 100)) + "hundra" + toWords(rem); } else { if (number < 20) return swedishUnits[(int)number]; int rem = (int)(number % 10); return swedishTens[(int)number / 10] + swedishUnits[rem]; } } public String toWords(long number, int wordCase) { String s; if (number == 0) { s = "noll"; } else { s = toWords(number); } if (wordCase == UPPER_CASE) { return s.toUpperCase(); } else if (wordCase == LOWER_CASE) { return s.toLowerCase(); } else { return s; } } private static String[] swedishMonths = { "januari", "februari", "mars", "april", "maj", "juni", "juli", "augusti", "september", "oktober", "november", "december" }; /** * Get a month name or abbreviation * @param month The month number (1=January, 12=December) * @param minWidth The minimum number of characters * @param maxWidth The maximum number of characters */ //@Override public String monthName(int month, int minWidth, int maxWidth) { String name = swedishMonths[month-1]; if (maxWidth < 3) { maxWidth = 3; } if (name.length() > maxWidth) { name = name.substring(0, maxWidth); } while (name.length() < minWidth) { name = name + ' '; } return name; } /** * Get a day name or abbreviation * @param day The day of the week (1=Monday, 7=Sunday) * @param minWidth The minimum number of characters * @param maxWidth The maximum number of characters */ public String dayName(int day, int minWidth, int maxWidth) { String name = swedishDays[day-1]; if (maxWidth < 2) { maxWidth = 2; } if (name.length() > maxWidth) { name = swedishDayAbbreviations[day-1]; if (name.length() > maxWidth) { name = name.substring(0, maxWidth); } } while (name.length() < minWidth) { name = name + ' '; } if (minWidth==1 && maxWidth==2) { // special case name = name.substring(0, minUniqueDayLength[day-1]); } return name; } private static String[] swedishDays = { "måndag", "tisdag", "onsdag", "torsdag", "fredag", "lördag", "söndag" }; private static String[] swedishDayAbbreviations = { "må", "ti", "on", "to", "fr", "lö", "sö" }; private static int[] minUniqueDayLength = { 1, 2, 1, 2, 1, 2, 2 }; } saxonb-9.1.0.8/bj/net/sf/saxon/number/NumberFormatter.java0000644000175000017500000001451111033112257022650 0ustar eugeneeugenepackage net.sf.saxon.number; import net.sf.saxon.charcode.UTF16; import net.sf.saxon.om.FastStringBuffer; import java.io.Serializable; import java.util.ArrayList; import java.util.List; /** * Class NumberFormatter defines a method to format a ArrayList of integers as a character * string according to a supplied format specification. * @author Michael H. Kay */ public class NumberFormatter implements Serializable { private ArrayList formatTokens; private ArrayList punctuationTokens; private boolean startsWithPunctuation; /** * Tokenize the format pattern. * @param format the format specification. Contains one of the following values:
      *
    • "1": conventional decimal numbering
    • *
    • "a": sequence a, b, c, ... aa, ab, ac, ...
    • *
    • "A": sequence A, B, C, ... AA, AB, AC, ...
    • *
    • "i": sequence i, ii, iii, iv, v ...
    • *
    • "I": sequence I, II, III, IV, V, ...
    • *
    * This symbol may be preceded and followed by punctuation (any other characters) which is * copied to the output string. */ public void prepare(String format) { // Tokenize the format string into alternating alphanumeric and non-alphanumeric tokens if (format.length()==0) { format="1"; } formatTokens = new ArrayList(10); punctuationTokens = new ArrayList(10); int len = format.length(); int i=0; int t; boolean first = true; startsWithPunctuation = true; while (it) { String tok = format.substring(t, i); formatTokens.add(tok); if (first) { punctuationTokens.add("."); startsWithPunctuation = false; first = false; } } if (i==len) break; t=i; c = format.charAt(i); if (UTF16.isHighSurrogate(c)) { c = UTF16.combinePair((char)c, format.charAt(++i)); } while (!isLetterOrDigit(c)) { first = false; i++; if (i==len) break; c = format.charAt(i); if (UTF16.isHighSurrogate(c)) { c = UTF16.combinePair((char)c, format.charAt(++i)); } } if (i>t) { String sep = format.substring(t, i); punctuationTokens.add(sep); } } if (formatTokens.isEmpty()) { formatTokens.add("1"); if (punctuationTokens.size() == 1) { punctuationTokens.add(punctuationTokens.get(0)); } } } /** * Determine whether a (possibly non-BMP) character is a letter or digit. * @param c the codepoint of the character to be tested * @return For a non-BMP character: on JDK1.4, always returns false. On JDK 1.5, returns the result * of calling Character.isLetterOrDigit(int codepoint). */ private static boolean isLetterOrDigit(int c) { if (c <= 0x7F) { // Fast path for ASCII characters return (c >= 0x30 && c <= 0x39) || (c >= 0x41 && c <= 0x5A) || (c >= 0x61 && c <= 0x7A); } else { return Alphanumeric.isAlphanumeric(c); } } /** * Format a list of numbers. * @param numbers the numbers to be formatted (a sequence of integer values; it may also contain * preformatted strings as part of the error recovery fallback) * @return the formatted output string. */ public CharSequence format(List numbers, int groupSize, String groupSeparator, String letterValue, String ordinal, Numberer numberer) { FastStringBuffer sb = new FastStringBuffer(20); int num = 0; int tok = 0; // output first punctuation token if (startsWithPunctuation) { sb.append((String)punctuationTokens.get(tok)); } // output the list of numbers while (num0) { if (tok==0 && startsWithPunctuation) { // The first punctuation token isn't a separator if it appears before the first // formatting token. Such a punctuation token is used only once, at the start. sb.append("."); } else { sb.append((String)punctuationTokens.get(tok)); } } Object o = numbers.get(num++); String s; if (o instanceof Long) { long nr = ((Long)o).longValue(); s = numberer.format(nr, (String)formatTokens.get(tok), groupSize, groupSeparator, letterValue, ordinal); } else { s = o.toString(); } sb.append(s); tok++; if (tok==formatTokens.size()) tok--; } // output the final punctuation token if (punctuationTokens.size()>formatTokens.size()) { sb.append((String)punctuationTokens.get(punctuationTokens.size()-1)); } return sb.condense(); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/number/NamedTimeZone.java0000644000175000017500000007757511033112257022256 0ustar eugeneeugenepackage net.sf.saxon.number; import net.sf.saxon.value.DateTimeValue; import net.sf.saxon.om.FastStringBuffer; import java.util.*; /** * This class attempts to identify a timezone name, given the date (including the time zone offset) * and the country. The process is heuristic: sometimes there is more than one timezone that matches * this information, sometimes there is none, but the class simply does its best. This is in support * of the XSLT format-date() function. */ public class NamedTimeZone { static HashMap idForCountry = new HashMap(50); /** * Register a timezone in use in a particular country. Note that some countries use multiple * time zones * @param country the two-character code for the country * @param zoneId the Olsen timezone name for the timezone */ static void tz(String country, String zoneId) { List list = (List)idForCountry.get(country); if (list == null) { list = new ArrayList(4); } list.add(zoneId); idForCountry.put(country, list); } static { // The table starts with countries that use multiple timezones, then proceeds in alphabetical order tz("us", "America/New_York"); tz("us", "America/Chicago"); tz("us", "America/Denver"); tz("us", "America/Los_Angeles"); tz("us", "America/Anchorage"); tz("us", "America/Halifax"); tz("ca", "Canada/Pacific"); tz("ca", "Canada/Mountain"); tz("ca", "Canada/Central"); tz("ca", "Canada/Eastern"); tz("ca", "Canada/Atlantic"); tz("au", "Australia/Sydney"); tz("au", "Australia/Darwin"); tz("au", "Australia/Perth"); tz("ru", "Europe/Moscow"); tz("ru", "Europe/Samara"); tz("ru", "Asia/Yekaterinburg"); tz("ru", "Asia/Novosibirsk"); tz("ru", "Asia/Krasnoyarsk"); tz("ru", "Asia/Irkutsk"); tz("ru", "Asia/Chita"); tz("ru", "Asia/Vladivostok"); tz("an", "Europe/Andorra"); tz("ae", "Asia/Abu_Dhabi"); tz("af", "Asia/Kabul"); tz("al", "Europe/Tirana"); tz("am", "Asia/Yerevan"); tz("ao", "Africa/Luanda"); tz("ar", "America/Buenos_Aires"); tz("as", "Pacific/Samoa"); tz("at", "Europe/Vienna"); tz("aw", "America/Aruba"); tz("az", "Asia/Baku"); tz("ba", "Europe/Sarajevo"); tz("bb", "America/Barbados"); tz("bd", "Asia/Dhaka"); tz("be", "Europe/Brussels"); tz("bf", "Africa/Ouagadougou"); tz("bg", "Europe/Sofia"); tz("bh", "Asia/Bahrain"); tz("bi", "Africa/Bujumbura"); tz("bm", "Atlantic/Bermuda"); tz("bn", "Asia/Brunei"); tz("bo", "America/La_Paz"); tz("br", "America/Sao_Paulo"); tz("bs", "America/Nassau"); tz("bw", "Gaborone"); tz("by", "Europe/Minsk"); tz("bz", "America/Belize"); tz("cd", "Africa/Kinshasa"); tz("ch", "Europe/Zurich"); tz("ci", "Africa/Abidjan"); tz("cl", "America/Santiago"); tz("cn", "Asia/Shanghai"); tz("co", "America/Bogota"); tz("cr", "America/Costa_Rica"); tz("cu", "America/Cuba"); tz("cv", "Atlantic/Cape_Verde"); tz("cy", "Asia/Nicosia"); tz("cz", "Europe/Prague"); tz("de", "Europe/Berlin"); tz("dj", "Africa/Djibouti"); tz("dk", "Europe/Copenhagen"); tz("do", "America/Santo_Domingo"); tz("dz", "Africa/Algiers"); tz("ec", "America/Quito"); tz("ee", "Europe/Tallinn"); tz("eg", "Africa/Cairo"); tz("er", "Africa/Asmara"); tz("es", "Europe/Madrid"); tz("fi", "Europe/Helsinki"); tz("fj", "Pacific/Fiji"); tz("fk", "America/Stanley"); tz("fr", "Europe/Paris"); tz("ga", "Africa/Libreville"); tz("gb", "Europe/London"); tz("gd", "America/Grenada"); tz("ge", "Asia/Tbilisi"); tz("gh", "Africa/Accra"); tz("gm", "Africa/Banjul"); tz("gn", "Africa/Conakry"); tz("gr", "Europe/Athens"); tz("gy", "America/Guyana"); tz("hk", "Asia/Hong_Kong"); tz("hn", "America/Tegucigalpa"); tz("hr", "Europe/Zagreb"); tz("ht", "America/Port-au-Prince"); tz("hu", "Europe/Budapest"); tz("id", "Asia/Jakarta"); tz("ie", "Europe/Dublin"); tz("il", "Asia/Tel_Aviv"); tz("in", "Asia/Calcutta"); tz("iq", "Asia/Baghdad"); tz("ir", "Asia/Tehran"); tz("is", "Atlantic/Reykjavik"); tz("it", "Europe/Rome"); tz("jm", "America/Jamaica"); tz("jo", "Asia/Amman"); tz("jp", "Asia/Tokyo"); tz("ke", "Africa/Nairobi"); tz("kg", "Asia/Bishkek"); tz("kh", "Asia/Phnom_Penh"); tz("kp", "Asia/Pyongyang"); tz("kr", "Asia/Seoul"); tz("kw", "Asia/Kuwait"); tz("lb", "Asia/Beirut"); tz("li", "Europe/Liechtenstein"); tz("lk", "Asia/Colombo"); tz("lr", "Africa/Monrovia"); tz("ls", "Africa/Maseru"); tz("lt", "Europe/Vilnius"); tz("lu", "Europe/Luxembourg"); tz("lv", "Europe/Riga"); tz("ly", "Africa/Tripoli"); tz("ma", "Africa/Rabat"); tz("mc", "Europe/Monaco"); tz("md", "Europe/Chisinau"); tz("mg", "Indian/Antananarivo"); tz("mk", "Europe/Skopje"); tz("ml", "Africa/Bamako"); tz("mm", "Asia/Rangoon"); tz("mn", "Asia/Ulaanbaatar"); tz("mo", "Asia/Macao"); tz("mq", "America/Martinique"); tz("mt", "Europe/Malta"); tz("mu", "Indian/Mauritius"); tz("mv", "Indian/Maldives"); tz("mw", "Africa/Lilongwe"); tz("mx", "America/Mexico_City"); tz("my", "Asia/Kuala_Lumpur"); tz("na", "Africa/Windhoek"); tz("ne", "Africa/Niamey"); tz("ng", "Africa/Lagos"); tz("ni", "America/Managua"); tz("nl", "Europe/Amsterdam"); tz("no", "Europe/Oslo"); tz("np", "Asia/Kathmandu"); tz("nz", "Pacific/Aukland"); tz("om", "Asia/Muscat"); tz("pa", "America/Panama"); tz("pe", "America/Lima"); tz("pg", "Pacific/Port_Moresby"); tz("ph", "Asia/Manila"); tz("pk", "Asia/Karachi"); tz("pl", "Europe/Warsaw"); tz("pr", "America/Puerto_Rico"); tz("pt", "Europe/Lisbon"); tz("py", "America/Asuncion"); tz("qa", "Asia/Qatar"); tz("ro", "Europe/Bucharest"); tz("rs", "Europe/Belgrade"); tz("rw", "Africa/Kigali"); tz("sa", "Asia/Riyadh"); tz("sd", "Africa/Khartoum"); tz("se", "Europe/Stockholm"); tz("sg", "Asia/Singapore"); tz("si", "Europe/Ljubljana"); tz("sk", "Europe/Bratislava"); tz("sl", "Africa/Freetown"); tz("so", "Africa/Mogadishu"); tz("sr", "America/Paramaribo"); tz("sv", "America/El_Salvador"); tz("sy", "Asia/Damascus"); tz("sz", "Africa/Mbabane"); tz("td", "Africa/Ndjamena"); tz("tg", "Africa/Lome"); tz("th", "Asia/Bangkok"); tz("tj", "Asia/Dushanbe"); tz("tm", "Asia/Ashgabat"); tz("tn", "Africa/Tunis"); tz("to", "Pacific/Tongatapu"); tz("tr", "Asia/Istanbul"); tz("tw", "Asia/Taipei"); tz("tz", "Africa/Dar_es_Salaam"); tz("ua", "Europe/Kiev"); tz("ug", "Africa/Kampala"); tz("uk", "Europe/London"); tz("uy", "America/Montevideo"); tz("uz", "Asia/Tashkent"); tz("ve", "America/Caracas"); tz("vn", "Asia/Hanoi"); tz("za", "Africa/Johannesburg"); tz("zm", "Africa/Lusaka"); tz("zw", "Africa/Harare"); } /** * Try to identify a timezone name corresponding to a given date (including time zone) * and a given country. Note that this takes account of Java's calendar of daylight savings time * changes in different countries. The returned value is the convenional short timezone name, for example * PDT for Pacific Daylight Time * @param date the dateTimeValue, including timezone * @param country the two-letter ISO country code * @return the short timezone name if a timezone with the given time displacement is in use in the country * in question (on the appropriate date, if known). Otherwise, the formatted (numeric) timezone offset. If * the dateTimeValue supplied has no timezone, return a zero-length string. */ public static String getTimeZoneNameForDate(DateTimeValue date, String country) { if (!date.hasTimezone()) { return ""; } if (country == null) { return formatTimeZoneOffset(date); } List possibleIds = (List)idForCountry.get(country.toLowerCase()); String exampleId; if (possibleIds == null) { return formatTimeZoneOffset(date); } else { exampleId = (String)possibleIds.get(0); } TimeZone exampleZone = TimeZone.getTimeZone(exampleId); Date javaDate = null; try { javaDate = date.getCalendar().getTime(); } catch (IllegalArgumentException e) { // this happens with timezones that are allowed in XPath but not in Java, especially on JDK 1.4 return formatTimeZoneOffset(date); } boolean inSummerTime = exampleZone.inDaylightTime(javaDate); int tzMinutes = date.getTimezoneInMinutes(); for (int i=0; i= 1000000000) { long rem = number % 1000000000; long n = number / 1000000000; String s = (n==1 ? "Eine" : toWords(n)); return s + " Milliarde" + (rem==0 ? "" : ' ' + toWords(rem)); } else if (number >= 1000000) { long rem = number % 1000000; long n = number / 1000000; String s = (n==1 ? "Eine" : toWords(n)); return s + " Million" + (rem==0 ? "" : ' ' + toWords(rem)); } else if (number >= 1000) { long rem = number % 1000; long n = number / 1000; String s = (n==1 ? "Ein" : toWords(n)); return s + "tausend" + (rem==0 ? "" : ' ' + toWords(rem)); } else if (number >= 100) { long rem = number % 100; long n = number / 100; String s = (n==1 ? "Ein" : toWords(n)); return s + "hundert" + (rem==0 ? "" : (rem>20 ? "" : "und") + toWords(rem, LOWER_CASE)); } else { if (number < 20) return germanUnits[(int)number]; int rem = (int)(number % 10); int tens = (int)number / 10; return (germanUnits[rem]) + (tens==0 ? "" : (rem==0 ? "" : "und") + germanTens[tens]); } } private static String[] germanUnits = { "", "Eins", "Zwei", "Drei", "Vier", "Fünf", "Sechs", "Sieben", "Acht", "Neun", "Zehn", "Elf", "Zwölf", "Dreizehn", "Vierzehn", "Fünfzehn", "Sechszehn", "Siebzehn", "Achtzehn", "Neunzehn"}; private static String[] germanTens = { "", "Zehn", "Zwanzig", "Dreißig", "Vierzig", "Fünfzig", "Sechzig", "Siebzig", "Achtzig", "Neunzig"}; /** * Show an ordinal number as German words (for example, Einundzwanzigste) */ public String toOrdinalWords(String ordinalParam, long number, int wordCase) { String suffix = "e"; if (ordinalParam.equalsIgnoreCase("-er")) { suffix = "er"; } else if (ordinalParam.equalsIgnoreCase("-es")) { suffix = "es"; } else if (ordinalParam.equalsIgnoreCase("-en")) { suffix = "en"; } long mod100 = number % 100; if (number < 20) { String ord = germanOrdinalUnits[(int)number] + suffix; if (wordCase==UPPER_CASE) { return ord.toUpperCase(); } else if (wordCase==LOWER_CASE) { return ord.toLowerCase(); } else { return ord; } } else if (mod100 < 20 && mod100 > 0) { return toWords(number - (mod100), wordCase) + toOrdinalWords(ordinalParam, mod100, (wordCase==TITLE_CASE ? LOWER_CASE : wordCase)); } else { String ending = "st" + suffix; if (wordCase==UPPER_CASE) { ending = ending.toUpperCase(); } return toWords(number, wordCase) + (wordCase==UPPER_CASE ? ending.toUpperCase() : ending); } } private static String[] germanOrdinalUnits = { "", "Erst", "Zweit", "Dritt", "Viert", "Fünft", "Sechst", "Siebt", "Acht", "Neunt", "Zehnt", "Elft", "Zwölft", "Dreizehnt", "Vierzehnt", "Fünfzehnt", "Sechszehnt", "Siebzehnt", "Achtzehnt", "Neunzehnt"}; /** * Get a month name or abbreviation * @param month The month number (1=January, 12=December) * @param minWidth The minimum number of characters * @param maxWidth The maximum number of characters */ public String monthName(int month, int minWidth, int maxWidth) { String name = germanMonths[month-1]; if (maxWidth < 3) { maxWidth = 3; } if (name.length() > maxWidth) { name = name.substring(0, maxWidth); } while (name.length() < minWidth) { name = name + " "; } return name; } private static String[] germanMonths = { "Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember" }; /** * Get a day name or abbreviation * @param day The month number (1=Sunday, 7=Saturday) * @param minWidth The minimum number of characters * @param maxWidth The maximum number of characters */ public String dayName(int day, int minWidth, int maxWidth) { String name = germanDays[day-1]; if (maxWidth < 10) { name = name.substring(0, 2); } while (name.length() < minWidth) { name = name + ' '; } return name; } private static String[] germanDays = { "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag", "Sonntag" }; /** * Get an ordinal suffix for a particular component of a date/time. * * @param component the component specifier from a format-dateTime picture, for * example "M" for the month or "D" for the day. * @return a string that is acceptable in the ordinal attribute of xsl:number * to achieve the required ordinal representation. For example, "-e" for the day component * in German, to have the day represented as "dritte August". */ public String getOrdinalSuffixForDateTime(String component) { return "-e"; } /** * Get the name for an era (e.g. "BC" or "AD") * @param year the proleptic gregorian year, using "0" for the year before 1AD */ public String getEraName(int year) { return (year <= 0 ? "v. Chr." : "n. Chr."); } /** * Get the name of a calendar * * @param code The code representing the calendar as in the XSLT 2.0 spec, e.g. AD for the Gregorian calendar */ public String getCalendarName(String code) { if (code.equals("AD")) { return "Gregorianisch"; } else { return code; } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/number/Numberer_da.java0000644000175000017500000001703211033112257021760 0ustar eugeneeugenepackage net.sf.saxon.number; /** * @author Karel Goossens * BTR-Services Belgium. * * Numberer class for the Danish language. * * @see "http://en.wikipedia.org/wiki/Danish_grammar#Numerals" */ public class Numberer_da extends AbstractNumberer { private static final long serialVersionUID = 1L; private static String[] danishOrdinalUnits = { "", "første", "anden", "tredje", "fjerde", "femte", "sjette", "syvende", "ottende", "niende", "tiende", "élfte", "tolvte", "trettende" , "fjortende", "femtende", "sekstende", "syttende", "attende", "nittende"}; private static String[] danishOrdinalTens = { "", "tiende", "tyvende", "tredivte", "fyrretyvende", "halvtredsindstyvende", "tresindstyvende", "halvfjerdsindstyvende", "firsindstyvende", "halvfemstyvende"}; private static String[] danishUnits = { "", "et", "to", "tre", "fire", "fem", "seks", "syv", "otte", "ni", "ti", "elleve", "tolv", "tretten", "fjorten", "femten", "seksten", "sytten", "atten", "nitten"}; private static String[] danishTens = { "", "ti", "tyve", "tredive", "fyrre", "halvtreds", "tres", "halvfjerds", "firs", "halvfems"}; /** * Show an ordinal number as Danish words in a requested case (for example, Twentyfirst) */ public String toOrdinalWords(String ordinalParam, long number, int wordCase) { String s; if(number==1000000000){ s="millardte"; } else if(number==1000000){ s="millonte"; } else if(number==1000){ s="tusinde"; } else if(number==100){ s="hundrede"; } else if (number >= 1000000000) { long rem = number % 1000000000; s = (number / 1000000000==1?"en":toWords(number / 1000000000)) + " milliard " + toOrdinalWords(ordinalParam, rem, wordCase); } else if (number >= 1000000) { long rem = number % 1000000; s = (number / 1000000==1?"en":toWords(number / 1000000)) + " million " + toOrdinalWords(ordinalParam, rem, wordCase); } else if (number >= 1000) { long rem = number % 1000; s = (number/1000==1?"et":toWords(number / 1000)) + "tusind" +" "+ toOrdinalWords(ordinalParam, rem, wordCase); } else if (number >= 100) { long rem = number % 100; s = (number/100==1?"":toWords(number / 100)) + "hundred" + (rem==0||rem > 19 ? "" : "en") + toOrdinalWords(ordinalParam, rem, wordCase); } else { if (number < 20) { s = danishOrdinalUnits[(int)number]; } else { int rem = (int)(number % 10); if (rem==0) { s = danishOrdinalTens[(int)number / 10]; } else { s = danishTens[(int)number / 10]+danishOrdinalUnits[rem]; } } } if (wordCase == UPPER_CASE) { return s.toUpperCase(); } else if (wordCase == LOWER_CASE) { return s.toLowerCase(); } else { return s; } } public String toWords(long number) { if (number >= 1000000000) { long rem = number % 1000000000; return (number / 1000000000==1?"en ":toWords(number / 1000000000)) + "milliard" + (rem==0 ? "" : " ") + toWords(rem); } else if (number >= 1000000) { long rem = number % 1000000; return (number/1000000==1?"en ":toWords(number / 1000000)) + "million" + (rem==0 ? "" :" ") + toWords(rem); } else if (number >= 1000) { long rem = number % 1000; return toWords(number / 1000) + "tusind" + (rem==0 ? "" : " ") + toWords(rem); } else if (number >= 100) { long rem = number % 100; return toWords(number / 100) + "hundred" + (rem>0?"og"+toWords(rem):""); } else { if (number < 20) return danishUnits[(int)number]; int rem = (int)(number % 10); return danishUnits[rem]+"og"+danishTens[(int)number / 10] ; } } public String toWords(long number, int wordCase) { String s; if (number == 0) { s = "nul"; } else { s = toWords(number); } if (wordCase == UPPER_CASE) { return s.toUpperCase(); } else if (wordCase == LOWER_CASE) { return s.toLowerCase(); } else { return s; } } private static String[] swedishMonths = { "januar", "februar", "marts", "april", "maj", "juni", "juli", "august", "september", "oktober", "november", "december" }; /** * Get a month name or abbreviation * @param month The month number (1=January, 12=December) * @param minWidth The minimum number of characters * @param maxWidth The maximum number of characters */ //@Override public String monthName(int month, int minWidth, int maxWidth) { String name = swedishMonths[month-1]; if (maxWidth < 3) { maxWidth = 3; } if (name.length() > maxWidth) { name = name.substring(0, maxWidth); } while (name.length() < minWidth) { name = name + ' '; } return name; } /** * Get a day name or abbreviation * @param day The day of the week (1=Monday, 7=Sunday) * @param minWidth The minimum number of characters * @param maxWidth The maximum number of characters */ public String dayName(int day, int minWidth, int maxWidth) { String name = danishDays[day-1]; if (maxWidth < 2) { maxWidth = 2; } if (name.length() > maxWidth) { name = swedishDayAbbreviations[day-1]; if (name.length() > maxWidth) { name = name.substring(0, maxWidth); } } while (name.length() < minWidth) { name = name + ' '; } if (minWidth==1 && maxWidth==2) { // special case name = name.substring(0, minUniqueDayLength[day-1]); } return name; } private static String[] danishDays = { "mandag", "tirsdag", "onsdag", "torsdag", "fredag", "lørdag", "søndag" }; private static String[] swedishDayAbbreviations = { "ma", "ti", "on", "to", "fr", "lø", "sø" }; private static int[] minUniqueDayLength = { 1, 2, 1, 2, 1, 2, 2 }; } // //The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); //you may not use this file except in compliance with the License. You may obtain a copy of the //License at http://www.mozilla.org/MPL/ // //Software distributed under the License is distributed on an "AS IS" basis, //WITHOUT WARRANTY OF ANY KIND, either express or implied. //See the License for the specific language governing rights and limitations under the License. // //The Original Code is: all this file. // //The Initial Developer of the Original Code is Michael H. Kay. // //Portions created by Karel Goossens are Copyright (C) BTR-services inc. All Rights Reserved. // //Contributor(s): Karel Goossens. //saxonb-9.1.0.8/bj/net/sf/saxon/number/AbstractNumberer.java0000644000175000017500000005175111033112257023006 0ustar eugeneeugenepackage net.sf.saxon.number; import net.sf.saxon.charcode.UTF16; import net.sf.saxon.om.FastStringBuffer; import net.sf.saxon.value.StringValue; import java.io.Serializable; /** * Class AbstractNumberer is a base implementation of Numberer that provides language-independent * default numbering * This supports the xsl:number element. * Methods and data are declared as protected, and static is avoided, to allow easy subclassing. * @author Michael H. Kay */ public abstract class AbstractNumberer implements Numberer, Serializable { private String country; public static final int UPPER_CASE = 0; public static final int LOWER_CASE = 1; public static final int TITLE_CASE = 2; /** * Set the country used by this numberer (currenly used only for names of timezones) */ public void setCountry(String country) { this.country = country; } /** * Get the country used by this numberer */ public String getCountry() { return country; } /** * Format a number into a string * @param number The number to be formatted * @param picture The format token. This is a single component of the format attribute * of xsl:number, e.g. "1", "01", "i", or "a" * @param groupSize number of digits per group (0 implies no grouping) * @param groupSeparator string to appear between groups of digits * @param letterValue The letter-value specified to xsl:number: "alphabetic" or * "traditional". Can also be an empty string or null. * @param ordinal The value of the ordinal attribute specified to xsl:number * The value "yes" indicates that ordinal numbers should be used; "" or null indicates * that cardinal numbers * @return the formatted number. Note that no errors are reported; if the request * is invalid, the number is formatted as if the string() function were used. */ public String format(long number, String picture, int groupSize, String groupSeparator, String letterValue, String ordinal) { if (number < 0) { return "" + number; } if (picture==null || picture.length()==0) { return "" + number; } int pictureLength = StringValue.getStringLength(picture); FastStringBuffer sb = new FastStringBuffer(16); int formchar = picture.charAt(0); if (UTF16.isHighSurrogate(formchar)) { formchar = UTF16.combinePair((char)formchar, picture.charAt(1)); } switch(formchar) { case '0': case '1': sb.append(toRadical(number, westernDigits, pictureLength, groupSize, groupSeparator)); if (ordinal != null && ordinal.length() > 0) { sb.append(ordinalSuffix(ordinal, number)); } break; case 'A': if (number==0) return "0"; sb.append(toAlphaSequence(number, latinUpper)); break; case 'a': if (number==0) return "0"; sb.append(toAlphaSequence(number, latinLower)); break; case 'w': case 'W': int wordCase; if (picture.equals("W")) { wordCase = UPPER_CASE; } else if (picture.equals("w")) { wordCase = LOWER_CASE; } else { // includes cases like "ww" or "Wz". The action here is conformant, but it's not clear what's best wordCase = TITLE_CASE; } if (ordinal != null && ordinal.length() > 0) { sb.append(toOrdinalWords(ordinal, number, wordCase)); } else { sb.append(toWords(number, wordCase)); } break; case 'i': if (number==0) return "0"; if (letterValue==null || letterValue.length() == 0 || letterValue.equals("traditional")) { sb.append(toRoman(number)); } else { alphaDefault(number, 'i', sb); } break; case 'I': if (number==0) return "0"; if (letterValue==null || letterValue.length() == 0 || letterValue.equals("traditional")) { sb.append(toRoman(number).toUpperCase()); } else { alphaDefault(number, 'I', sb); } break; case '\u0391': if (number==0) return "0"; sb.append(toAlphaSequence(number, greekUpper)); break; case '\u03b1': if (number==0) return "0"; sb.append(toAlphaSequence(number, greekLower)); break; case '\u0410': if (number==0) return "0"; sb.append(toAlphaSequence(number, cyrillicUpper)); break; case '\u0430': if (number==0) return "0"; sb.append(toAlphaSequence(number, cyrillicLower)); break; case '\u05d0': if (number==0) return "0"; sb.append(toAlphaSequence(number, hebrew)); break; case '\u3042': if (number==0) return "0"; sb.append(toAlphaSequence(number, hiraganaA)); break; case '\u30a2': if (number==0) return "0"; sb.append(toAlphaSequence(number, katakanaA)); break; case '\u3044': if (number==0) return "0"; sb.append(toAlphaSequence(number, hiraganaI)); break; case '\u30a4': if (number==0) return "0"; sb.append(toAlphaSequence(number, katakanaI)); break; case '\u4e00': if (number==0) return "0"; sb.append(toRadical(number, kanjiDigits, pictureLength, groupSize, groupSeparator)); break; default: int digitValue = Alphanumeric.getDigitValue(formchar); if (digitValue >= 0) { int zero = formchar - digitValue; int[] digits = new int[10]; for (int z=0; z<=9; z++) { digits[z] = zero+z; } sb.append(toRadical(number, digits, pictureLength, groupSize, groupSeparator)); break; } else { if (number==0) return "0"; if (formchar < '\u1100') { alphaDefault(number, (char)formchar, sb); } else { // fallback to western numbering sb.append( toRadical(number, westernDigits, pictureLength, groupSize, groupSeparator)); } break; } } return sb.toString(); } /** * Construct the ordinal suffix for a number, for example "st", "nd", "rd". The default * (language-neutral) implementation returns a zero-length string * @param ordinalParam the value of the ordinal attribute (used in non-English * language implementations) * @param number the number being formatted * @return the ordinal suffix to be appended to the formatted number */ protected String ordinalSuffix(String ordinalParam, long number) { return ""; } protected static final int[] westernDigits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}; protected static final String latinUpper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; protected static final String latinLower = "abcdefghijklmnopqrstuvwxyz"; protected static final String greekUpper = "\u0391\u0392\u0393\u0394\u0395\u0396\u0397\u0398\u0399\u039a" + "\u039b\u039c\u039d\u039e\u039f\u03a0\u03a1\u03a2\u03a3\u03a4" + "\u03a5\u03a6\u03a7\u03a8\u03a9"; protected static final String greekLower = "\u03b1\u03b2\u03b3\u03b4\u03b5\u03b6\u03b7\u03b8\u03b9\u03ba" + "\u03bb\u03bc\u03bd\u03be\u03bf\u03c0\u03c1\u03c2\u03c3\u03c4" + "\u03c5\u03c6\u03c7\u03c8\u03c9"; // Cyrillic information from Dmitry Kirsanov [dmitry@kirsanov.com] // (based on his personal knowledge of Russian texts, not any authoritative source) protected static final String cyrillicUpper = "\u0410\u0411\u0412\u0413\u0414\u0415\u0416\u0417\u0418" + "\u041a\u041b\u041c\u041d\u041e\u041f\u0420\u0421\u0421\u0423" + "\u0424\u0425\u0426\u0427\u0428\u0429\u042b\u042d\u042e\u042f"; protected static final String cyrillicLower = "\u0430\u0431\u0432\u0433\u0434\u0435\u0436\u0437\u0438" + "\u043a\u043b\u043c\u043d\u043e\u043f\u0440\u0441\u0441\u0443" + "\u0444\u0445\u0446\u0447\u0448\u0449\u044b\u044d\u044e\u044f"; protected static final String hebrew = "\u05d0\u05d1\u05d2\u05d3\u05d4\u05d5\u05d6\u05d7\u05d8\u05d9\u05db\u05dc" + "\u05de\u05e0\u05e1\u05e2\u05e4\u05e6\u05e7\u05e8\u05e9\u05ea"; // The following Japanese sequences were supplied by // MURAKAMI Shinyu [murakami@nadita.com] protected static final String hiraganaA = "\u3042\u3044\u3046\u3048\u304a\u304b\u304d\u304f\u3051\u3053" + "\u3055\u3057\u3059\u305b\u305d\u305f\u3061\u3064\u3066\u3068" + "\u306a\u306b\u306c\u306d\u306e\u306f\u3072\u3075\u3078\u307b" + "\u307e\u307f\u3080\u3081\u3082\u3084\u3086\u3088\u3089\u308a" + "\u308b\u308c\u308d\u308f\u3092\u3093"; protected static final String katakanaA = "\u30a2\u30a4\u30a6\u30a8\u30aa\u30ab\u30ad\u30af\u30b1\u30b3" + "\u30b5\u30b7\u30b9\u30bb\u30bd\u30bf\u30c1\u30c4\u30c6\u30c8" + "\u30ca\u30cb\u30cc\u30cd\u30ce\u30cf\u30d2\u30d5\u30d8\u30db" + "\u30de\u30df\u30e0\u30e1\u30e2\u30e4\u30e6\u30e8\u30e9\u30ea" + "\u30eb\u30ec\u30ed\u30ef\u30f2\u30f3"; protected static final String hiraganaI = "\u3044\u308d\u306f\u306b\u307b\u3078\u3068\u3061\u308a\u306c" + "\u308b\u3092\u308f\u304b\u3088\u305f\u308c\u305d\u3064\u306d" + "\u306a\u3089\u3080\u3046\u3090\u306e\u304a\u304f\u3084\u307e" + "\u3051\u3075\u3053\u3048\u3066\u3042\u3055\u304d\u3086\u3081" + "\u307f\u3057\u3091\u3072\u3082\u305b\u3059"; protected static final String katakanaI = "\u30a4\u30ed\u30cf\u30cb\u30db\u30d8\u30c8\u30c1\u30ea\u30cc" + "\u30eb\u30f2\u30ef\u30ab\u30e8\u30bf\u30ec\u30bd\u30c4\u30cd" + "\u30ca\u30e9\u30e0\u30a6\u30f0\u30ce\u30aa\u30af\u30e4\u30de" + "\u30b1\u30d5\u30b3\u30a8\u30c6\u30a2\u30b5\u30ad\u30e6\u30e1" + "\u30df\u30b7\u30f1\u30d2\u30e2\u30bb\u30b9"; protected static final int[] kanjiDigits = {0x3007, 0x4e00, 0x4e8c, 0x4e09, 0x56db, 0x4e94, 0x516d, 0x4e03, 0x516b, 0x4e5d}; //"\u3007\u4e00\u4e8c\u4e09\u56db\u4e94\u516d\u4e03\u516b\u4e5d"; /** * Default processing with an alphabetic format token: use the contiguous * range of Unicode letters starting with that token. * @param number the number to be formatted * @param formchar the format character, for example 'A' for the numbering sequence A,B,C * @param sb buffer to hold the result of the formatting */ protected void alphaDefault(long number, char formchar, FastStringBuffer sb) { int min = (int)formchar; int max = (int)formchar; // use the contiguous range of letters starting with the specified one while (Character.isLetterOrDigit((char)(max+1))) { max++; } sb.append(toAlpha(number, min, max)); } /** * Format the number as an alphabetic label using the alphabet consisting * of consecutive Unicode characters from min to max * @param number the number to be formatted * @param min the start of the Unicode codepoint range * @param max the end of the Unicode codepoint range * @return the formatted number */ protected String toAlpha(long number, int min, int max) { if (number<=0) return "" + number; int range = max - min + 1; char last = (char)(((number-1) % range) + min); if (number>range) { return toAlpha((number-1)/range, min, max) + last; } else { return "" + last; } } /** * Convert the number into an alphabetic label using a given alphabet. * For example, if the alphabet is "xyz" the sequence is x, y, z, xx, xy, xz, .... * @param number the number to be formatted * @param alphabet a string containing the characters to be used, for example "abc...xyz" * @return the formatted number */ protected String toAlphaSequence(long number, String alphabet) { if (number<=0) return "" + number; int range = alphabet.length(); char last = alphabet.charAt((int)((number-1) % range)); if (number>range) { return toAlphaSequence((number-1)/range, alphabet) + last; } else { return "" + last; } } /** * Convert the number into a decimal or other representation using the given set of * digits. * For example, if the digits are "01" the sequence is 1, 10, 11, 100, 101, 110, 111, ... * More commonly, the digits will be "0123456789", giving the usual decimal numbering. * @param number the number to be formatted * @param digits the codepoints to be used for the digits * @param pictureLength the length of the picture that is significant: for example "3" if the * picture is "001" * @param groupSize the number of digits in each group * @param groupSeparator the separator to use between groups of digits. * @return the formatted number */ private String toRadical(long number, int[] digits, int pictureLength, int groupSize, String groupSeparator) { FastStringBuffer sb = new FastStringBuffer(16); FastStringBuffer temp = new FastStringBuffer(16); int base = digits.length; int width = (digits[0] > 0xffff ? 2 : 1); FastStringBuffer s = new FastStringBuffer(16); long n = number; int count = 0; while (n>0) { int digit = digits[(int)(n % base)]; s.prependWideChar(digit); count++; n = n / base; } for (int i=0; i<(pictureLength-count); i++) { temp.appendWideChar(digits[0]); } temp.append(s); if (groupSize>0) { groupSize *= width; for (int i=0; i9999) return "" + n; return romanThousands[(int)n/1000] + romanHundreds[((int)n/100) % 10] + romanTens[((int)n/10) % 10] + romanUnits[(int)n % 10]; } // Roman numbers beyond 4000 use overlining and other conventions which we won't // attempt to reproduce. We'll go high enough to handle present-day Gregorian years. private static String[] romanThousands = {"", "m", "mm", "mmm", "mmmm", "mmmmm", "mmmmmm", "mmmmmmm", "mmmmmmmm", "mmmmmmmmm"}; private static String[] romanHundreds = {"", "c", "cc", "ccc", "cd", "d", "dc", "dcc", "dccc", "cm"}; private static String[] romanTens = {"", "x", "xx", "xxx", "xl", "l", "lx", "lxx", "lxxx", "xc"}; private static String[] romanUnits = {"", "i", "ii", "iii", "iv", "v", "vi", "vii", "viii", "ix"}; /** * Show the number as words in title case. (We choose title case because * the result can then be converted algorithmically to lower case or upper case). * @param number the number to be formatted * @return the number formatted as English words */ public abstract String toWords(long number); /** * Format a number as English words with specified case options * @param number the number to be formatted * @param wordCase the required case for example {@link #UPPER_CASE}, * {@link #LOWER_CASE}, {@link #TITLE_CASE} * @return the formatted number */ public String toWords(long number, int wordCase) { String s; if (number == 0) { s = "Zero"; } else { s = toWords(number); } if (wordCase == UPPER_CASE) { return s.toUpperCase(); } else if (wordCase == LOWER_CASE) { return s.toLowerCase(); } else { return s; } } /** * Show an ordinal number as English words in a requested case (for example, Twentyfirst) * @param ordinalParam the value of the "ordinal" attribute as supplied by the user * @param number the number to be formatted * @param wordCase the required case for example {@link #UPPER_CASE}, * {@link #LOWER_CASE}, {@link #TITLE_CASE} * @return the formatted number */ public abstract String toOrdinalWords(String ordinalParam, long number, int wordCase); /** * Get a month name or abbreviation * @param month The month number (1=January, 12=December) * @param minWidth The minimum number of characters * @param maxWidth The maximum number of characters */ public abstract String monthName(int month, int minWidth, int maxWidth); /** * Get a day name or abbreviation * @param day The day of the week (1=Monday, 7=Sunday) * @param minWidth The minimum number of characters * @param maxWidth The maximum number of characters */ public abstract String dayName(int day, int minWidth, int maxWidth); /** * Get an am/pm indicator. Default implementation works for English, on the basis that some * other languages might like to copy this (most non-English countries don't actually use the * 12-hour clock, so it's irrelevant). * @param minutes the minutes within the day * @param minWidth minimum width of output * @param maxWidth maximum width of output * @return the AM or PM indicator */ public String halfDayName(int minutes, int minWidth, int maxWidth) { String s; if (minutes == 0 && maxWidth >= 8) { s = "Midnight"; } else if (minutes < 12*60) { switch (maxWidth) { case 1: s = "A"; break; case 2: case 3: s = "Am"; break; default: s = "A.M."; } } else if (minutes == 12*60 && maxWidth >= 8) { s = "Noon"; } else { switch (maxWidth) { case 1: s = "P"; break; case 2: case 3: s = "Pm"; break; default: s = "P.M."; } } return s; } /** * Get an ordinal suffix for a particular component of a date/time. * * @param component the component specifier from a format-dateTime picture, for * example "M" for the month or "D" for the day. * @return a string that is acceptable in the ordinal attribute of xsl:number * to achieve the required ordinal representation. For example, "-e" for the day component * in German, to have the day represented as "dritte August". */ public String getOrdinalSuffixForDateTime(String component) { return "yes"; } /** * Get the name for an era (e.g. "BC" or "AD") * * @param year the proleptic gregorian year, using "0" for the year before 1AD */ public String getEraName(int year) { return (year > 0 ? "AD" : "BC"); } /** * Get the name of a calendar * * @param code The code representing the calendar as in the XSLT 2.0 spec, e.g. AD for the Gregorian calendar */ public String getCalendarName(String code) { if (code.equals("AD")) { return "Gregorian"; } else { return code; } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/number/Numberer.java0000644000175000017500000001023111033112257021306 0ustar eugeneeugenepackage net.sf.saxon.number; /** * Interface Numberer supports number formatting. There is a separate * implementation for each language, e.g. Numberer_en for English. * This supports the xsl:number element * @author Michael H. Kay */ public interface Numberer { /** * Set the country used by this numberer (currently used only for names of timezones) */ public void setCountry(String country); /** * Get the country used by this numberer */ public String getCountry(); /** * Format a number into a string * @param number The number to be formatted * @param picture The format token. This is a single component of the format attribute * of xsl:number, e.g. "1", "01", "i", or "a" * @param groupSize number of digits per group (0 implies no grouping) * @param groupSeparator string to appear between groups of digits * @param letterValue The letter-value specified to xsl:number: "alphabetic" or * "traditional". Can also be an empty string or null. * @param ordinal The value of the ordinal attribute specified to xsl:number * The value "yes" indicates that ordinal numbers should be used; "" or null indicates * that cardinal numbers * @return the formatted number. Note that no errors are reported; if the request * is invalid, the number is formatted as if the string() function were used. */ public String format(long number, String picture, int groupSize, String groupSeparator, String letterValue, String ordinal); /** * Get a month name or abbreviation * @param month The month number (1=January, 12=December) * @param minWidth The minimum number of characters * @param maxWidth The maximum number of characters */ public String monthName(int month, int minWidth, int maxWidth); /** * Get a day name or abbreviation * @param day The month number (1=Monday, 7=Sunday) * @param minWidth The minimum number of characters * @param maxWidth The maximum number of characters */ public String dayName(int day, int minWidth, int maxWidth); /** * Get an am/pm indicator * @param minutes the minutes within the day * @param minWidth minimum width of output * @param maxWidth maximum width of output * @return the AM or PM indicator */ public String halfDayName(int minutes, int minWidth, int maxWidth); /** * Get an ordinal suffix for a particular component of a date/time. * @param component the component specifier from a format-dateTime picture, for * example "M" for the month or "D" for the day. * @return a string that is acceptable in the ordinal attribute of xsl:number * to achieve the required ordinal representation. For example, "-e" for the day component * in German, to have the day represented as "dritte August". */ public String getOrdinalSuffixForDateTime(String component); /** * Get the name for an era (e.g. "BC" or "AD") * @param year the proleptic gregorian year, using "0" for the year before 1AD */ public String getEraName(int year); /** * Get the name of a calendar * @param code The code representing the calendar as in the XSLT 2.0 spec, e.g. AD for the Gregorian calendar */ public String getCalendarName(String code); } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/number/Numberer_it.java0000644000175000017500000002227111033112257022011 0ustar eugeneeugenepackage net.sf.saxon.number; /** * * @author Karel Goossens * BTR-Services Belgium. * Numberer class for the Italian language. * @see Italian numbers * @see Italian months * @see Italian days */ public class Numberer_it extends AbstractNumberer { private static final long serialVersionUID = 1L; private static String[] italianOrdinalUnits = { "", "primo", "secondo", "terzo", "quarto", "quinto", "sesto", "settimo", "ottavo", "nono", "decimo", "undicesimo ", "dodicesimo", "tredicesimo" , "quattordicesimo", "quindiczesimo", "sedicesimo", "diciassettesimo", "diciottesimo", "novantesimo"}; private static String[] italianOrdinalTens = { "", "decimo", "ventesimo", "trentesimo", "quarantesimo", "cinquantesimo", "sessantesimo", "settantesimo", "ottantesimo", "novantesimo"}; private static String[] italianUnits = { "", "uno", "due", "tre", "quattro", "cinque", "sei", "sette", "otto", "nove", "dieci", "undici", "dodici", "tredici", "quattordici", "quindici", "sedici", "diciassette", "diciotto", "diciannove"}; private static String[] italianTens = { "", "dieci", "venti", "trenta", "quaranta", "cinquanta", "sessanta", "settanta", "ottanta", "novanta"}; /** * Show an ordinal number as Italian words in a requested case (for example, Twentyfirst) */ public String toOrdinalWords(String ordinalParam, long number, int wordCase) { String s; /* there is no such thing as zero-est */ if(number==0 && !"notNull".equalsIgnoreCase(ordinalParam))return ""; ordinalParam="notNull"; if (number >= 1000000000) { long rem = number % 1000000000; long num = number / 1000000000; s = (num==1?"un":toWords(num)) + (rem==0 ?" miliardesimo":(num==1?" miliardo ":" miliardi ") +toOrdinalWords(ordinalParam, rem, wordCase)); } else if (number >= 1000000) { long rem = number % 1000000; long num = number /1000000; s = (num==1?"un":toWords(num)) + (rem==0?" milionesimo":(num==1?" milione ":" milioni ") + toOrdinalWords(ordinalParam, rem, wordCase)); } else if (number >= 1000) { if(number==100000){ s="centomillesimo"; } else if(number==10000){ s="diecimillesimo"; } else { long rem = number % 1000; long num = number/1000; s = (num==1?"":toWords(num)) + (rem==0?"millesimo":(num==1?"mille":"mila") + toOrdinalWords(ordinalParam, rem, wordCase)); } } else if (number >= 100) { int rem = (int)number % 100; int num = (int)number / 100; if(number==100){ s="centesimo"; } else{ if(rem==0&&num!=1){ s=toWords(num)+"centesimo"; } else{ s=(num==1?"":toWords(num))+"cento"+ toOrdinalWords(ordinalParam, rem, wordCase); } } } else { if (number < 20) { s = italianOrdinalUnits[(int)number]; } else { int rem = (int)(number % 10); if (rem==0) { s = italianOrdinalTens[(int)number / 10]; } else { s = italianTens[(int)number / 10]; switch (rem){ case 1:s= s.substring(0, s.length()-1)+"unesimo"; break; case 3: case 6: s=s+italianUnits[rem]+"esimo"; break; default: s=s+italianUnits[rem].substring(0,italianUnits[rem].length()-1)+"esimo"; } } } } s=s.toLowerCase(); s=s.replaceAll("centoun", "centun"); if (wordCase == UPPER_CASE) { s=s.toUpperCase(); } return s; } public String toWords(long number) { if (number >= 1000000000) { long rem = number % 1000000000; long num = number / 1000000000; return (num==1?"un miliardo":toWords(num) + " miliardi" )+ (rem==0 ? "" : " ") + toWords(rem); } else if (number >= 1000000) { long rem = number % 1000000; long num = number / 1000000; return (num==1?"un milione":toWords(num) + " milioni") + (rem==0 ? "" : " ") + toWords(rem); } else if (number >= 1000) { long rem = number % 1000; long num = number / 1000; return (num==1?"mille":toWords(num)+"mila") + toWords(rem); } else if (number >= 100) { long rem = number % 100; return (number/100==1?"":toWords(number / 100)) + "cento" + toWords(rem); } else { if (number < 20){ return italianUnits[(int)number]; } int rem = (int)(number % 10); String s=italianTens[(int)number / 10]; switch(rem){ case 0: return italianTens[(int)number / 10]; case 1: case 8: return s.substring(0,s.length()-1)+italianUnits[rem]; case 3: return s+"trè"; default: return s+italianUnits[rem]; } } } public String toWords(long number, int wordCase) { String s; if (number == 0) { s = "zero"; } else { s = toWords(number); } if (wordCase == UPPER_CASE) { return s.toUpperCase(); } else if (wordCase == LOWER_CASE) { return s.toLowerCase(); } else { return s; } } private static String[] italianMonths = { "gennaio", "febbraio", "marzo", "aprile", "maggio", "giugno", "luglio", "agosto", "settembre", "ottobre", "novembre", "dicembre" }; private static String[] italianMonthAbbreviations = { "gen", "feb", "mar", "apr", "mag", "giu", "lug", "ago", "set", "ott", "nov", "dic" }; /** * Get a month name or abbreviation * @param month The month number (1=January, 12=December) * @param minWidth The minimum number of characters * @param maxWidth The maximum number of characters */ //@Override public String monthName(int month, int minWidth, int maxWidth) { String name = italianMonths[month-1]; if (maxWidth < 3) { maxWidth = 3; } if (name.length() > maxWidth) { name = italianMonthAbbreviations[month-1]; if (name.length() > maxWidth) { name = name.substring(0, maxWidth); } } while (name.length() < minWidth) { name = name + ' '; } return name; } /** * Get a day name or abbreviation * @param day The day of the week (1=Monday, 7=Sunday) * @param minWidth The minimum number of characters * @param maxWidth The maximum number of characters */ public String dayName(int day, int minWidth, int maxWidth) { String name = italianDays[day-1]; if (maxWidth < 2) { maxWidth = 2; } if (name.length() > maxWidth) { name = italianDayAbbreviations[day-1]; if (name.length() > maxWidth) { name = name.substring(0, maxWidth); } } while (name.length() < minWidth) { name = name + ' '; } if (minWidth==1 && maxWidth==2) { // special case name = name.substring(0, minUniqueDayLength[day-1]); } return name; } private static String[] italianDays = { "lunedì", "martedì ", "mercoledì", "giovedì", "venerdì", "sabato", "domenica" }; private static String[] italianDayAbbreviations = { "lun", "mar", "mer", "gio", "ven", "sab", "dom" }; private static int[] minUniqueDayLength = { 1, 2, 2, 1, 1, 1, 1 }; } // //The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); //you may not use this file except in compliance with the License. You may obtain a copy of the //License at http://www.mozilla.org/MPL/ // //Software distributed under the License is distributed on an "AS IS" basis, //WITHOUT WARRANTY OF ANY KIND, either express or implied. //See the License for the specific language governing rights and limitations under the License. // //The Original Code is: all this file. // //The Initial Developer of the Original Code is Michael H. Kay. // //Portions created by Karel Goossens are Copyright (C) BTR-services inc. All Rights Reserved. // //Contributor(s): Karel Goossens. // saxonb-9.1.0.8/bj/net/sf/saxon/number/Numberer_fr.java0000644000175000017500000002075111033112257022005 0ustar eugeneeugenepackage net.sf.saxon.number; /** * Class Numberer_fr is a number formatter for french. This one will be * activated for language="fr" * * @author Luc Rochefort * @version 1.0 * */ public class Numberer_fr extends AbstractNumberer { /** * Automatically generated serialVersionUID number */ private static final long serialVersionUID = -222104830008011842L; private static String[] frenchUnits = { "", "Un", "Deux", "Trois", "Quatre", "Cinq", "Six", "Sept", "Huit", "Neuf", "Dix", "Onze", "Douze", "Treize", "Quatorze", "Quinze", "Seize", "Dix-sept", "Dix-huit", "Dix-neuf" }; private static String[] frenchTens = { "", "Dix", "Vingt", "Trente", "Quarante", "Cinquante", "Soixante", "Soixante", "Quatre-vingt", "Quatre-vingt" }; private static String[] frenchOrdinalUnits = { "", "Premier", "Deuxième", "Troisième", "Quatrième", "Cinquième", "Sixième", "Septième", "Huitième", "Neuvième", "Dixième", "Onzième", "Douzième", "Treizième", "Quatorzième", "Quinzième", "Seizième", "Dix-septième", "Dix-huitième", "Dix-neuvième" }; private static String[] frenchOrdinalTens = { "", "Dixième", "Vingtième", "Trentième", "Quarantième", "Cinquantième", "Soixantième", "Soixante", "Quatre-vingtième", "Quatre-vingt" }; private static String[] frenchDays = { "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi", "Dimanche" }; private static String[] frenchMonths = { "Janvier", "Février", "Mars", "Avril", "Mai", "Juin", "Juillet", "Août", "Septembre", "Octobre", "Novembre", "Décembre" }; /* * (non-Javadoc) * * @see net.sf.saxon.number.Numberer_en#ordinalSuffix(java.lang.String, * long) */ protected String ordinalSuffix(String ordinalParam, long number) { if (number != 1) { return "e"; } else { return "er"; } } /* * (non-Javadoc) * * @see net.sf.saxon.number.Numberer_en#toWords(long) */ public String toWords(long number) { return toWords(number, true); } /* * (non-Javadoc) * * @see net.sf.saxon.number.Numberer_en#toWords(long, int) */ public String toWords(long number, int wordCase) { String s = toWords(number); if (wordCase == UPPER_CASE) { return s.toUpperCase(); } else if (wordCase == LOWER_CASE) { return s.toLowerCase(); } else { return s; } } private String toWords(long number, boolean terminal) { if (number == 0) { return "Zéro"; } else if (number >= 1000000000000000000l) { long rem = number % 1000000000000000000l; long n = number / 1000000000000000000l; String s = (n == 1 ? "Un" : toWords(n, true)); return s + " quintillion" + (n > 1 ? "s" : "") + (rem == 0 ? "" : " " + toWords(rem, LOWER_CASE, terminal)); } else if (number >= 1000000000000000l) { long rem = number % 1000000000000000l; long n = number / 1000000000000000l; String s = (n == 1 ? "Un" : toWords(n, true)); return s + " quatrillion" + (n > 1 ? "s" : "") + (rem == 0 ? "" : " " + toWords(rem, LOWER_CASE, terminal)); } else if (number >= 1000000000000l) { long rem = number % 1000000000000l; long n = number / 1000000000000l; String s = (n == 1 ? "Un" : toWords(n, true)); return s + " trillion" + (n > 1 ? "s" : "") + (rem == 0 ? "" : " " + toWords(rem, LOWER_CASE, terminal)); } else if (number >= 1000000000) { long rem = number % 1000000000; long n = number / 1000000000; String s = (n == 1 ? "Un" : toWords(n, true)); return s + " milliard" + (n > 1 ? "s" : "") + (rem == 0 ? "" : " " + toWords(rem, LOWER_CASE, terminal)); } else if (number >= 1000000) { long rem = number % 1000000; long n = number / 1000000; String s = (n == 1 ? "Un" : toWords(n, true)); return s + " million" + (n > 1 ? "s" : "") + (rem == 0 ? "" : " " + toWords(rem, LOWER_CASE, terminal)); } else if (number >= 1000) { long rem = number % 1000; long n = number / 1000; String s = (n == 1 ? "" : toWords(n, false)); return s + (n == 1 ? "Mille" : " mille") + (rem == 0 ? "" : " " + toWords(rem, LOWER_CASE, terminal)); } else if (number >= 100) { long rem = number % 100; long n = number / 100; String s = (n == 1 ? "" : toWords(n, false)); return s + (n == 1 ? "Cent" : " cent") + (rem == 0 && n > 1 && terminal ? "s" : ((rem != 0) ? " " + toWords(rem, LOWER_CASE, terminal) : "")); } else { if (number < 20) return frenchUnits[(int) number]; int rem = (int) (number % 10); int tens = (int) number / 10; if (tens == 7 || tens == 9) { rem += 10; } String link = (rem == 1 || rem == 11) ? ((tens == 8 || tens == 9) ? "-" : " et ") : "-"; return frenchTens[tens] + (rem == 0 ? ((tens == 8 && terminal) ? "s" : "") : link) + (tens == 0 ? frenchUnits[rem] : frenchUnits[rem].toLowerCase()); } } private String toWords(long number, int wordCase, boolean terminal) { String s = toWords(number, terminal); if (wordCase == UPPER_CASE) { return s.toUpperCase(); } else if (wordCase == LOWER_CASE) { return s.toLowerCase(); } else { return s; } } /* * (non-Javadoc) * * @see net.sf.saxon.number.Numberer_en#toOrdinalWords(java.lang.String, * long, int) */ public String toOrdinalWords(String ordinalParam, long number, int wordCase) { String ord; if (number < 20) { if (number == 0) { ord = "Zéroième"; } else { ord = frenchOrdinalUnits[(int) number]; } } else if (number < 100) { long mod10 = number % 10; long int10 = number / 10; if (int10 == 7 || int10 == 9) { int10 -= 1; mod10 += 10; } if (mod10 == 0) { ord = frenchOrdinalTens[(int) int10]; } else { String link = (mod10 == 1 || mod10 == 11) ? ((int10 == 8) ? "-" : " et ") : "-"; String prefix = toWords(int10 * 10); if (int10 == 8) { prefix = prefix.substring(0, prefix.length() - 1); } String result = prefix + link; ord = result + ((mod10 == 1) ? "unième" : toOrdinalWords("", mod10, LOWER_CASE)); } } else { String suffix = "ième"; long mod100 = number % 100; long int100 = number / 100; if (int100 == 70 || int100 == 90) { int100 -= 10; mod100 += 100; } String prefix = toWords(int100 * 100, false); if (int100 % 10000 == 0) { prefix = prefix.replaceFirst("Un ", ""); } /* strip prefix, if needed */ if ((prefix.endsWith("mille") || prefix.endsWith("Mille")) && mod100 == 0) { prefix = prefix.substring(0, prefix.length() - 1); } else if (prefix.endsWith("illions") || prefix.endsWith("illiards")) { prefix = prefix.substring(0, prefix.length() - 1); } ord = prefix + ((mod100 == 0) ? suffix : " " + ((mod100 == 1) ? "unième" : toOrdinalWords("", mod100, LOWER_CASE))); } if (wordCase == UPPER_CASE) { return ord.toUpperCase(); } else if (wordCase == LOWER_CASE) { return ord.toLowerCase(); } else { return ord; } } /* * (non-Javadoc) * * @see net.sf.saxon.number.Numberer#monthName(int, int, int) */ public String monthName(int month, int minWidth, int maxWidth) { String name = frenchMonths[month - 1]; if (maxWidth < 3) { maxWidth = 3; } if (name.length() > maxWidth) { name = name.substring(0, maxWidth); } while (name.length() < minWidth) { name = name + " "; } return name; } /* * (non-Javadoc) * * @see net.sf.saxon.number.Numberer#dayName(int, int, int) */ public String dayName(int day, int minWidth, int maxWidth) { String name = frenchDays[day - 1]; if (maxWidth < 3) { maxWidth = 3; } if (name.length() > maxWidth) { name = name.substring(0, maxWidth); } while (name.length() < minWidth) { name = name + " "; } return name; } } // // The contents of this file are subject to the Mozilla Public License Version // 1.0 (the "License"); // you may not use this file except in compliance with the License. You may // obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations // under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by Luc Rochefort are Copyright (C) Luc Rochefort. All // Rights Reserved. // // Contributor(s): Laurent Bourbeau, for the elaboration of JUnit tests // and Jean-Grégoire Djénandji, for acceptance testing. //saxonb-9.1.0.8/bj/net/sf/saxon/number/Numberer_en.java0000644000175000017500000002022011033112257021767 0ustar eugeneeugenepackage net.sf.saxon.number; /** * Numberer class for the English language */ public class Numberer_en extends AbstractNumberer { /** * Construct the ordinal suffix for a number, for example "st", "nd", "rd" * @param ordinalParam the value of the ordinal attribute (used in non-English * language implementations) * @param number the number being formatted * @return the ordinal suffix to be appended to the formatted number */ protected String ordinalSuffix(String ordinalParam, long number) { int penult = ((int)(number % 100)) / 10; int ult = (int)(number % 10); if (penult==1) { // e.g. 11th, 12th, 13th return "th"; } else { if (ult==1) { return "st"; } else if (ult==2) { return "nd"; } else if (ult==3) { return "rd"; } else { return "th"; } } } /** * Show the number as words in title case. (We choose title case because * the result can then be converted algorithmically to lower case or upper case). * @param number the number to be formatted * @return the number formatted as English words */ public String toWords(long number) { if (number >= 1000000000) { long rem = number % 1000000000; return toWords(number / 1000000000) + " Billion" + (rem==0 ? "" : (rem < 100 ? " and " : " ") + toWords(rem)); } else if (number >= 1000000) { long rem = number % 1000000; return toWords(number / 1000000) + " Million" + (rem==0 ? "" : (rem < 100 ? " and " : " ") + toWords(rem)); } else if (number >= 1000) { long rem = number % 1000; return toWords(number / 1000) + " Thousand" + (rem==0 ? "" : (rem < 100 ? " and " : " ") + toWords(rem)); } else if (number >= 100) { long rem = number % 100; return toWords(number / 100) + " Hundred" + (rem==0 ? "" : " and " + toWords(rem)); } else { if (number < 20) return englishUnits[(int)number]; int rem = (int)(number % 10); return englishTens[(int)number / 10] + (rem==0 ? "" : ' ' + englishUnits[rem]); } } /** * Show an ordinal number as English words in a requested case (for example, Twentyfirst) * @param ordinalParam the value of the "ordinal" attribute as supplied by the user * @param number the number to be formatted * @param wordCase the required case for example {@link #UPPER_CASE}, * {@link #LOWER_CASE}, {@link #TITLE_CASE} * @return the formatted number */ public String toOrdinalWords(String ordinalParam, long number, int wordCase) { String s; if (number >= 1000000000) { long rem = number % 1000000000; s = toWords(number / 1000000000) + " Billion" + (rem==0 ? "th" : (rem < 100 ? " and " : " ") + toOrdinalWords(ordinalParam, rem, wordCase)); } else if (number >= 1000000) { long rem = number % 1000000; s = toWords(number / 1000000) + " Million" + (rem==0 ? "th" : (rem < 100 ? " and " : " ") + toOrdinalWords(ordinalParam, rem, wordCase)); } else if (number >= 1000) { long rem = number % 1000; s = toWords(number / 1000) + " Thousand" + (rem==0 ? "th" : (rem < 100 ? " and " : " ") + toOrdinalWords(ordinalParam, rem, wordCase)); } else if (number >= 100) { long rem = number % 100; s = toWords(number / 100) + " Hundred" + (rem==0 ? "th" : " and " + toOrdinalWords(ordinalParam, rem, wordCase)); } else { if (number < 20) { s = englishOrdinalUnits[(int)number]; } else { int rem = (int)(number % 10); if (rem==0) { s = englishOrdinalTens[(int)number / 10]; } else { s = englishTens[(int)number / 10] + '-' + englishOrdinalUnits[rem]; } } } if (wordCase == UPPER_CASE) { return s.toUpperCase(); } else if (wordCase == LOWER_CASE) { return s.toLowerCase(); } else { return s; } } private static String[] englishUnits = { "", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten", "Eleven", "Twelve", "Thirteen", "Fourteen", "Fifteen", "Sixteen", "Seventeen", "Eighteen", "Nineteen"}; private static String[] englishTens = { "", "Ten", "Twenty", "Thirty", "Forty", "Fifty", "Sixty", "Seventy", "Eighty", "Ninety"}; private static String[] englishOrdinalUnits = { "", "First", "Second", "Third", "Fourth", "Fifth", "Sixth", "Seventh", "Eighth", "Ninth", "Tenth", "Eleventh", "Twelfth", "Thirteenth", "Fourteenth", "Fifteenth", "Sixteenth", "Seventeenth", "Eighteenth", "Nineteenth"}; private static String[] englishOrdinalTens = { "", "Tenth", "Twentieth", "Thirtieth", "Fortieth", "Fiftieth", "Sixtieth", "Seventieth", "Eightieth", "Ninetieth"}; /** * Get a month name or abbreviation * @param month The month number (1=January, 12=December) * @param minWidth The minimum number of characters * @param maxWidth The maximum number of characters */ public String monthName(int month, int minWidth, int maxWidth) { String name = englishMonths[month-1]; if (maxWidth < 3) { maxWidth = 3; } if (name.length() > maxWidth) { name = name.substring(0, maxWidth); } while (name.length() < minWidth) { name = name + ' '; } return name; } private static String[] englishMonths = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; /** * Get a day name or abbreviation * @param day The day of the week (1=Monday, 7=Sunday) * @param minWidth The minimum number of characters * @param maxWidth The maximum number of characters */ public String dayName(int day, int minWidth, int maxWidth) { String name = englishDays[day-1]; if (maxWidth < 2) { maxWidth = 2; } if (name.length() > maxWidth) { name = englishDayAbbreviations[day-1]; if (name.length() > maxWidth) { name = name.substring(0, maxWidth); } } while (name.length() < minWidth) { name = name + ' '; } if (minWidth==1 && maxWidth==2) { // special case name = name.substring(0, minUniqueDayLength[day-1]); } return name; } private static String[] englishDays = { "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" }; private static String[] englishDayAbbreviations = { "Mon", "Tues", "Weds", "Thurs", "Fri", "Sat", "Sun" }; private static int[] minUniqueDayLength = { 1, 2, 1, 2, 1, 2, 2 }; } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file // // The Initial Developer of the Original Code is Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/number/Numberer_nlBE.java0000644000175000017500000002111411033112257022210 0ustar eugeneeugenepackage net.sf.saxon.number; /** * @author Karel Goossens * BTR-Services Belgium. * Numberer class for the Belgian-Dutch language region. * * @see http://woordenlijst.org/leidraad/6/9/#r6n * @see http://taaladvies.net/taal/advies/popup.php?id=88 * @see http://www.vlaanderen.be/servlet/Satellite?c=Page&cid=1120536021990&pagename=taaltelefoon%2FPage%2FHomePageMIN */ public class Numberer_nlBE extends AbstractNumberer { private static final long serialVersionUID = 1L; private static String[] dutchOrdinalUnits = { "", "eenste", "tweede", "derde", "vierde", "vijfde", "zesde", "zevende", "achtste", "negende", "tiende", "elfde ", "twaalfde", "dertiende" , "veertiende", "vijftiende", "zestiende", "zeventiende", "achtiende", "negentiende"}; private static String[] dutchOrdinalTens = { "", "tiende", "twintigste", "dertigste", "veertigste", "vijftigste", "zestigste", "zeventigste", "tachtigste", "negentigste"}; private static String[] dutchUnits = { "", "een", "twee", "drie", "vier", "vijf", "zes", "zeven", "acht", "negen", "tien", "elf", "twaalf", "dertien", "veertien", "vijftien", "zestien", "zeventien", "achtien", "negentien"}; private static String[] dutchTens = { "", "tien", "twintig", "dertig", "veertig", "vijftig", "zestig", "zeventig", "tachtig", "negentig"}; /** * Show an ordinal number as dutch words in a requested case (for example, Twentyfirst) */ public String toOrdinalWords(String ordinalParam, long number, int wordCase) { String s; if(number==1000000000){ s="miljardste"; } else if(number==1000000){ s="miljoenste"; } else if(number==1000){ s="duizendste"; } else if(number==100){ s="honderste"; } else if (number >= 1000000000) { long rem = number % 1000000000; s = toWords(number / 1000000000) + " miljard" + (rem==0 ? "" : (rem < 100 ? " en " : " ") + toOrdinalWords(ordinalParam, rem, wordCase)); } else if (number >= 1000000) { long rem = number % 1000000; s = toWords(number / 1000000) + " miljoen" + (rem==0 ? "" : (rem < 100 ? " en " : " ") + toOrdinalWords(ordinalParam, rem, wordCase)); } else if (number >= 1000) { long rem = number % 1000; s = (number/1000==1?"":toWords(number / 1000)) + "duizend" +" "+ toOrdinalWords(ordinalParam, rem, wordCase); } else if (number >= 100) { long rem = number % 100; s = (number/100==1?"":toWords(number / 100)) + "honderd" + toOrdinalWords(ordinalParam, rem, wordCase); } else { if (number < 20) { s = dutchOrdinalUnits[(int)number]; } else { int rem = (int)(number % 10); if (rem==0) { s = dutchOrdinalTens[(int)number / 10]; } else { s = dutchUnits[rem]+(rem==2?"ën":"en")+dutchTens[(int)number / 10]+"ste"; } } } if (wordCase == UPPER_CASE) { return s.toUpperCase(); } else if (wordCase == LOWER_CASE) { return s.toLowerCase(); } else { return s; } } public String toWords(long number) { if (number >= 1000000000) { long rem = number % 1000000000; return toWords(number / 1000000000) + " miljard" + (rem==0 ? "" : (rem < 100 ? "en" : " ") + toWords(rem)); } else if (number >= 1000000) { long rem = number % 1000000; return toWords(number / 1000000) + " miljoen" + (rem==0 ? "" : (rem < 100 ? "en" : " ") + toWords(rem)); } else if (number >= 1000) { long rem = number % 1000; return (number/1000==1?"":toWords(number / 1000)) + "duizend" + (rem==0 ? "" : (rem < 100 ? "en" : " ") + toWords(rem)); } else if (number >= 100) { long rem = number % 100; return (number/100==1?"":toWords(number / 100)) + "honderd" + toWords(rem); } else { if (number < 20) return dutchUnits[(int)number]; int rem = (int)(number % 10); return (rem==0 ? "" : dutchUnits[rem])+(rem==2?"ën":"en")+dutchTens[(int)number / 10] ; } } public String toWords(long number, int wordCase) { String s; if (number == 0) { s = "nul"; } else { s = toWords(number); } if (wordCase == UPPER_CASE) { return s.toUpperCase(); } else if (wordCase == LOWER_CASE) { return s.toLowerCase(); } else { return s; } } private static String[] dutchMonths = { "januari", "februari", "maart", "april", "mei", "juni", "juli", "augustus", "september", "oktober", "november", "december" }; /** * Get a month name or abbreviation * @param month The month number (1=January, 12=December) * @param minWidth The minimum number of characters * @param maxWidth The maximum number of characters */ //@Override public String monthName(int month, int minWidth, int maxWidth) { String name = dutchMonths[month-1]; if (maxWidth < 3) { maxWidth = 3; } if (name.length() > maxWidth) { name = name.substring(0, maxWidth); } while (name.length() < minWidth) { name = name + ' '; } return name; } /** * Get a day name or abbreviation * @param day The day of the week (1=Monday, 7=Sunday) * @param minWidth The minimum number of characters * @param maxWidth The maximum number of characters */ public String dayName(int day, int minWidth, int maxWidth) { String name = dutchDays[day-1]; if (maxWidth < 2) { maxWidth = 2; } if (name.length() > maxWidth) { name = dutchDayAbbreviations[day-1]; if (name.length() > maxWidth) { name = name.substring(0, maxWidth); } } while (name.length() < minWidth) { name = name + ' '; } if (minWidth==1 && maxWidth==2) { // special case name = name.substring(0, minUniqueDayLength[day-1]); } return name; } private static String[] dutchDays = { "maandag", "dinsdag", "woensdag", "donderdag", "vrijdag", "zaterdag", "zondag" }; private static String[] dutchDayAbbreviations = { "ma", "di", "woe", "do", "vrij", "zat", "zon" }; private static int[] minUniqueDayLength = { 1, 2, 1, 2, 1, 2, 2 }; /** * Get an am/pm indicator * @param minutes the minutes within the day * @param minWidth minimum width of output * @param maxWidth maximum width of output * @return the AM or PM indicator */ public String halfDayName(int minutes, int minWidth, int maxWidth) { String s; if (minutes < 12*60) { switch (maxWidth) { case 1: s = "v"; break; case 2: case 3: s = "vm"; break; default: s = "v.m."; } } else { switch (maxWidth) { case 1: s = "n"; break; case 2: case 3: s = "nm"; break; default: s = "n.m."; } } return s; } /** * Get the name for an era (e.g. "BC" or "AD") * * @param year the proleptic gregorian year, using "0" for the year before 1AD */ public String getEraName(int year) { return (year > 0 ? "n.C." : "v.C."); } } saxonb-9.1.0.8/bj/net/sf/saxon/number/package.html0000644000175000017500000000306011033112257021147 0ustar eugeneeugene Package overview for net.sf.saxon.number

    This package provides classes associated with numbering and the xsl:number element.

    It is possible to extend the range of numberings available by providing a Numberer for a specific language. This should be named Numberer_xx where xx is the language code, corresponding to the value of the lang attribute in xsl:number.

    The class Numberer_de is provided as an illustration of how to do this; it is invoked when the stylesheet specifies <xsl:number lang="de">, and a format token of "eins" is used: it allows numbers up to ten to be output as "eins", "zwei", "drei", etc.

    The class Numberer_en provides the standard numbering options. As well as the format tokens defined in the XSLT 1.0 specification (for example, "1", "001", "a", "i") it supports other numbering options including:

    • Greek upper and lower case letters
      Cyrillic upper and lower case letters
      Hebrew letters
      Japanese: Hiragana-A, Hiragana-B, Katakana-A, or Katakana-B letters, and Kanji digits
      English words: the format token "one" produces numbers such as "twenty five"
  • These classes also include code to support the localization of dates as defined in the XSLT format-dateTime() group of functions.


    Michael H. Kay
    Saxonica Limited
    9 February 2005

    saxonb-9.1.0.8/bj/net/sf/saxon/xpath/0000755000175000017500000000000012216261747016540 5ustar eugeneeugenesaxonb-9.1.0.8/bj/net/sf/saxon/xpath/XPathEvaluator.java0000644000175000017500000006560611072661167022326 0ustar eugeneeugenepackage net.sf.saxon.xpath; import net.sf.saxon.AugmentedSource; import net.sf.saxon.Configuration; import net.sf.saxon.dom.DocumentWrapper; import net.sf.saxon.dom.NodeWrapper; import net.sf.saxon.expr.Expression; import net.sf.saxon.expr.ExpressionTool; import net.sf.saxon.expr.ExpressionVisitor; import net.sf.saxon.expr.XPathContextMajor; import net.sf.saxon.instruct.Executable; import net.sf.saxon.instruct.SlotManager; import net.sf.saxon.om.*; import net.sf.saxon.trans.SaxonErrorCode; import net.sf.saxon.type.SchemaException; import net.sf.saxon.type.Type; import net.sf.saxon.value.Value; import net.sf.saxon.value.Whitespace; import org.xml.sax.InputSource; import org.w3c.dom.Node; import javax.xml.namespace.NamespaceContext; import javax.xml.namespace.QName; import javax.xml.transform.Source; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamSource; import javax.xml.xpath.*; import java.io.File; import java.util.ArrayList; import java.util.List; /** *

    XPathEvaluator provides a simple API for standalone XPath processing (that is, * executing XPath expressions in the absence of an XSLT stylesheet). It is an implementation * of the JAXP 1.3 XPath interface, with additional methods provided (a) for backwards * compatibility (b) to give extra control over the XPath evaluation, and (c) to support * XPath 2.0.

    * *

    It is intended to evolve this so that it only supports the JAXP style of operation. * Some of the methods are therefore marked as deprecated in this release, and will be * dropped in a future release.

    * *

    For an alternative XPath API, offering more direct access to Saxon capabilities, * see {@link net.sf.saxon.sxpath.XPathEvaluator}.

    * *

    Note that the XPathEvaluator links to a Saxon {@link Configuration} * object. By default a new Configuration is created automatically. In many * applications, however, it is desirable to share a configuration. The default configuration * is not schema aware. All source documents used by XPath expressions under this evaluator * must themselves be built using the Configuration used by this evaluator.

    * * @author Michael H. Kay */ public class XPathEvaluator implements XPath { private Configuration config; private NodeInfo contextNode = null; private JAXPXPathStaticContext staticContext; private boolean stripSpace = false; /** * Default constructor. Creates an XPathEvaluator with a default configuration and name pool. * The default Configuration is not schema-aware. */ public XPathEvaluator() { this(new Configuration()); } /** * Construct an XPathEvaluator with a specified configuration. * @param config the configuration to be used. If schema-aware XPath expressions are to be used, * this must be a SchemaAwareConfiguration. */ public XPathEvaluator(Configuration config) { this.config = config; staticContext = new JAXPXPathStaticContext(config); } /** * Construct an XPathEvaluator to process a particular source document. This is equivalent to * using the default constructor and immediately calling setSource(). * @param source The source document (or a specific node within it). */ public XPathEvaluator(Source source) throws net.sf.saxon.trans.XPathException { if (source instanceof NodeInfo) { config = ((NodeInfo)source).getDocumentRoot().getConfiguration(); } else { config = new Configuration(); } staticContext = new JAXPXPathStaticContext(config); setSource(source); } /** * Get the Configuration used by this XPathEvaluator * @return the Configuration used by this XPathEvaluator */ public Configuration getConfiguration() { return config; } /** * Indicate whether all whitespace text nodes in the source document are to be * removed. This option has no effect unless it is called before the call on setSource(), * and unless the Source supplied to setSource() is a SAXSource or StreamSource. * @param strip True if all whitespace text nodes are to be stripped from the source document, * false otherwise. The default if the method is not called is false. * @deprecated since 8.9. The preferred way to define options for the way in which source * documents are built is to use the class {@link net.sf.saxon.AugmentedSource} for any * of the methods expecting a {@link Source} object. */ public void setStripSpace(boolean strip) { stripSpace = strip; } /** * Supply the document against which XPath expressions are to be executed. This * method must be called before preparing or executing an XPath expression. * Setting a new source document clears all the namespaces that have been declared. * @param source Any javax.xml.transform.Source object representing the document against * which XPath expressions will be executed. Note that a Saxon {@link net.sf.saxon.om.DocumentInfo DocumentInfo} * (indeed any {@link net.sf.saxon.om.NodeInfo NodeInfo}) * can be used as a Source. To use a third-party DOM Document as a source, create an instance of * {@link javax.xml.transform.dom.DOMSource DOMSource} to wrap it. *

    The Source object supplied also determines the initial setting * of the context item. In most cases the context node will be the root of the supplied document; * however, if a NodeInfo or DOMSource is supplied it can be any node in the document.

    * @return the NodeInfo of the start node in the resulting document object. */ public NodeInfo setSource(Source source) throws net.sf.saxon.trans.XPathException { if (source instanceof DOMSource) { Node node = ((DOMSource)source).getNode(); String baseURI = source.getSystemId(); DocumentWrapper documentWrapper = new DocumentWrapper(node.getOwnerDocument(), baseURI, config); NodeWrapper nodeWrapper = documentWrapper.wrap(node); if (stripSpace) { StrippedDocument sdoc = new StrippedDocument(documentWrapper, AllElementStripper.getInstance()); return sdoc.wrap(nodeWrapper); } else { return nodeWrapper; } } else if (source instanceof NodeInfo) { NodeInfo origin = (NodeInfo)source; if (!origin.getConfiguration().isCompatible(config)) { throw new net.sf.saxon.trans.XPathException( "Supplied node must be built using the same or a compatible Configuration", SaxonErrorCode.SXXP0004); } if (stripSpace) { StrippedDocument sdoc = new StrippedDocument(origin.getDocumentRoot(), AllElementStripper.getInstance()); return sdoc.wrap(origin); } else { return origin; } } else { if (stripSpace) { AugmentedSource as = AugmentedSource.makeAugmentedSource(source); as.setStripSpace(Whitespace.ALL); source = as; } return config.buildDocument(source); } } /** * Set the static context for compiling XPath expressions. This provides control over the * environment in which the expression is compiled, for example it allows namespace prefixes to * be declared, variables to be bound and functions to be defined. For most purposes, the static * context can be defined by providing and tailoring an instance of the JAXPXPathStaticContext class. * Until this method is called, a default static context is used, in which no namespaces are defined * other than the standard ones (xml, xslt, and saxon), and no variables or functions (other than the * core XPath functions) are available. * @param context the static context * @throws IllegalArgumentException if the supplied static context uses a different and incompatible * Configuration from the one used in this XPathEvaluator */ public void setStaticContext(JAXPXPathStaticContext context) { if (!config.isCompatible(context.getConfiguration())) { throw new IllegalArgumentException("Supplied static context uses a different and incompatible Configuration"); } staticContext = context; } /** * Get the current static context * @return the static context */ public JAXPXPathStaticContext getStaticContext() { return staticContext; } /** * Get the executable * @return the executable */ public Executable getExecutable() { return staticContext.getExecutable(); } /** * Prepare an XPath expression for subsequent evaluation. * @param expression The XPath expression to be evaluated, supplied as a string. * @return an XPathExpression object representing the prepared expression * @throws net.sf.saxon.trans.XPathException if the syntax of the expression is wrong, or if it references namespaces, * variables, or functions that have not been declared. * @deprecated since Saxon 8.9 - use {@link #compile(String)} */ public XPathExpressionImpl createExpression(String expression) throws net.sf.saxon.trans.XPathException { return createExpressionInternal(expression); } private XPathExpressionImpl createExpressionInternal(String expression) throws net.sf.saxon.trans.XPathException { Expression exp = ExpressionTool.make(expression, staticContext, 0, -1, 1, false); ExpressionVisitor visitor = ExpressionVisitor.make(staticContext); visitor.setExecutable(getExecutable()); exp = visitor.typeCheck(exp, Type.ITEM_TYPE); SlotManager map = staticContext.getConfiguration().makeSlotManager(); ExpressionTool.allocateSlots(exp, 0, map); exp.setContainer(staticContext); XPathExpressionImpl xpe = new XPathExpressionImpl(exp, getExecutable()); xpe.setStackFrameMap(map); if (contextNode != null) { xpe.privatelySetContextNode(contextNode); } return xpe; } /** * Set the context node. This provides the context node for any expressions executed after this * method is called, including expressions that were prepared before it was called. * @param node The node to be used as the context node. The node must be within a tree built using * the same Saxon {@link Configuration} as used by this XPathEvaluator. * @deprecated since Saxon 8.9 - use the various method defined in the JAXP interface definition, * which allow a NodeInfo object to be supplied as the value of the Source argument * @throws IllegalArgumentException if the supplied node was built using the wrong Configuration */ public void setContextNode(NodeInfo node) { if (!node.getConfiguration().isCompatible(config)) { throw new IllegalArgumentException( "Supplied node must be built using the same or a compatible Configuration"); } contextNode = node; } /** * Prepare and execute an XPath expression, supplied as a string, and returning the results * as a List. * @param expression The XPath expression to be evaluated, supplied as a string. * @return The results of the expression, as a List. The List represents the sequence * of items returned by the expression. Each item in the list will either be an object * representing a node, or a Java object representing an atomic value. * The types of Java object that may be included in the list, and the XML Schema data types that they * correspond to, are as follows:

    *

      *
    • Boolean (xs:boolean)
    • *
    • String (xs:string)
    • *
    • BigDecimal (xs:decimal)
    • *
    • Long (xs:integer and its derived types)
    • *
    • Double (xs:double)
    • *
    • Float (xs:float)
    • *
    • Date (xs:date, xs:dateTime)
    • *
    * @deprecated since Saxon 8.9 - use the various method defined in the JAXP interface definition */ public List evaluate(String expression) throws net.sf.saxon.trans.XPathException { Expression exp = ExpressionTool.make(expression, staticContext,0,-1,1, false); ExpressionVisitor visitor = ExpressionVisitor.make(staticContext); visitor.setExecutable(getExecutable()); exp = visitor.typeCheck(exp, Type.ITEM_TYPE); SlotManager map = staticContext.getConfiguration().makeSlotManager(); ExpressionTool.allocateSlots(exp, 0, map); XPathContextMajor context = new XPathContextMajor(contextNode, staticContext.getExecutable()); context.openStackFrame(map); SequenceIterator iterator = exp.iterate(context); ArrayList list = new ArrayList(20); while (true) { Item item = iterator.next(); if (item == null) { return list; } list.add(Value.convertToJava(item)); } } public void reset() { contextNode = null; stripSpace = false; staticContext = new JAXPXPathStaticContext(config); } /** * Set XPath 1.0 compatibility mode on or off (by default, it is false). This applies * to any XPath expression compiled while this option is in force. * @param compatible true if XPath 1.0 compatibility mode is to be set to true, false * if it is to be set to false. */ public void setBackwardsCompatible(boolean compatible) { staticContext.setBackwardsCompatibilityMode(compatible); } /** * Get the value of XPath 1.0 compatibility mode * @return true if XPath 1.0 compatibility mode is set */ public boolean isBackwardsCompatible() { return staticContext.isInBackwardsCompatibleMode(); } /** * Set the resolver for XPath variables * @param xPathVariableResolver a resolver for variables */ public void setXPathVariableResolver(XPathVariableResolver xPathVariableResolver) { staticContext.setXPathVariableResolver(xPathVariableResolver); } /** * Get the resolver for XPath variables * @return the resolver, if one has been set */ public XPathVariableResolver getXPathVariableResolver() { return staticContext.getXPathVariableResolver(); } /** * Set the resolver for XPath functions * @param xPathFunctionResolver a resolver for XPath function calls */ public void setXPathFunctionResolver(XPathFunctionResolver xPathFunctionResolver) { staticContext.setXPathFunctionResolver(xPathFunctionResolver); } /** * Get the resolver for XPath functions * @return the resolver, if one has been set */ public XPathFunctionResolver getXPathFunctionResolver() { return staticContext.getXPathFunctionResolver(); } /** * Set the namespace context to be used. * @param namespaceContext The namespace context */ public void setNamespaceContext(NamespaceContext namespaceContext) { staticContext.setNamespaceContext(namespaceContext); } /** * Get the namespace context, if one has been set using {@link #setNamespaceContext} * @return the namespace context if set, or null otherwise */ public NamespaceContext getNamespaceContext() { return staticContext.getNamespaceContext(); } /** * Import a schema. This is possible only if the schema-aware version of Saxon is being used, * and if the Configuration is a SchemaAwareConfiguration. Having imported a schema, the types * defined in that schema become part of the static context. * @param source A Source object identifying the schema document to be loaded * @throws net.sf.saxon.type.SchemaException if the schema contained in this document is invalid * @throws UnsupportedOperationException if the configuration is not schema-aware */ public void importSchema(Source source) throws SchemaException { staticContext.importSchema(source); } /** * Compile an XPath 2.0 expression * @param expr the XPath 2.0 expression to be compiled, as a string * @return the compiled form of the expression * @throws XPathExpressionException if there are any static errors in the expression. * Note that references to undeclared variables are not treated as static errors, because * variables are not pre-declared using this API. */ public XPathExpression compile(String expr) throws XPathExpressionException { if (expr == null) { throw new NullPointerException("expr"); } try { return createExpressionInternal(expr); } catch (net.sf.saxon.trans.XPathException e) { throw new XPathExpressionException(e); } } /** * Single-shot method to compile and execute an XPath 2.0 expression. * @param expr The XPath 2.0 expression to be compiled and executed * @param node The context node for evaluation of the expression. * *

    This may be a NodeInfo object, representing a node in Saxon's native * implementation of the data model, or it may be a node in any supported * external object model: DOM, JDOM, DOM4J, or XOM, or any other model for * which support has been configured in the Configuration. Note that the * supporting libraries for the chosen model must be on the class path.

    * *

    Contrary to the interface specification, Saxon does not supply an empty * document when the value is null. This is because Saxon supports multiple object models, * and it's unclear what kind of document node would be appropriate. Instead, Saxon uses * the node supplied to the {@link #setContextNode} method if available, and if none * is available, executes the XPath expression with the context item undefined.

    * * @param qName The type of result required. For details, see * {@link XPathExpressionImpl#evaluate(Object, javax.xml.namespace.QName)} * @return the result of evaluating the expression, returned as described in * {@link XPathExpressionImpl#evaluate(Object, javax.xml.namespace.QName)} * @throws XPathExpressionException if any static or dynamic error occurs * in evaluating the expression. */ public Object evaluate(String expr, Object node, QName qName) throws XPathExpressionException { XPathExpression exp = compile(expr); return exp.evaluate(node, qName); } /** * Single-shot method to compile an execute an XPath 2.0 expression, returning * the result as a string. * @param expr The XPath 2.0 expression to be compiled and executed * @param node The context node for evaluation of the expression * *

    This may be a NodeInfo object, representing a node in Saxon's native * implementation of the data model, or it may be a node in any supported * external object model: DOM, JDOM, DOM4J, or XOM, or any other model for * which support has been configured in the Configuration. Note that the * supporting libraries for the chosen model must be on the class path.

    * *

    Contrary to the interface specification, Saxon does not supply an empty * document when the value is null. This is because Saxon supports multiple object models, * and it's unclear what kind of document node would be appropriate. Instead, Saxon uses * the node supplied to the {@link #setContextNode} method if available, and if none * is available, executes the XPath expression with the context item undefined.

    * @return the result of evaluating the expression, converted to a string as if * by calling the XPath string() function * @throws XPathExpressionException if any static or dynamic error occurs * in evaluating the expression. */ public String evaluate(String expr, Object node) throws XPathExpressionException { XPathExpression exp = compile(expr); return exp.evaluate(node); } /** * Single-shot method to parse and build a source document, and * compile an execute an XPath 2.0 expression, against that document * @param expr The XPath 2.0 expression to be compiled and executed * @param inputSource The source document: this will be parsed and built into a tree, * and the XPath expression will be executed with the root node of the tree as the * context node. * @param qName The type of result required. For details, see * {@link XPathExpressionImpl#evaluate(Object, javax.xml.namespace.QName)} * @return the result of evaluating the expression, returned as described in * {@link XPathExpressionImpl#evaluate(Object, javax.xml.namespace.QName)} * @throws XPathExpressionException if any static or dynamic error occurs * in evaluating the expression. * @throws NullPointerException if any of the three arguments is null */ public Object evaluate(String expr, InputSource inputSource, QName qName) throws XPathExpressionException { if (expr == null) { throw new NullPointerException("expr"); } if (inputSource == null) { throw new NullPointerException("inputSource"); } if (qName == null) { throw new NullPointerException("qName"); } XPathExpression exp = compile(expr); return exp.evaluate(inputSource, qName); } /** * Single-shot method to parse and build a source document, and * compile an execute an XPath 2.0 expression, against that document, * returning the result as a string * @param expr The XPath 2.0 expression to be compiled and executed * @param inputSource The source document: this will be parsed and built into a tree, * and the XPath expression will be executed with the root node of the tree as the * context node * @return the result of evaluating the expression, converted to a string as * if by calling the XPath string() function * @throws XPathExpressionException if any static or dynamic error occurs * in evaluating the expression. * @throws NullPointerException if either of the two arguments is null */ public String evaluate(String expr, InputSource inputSource) throws XPathExpressionException { if (expr == null) { throw new NullPointerException("expr"); } if (inputSource == null) { throw new NullPointerException("inputSource"); } XPathExpression exp = compile(expr); return exp.evaluate(inputSource); } /** * Prepare and execute an XPath expression, supplied as a string, and returning the first * item in the result. This is useful where it is known that the expression will only return * a singleton value (for example, a single node, or a boolean). * @param expression The XPath expression to be evaluated, supplied as a string. * @return The first item in the sequence returned by the expression. If the expression * returns an empty sequence, this method returns null. Otherwise, it returns the first * item in the result sequence, represented as a Java object using the same mapping as for * the evaluate() method * @deprecated since Saxon 8.9 - use the methods defined in the JAXP interface */ public Object evaluateSingle(String expression) throws net.sf.saxon.trans.XPathException { Expression exp = ExpressionTool.make(expression, staticContext,0,-1,1, false); ExpressionVisitor visitor = ExpressionVisitor.make(staticContext); visitor.setExecutable(getExecutable()); exp = visitor.typeCheck(exp, Type.ITEM_TYPE); SlotManager map = staticContext.getConfiguration().makeSlotManager(); ExpressionTool.allocateSlots(exp, 0, map); XPathContextMajor context = new XPathContextMajor(contextNode, staticContext.getExecutable()); context.openStackFrame(map); SequenceIterator iterator = exp.iterate(context); Item item = iterator.next(); if (item == null) { return null; } else { return Value.convertToJava(item); } } /** * A simple command-line interface for the XPathEvaluator (not documented). * @param args command line arguments. * First parameter is the filename containing the source document, second * parameter is the XPath expression. */ public static void main(String[] args) throws Exception { if (args.length != 2) { System.err.println("format: java XPathEvaluator source.xml \"expression\""); return; } XPathEvaluator xpe = new XPathEvaluator(); List results = (List)xpe.evaluate(args[1], new StreamSource(new File(args[0])), XPathConstants.NODESET); for (int i = 0; i < results.size(); i++) { Object o = results.get(i); System.err.println(o); } // Configuration config = new Configuration(); // config.setLineNumbering(true); // XPathEvaluator xpath = new XPathEvaluator(config); // xpath.setXPathVariableResolver( // new XPathVariableResolver() { // public Object resolveVariable(QName variableName) { // if (variableName.getLocalPart().equals("in")) { // return "a/b/c/a"; // } // return null; // } // } // ); // NodeInfo doca = xpath.setSource(new StreamSource((new File(args[0])))); // List list = xpath.evaluate("for $v in distinct-values(tokenize($in, '/')) return concat(' +', $v)"); // for (int i=0; i *
  • {@link XMLConstants#FEATURE_SECURE_PROCESSING}
  • *
  • {@link net.sf.saxon.FeatureKeys#SCHEMA_VALIDATION}: requests schema validation of source documents. * The property is rejected if the configuration is not schema-aware.
  • * * @param feature a URI identifying the feature * @param b true to set the feature on, false to set it off * @throws XPathFactoryConfigurationException if the feature name is not recognized */ public void setFeature(String feature, boolean b) throws XPathFactoryConfigurationException { if (feature.equals(FEATURE_SECURE_PROCESSING)) { config.setAllowExternalFunctions(!b); } else if (feature.equals(FeatureKeys.SCHEMA_VALIDATION)) { config.setSchemaValidationMode(b ? Validation.STRICT : Validation.STRIP); } else { throw new XPathFactoryConfigurationException("Unknown feature: " + feature); } } /** * Get a feature of this XPath implementation. The only features currently * recognized are: *
      *
    • {@link #FEATURE_SECURE_PROCESSING}
    • *
    • {@link net.sf.saxon.FeatureKeys#SCHEMA_VALIDATION}: requests schema validation of source documents.
    • *
    * @param feature a URI identifying the feature * @return true if the feature is on, false if it is off * @throws XPathFactoryConfigurationException if the feature name is not recognized */ public boolean getFeature(String feature) throws XPathFactoryConfigurationException { if (feature.equals(FEATURE_SECURE_PROCESSING)) { return !config.isAllowExternalFunctions(); } else if (feature.equals(FeatureKeys.SCHEMA_VALIDATION)) { return config.getSchemaValidationMode() == Validation.STRICT; } else { throw new XPathFactoryConfigurationException("Unknown feature: " + feature); } } /** * Set a resolver for XPath variables. This will be used to obtain the value of * any variable referenced in an XPath expression. The variable resolver must be allocated * before the expression is compiled, but it will only be called when the expression * is evaluated. * @param xPathVariableResolver The object used to resolve references to variables. */ public void setXPathVariableResolver(XPathVariableResolver xPathVariableResolver) { variableResolver = xPathVariableResolver; } /** * Set a resolver for XPath functions. This will be used to obtain an implementation * of any external function referenced in an XPath expression. This is not required for * system functions, Saxon extension functions, constructor functions named after types, * or extension functions bound using a namespace that maps to a Java class. * @param xPathFunctionResolver The object used to resolve references to external functions. */ public void setXPathFunctionResolver(XPathFunctionResolver xPathFunctionResolver) { functionResolver = xPathFunctionResolver; } /** * Create an XPath evaluator * @return an XPath object, which can be used to compile and execute XPath expressions. */ public XPath newXPath() { XPathEvaluator xpath = new XPathEvaluator(config); xpath.setXPathFunctionResolver(functionResolver); xpath.setXPathVariableResolver(variableResolver); return xpath; } private static String FEATURE_SECURE_PROCESSING = "http://javax.xml.XMLConstants/feature/secure-processing"; // XMLConstants.FEATURE_SECURE_PROCESSING in JDK 1.5 } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): //saxonb-9.1.0.8/bj/net/sf/saxon/xpath/JAXPXPathStaticContext.java0000644000175000017500000003106111033112257023613 0ustar eugeneeugenepackage net.sf.saxon.xpath; import net.sf.saxon.Configuration; import net.sf.saxon.expr.Container; import net.sf.saxon.expr.StaticContext; import net.sf.saxon.expr.VariableReference; import net.sf.saxon.instruct.SlotManager; import net.sf.saxon.om.NamespaceConstant; import net.sf.saxon.om.NamespaceResolver; import net.sf.saxon.om.StructuredQName; import net.sf.saxon.sxpath.AbstractStaticContext; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.SchemaException; import javax.xml.XMLConstants; import javax.xml.namespace.NamespaceContext; import javax.xml.transform.Source; import javax.xml.xpath.XPathFunctionResolver; import javax.xml.xpath.XPathVariableResolver; import java.util.Arrays; import java.util.Iterator; import java.util.Set; /** * A StandaloneContext provides a context for parsing an XPath expression * in a context other than a stylesheet. In particular, it is used to support * the JAXP 1.3 XPath API. The JAXP API does not actually expose the StaticContext * object directly; rather, the static context (namespaces, variables, and functions) * is manipulated through the XPath object, implemented in Saxon by the {@link XPathEvaluator} */ public class JAXPXPathStaticContext extends AbstractStaticContext implements StaticContext, NamespaceResolver, Container { private SlotManager stackFrameMap; private XPathFunctionLibrary xpathFunctionLibrary; private NamespaceContext namespaceContext = new MinimalNamespaceContext(); private XPathVariableResolver variableResolver; /** * Create a StandaloneContext using a specific Configuration. * @param config the Configuration. For schema-aware XPath expressions, this must be a SchemaAwareConfiguration. */ public JAXPXPathStaticContext(Configuration config) { setConfiguration(config); stackFrameMap = config.makeSlotManager(); setDefaultFunctionLibrary(); xpathFunctionLibrary = new XPathFunctionLibrary(); addFunctionLibrary(xpathFunctionLibrary); } /** * Supply the NamespaceContext used to resolve namespaces. */ public void setNamespaceContext(NamespaceContext context) { this.namespaceContext = context; } /** * Get the NamespaceContext that was set using {@link #setNamespaceContext} */ public NamespaceContext getNamespaceContext() { return namespaceContext; } /** * Get the stack frame map containing the slot number allocations for the variables declared * in this static context */ public SlotManager getStackFrameMap() { return stackFrameMap; } /** * Set an XPathVariableResolver. This is used to resolve variable references * if no variable has been explicitly declared. * @param resolver A JAXP 1.3 XPathVariableResolver */ public void setXPathVariableResolver(XPathVariableResolver resolver) { this.variableResolver = resolver; } /** * Get the XPathVariableResolver */ public XPathVariableResolver getXPathVariableResolver() { return variableResolver; } public void setXPathFunctionResolver(XPathFunctionResolver xPathFunctionResolver) { if (xpathFunctionLibrary != null) { xpathFunctionLibrary.setXPathFunctionResolver(xPathFunctionResolver); } } public XPathFunctionResolver getXPathFunctionResolver() { if (xpathFunctionLibrary != null) { return xpathFunctionLibrary.getXPathFunctionResolver(); } else { return null; } } /** * Get the URI for a prefix, using the declared namespaces as * the context for namespace resolution. The default namespace is NOT used * when the prefix is empty. * This method is provided for use by the XPath parser. * @param prefix The prefix * @throws net.sf.saxon.trans.XPathException if the prefix is not declared */ public String getURIForPrefix(String prefix) throws XPathException { String uri = getURIForPrefix(prefix, false); if (uri==null) { throw new XPathException("Prefix " + prefix + " has not been declared"); } return uri; } public NamespaceResolver getNamespaceResolver() { return this; } /** * Get the namespace URI corresponding to a given prefix. Return null * if the prefix is not in scope. This method searches * any namespace context supplied using {@link #setNamespaceContext(javax.xml.namespace.NamespaceContext)}. * @param prefix the namespace prefix * @param useDefault true if the default namespace for elements and types is to be used when the * prefix is "" * @return the uri for the namespace, or null if the prefix is not in scope. * Return "" if the prefix maps to the null namespace. */ public String getURIForPrefix(String prefix, boolean useDefault) { if (prefix.equals("")) { if (useDefault) { return getDefaultElementNamespace(); } else { return ""; } } else { return namespaceContext.getNamespaceURI(prefix); } } /** * Get an iterator over all the prefixes declared in this namespace context. This method is implemented * only in the case where the NamespaceContext supplied using {@link #setNamespaceContext} is an * instance of Saxon's {@link NamespaceResolver} class. In other cases the method throws an * UnsupportedOperationException * @return an iterator over all the inscope namespace prefixes, if available * @throws UnsupportedOperationException if the NamespaceContext object is not a NamespaceResolver. */ public Iterator iteratePrefixes() { if (namespaceContext instanceof NamespaceResolver) { return ((NamespaceResolver)namespaceContext).iteratePrefixes(); } else { throw new UnsupportedOperationException(); } } /** * Bind a variable used in an XPath Expression to the XSLVariable element in which it is declared. * This method is provided for use by the XPath parser, and it should not be called by the user of * the API. * * @throws XPathException if no VariableResolver has been supplied. * @param qName */ public final VariableReference bindVariable(StructuredQName qName) throws XPathException { // bindVariable is called at compile time, but the JAXP variable resolver // is designed to be called at run time. So we need to create a variable now, // which will call the variableResolver when called upon to return the run-time value if (variableResolver != null) { return new VariableReference(new JAXPVariable(qName, variableResolver)); } else { throw new XPathException( "Variable is used in XPath expression, but no JAXP VariableResolver is available"); } } /** * Import a schema. This is possible only if the schema-aware version of Saxon is being used, * and if the Configuration is a SchemaAwareConfiguration. Having imported a schema, the types * defined in that schema become part of the static context. * @param source A Source object identifying the schema document to be loaded * @throws net.sf.saxon.type.SchemaException if the schema contained in this document is invalid * @throws UnsupportedOperationException if the configuration is not schema-aware */ public void importSchema(Source source) throws SchemaException { getConfiguration().addSchemaSource(source, getConfiguration().getErrorListener()); } /** * Determine whether a Schema for a given target namespace has been imported. Note that the * in-scope element declarations, attribute declarations and schema types are the types registered * with the (schema-aware) configuration, provided that their namespace URI is registered * in the static context as being an imported schema namespace. (A consequence of this is that * within a Configuration, there can only be one schema for any given namespace, including the * null namespace). * @return true if schema components for the given namespace have been imported into the * schema-aware configuration */ public boolean isImportedSchema(String namespace) { return getConfiguration().isSchemaAvailable(namespace); } /** * Get the set of imported schemas * * @return a Set, the set of URIs representing the names of imported schemas */ public Set getImportedSchemaNamespaces() { return getConfiguration().getImportedNamespaces(); } /** * Define a minimal namespace context for use when no user-defined namespace context has been * registered */ private static class MinimalNamespaceContext implements NamespaceContext, NamespaceResolver { /** * Get the namespace URI bound to a prefix in the current scope.

    * @param prefix the prefix to look up * @return Namespace URI bound to prefix in the current scope */ public String getNamespaceURI(String prefix) { if (prefix == null) { throw new IllegalArgumentException("prefix"); } else if (prefix.equals(XMLConstants.DEFAULT_NS_PREFIX)) { return ""; //XMLConstants.NULL_NS_URI; } else if (prefix.equals("xml")) { return NamespaceConstant.XML; } else if (prefix.equals("xs")) { return NamespaceConstant.SCHEMA; } else if (prefix.equals("xsi")) { return NamespaceConstant.SCHEMA_INSTANCE; } else if (prefix.equals("saxon")) { return NamespaceConstant.SAXON; } else { return null; } } /** *

    Get prefix bound to Namespace URI in the current scope.

    * @throws UnsupportedOperationException (always) */ public String getPrefix(String namespaceURI) { throw new UnsupportedOperationException(); } /** *

    Get all prefixes bound to a Namespace URI in the current * @throws UnsupportedOperationException (always) */ public Iterator getPrefixes(String namespaceURI) { throw new UnsupportedOperationException(); } /** * Get an iterator over all the prefixes declared in this namespace context. This will include * the default namespace (prefix="") and the XML namespace where appropriate */ public Iterator iteratePrefixes() { String[] prefixes = {"", "xml", "xs", "xsi", "saxon"}; return Arrays.asList(prefixes).iterator(); } /** * Get the namespace URI corresponding to a given prefix. Return null * if the prefix is not in scope. * * @param prefix the namespace prefix. May be the zero-length string, indicating * that there is no prefix. This indicates either the default namespace or the * null namespace, depending on the value of useDefault. * @param useDefault true if the default namespace is to be used when the * prefix is "". If false, the method returns "" when the prefix is "". * @return the uri for the namespace, or null if the prefix is not in scope. * The "null namespace" is represented by the pseudo-URI "". */ public String getURIForPrefix(String prefix, boolean useDefault) { return getNamespaceURI(prefix); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/xpath/JAXPVariable.java0000644000175000017500000001254111033112257021601 0ustar eugeneeugenepackage net.sf.saxon.xpath; import net.sf.saxon.expr.*; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.*; import net.sf.saxon.om.ValueRepresentation; import net.sf.saxon.om.StructuredQName; import net.sf.saxon.Configuration; import javax.xml.namespace.QName; import javax.xml.xpath.XPathVariableResolver; /** * An object representing an XPath variable for use in the JAXP XPath API. The object * is created at compile time when the parser tries to bind a variable reference; the * value is fetched at run-time from the XPathVariableResolver. With this interface, * there is no way of reporting a static error if the variable has not been declared. *

    * In Saxon terms, this class is both a VariableDeclaration and a Binding. Unlike * a normal VariableDeclaration, it isn't created in advance, but is created on demand * when the parser encounters a variable reference. This actually means that if the * XPath expression contains two references to the same variable, two VariableDeclarations * will be created; however, they will be indistinguishable to the VariableResolver. * Acting as a VariableDeclaration, the object goes through the motions of fixing up * a binding to a variable reference (in practice, of course, there is exactly one * reference to the variable). Acting as a run-time binding, it then evaluates the * variable by calling the XPathVariableResolver supplied by the API caller. If no * XPathVariableResolver was supplied, an error is reported when a variable is encountered; * but if the variable resolver doesn't recognize the variable name, it returns null, * which is treated as an empty sequence. *

    */ public final class JAXPVariable implements VariableDeclaration, Binding { private StructuredQName name; private XPathVariableResolver resolver; /** * Private constructor: for use only be the protected factory method make() * @param name the name of the variable * @param resolver the resolver used in conjunction with this variable */ protected JAXPVariable(StructuredQName name, XPathVariableResolver resolver) { this.name = name; this.resolver = resolver; } public SequenceType getRequiredType() { return SequenceType.ANY_SEQUENCE; } /** * Indicate whether the binding is local or global. A global binding is one that has a fixed * value for the life of a query or transformation; any other binding is local. */ public boolean isGlobal() { return true; } /** * Test whether it is permitted to assign to the variable using the saxon:assign * extension element. This will only be for an XSLT global variable where the extra * attribute saxon:assignable="yes" is present. */ public final boolean isAssignable() { return false; } /** * If this is a local variable held on the local stack frame, return the corresponding slot number. * In other cases, return -1. */ public int getLocalSlotNumber() { return -1; } /** * Get the name of the variable as a structured QName */ public StructuredQName getVariableQName() { return name; } /** * Method called by the XPath expression parser to register a reference to this variable. * This method should not be called by users of the API. */ public void registerReference(BindingReference ref) { ref.setStaticType(SequenceType.ANY_SEQUENCE, null, 0); ref.fixup(this); } /** * Get the value of the variable. This method is used by the XPath execution engine * to retrieve the value. * @param context The dynamic evaluation context * @return The value of the variable */ public ValueRepresentation evaluateVariable(XPathContext context) throws XPathException { Configuration config = context.getConfiguration(); Object value = resolver.resolveVariable((QName)name.makeQName(config)); if (value == null) { return EmptySequence.getInstance(); } JPConverter converter = JPConverter.allocate(value.getClass(), config); return converter.convert(value, context); //return Value.convertJavaObjectToXPath(value, SequenceType.ANY_SEQUENCE, context); } /** * Construct a JAXP QName from a Saxon QNameValue * @param in the Saxon QNameValue * @return the JAXP QName */ QName makeQName(QNameValue in) { return new QName(in.getNamespaceURI(), in.getLocalName(), in.getPrefix()); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/xpath/XPathFunctionLibrary.java0000644000175000017500000001036111033112257023446 0ustar eugeneeugenepackage net.sf.saxon.xpath; import net.sf.saxon.expr.Expression; import net.sf.saxon.expr.StaticContext; import net.sf.saxon.functions.FunctionLibrary; import net.sf.saxon.trans.XPathException; import net.sf.saxon.om.StructuredQName; import javax.xml.namespace.QName; import javax.xml.xpath.XPathFunction; import javax.xml.xpath.XPathFunctionResolver; /** * The XPathFunctionLibrary is a FunctionLibrary that supports binding of XPath function * calls to instances of the JAXP XPathFunction interface returned by an XPathFunctionResolver. */ public class XPathFunctionLibrary implements FunctionLibrary { private XPathFunctionResolver resolver; /** * Construct a XPathFunctionLibrary */ public XPathFunctionLibrary() { } /** * Set the resolver * @param resolver The XPathFunctionResolver wrapped by this FunctionLibrary */ public void setXPathFunctionResolver(XPathFunctionResolver resolver) { this.resolver = resolver; } /** * Get the resolver * @return the XPathFunctionResolver wrapped by this FunctionLibrary */ public XPathFunctionResolver getXPathFunctionResolver() { return resolver; } /** * Test whether an XPath function with a given name and arity is available. This supports * the function-available() function in XSLT. It is thus never used, and always returns false * @param functionName * @param arity The number of arguments. This is set to -1 in the case of the single-argument * function-available() function; in this case the method should return true if there is some */ public boolean isAvailable(StructuredQName functionName, int arity) { return false; } /** * Bind a function, given the URI and local parts of the function name, * and the list of expressions supplied as arguments. This method is called at compile * time. * @param functionName * @param staticArgs The expressions supplied statically in the function call. The intention is * that the static type of the arguments (obtainable via getItemType() and getCardinality() may * be used as part of the binding algorithm. * @param env * @return An object representing the extension function to be called, if one is found; * null if no extension function was found matching the required name, arity, or signature. */ public Expression bind(StructuredQName functionName, Expression[] staticArgs, StaticContext env) throws XPathException { if (resolver == null) { return null; } QName name = new QName(functionName.getNamespaceURI(), functionName.getLocalName()); XPathFunction function = resolver.resolveFunction(name, staticArgs.length); if (function == null) { return null; } XPathFunctionCall fc = new XPathFunctionCall(function); fc.setArguments(staticArgs); return fc; } /** * This method creates a copy of a FunctionLibrary: if the original FunctionLibrary allows * new functions to be added, then additions to this copy will not affect the original, or * vice versa. * * @return a copy of this function library. This must be an instance of the original class. */ public FunctionLibrary copy() { XPathFunctionLibrary xfl = new XPathFunctionLibrary(); xfl.resolver = resolver; return xfl; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. //saxonb-9.1.0.8/bj/net/sf/saxon/xpath/XPathExpressionImpl.java0000644000175000017500000005237011055011061023316 0ustar eugeneeugenepackage net.sf.saxon.xpath; import net.sf.saxon.Configuration; import net.sf.saxon.expr.*; import net.sf.saxon.functions.NumberFn; import net.sf.saxon.instruct.SlotManager; import net.sf.saxon.instruct.Executable; import net.sf.saxon.om.*; import net.sf.saxon.pattern.NodeTest; import net.sf.saxon.sort.AtomicComparer; import net.sf.saxon.sort.SortKeyDefinition; import net.sf.saxon.sort.SortKeyEvaluator; import net.sf.saxon.sort.SortedIterator; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.*; import org.xml.sax.InputSource; import javax.xml.namespace.QName; import javax.xml.transform.sax.SAXSource; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpression; import javax.xml.xpath.XPathExpressionException; import java.util.List; /** *

    The JAXP XPathExpression interface represents a compiled XPath expression that can be repeatedly * evaluated. This class is Saxon's implementation of that interface.

    * *

    The class also includes some methods retained from Saxon's original XPath API. When these methods * are used, the object contains the context node and other state, so it is not thread-safe.

    * * @author Michael H. Kay */ public class XPathExpressionImpl implements XPathExpression, SortKeyEvaluator { private Configuration config; private Executable executable; private Expression expression; private Expression atomizer; private NodeInfo contextNode; private SlotManager stackFrameMap; private XPathExpressionImpl sortKey = null; /** * The constructor is protected, to ensure that instances can only be * created using the createExpression() method of XPathEvaluator * @param exp the compiled expression * @param exec the executable */ protected XPathExpressionImpl(Expression exp, Executable exec) { expression = exp; executable = exec; config = exec.getConfiguration(); } /** * Define the number of slots needed for local variables within the expression. * This method is for internal use only. * @param map description of the stack frame */ protected void setStackFrameMap(SlotManager map) { stackFrameMap = map; } /** * Get the stack frame map. This holds information about the allocation of slots to variables. * This is needed by applications using low-level interfaces for evaluating the expression * @return a description of the stack frame */ public SlotManager getStackFrameMap() { return stackFrameMap; } /** * Get the Configuration under which this XPath expression was compiled * @return the Saxon configuration */ public Configuration getConfiguration() { return config; } /** * Define the sort order for the results of the expression. If this method is called, then * the list returned by a subsequent call on the evaluate() method will first be sorted. * @param sortKey an XPathExpression, which will be applied to each item in the sequence; * the result of this expression determines the ordering of the list returned by the evaluate() * method. The sortKey can be null, to clear a previous sort key. Note that the expression is * not automatically atomized; if it selects nodes, these should be explicitly converted to * atomic values by calling the string() or data() functions. * @deprecated since 9.0. This method is not present in the JAXP interface. The recommended * way to get a sorted result is to use XQuery instead of XPath. */ public void setSortKey(XPathExpressionImpl sortKey) { this.sortKey = sortKey; } /** * Set the context node for evaluating the expression. If this method is not called, * the context node will be the root of the document to which the prepared expression is * bound. * @param node the context node * @deprecated since 9.0. Using this method is not thread-safe. Use a method instead * such as {@link #evaluate(Object, QName)} that allows the context node to be specified * as a parameter to the call. */ public void setContextNode(NodeInfo node) { if (node==null) { throw new NullPointerException("Context node cannot be null"); } if (node.getConfiguration() != config) { throw new IllegalArgumentException("Supplied node uses the wrong Configuration"); } contextNode = node; } /** * Protected, undeprecated version of setContextNode() for use by deprecated paths within the package * (exists to avoid deprecation warnings when compiling Saxon) * @param node the context node */ protected void privatelySetContextNode(NodeInfo node) { if (node==null) { throw new NullPointerException("Context node cannot be null"); } if (node.getConfiguration() != config) { throw new IllegalArgumentException("Supplied node uses the wrong Configuration"); } contextNode = node; } /** * Execute a prepared XPath expression, returning the results as a List. The context * node must have been set previously using {@link #setContextNode(net.sf.saxon.om.NodeInfo)}. * @return The results of the expression, as a List. The List represents the sequence * of items returned by the expression. Each item in the list will either be an instance * of net.sf.saxon.om.NodeInfo, representing a node, or a Java object representing an atomic value. * For the types of Java object that may be returned, see {@link #evaluate(Object, javax.xml.namespace.QName)} * with the second argument set to NODESET. * @deprecated since 9.0. This method is not present in the JAXP interface. Either use * the JAXP methods such as {@link #evaluate(Object, QName)}, or use the Saxon XPath * API instead of JAXP. */ public List evaluate() throws XPathException { XPathContextMajor context = new XPathContextMajor(contextNode, executable); context.openStackFrame(stackFrameMap); SequenceIterator iter = expression.iterate(context); SequenceExtent extent = new SequenceExtent(iter); return (List)PJConverter.ToCollection.INSTANCE.convert(extent, List.class, context); } /** * Execute a prepared XPath expression, returning the first item in the result. * This is useful where it is known that the expression will only return * a singleton value (for example, a single node, or a boolean). The context node * must be set previously using {@link #setContextNode(net.sf.saxon.om.NodeInfo)}. * @return The first item in the sequence returned by the expression. If the expression * returns an empty sequence, this method returns null. Otherwise, it returns the first * item in the result sequence, represented as a Java object using the same mapping as for * the evaluate() method * @deprecated since 9.0. This method is not present in the JAXP interface. Either use * the JAXP methods such as {@link #evaluate(Object, QName)}, or use the Saxon XPath * API instead of JAXP. */ public Object evaluateSingle() throws XPathException { XPathContextMajor context = new XPathContextMajor(contextNode, executable); context.openStackFrame(stackFrameMap); SequenceIterator iterator = expression.iterate(context); Item item = iterator.next(); if (item == null) { return null; } else { return Value.convertToJava(item); } } /** * Get a raw iterator over the results of the expression. This returns results without * any conversion of the returned items to "native" Java classes. This method is intended * for use by applications that need to process the results of the expression using * internal Saxon interfaces. * @param contextItem the context item for evaluating the expression * @return an iterator over the results of the expression, with no conversion of returned items * @since 9.0 */ public SequenceIterator rawIterator(Item contextItem) throws XPathException { XPathContextMajor context = new XPathContextMajor(contextItem, executable); return rawIterator(context); } private SequenceIterator rawIterator(XPathContextMajor context) throws XPathException { context.openStackFrame(stackFrameMap); SequenceIterator iterator = expression.iterate(context); if (sortKey != null) { Expression key = sortKey.expression; if (key.getItemType(config.getTypeHierarchy()) instanceof NodeTest) { sortKey.expression = new Atomizer(key, config); } SortKeyDefinition sk = new SortKeyDefinition(); sk.setSortKey(sortKey.expression); AtomicComparer comp = sk.makeComparator(context); AtomicComparer[] comps = {comp}; iterator = new SortedIterator(context, iterator, this, comps); ((SortedIterator)iterator).setHostLanguage(Configuration.XPATH); } return iterator; } /** * JAXP 1.3 evaluate() method * @param node The context node. This must use a representation of nodes that this implementation understands. * This may be a Saxon NodeInfo, or a node in one of the external object models supported, for example * DOM, DOM4J, JDOM, or XOM, provided the support module for that object model is loaded. * *

    Contrary to the interface specification, Saxon does not supply an empty * document when the value is null. This is because Saxon supports multiple object models, * and it's unclear what kind of document node would be appropriate. Instead, Saxon uses * the node supplied to the {@link #setContextNode} method if available, and if none * is available, executes the XPath expression with the context item undefined.

    *

    Saxon does not allow a NodeList to be supplied for this parameter. It's not clear * what this would be intended to mean.

    * @param qName Indicates the type of result required. This must be one of the constants defined in * the JAXP {@link XPathConstants} class. * Saxon will attempt to convert the actual result of the expression to the required type using the * XPath 1.0 conversion rules. * @return the result of the evaluation, as a Java object of the appropriate type. Saxon interprets the * rules as follows: * * * * * * * * * * * * *
    QNameReturn Value
    BOOLEANThe effective boolean value of the actual result, * as a Java Boolean object
    STRINGThe result of applying the string() function to the actual result, * as a Java String object
    NUMBERThe result of applying the number() function to the actual result, * as a Java Double object
    NODEA single node, in the native data model supplied as input. If the * expression returns more than one node, the first is returned. If * the expression returns an empty sequence, null is returned. If the * expression returns an atomic value, or if the first item in the * result sequence is an atomic value, an exception is thrown.
    NODESETThis is interpreted as allowing any sequence, of nodes or atomic values. * If the first argument is a wrapper around a DOM Node, then the result is * returned as a DOM NodeList, and an exception is then thrown if the result sequence * contains a value that is not a DOM Node. In all other cases * the result is returned as a Java List object, unless it is empty, in which * case null is returned. The contents of the list may be node objects (in the * native data model supplied as input), or Java objects representing the XPath * atomic values in the actual result: String for an xs:string, Double for a xs:double, * Long for an xs:integer, and so on. (For safety, cast the values to a type * such as xs:string within the XPath expression).
    * * @throws XPathExpressionException if evaluation of the expression fails or if the * result cannot be converted to the requested type. */ public Object evaluate(Object node, QName qName) throws XPathExpressionException { NodeInfo contextNode = this.contextNode; if (node != null) { if (node instanceof SingletonNode) { node = ((SingletonNode)node).getNode(); } if (node instanceof NodeInfo) { if (!((NodeInfo)node).getConfiguration().isCompatible(config)) { throw new XPathExpressionException( "Supplied node must be built using the same or a compatible Configuration"); } contextNode = ((NodeInfo)node); } else { JPConverter converter = JPConverter.allocate(node.getClass(), config); ValueRepresentation val; try { val = converter.convert(node, new EarlyEvaluationContext(config, null)); } catch (XPathException e) { throw new XPathExpressionException( "Failure converting a node of class " + node.getClass().getName() + ": " + e.getMessage()); } if (val instanceof NodeInfo) { contextNode = (NodeInfo)val; } else { throw new XPathExpressionException( "Cannot locate an object model implementation for nodes of class " + node.getClass().getName()); } } } XPathContextMajor context = new XPathContextMajor(contextNode, executable); context.openStackFrame(stackFrameMap); try { if (qName.equals(XPathConstants.BOOLEAN)) { return Boolean.valueOf(expression.effectiveBooleanValue(context)); } else if (qName.equals(XPathConstants.STRING)) { SequenceIterator iter = expression.iterate(context); Item first = iter.next(); if (first == null) { return ""; } return first.getStringValue(); } else if (qName.equals(XPathConstants.NUMBER)) { if (atomizer == null) { atomizer = new Atomizer(expression, config); } SequenceIterator iter = atomizer.iterate(context); Item first = iter.next(); if (first == null) { return new Double(Double.NaN); } if (first instanceof NumericValue) { return new Double(((NumericValue)first).getDoubleValue()); } else { DoubleValue v = NumberFn.convert((AtomicValue)first); return new Double(v.getDoubleValue()); } } else if (qName.equals(XPathConstants.NODE)) { SequenceIterator iter = expression.iterate(context); Item first = iter.next(); if (first instanceof VirtualNode) { return ((VirtualNode)first).getUnderlyingNode(); } if (first == null || first instanceof NodeInfo) { return first; } throw new XPathExpressionException("Expression result is not a node"); } else if (qName.equals(XPathConstants.NODESET)) { //SequenceIterator iter = expression.iterate(context); SequenceIterator iter = rawIterator(context); SequenceExtent extent = new SequenceExtent(iter); PJConverter converter = PJConverter.allocateNodeListCreator(config, node); return converter.convert(extent, Object.class, context); } else { throw new IllegalArgumentException("qName: Unknown type for expected result"); } } catch (XPathException e) { throw new XPathExpressionException(e); } } /** * Evaluate the expression to return a string value * @param node the initial context node. This must be either an instance of NodeInfo or a node * recognized by a known external object model. *

    Contrary to the interface specification, Saxon does not supply an empty * document when the value is null. This is because Saxon supports multiple object models, * and it's unclear what kind of document node would be appropriate. Instead, Saxon uses * the node supplied to the {@link #setContextNode} method if available, and if none * is available, executes the XPath expression with the context item undefined.

    * @return the results of the expression, converted to a String * @throws XPathExpressionException if evaluation fails */ public String evaluate(Object node) throws XPathExpressionException { return (String)evaluate(node, XPathConstants.STRING); } /** * Evaluate the XPath expression against an input source to obtain a result of a specified type * @param inputSource The input source document against which the expression is evaluated. * (Note that there is no caching. This will be parsed, and the parsed result will be discarded.) * If the supplied value is null then (contrary to the JAXP specifications), the XPath expression * is evaluated with the context item undefined. * @param qName The type required, identified by a constant in {@link XPathConstants} * @return the result of the evaluation, as a Java object of the appropriate type: * see {@link #evaluate(Object, javax.xml.namespace.QName)} * @throws XPathExpressionException */ public Object evaluate(InputSource inputSource, QName qName) throws XPathExpressionException { if (qName == null) { throw new NullPointerException("qName"); } try { NodeInfo doc = null; if (inputSource != null) { doc = config.buildDocument(new SAXSource(inputSource)); } return evaluate(doc, qName); } catch (XPathException e) { throw new XPathExpressionException(e); } } /** * Evaluate the XPath expression against an input source to obtain a string result * @param inputSource The input source document against which the expression is evaluated. * (Note that there is no caching. This will be parsed, and the parsed result will be discarded.) * @return the result of the evaluation, converted to a String * @throws XPathExpressionException in the event of an XPath dynamic error * @throws NullPointerException If inputSource is null. */ public String evaluate(InputSource inputSource) throws XPathExpressionException { if (inputSource == null) { throw new NullPointerException("inputSource"); } try { NodeInfo doc = config.buildDocument(new SAXSource(inputSource)); return (String)evaluate(doc, XPathConstants.STRING); } catch (XPathException e) { throw new XPathExpressionException(e); } } /** * Callback for evaluating the sort keys. For internal use only. */ public Item evaluateSortKey(int n, XPathContext c) throws XPathException { return sortKey.getInternalExpression().evaluateItem(c); } /** * Low-level method to get the internal Saxon expression object. This exposes a wide range of * internal methods that may be needed by specialized applications, and allows greater control * over the dynamic context for evaluating the expression. * @return the underlying Saxon expression object. */ public Expression getInternalExpression() { return expression; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // The Initial Developer of the Original Code is // Michael H. Kay. // // Contributor(s): // saxonb-9.1.0.8/bj/net/sf/saxon/xpath/XPathFunctionCall.java0000644000175000017500000001655511033112257022730 0ustar eugeneeugenepackage net.sf.saxon.xpath; import net.sf.saxon.Configuration; import net.sf.saxon.expr.*; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.om.ValueRepresentation; import net.sf.saxon.om.EmptyIterator; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.Type; import net.sf.saxon.type.TypeHierarchy; import net.sf.saxon.value.Value; import javax.xml.xpath.XPathFunction; import javax.xml.xpath.XPathFunctionException; import java.util.ArrayList; import java.util.List; /** * This class is an expression that calls an external function supplied using the * JAXP XPathFunction interface */ public class XPathFunctionCall extends FunctionCall { private XPathFunction function; /** * Default constructor */ public XPathFunctionCall(XPathFunction function) { this.function = function; } /** * preEvaluate: this method suppresses compile-time evaluation by doing nothing * (because the external function might have side-effects and might use the context) * @param visitor an expression visitor */ public Expression preEvaluate(ExpressionVisitor visitor) { return this; } /** * Method called by the expression parser when all arguments have been supplied */ public void checkArguments(ExpressionVisitor visitor) throws XPathException { } /** * Determine which aspects of the context the expression depends on. XPath external * functions are given no access to context information so they cannot have any * dependencies on it. */ public int getIntrinsicDependencies() { return 0; } /** * Copy an expression. This makes a deep copy. * * @return the copy of the original expression */ public Expression copy() { throw new UnsupportedOperationException("copy"); } /** * Add a representation of this expression to a PathMap. The PathMap captures a map of the nodes visited * by an expression in a source tree. *

    *

    The default implementation of this method assumes that an expression does no navigation other than * the navigation done by evaluating its subexpressions, and that the subexpressions are evaluated in the * same context as the containing expression. The method must be overridden for any expression * where these assumptions do not hold. For example, implementations exist for AxisExpression, ParentExpression, * and RootExpression (because they perform navigation), and for the doc(), document(), and collection() * functions because they create a new navigation root. Implementations also exist for PathExpression and * FilterExpression because they have subexpressions that are evaluated in a different context from the * calling expression.

    * * @param pathMap the PathMap to which the expression should be added * @param pathMapNodeSet * @return the pathMapNode representing the focus established by this expression, in the case where this * expression is the first operand of a path expression or filter expression. For an expression that does * navigation, it represents the end of the arc in the path map that describes the navigation route. For other * expressions, it is the same as the input pathMapNode. */ public PathMap.PathMapNodeSet addToPathMap(PathMap pathMap, PathMap.PathMapNodeSet pathMapNodeSet) { return addExternalFunctionCallToPathMap(pathMap, pathMapNodeSet); } /** * Evaluate the function.
    * @param context The context in which the function is to be evaluated * @return a Value representing the result of the function. * @throws XPathException if the function cannot be evaluated. */ public SequenceIterator iterate(XPathContext context) throws XPathException { ValueRepresentation[] argValues = new ValueRepresentation[argument.length]; for (int i=0; iThis method will always return a result, though it may be the best approximation * that is available at the time.

    * * @return the item type * @param th the type hierarchy cache */ public ItemType getItemType(TypeHierarchy th) { return Type.ITEM_TYPE; } /** * Determine the cardinality of the result * @return ZERO_OR_MORE (we don't know) */ public int computeCardinality() { return StaticProperty.ALLOWS_ZERO_OR_MORE; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): Gunther Schadow (changes to allow access to public fields; also wrapping // of extensions and mapping of null to empty sequence). // saxonb-9.1.0.8/bj/net/sf/saxon/xpath/package.html0000644000175000017500000000351711033112257021012 0ustar eugeneeugene Package overview for net.sf.saxon.xpath

    This package provides an API for executing XPath expressions directly from a Java application. The API can be used either in a free-standing Java application (that is, where there is no XSLT stylesheet), or it can be used from within Java extension functions called from XPath expressions within a stylesheet.

    The API itself is defined by JAXP 1.3, in interfaces such as javax.xml.xpath.XPath. This package is therefore dependent on JAXP 1.3. J2SE 5.0 (also known as JDK 1.5) includes JAXP 1.3 as a standard component, but JDK 1.4 does not. To run the code in this package under JDK 1.4, you therefore need to install JAXP 1.3 separately. You can get this from https://jaxp.dev.java.net/. At the time of writing it is reached via a link labelled "Unbundled EA Build".

    This package (net.sf.saxon.xpath) is distributed in a separate JAR file, saxon8-xpath.jar to avoid making the whole of Saxon dependent on JAXP 1.3.

    The interfaces provided by Saxon extend the JAXP 1.3 interfaces in various ways. There are three reasons for this:

    • Saxon supports XPath 2.0 rather than 1.0

    • The package retains support for some interfaces that were provided before JAXP 1.3 came along. (These might disappear in the course of time).

    • There are methods that allow an escape into Saxon's more low-level APIs, needed by anyone doing serious software integration.

    An alternative XPath interface, which is not dependent on JAXP 1.3, is available in the package net.sf.saxon.sxpath.

    Michael H. Kay
    Saxonica Limited
    9 February 2005

    saxonb-9.1.0.8/bj/net/sf/saxon/TransformerHandlerImpl.java0000644000175000017500000001756011033112257022675 0ustar eugeneeugenepackage net.sf.saxon; import net.sf.saxon.event.Builder; import net.sf.saxon.event.Receiver; import net.sf.saxon.event.ReceivingContentHandler; import net.sf.saxon.om.DocumentInfo; import net.sf.saxon.om.Validation; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.Whitespace; import org.xml.sax.SAXException; import javax.xml.transform.Result; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerException; import javax.xml.transform.sax.TransformerHandler; /** * TransformerHandlerImpl implements the javax.xml.transform.sax.TransformerHandler * interface. It acts as a ContentHandler and LexicalHandler which receives a stream of * SAX events representing an input document, and performs a transformation treating this * SAX stream as the source document of the transformation. * @author Michael H. Kay */ public class TransformerHandlerImpl extends ReceivingContentHandler implements TransformerHandler { Controller controller; Builder builder; Receiver receiver; Result result; String systemId; boolean started = false; /** * Create a TransformerHandlerImpl and initialise variables. The constructor is protected, because * the Filter should be created using newTransformerHandler() in the SAXTransformerFactory * class * @param controller the Controller to be used */ protected TransformerHandlerImpl(Controller controller) { this.controller = controller; Configuration config = controller.getConfiguration(); int validation = config.getSchemaValidationMode(); builder = controller.makeBuilder(); setPipelineConfiguration(builder.getPipelineConfiguration()); receiver = controller.makeStripper(builder); if (controller.getExecutable().stripsInputTypeAnnotations()) { receiver = controller.getConfiguration().getAnnotationStripper(receiver); } int val = validation & Validation.VALIDATION_MODE_MASK; if (val != Validation.PRESERVE) { receiver = config.getDocumentValidator( receiver, getSystemId(), val, Whitespace.NONE, null, -1); } setReceiver(receiver); } /** * Start of a new document. The TransformerHandler is not serially reusable, so this method * must only be called once. * @throws SAXException only if an overriding subclass throws this exception * @throws UnsupportedOperationException if an attempt is made to reuse the TransformerHandler by calling * startDocument() more than once. */ public void startDocument () throws SAXException { if (started) { throw new UnsupportedOperationException( "The TransformerHandler is not serially reusable. The startDocument() method must be called once only."); } started = true; super.startDocument(); } /** * Get the Transformer used for this transformation */ public Transformer getTransformer() { return controller; } /** * Set the SystemId of the document. Note that in reporting location information, Saxon gives * priority to the system Id reported by the SAX Parser in the Locator passed to the * {@link #setDocumentLocator(org.xml.sax.Locator)} method. The SystemId passed to this method * is used as the base URI for resolving relative references. * @param url the systemId of the source document */ public void setSystemId(String url) { systemId = url; receiver.setSystemId(url); } /** * Get the systemId of the document. This will be the systemId obtained from the Locator passed to the * {@link #setDocumentLocator(org.xml.sax.Locator)} method if available, otherwise the SystemId passed * to the {@link #setSystemId(String)} method. */ public String getSystemId() { return systemId; // String s = super.getSystemId(); // return (s == null ? systemId : s); } /** * Set the output destination of the transformation */ public void setResult(Result result) { if (result==null) { throw new IllegalArgumentException("Result must not be null"); } this.result = result; } /** * Get the output destination of the transformation * @return the output destination */ public Result getResult() { return result; } /** * Override the behaviour of endDocument() in ReceivingContentHandler, so that it fires off * the transformation of the constructed document */ public void endDocument() throws SAXException { super.endDocument(); DocumentInfo doc = (DocumentInfo)builder.getCurrentRoot(); builder.reset(); if (doc==null) { throw new SAXException("No source document has been built"); } try { controller.transformDocument(doc, result); } catch (TransformerException err) { if (err instanceof XPathException) { controller.reportFatalError((XPathException)err); } throw new SAXException(err); } } // public static void main(String[] args) throws Exception { // test case for a TransformerHandler that validates the source document // TransformerFactory tfactory = new SchemaAwareTransformerFactory(); // tfactory.setAttribute(FeatureKeys.SCHEMA_VALIDATION, new Integer(Validation.STRICT)); // // Does this factory support SAX features? // if (tfactory.getFeature(SAXSource.FEATURE)) { // // // If so, we can safely cast. // SAXTransformerFactory stfactory = // ((SAXTransformerFactory) tfactory); // // // A TransformerHandler is a ContentHandler that will listen for // // SAX events, and transform them to the result. // TransformerHandler handler = // stfactory.newTransformerHandler(new StreamSource(new File("c:/MyJava/samples/styles/books.xsl"))); // // // Set the result handling to be a serialization to System.out. // Result result = new StreamResult(System.out); // // handler.setResult(result); // // // Create a reader, and set it's content handler to be the TransformerHandler. // SAXParserFactory factory = SAXParserFactory.newInstance(); // factory.setNamespaceAware(true); // XMLReader reader = factory.newSAXParser().getXMLReader(); // // reader.setContentHandler(handler); // // // It's a good idea for the parser to send lexical events. // // The TransformerHandler is also a LexicalHandler. // reader.setProperty( // "http://xml.org/sax/properties/lexical-handler", handler); // // // Parse the source XML, and send the parse events to the TransformerHandler. // handler.setSystemId("file:///MyJava/samples/data/books.xml"); // reader.parse("file:///MyJava/samples/data/books.xml"); // } else { // System.out.println( // "Can't do exampleContentHandlerToContentHandler because tfactory is not a SAXTransformerFactory"); // } // } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): None // saxonb-9.1.0.8/bj/net/sf/saxon/exslt/0000755000175000017500000000000012216261750016545 5ustar eugeneeugenesaxonb-9.1.0.8/bj/net/sf/saxon/exslt/Random.java0000644000175000017500000001107511033112257020625 0ustar eugeneeugenepackage net.sf.saxon.exslt; import net.sf.saxon.om.Item; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.om.UnfailingIterator; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.DoubleValue; /** * This class implements extension functions in the * http://exslt.org/random namespace. * * @author Martin Szugat * @version 1.0, 30.06.2004 * Rewritten by Michael Kay to generate a SequenceIterator */ public abstract class Random { /** * Returns a sequence of random numbers * between 0 and 1. * @param numberOfItems number of random items * in the sequence. * @param seed the initial seed. * @return sequence of random numbers as an iterator. * @throws IllegalArgumentException * numberOfItems is not positive. */ public static SequenceIterator randomSequence(int numberOfItems, double seed) throws IllegalArgumentException { if (numberOfItems < 1) { throw new IllegalArgumentException("numberOfItems supplied to randomSequence() must be positive"); } long javaSeed = Double.doubleToLongBits(seed); return new RandomIterator(numberOfItems, javaSeed); } /** * Returns a sequence of random numbers * between 0 and 1. * @param numberOfItems number of random items * in the sequence. * @return sequence of random numbers. * @throws IllegalArgumentException * numberOfItems is not positive. */ public static SequenceIterator randomSequence(int numberOfItems) throws IllegalArgumentException { return randomSequence(numberOfItems, System.currentTimeMillis()); } /** * Returns a single random number X * between 0 and 1. * @return sequence random number. */ public static DoubleValue randomSequence() throws XPathException { return (DoubleValue)randomSequence(1).next(); } /** * Iterator over a sequence of random numbers */ private static class RandomIterator implements UnfailingIterator { protected int position = 0; protected Item current; private int count; private long seed; private java.util.Random generator; public RandomIterator(int count, long seed) { this.count = count; this.seed = seed; generator = new java.util.Random(seed); } /** * Get the next item in the sequence.
    * @return the next item, or null if there are no more items. */ public Item next() { if (position++ >= count) { current = null; position = -1; return null; } else { current = new DoubleValue(generator.nextDouble()); return current; } } /** * Get the current node in the sequence. * @return the node returned by the most recent call on next() */ public final Item current() { return current; } /** * Get the current position * @return the position of the most recent node returned by next() */ public final int position() { return position; } public void close() { } /** * Get another SequenceIterator that iterates over the same items as the original, * but which is repositioned at the start of the sequence. * * @return a SequenceIterator that iterates over the same items, * positioned before the first item */ public SequenceIterator getAnother() { return new RandomIterator(count, seed); } public int getProperties() { return 0; } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Martin Szugat. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): Michael H. Kay. //saxonb-9.1.0.8/bj/net/sf/saxon/exslt/Sets.java0000644000175000017500000001070311033112257020320 0ustar eugeneeugenepackage net.sf.saxon.exslt; import net.sf.saxon.expr.*; import net.sf.saxon.om.Item; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.sort.GlobalOrderComparer; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.SingletonNode; /** * This class implements extension functions in the * http://exslt.org/sets namespace.

    */ public abstract class Sets { private Sets() {} /** * Return the intersection of two node-sets * @param p1 The first node-set * @param p2 The second node-set * @return A node-set containing all nodes that are in both p1 and p2 */ public static SequenceIterator intersection(SequenceIterator p1, SequenceIterator p2) throws XPathException { return new IntersectionEnumeration(p1, p2, GlobalOrderComparer.getInstance()); } /** * Return the difference of two node-sets * @param p1 The first node-set * @param p2 The second node-set * @return A node-set containing all nodes that are in p1 and not in p2 */ public static SequenceIterator difference(SequenceIterator p1, SequenceIterator p2) throws XPathException { return new DifferenceEnumeration(p1, p2, GlobalOrderComparer.getInstance()); } /** * Determine whether two node-sets contain at least one node in common * @param p1 The first node-set * @param p2 The second node-set * @return true if p1 and p2 contain at least one node in common (i.e. if the intersection * is not empty) */ public static boolean hasSameNode(SequenceIterator p1, SequenceIterator p2) throws XPathException { SequenceIterator intersection = new IntersectionEnumeration(p1, p2, GlobalOrderComparer.getInstance()); return intersection.next() != null; } /** * Find all the nodes in ns1 that are before the first node in ns2. * Return empty set if ns2 is empty, */ public static SequenceIterator leading ( XPathContext context, SequenceIterator ns1, SequenceIterator ns2) throws XPathException { NodeInfo first = null; // Find the first node in ns2 (in document order) GlobalOrderComparer comparer = GlobalOrderComparer.getInstance(); while (true) { Item item = ns2.next(); if (item == null) { if (first == null) { return ns1; } break; } if (item instanceof NodeInfo) { NodeInfo node = (NodeInfo)item; if (first==null) { first = node; } else { if (comparer.compare(node, first) < 0) { first = node; } } } else { XPathException e = new XPathException("Operand of leading() contains an item that is not a node"); e.setXPathContext(context); throw e; } } // Filter ns1 to select nodes that come before this one Expression filter = new IdentityComparison( new ContextItemExpression(), Token.PRECEDES, Literal.makeLiteral(new SingletonNode(first))); return new FilterIterator(ns1, filter, context); } /** * Find all the nodes in ns1 that are after the first node in ns2. * Return empty set if ns2 is empty, */ public static SequenceIterator trailing ( XPathContext c, SequenceIterator ns1, SequenceIterator ns2) throws XPathException { return net.sf.saxon.functions.Extensions.after(c, ns1, ns2); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/exslt/Math.java0000644000175000017500000002440611033112257020300 0ustar eugeneeugenepackage net.sf.saxon.exslt; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.Item; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.*; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.math.BigDecimal; import java.util.ArrayList; /** * This class implements extension functions in the * http://exslt.org/math namespace.

    */ public abstract class Math { /** * Get the maximum numeric value of the string-value of each of a set of nodes */ public static double max (SequenceIterator nsv) throws XPathException { double max = Double.NEGATIVE_INFINITY; try { while (true) { Item it = nsv.next(); if (it == null) break; double x = Value.stringToNumber(it.getStringValueCS()); if (Double.isNaN(x)) return x; if (x>max) max = x; } return max; } catch (NumberFormatException err) { return Double.NaN; } } /** * Get the minimum numeric value of the string-value of each of a set of nodes */ public static double min (SequenceIterator nsv) throws XPathException { try { double min = Double.POSITIVE_INFINITY; while (true) { Item it = nsv.next(); if (it == null) break; double x = Value.stringToNumber(it.getStringValueCS()); if (Double.isNaN(x)) return x; if (xmax) { max = x; highest.clear(); highest.add(it); } } return new SequenceExtent(highest); } catch (NumberFormatException e) { return EmptySequence.getInstance(); } } /** * Get the items with minimum numeric value of the string-value of each of a sequence of items * The items are returned in the order of the original sequence. */ public static Value lowest (SequenceIterator nsv) throws XPathException { try { double min = Double.POSITIVE_INFINITY; ArrayList lowest = new ArrayList(); while (true) { Item it = nsv.next(); if (it == null) break; double x = Value.stringToNumber(it.getStringValueCS()); if (Double.isNaN(x)) return EmptySequence.getInstance(); if (x==min) { lowest.add(it); } else if (xIf e is a non-negative integer, then the result will have the same type as n, except * that a float is always promoted to double.

    * *

    If e is a negative integer, then the result will have the same type as n except that a float * is treated as a double and an integer is treated as a decimal.

    * *

    If e is not an integer (or an xs:decimal representing an integer), * the result will be a double.

    * * @param n the first argument. * @param e the second argument. M * @return the result of n^e * @throws XPathException if an arithmetic overflow is detected. However, there is no guarantee that * overflow will always be detected, it may (especially with double arithmetic) lead to wrong answers * being returned. */ public static NumericValue power(NumericValue n, NumericValue e) throws XPathException { if (n instanceof DoubleValue || n instanceof FloatValue || e instanceof DoubleValue || e instanceof FloatValue || !e.isWholeNumber()) { return new DoubleValue(java.lang.Math.pow(n.getDoubleValue(), e.getDoubleValue())); } else if (e instanceof IntegerValue && n instanceof IntegerValue && e.signum() >= 0) { long le = e.longValue(); if (le > Integer.MAX_VALUE) { throw new XPathException("exponent out of range"); } return IntegerValue.makeIntegerValue(((IntegerValue)n).asBigInteger().pow((int)le)); } else { BigDecimal nd = n.getDecimalValue(); long le = e.longValue(); if (le > Integer.MAX_VALUE || le < Integer.MIN_VALUE) { throw new XPathException("exponent out of range"); } // JDK 1.5 code: return new DecimalValue(nd.pow((int)le)); try { Class bigDecimalClass = nd.getClass(); Method pow = bigDecimalClass.getMethod("pow", new Class[]{int.class}); Integer[] argValues = {new Integer((int)le)}; BigDecimal result = (BigDecimal)pow.invoke(nd, (Object[])argValues); return new DecimalValue(result); } catch (NoSuchMethodException err) { throw new XPathException("power(decimal) not available in JDK 1.4"); } catch (IllegalAccessException err) { throw new XPathException("power(decimal) not available in JDK 1.4"); } catch (InvocationTargetException err) { throw new XPathException("power(decimal) not available in JDK 1.4"); } } } /** * Get a named constant to a given precision (SStL) */ public static double constant (XPathContext context, String name, double precision) throws XPathException { //PI, E, SQRRT2, LN2, LN10, LOG2E, SQRT1_2 String con = ""; if (name.equals("PI")) { con="3.1415926535897932384626433832795028841971693993751"; } else if (name.equals("E")) { con="2.71828182845904523536028747135266249775724709369996"; } else if (name.equals("SQRRT2")) { con="1.41421356237309504880168872420969807856967187537694"; } else if (name.equals("LN2")) { con="0.69314718055994530941723212145817656807550013436025"; } else if (name.equals("LN10")) { con="2.302585092994046"; } else if (name.equals("LOG2E")) { con="1.4426950408889633"; } else if (name.equals("SQRT1_2")) { con="0.7071067811865476"; } else { XPathException e = new XPathException("Unknown math constant " + name); e.setXPathContext(context); throw e; } return Double.parseDouble(con.substring(0, ((int)precision) + 2)); } /** * Get the logarithm of a numeric value (SStL) */ public static double log (double x) { return java.lang.Math.log(x); } /** * Get a random numeric value (SStL) */ public static double random() { return java.lang.Math.random(); } /** * Get the sine of a numeric value (SStL) */ public static double sin (double x) { return java.lang.Math.sin(x); } /** * Get the cosine of a numeric value (SStL) */ public static double cos (double x) { return java.lang.Math.cos(x); } /** * Get the tangent of a numeric value (SStL) */ public static double tan (double x) { return java.lang.Math.tan(x); } /** * Get the arcsine of a numeric value (SStL) */ public static double asin (double x) { return java.lang.Math.asin(x); } /** * Get the arccosine of a numeric value (SStL) */ public static double acos (double x) { return java.lang.Math.acos(x); } /** * Get the arctangent of a numeric value (SStL) */ public static double atan (double x) { return java.lang.Math.atan(x); } /** * Converts rectangular coordinates to polar (SStL) */ public static double atan2 (double x, double y) { return java.lang.Math.atan2(x,y); } /** * Get the exponential of a numeric value (SStL) */ public static double exp (double x) { return java.lang.Math.exp(x); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions marked SStL were provided by Simon St.Laurent [simonstl@simonstl.com]. All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/exslt/Date.java0000644000175000017500000004515111033112257020264 0ustar eugeneeugenepackage net.sf.saxon.exslt; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.trans.XPathException; import java.util.Calendar; import java.util.GregorianCalendar; /** * This class implements extension functions in the * http://exslt.org/dates-and-times namespace.

    */ public final class Date { /** * Private constructor to disallow instantiation */ private Date() {} /** * The date:date-time function returns the current date and time as a date/time string. * The date/time string that's returned must be a string in the format defined as the * lexical representation of xs:dateTime in [3.2.7 dateTime] of [XML Schema Part 2: Datatypes]. * The date/time format is basically CCYY-MM-DDThh:mm:ss+hh:mm. * The date/time string format must include a time zone, either a Z to indicate * Coordinated Universal Time or a + or - followed by the difference between the * difference from UTC represented as hh:mm. * @param context the XPath dynamic context * @return the current date and time as a date/time string */ public static String dateTime(XPathContext context) throws XPathException { return context.getCurrentDateTime().getStringValue(); } /** * The date:date function returns the date specified in the date/time string given as the * argument. * @param dateTime must start with [+|-]CCYY-MM-DD * @return the date portion of the supplied dateTime */ public static String date(String dateTime) { int offset = 0; if (dateTime.length() >= 1 && (dateTime.charAt(0) == '-' || dateTime.charAt(0) == '+')) { offset = 1; } if (dateTime.length() >= offset+10) { return dateTime.substring(0, offset+10); } else { return ""; } } /** * The date:date function returns the current date. * @param context the XPath dynamic context * @return the current date as a string */ public static String date(XPathContext context) throws XPathException { return date(dateTime(context)); } /** * The date:time function returns the time specified in the date/time string given as the * argument. * @param dateTime must start with [+|-]CCYY-MM-DDThh:mm:ss * @return the time part of the string */ public static String time(String dateTime) { int t = dateTime.indexOf('T'); if (t<0 || t==dateTime.length()-1) { return ""; } else { return dateTime.substring(t+1); } } /** * The date:time function returns the current time. * @param context the XPath dynamic context * @return the current time as a string */ public static String time(XPathContext context) throws XPathException { return time(dateTime(context)); } /** * The date:year function returns the year specified in the date/time string given as the * argument. * @param dateTime must begin with CCYY * @return the year part of the supplied date/time */ public static double year(String dateTime) { if (dateTime.startsWith("-")) { return Double.NaN; } try { return (double)Integer.parseInt(dateTime.substring(0, 4)); } catch (Exception err) { return Double.NaN; } } /** * The date:year function returns the current year. * @param context the XPath dynamic context * @return the current year as a double */ public static double year(XPathContext context) throws XPathException { return year(dateTime(context)); } /** * Return true if the year specified in the date/time string * given as the argument is a leap year. * @param dateTime a dateTime as a string * @return true if the year is a leap year */ public static boolean leapYear(String dateTime) { double year = year(dateTime); if (Double.isNaN(year)) { return false; } int y = (int)year; return (y % 4 == 0) && !((y % 100 == 0) && !(y % 400 == 0)); } /** * Returns true if the current year is a leap year * @param context the XPath dynamic context * @return true if the current year is a leap year */ public static boolean leapYear(XPathContext context) throws XPathException { return leapYear(dateTime(context)); } /** * Return the month number from a date. * The date must start with either "CCYY-MM" or "--MM" * @param dateTime a dateTime as a string * @return the month extracted from the dateTime */ public static double monthInYear(String dateTime) { try { if (dateTime.startsWith("--")) { return (double)Integer.parseInt(dateTime.substring(2, 4)); } else { if (dateTime.indexOf('-')!=4) { return Double.NaN; } return (double)Integer.parseInt(dateTime.substring(5, 7)); } } catch (Exception err) { return Double.NaN; } } /** * Return the month number from the current date. * @param context the XPath dynamic context * @return the current month number */ public static double monthInYear(XPathContext context) throws XPathException { return monthInYear(dateTime(context)); } /** * Return the month name from a date. * The date must start with either "CCYY-MM" or "--MM" * @param date the date/time as a string * @return the English month name, for example "January", "February" */ public static String monthName(String date) { String[] months = {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"}; double m = monthInYear(date); if (Double.isNaN(m)) { return ""; } return months[(int)m - 1]; } /** * Return the month name from the current date. * @param context the XPath dynamic context * @return the English month name, for example "January", "February" */ public static String monthName(XPathContext context) throws XPathException { return monthName(dateTime(context)); } /** * Return the month abbreviation from a date. * @param date The date must start with either "CCYY-MM" or "--MM" * @return the English month abbreviation, for example "Jan", "Feb" */ public static String monthAbbreviation(String date) { String[] months = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; double m = monthInYear(date); if (Double.isNaN(m)) { return ""; } return months[(int)m - 1]; } /** * Return the month abbreviation from the current date. * @param context the XPath dynamic context * @return the English month abbreviation, for example "Jan", "Feb" */ public static String monthAbbreviation(XPathContext context) throws XPathException { return monthAbbreviation(dateTime(context)); } /** * Return the ISO week number of a specified date within the year * (Note, this returns the ISO week number: the result in EXSLT is underspecified) * @param dateTime the current date starting CCYY-MM-DD * @return the ISO week number */ public static double weekInYear(String dateTime) { int dayInYear = (int)dayInYear(dateTime); String firstJan = dateTime.substring(0,4) + "-01-01"; int jan1day = ((int)dayInWeek(firstJan) + 5) % 7; int daysInFirstWeek = (jan1day==0 ? 0 : 7 - jan1day); int rawWeek = (dayInYear - daysInFirstWeek + 6) / 7; if (daysInFirstWeek >= 4) { return rawWeek + 1; } else { if (rawWeek>0) { return rawWeek; } else { // week number should be 52 or 53: same as 31 Dec in previous year int lastYear = Integer.parseInt(dateTime.substring(0,4)) - 1; String dec31 = lastYear + "-12-31"; // assumes year > 999 return weekInYear(dec31); } } } /** * Return the ISO week number of the current date * @param context the XPath dynamic context * (Note, this returns the ISO week number: the result in EXSLT is underspecified) * @return the ISO week number */ public static double weekInYear(XPathContext context) throws XPathException { return weekInYear(dateTime(context)); } /** * Return the week number of a specified date within the month * (Note, this function is underspecified in EXSLT) * @param dateTime the date starting CCYY-MM-DD * @return the week number within the month */ public static double weekInMonth(String dateTime) { return (double)(int)((dayInMonth(dateTime)-1) / 7 + 1); } /** * Return the ISO week number of the current date within the month * @param context the XPath dynamic context * @return the week number within the month */ public static double weekInMonth(XPathContext context) throws XPathException { return weekInMonth(dateTime(context)); } /** * Return the day number of a specified date within the year * @param dateTime the date starting with CCYY-MM-DD * @return the day number within the year, as a double */ public static double dayInYear(String dateTime) { int month=(int)monthInYear(dateTime); int day = (int)dayInMonth(dateTime); int[] prev = { 0, 31, 31+28, 31+28+31, 31+28+31+30, 31+28+31+30+31, 31+28+31+30+31+30, 31+28+31+30+31+30+31, 31+28+31+30+31+30+31+31, 31+28+31+30+31+30+31+31+30, 31+28+31+30+31+30+31+31+30+31, 31+28+31+30+31+30+31+31+30+31+30, 31+28+31+30+31+30+31+31+30+31+30+31 }; int leap = (month>2 && leapYear(dateTime) ? 1 : 0); return prev[month-1] + leap + day; } /** * Return the day number of the current date within the year * @param context the XPath dynamic context * @return the day number within the year, as a double */ public static double dayInYear(XPathContext context) throws XPathException { return dayInYear(dateTime(context)); } /** * Return the day number of a specified date within the month * @param dateTime must start with CCYY-MM-DD, or --MM-DD, or ---DD * @return the day number within the month, as a double */ public static double dayInMonth(String dateTime) { try { if (dateTime.startsWith("---")) { return (double)Integer.parseInt(dateTime.substring(3,5)); } else if (dateTime.startsWith("--")) { return (double)Integer.parseInt(dateTime.substring(5,7)); } else { return (double)Integer.parseInt(dateTime.substring(8,10)); } } catch (Exception err) { return Double.NaN; } } /** * Return the day number of the current date within the month * @param context the XPath dynamic context * @return the current day number, as a double */ public static double dayInMonth(XPathContext context) throws XPathException { return dayInMonth(dateTime(context)); } /** * Return the day-of-the-week in a month of a date as a number * (for example 3 for the 3rd Tuesday in May). * @param dateTime must start with CCYY-MM-DD * @return the the day-of-the-week in a month of a date as a number * (for example 3 for the 3rd Tuesday in May). */ public static double dayOfWeekInMonth(String dateTime) { double dd = dayInMonth(dateTime); if (Double.isNaN(dd)) { return dd; } return (((int)dd) - 1) / 7 + 1; } /** * Return the day-of-the-week in a month of the current date as a number * (for example 3 for the 3rd Tuesday in May). * @param context the XPath dynamic context * @return the the day-of-the-week in a month of the current date as a number * (for example 3 for the 3rd Tuesday in May). */ public static double dayOfWeekInMonth(XPathContext context) throws XPathException { return dayOfWeekInMonth(dateTime(context)); } /** * Return the day of the week given in a date as a number. * The numbering of days of the week starts at 1 for Sunday, 2 for Monday * and so on up to 7 for Saturday. * @param dateTime must start with CCYY-MM-DD * @return the day of the week as a number */ public static double dayInWeek(String dateTime) { double yy = year(dateTime); double mm = monthInYear(dateTime); double dd = dayInMonth(dateTime); if (Double.isNaN(yy) || Double.isNaN(mm) || Double.isNaN(dd)) { return Double.NaN; } GregorianCalendar calDate = new GregorianCalendar( (int)yy, (int)mm-1, (int)dd); calDate.setFirstDayOfWeek(Calendar.SUNDAY); return calDate.get(Calendar.DAY_OF_WEEK); } /** * Return the day of the week in the current date as a number. * The numbering of days of the week starts at 1 for Sunday, 2 for Monday * and so on up to 7 for Saturday. * @param context the XPath dynamic context * @return the day of the week as a number */ public static double dayInWeek(XPathContext context) throws XPathException { return dayInWeek(dateTime(context)); } /** * Return the day of the week given in a date as an English day name: * one of 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday' or 'Friday'. * @param dateTime must start with CCYY-MM-DD * @return the English name of the day of the week */ public static String dayName(String dateTime) { String[] days = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" }; double d = dayInWeek(dateTime); if (Double.isNaN(d)) { return ""; } return days[(int)d - 1]; } /** * Return the day of the week given in the current date as an English day name: * one of 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday' or 'Friday'. * @param context the XPath dynamic context * @return the English name of the day of the week */ public static String dayName(XPathContext context) throws XPathException { return dayName(dateTime(context)); } /** * Return the day of the week given in a date as an English day abbreviation: * one of 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', or 'Sat'. * @param dateTime must start with CCYY-MM-DD * @return the English day abbreviation */ public static String dayAbbreviation(String dateTime) { String[] days = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; double d = dayInWeek(dateTime); if (Double.isNaN(d)) { return ""; } return days[(int)d - 1]; } /** * Return the day of the week given in the current date as an English day abbreviation: * one of 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', or 'Sat'. * @param context the XPath dynamic context * @return the English day abbreviation */ public static String dayAbbreviation(XPathContext context) throws XPathException { return dayAbbreviation(dateTime(context)); } /** * Return the hour of the day in the specified date or date/time * @param dateTime must start with CCYY-MM-DDThh:mm:ss or hh:mm:ss * @return the hour */ public static double hourInDay(String dateTime) { int t = dateTime.indexOf('T'); try { int hh = Integer.parseInt(dateTime.substring(t+1, t+3)); return (double)hh; } catch (Exception err) { return Double.NaN; } } /** * Return the current hour of the day * @param context the XPath dynamic context * @return the hour */ public static double hourInDay(XPathContext context) throws XPathException { return hourInDay(dateTime(context)); } /** * Return the minute of the hour in the specified date or date/time * @param dateTime must start with CCYY-MM-DDThh:mm:ss or hh:mm:ss * @return the minute */ public static double minuteInHour(String dateTime) { int t = dateTime.indexOf('T'); try { int mm = Integer.parseInt(dateTime.substring(t+4, t+6)); return (double)mm; } catch (Exception err) { return Double.NaN; } } /** * Return the current minute of the hour * @param context the XPath dynamic context * @return the minute */ public static double minuteInHour(XPathContext context) throws XPathException { return minuteInHour(dateTime(context)); } /** * Return the second of the minute in the specified date or date/time * @param dateTime must start with CCYY-MM-DDThh:mm:ss or hh:mm:ss * @return the second */ public static double secondInMinute(String dateTime) { int t = dateTime.indexOf('T'); try { int ss = Integer.parseInt(dateTime.substring(t+7, t+9)); return (double)ss; } catch (Exception err) { return Double.NaN; } } /** * Return the current second of the minute * @param context the XPath dynamic context * @return the second */ public static double secondInMinute(XPathContext context) throws XPathException { return secondInMinute(dateTime(context)); } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/exslt/Common.java0000644000175000017500000000451011033112257020631 0ustar eugeneeugenepackage net.sf.saxon.exslt; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.pattern.AnyNodeTest; import net.sf.saxon.type.BuiltInAtomicType; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.TypeHierarchy; import net.sf.saxon.value.Value; import net.sf.saxon.om.ValueRepresentation; /** * This class implements extension functions in the * http://exslt.org/common namespace.

    */ public abstract class Common { /** * Class is not instantiated */ private Common() { } /** * Convert a result tree fragment to a node-set. This is a hangover from XSLT 1.0; * it is implemented as a no-op. */ public static ValueRepresentation nodeSet(ValueRepresentation frag) { return frag; } /** * Return the type of the supplied value: "sequence", "string", "number", "boolean", * "external". (EXSLT spec not yet modified to cater for XPath 2.0 data model) */ public static String objectType(XPathContext context, ValueRepresentation value) { final TypeHierarchy th = context.getConfiguration().getTypeHierarchy(); ItemType type = Value.asValue(value).getItemType(th); if (th.isSubType(type, AnyNodeTest.getInstance())) { return "node-set"; } else if (th.isSubType(type, BuiltInAtomicType.STRING)) { return "string"; } else if (th.isSubType(type, BuiltInAtomicType.NUMERIC)) { return "number"; } else if (th.isSubType(type, BuiltInAtomicType.BOOLEAN)) { return "boolean"; } else { return type.toString(context.getNamePool()); } } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/exslt/package.html0000644000175000017500000000103711033112257021020 0ustar eugeneeugene Package overview for net.sf.saxon.exslt

    This package provides implementations of the functions defined in EXSLT.

    The implementation of EXSLT functions is by no means complete (the specifications are continually evolving), but the major functions are provided - even where they are effectively superseded by functions available in XPath 2.0.


    Michael H. Kay
    25 April 2002

    saxonb-9.1.0.8/bj/net/sf/saxon/Filter.java0000644000175000017500000003772111033112257017501 0ustar eugeneeugenepackage net.sf.saxon; import net.sf.saxon.event.ContentHandlerProxy; import org.xml.sax.*; import org.xml.sax.ext.LexicalHandler; import javax.xml.parsers.SAXParserFactory; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerException; import javax.xml.transform.sax.SAXSource; import java.io.IOException; /** * Filter is an XMLFilter (a SAX2 filter) that performs a transformation * taking a SAX stream as input and producing a SAX stream as output. * @author Michael H. Kay */ public class Filter implements XMLFilter { private Controller controller; private XMLReader parser; private ContentHandler contentHandler; // destination for output of this filter private LexicalHandler lexicalHandler; // destination for output of this filter /** * Create a Filter and initialise variables. The constructor is protected, because * the Filter should be created using newXMLFilter() in the SAXTransformerFactory * class */ protected Filter(Controller controller) { this.controller = controller; } ////////////////////////////////////////////////////////////////// // Implement XMLFilter interface methods ////////////////////////////////////////////////////////////////// /** * Set the parent reader. * *

    This method allows the application to link the filter to * a parent reader (which may be another filter). The argument * may not be null.

    * * @param parent The parent reader (the supplier of SAX events). */ public void setParent (XMLReader parent) { parser = parent; } /** * Get the parent reader. * *

    This method allows the application to query the parent * reader (which may be another filter). It is generally a * bad idea to perform any operations on the parent reader * directly: they should all pass through this filter.

    * * @return The parent filter, or null if none has been set. */ public XMLReader getParent() { return parser; } /////////////////////////////////////////////////////////////////// // implement XMLReader interface methods /////////////////////////////////////////////////////////////////// /** * Look up the value of a feature. * *

    The feature name is any fully-qualified URI. It is * possible for an XMLReader to recognize a feature name but * to be unable to return its value; this is especially true * in the case of an adapter for a SAX1 Parser, which has * no way of knowing whether the underlying parser is * performing validation or expanding external entities.

    * *

    All XMLReaders are required to recognize the * http://xml.org/sax/features/namespaces and the * http://xml.org/sax/features/namespace-prefixes feature names.

    * * @param name The feature name, which is a fully-qualified URI. * @return The current state of the feature (true or false). * @exception org.xml.sax.SAXNotRecognizedException When the * XMLReader does not recognize the feature name. * @exception org.xml.sax.SAXNotSupportedException When the * XMLReader recognizes the feature name but * cannot determine its value at this time. * @see #setFeature */ public boolean getFeature (String name) throws SAXNotRecognizedException, SAXNotSupportedException { if (name.equals("http://xml.org/sax/features/namespaces")) { return true; } else if (name.equals("http://xml.org/sax/features/namespace-prefixes")) { return false; } else { throw new SAXNotRecognizedException(name); } } /** * Set the state of a feature. * *

    The feature name is any fully-qualified URI. It is * possible for an XMLReader to recognize a feature name but * to be unable to set its value

    * *

    All XMLReaders are required to support setting * http://xml.org/sax/features/namespaces to true and * http://xml.org/sax/features/namespace-prefixes to false.

    * *

    Some feature values may be immutable or mutable only * in specific contexts, such as before, during, or after * a parse.

    * * @param name The feature name, which is a fully-qualified URI. * @param value The requested state of the feature (true or false). * @exception org.xml.sax.SAXNotRecognizedException When the * XMLReader does not recognize the feature name. * @exception org.xml.sax.SAXNotSupportedException When the * XMLReader recognizes the feature name but * cannot set the requested value. * @see #getFeature */ public void setFeature (String name, boolean value) throws SAXNotRecognizedException, SAXNotSupportedException { if (name.equals("http://xml.org/sax/features/namespaces")) { if (!value) { throw new SAXNotSupportedException(name); } } else if (name.equals("http://xml.org/sax/features/namespace-prefixes")) { if (value) { throw new SAXNotSupportedException(name); } } else { throw new SAXNotRecognizedException(name); } } /** * Look up the value of a property. * *

    The property name is any fully-qualified URI. It is * possible for an XMLReader to recognize a property name but * to be unable to return its state.

    * *

    XMLReaders are not required to recognize any specific * property names, though an initial core set is documented for * SAX2.

    * *

    Some property values may be available only in specific * contexts, such as before, during, or after a parse.

    * *

    Implementors are free (and encouraged) to invent their own properties, * using names built on their own URIs.

    * * @param name The property name, which is a fully-qualified URI. * @return The current value of the property. * @exception org.xml.sax.SAXNotRecognizedException When the * XMLReader does not recognize the property name. * @exception org.xml.sax.SAXNotSupportedException When the * XMLReader recognizes the property name but * cannot determine its value at this time. * @see #setProperty */ public Object getProperty (String name) throws SAXNotRecognizedException, SAXNotSupportedException { if (name.equals("http://xml.org/sax/properties/lexical-handler")) { return lexicalHandler; } else { throw new SAXNotRecognizedException(name); } } /** * Set the value of a property. * *

    The property name is any fully-qualified URI. It is * possible for an XMLReader to recognize a property name but * to be unable to set its value.

    * *

    XMLReaders are not required to recognize setting * any specific property names, though a core set is provided with * SAX2.

    * *

    Some property values may be immutable or mutable only * in specific contexts, such as before, during, or after * a parse.

    * *

    This method is also the standard mechanism for setting * extended handlers.

    * * @param name The property name, which is a fully-qualified URI. * @param value The requested value for the property. * @exception org.xml.sax.SAXNotRecognizedException When the * XMLReader does not recognize the property name. * @exception org.xml.sax.SAXNotSupportedException When the * XMLReader recognizes the property name but * cannot set the requested value. */ public void setProperty (String name, Object value) throws SAXNotRecognizedException, SAXNotSupportedException { if (name.equals("http://xml.org/sax/properties/lexical-handler")) { if (value instanceof LexicalHandler) { lexicalHandler = (LexicalHandler)value; } else { throw new SAXNotSupportedException( "Lexical Handler must be instance of org.xml.sax.ext.LexicalHandler"); } } else { throw new SAXNotRecognizedException(name); } } /** * Register a content handler to receive the output of the transformation * filter. If the content handler is also a LexicalHandler, and if no LexicalHandler * is separately registered, the ContentHandler will also act as the LexicalHandler */ public void setContentHandler(ContentHandler handler) { contentHandler = handler; if (handler instanceof LexicalHandler && lexicalHandler==null) { lexicalHandler = (LexicalHandler)handler; } } /** * Get the ContentHandler registered using setContentHandler() */ public ContentHandler getContentHandler() { return contentHandler; } /** * Allow an application to register an entity resolver. * *

    If the application does not register an entity resolver, * the XMLReader will perform its own default resolution.

    * *

    Applications may register a new or different resolver in the * middle of a parse, and the SAX parser must begin using the new * resolver immediately.

    * * @param resolver The entity resolver. * @exception java.lang.NullPointerException If the resolver * argument is null. * @see #getEntityResolver */ public void setEntityResolver (EntityResolver resolver) { // XSLT output does not use entities, so the resolver is never used } /** * Return the current entity resolver. * * @return Always null, since no entity resolver is used even if one * is supplied. * @see #setEntityResolver */ public EntityResolver getEntityResolver () { return null; } /** * Allow an application to register a DTD event handler. * *

    If the application does not register a DTD handler, all DTD * events reported by the SAX parser will be silently ignored.

    * *

    Applications may register a new or different handler in the * middle of a parse, and the SAX parser must begin using the new * handler immediately.

    * * @param handler The DTD handler. * @exception java.lang.NullPointerException If the handler * argument is null. * @see #getDTDHandler */ public void setDTDHandler (DTDHandler handler) { // XSLT output does not include a DTD } /** * Return the current DTD handler. * * @return Always null, since no DTD handler is used even if one has been * supplied. * @see #setDTDHandler */ public DTDHandler getDTDHandler () { return null; } /** * Allow an application to register an error event handler. * *

    If the application does not register an error handler, all * error events reported by the SAX parser will be silently * ignored; however, normal processing may not continue. It is * highly recommended that all SAX applications implement an * error handler to avoid unexpected bugs.

    * *

    Applications may register a new or different handler in the * middle of a parse, and the SAX parser must begin using the new * handler immediately.

    * * @param handler The error handler. * @exception java.lang.NullPointerException If the handler * argument is null. * @see #getErrorHandler */ public void setErrorHandler (ErrorHandler handler) { // No effect } /** * Return the current error handler. * * @return The current error handler, or null if none * has been registered. * @see #setErrorHandler */ public ErrorHandler getErrorHandler () { return null; } /** * Parse an XML document - In the context of a Transformer, this means * perform a transformation. The method is equivalent to transform(). * * @param input The input source (the XML document to be transformed) * @exception org.xml.sax.SAXException Any SAX exception, possibly * wrapping another exception. * @exception java.io.IOException An IO exception from the parser, * possibly from a byte stream or character stream * supplied by the application. * @see org.xml.sax.InputSource * @see #parse(java.lang.String) * @see #setEntityResolver * @see #setDTDHandler * @see #setContentHandler * @see #setErrorHandler */ public void parse (InputSource input) throws IOException, SAXException { if (parser==null) { try { parser = SAXParserFactory.newInstance().newSAXParser().getXMLReader(); } catch (Exception err) { throw new SAXException(err); } } SAXSource source = new SAXSource(); source.setInputSource(input); source.setXMLReader(parser); ContentHandlerProxy result = new ContentHandlerProxy(); result.setPipelineConfiguration(controller.makePipelineConfiguration()); result.setUnderlyingContentHandler(contentHandler); if (lexicalHandler!=null) { result.setLexicalHandler(lexicalHandler); } try { //result.open(); result.setOutputProperties(controller.getOutputProperties()); controller.transform(source, result); } catch (TransformerException err) { Throwable cause = err.getException(); if (cause != null && cause instanceof SAXException) { throw (SAXException)cause; } else if (cause != null && cause instanceof IOException) { throw (IOException)cause; } else { throw new SAXException(err); } } } /** * Parse (that is, transform) an XML document given a system identifier (URI). * *

    This method is a shortcut for the common case of reading a * document from a system identifier. It is the exact * equivalent of the following:

    * *
         * parse(new InputSource(systemId));
         * 
    * *

    If the system identifier is a URL, it must be fully resolved * by the application before it is passed to the parser.

    * * @param systemId The system identifier (URI). * @exception org.xml.sax.SAXException Any SAX exception, possibly * wrapping another exception. * @exception java.io.IOException An IO exception from the parser, * possibly from a byte stream or character stream * supplied by the application. * @see #parse(org.xml.sax.InputSource) */ public void parse (String systemId) throws IOException, SAXException { InputSource input = new InputSource(systemId); parse(input); } /** * Get the underlying Transformer. This is a Saxon-specific method that allows the * user to set parameters on the transformation, set a URIResolver or ErrorListener, etc. * New in Saxon 7.2 */ public Transformer getTransformer() { return controller; } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): None // saxonb-9.1.0.8/bj/net/sf/saxon/NonDelegatingURIResolver.java0000644000175000017500000000246111033112257023065 0ustar eugeneeugenepackage net.sf.saxon; import javax.xml.transform.URIResolver; /** * This is a marker interface: if a URIResolver implements this interface and returns null from * its resolve() method, then the standard URI resolver will not be invoked. *

    * The main use case for this is to support protocols that the standard Java java.net.URL class * does not recognize. In the case of doc-available(), we want to return false, rather than throwing * an exception in such cases. */ public interface NonDelegatingURIResolver extends URIResolver { // marker interface only } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. //saxonb-9.1.0.8/bj/net/sf/saxon/ant/0000755000175000017500000000000012216261746016175 5ustar eugeneeugenesaxonb-9.1.0.8/bj/net/sf/saxon/ant/AntTransform.java0000644000175000017500000011545011033112257021450 0ustar eugeneeugene/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ // The NOTICE file referred to above is reproduced at the bottom of this file. package net.sf.saxon.ant; import net.sf.saxon.Configuration; import net.sf.saxon.Controller; import net.sf.saxon.PreparedStylesheet; import net.sf.saxon.Version; import net.sf.saxon.trace.XSLTTraceListener; import net.sf.saxon.om.Validation; import net.sf.saxon.trans.CompilerInfo; import org.apache.tools.ant.AntClassLoader; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.DirectoryScanner; import org.apache.tools.ant.Project; import org.apache.tools.ant.taskdefs.MatchingTask; import org.apache.tools.ant.taskdefs.XSLTLogger; import org.apache.tools.ant.types.*; import org.apache.tools.ant.types.resources.FileResource; import org.apache.tools.ant.types.resources.Resources; import org.apache.tools.ant.types.resources.Union; import org.apache.tools.ant.util.FileNameMapper; import org.apache.tools.ant.util.FileUtils; import javax.xml.transform.Result; import javax.xml.transform.Source; import javax.xml.transform.TransformerException; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; import java.io.File; import java.util.Enumeration; import java.util.Iterator; import java.util.Vector; /** * Processes a set of XML documents via XSLT. This is * useful for building views of XML based documentation. * * This task for running Saxon transformations within Ant is modelled on the * standard Ant xslt task (org.apache.tools.ant.taskdefs.XSLTProcess), and makes heavy reuse of its code. * See Apache notice above. * */ public class AntTransform extends MatchingTask implements XSLTLogger { /** destination directory */ private File destDir = null; /** where to find the source XML file, default is the project's basedir */ private File baseDir = null; /** XSL stylesheet as a filename */ private String xslFile = null; /** XSL stylesheet as a {@link org.apache.tools.ant.types.Resource} */ private Resource xslResource = null; /** extension of the files produced by XSL processing */ private String targetExtension = ".html"; /** name for XSL parameter containing the filename */ private String fileNameParameter = null; /** name for XSL parameter containing the file directory */ private String fileDirParameter = null; /** additional parameters to be passed to the stylesheets */ private Vector params = new Vector(); /** Input XML document to be used */ private File inFile = null; /** Output file */ private File outFile = null; /** Whether schema-aware processing is required */ private boolean schemaAware; /** Classpath to use when trying to load the XSL processor */ private Path classpath = null; /** Flag which indicates if the stylesheet has been loaded into * the processor */ private boolean stylesheetLoaded = false; /** force output of target files even if they already exist */ private boolean force = false; /** XSL output properties to be used */ private Vector outputProperties = new Vector(); /** for resolving entities such as dtds */ private XMLCatalog xmlCatalog = new XMLCatalog(); /** Utilities used for file operations */ private static final FileUtils FILE_UTILS = FileUtils.getFileUtils(); /** * Whether to style all files in the included directories as well. * * @since Ant 1.5 */ private boolean performDirectoryScan = true; /** * Saxon configuration object */ private Configuration config; /** * whether to reuse Transformer if transforming multiple files. * @since 1.5.2 */ private boolean reuseLoadedStylesheet = true; /** * AntClassLoader for the nested <classpath> - if set. * *

    We keep this here in order to reset the context classloader * in execute. We can't use liaison.getClass().getClassLoader() * since the actual liaison class may have been loaded by a loader * higher up (system classloader, for example).

    * * @since Ant 1.6.2 */ private AntClassLoader loader = null; /** * Mapper to use when a set of files gets processed. * * @since Ant 1.6.2 */ private Mapper mapperElement = null; /** * Additional resource collections to process. * * @since Ant 1.7 */ private Union resources = new Union(); /** * Whether to use the implicit fileset. * * @since Ant 1.7 */ private boolean useImplicitFileset = true; /** * The XSLT transformer */ private Controller transformer = null; /** * Whether schema validation is strict, lax, or skip */ private String schemaValidation = "skip"; /** * Whether DTD validation is on or off. Default is off. */ private boolean dtdValidation = false; /** * Whether attribute defaults should be expanded */ private boolean expandAttributeDefaults = true; /** * Whether extension functions are permitted or not. Default is true. */ private boolean allowExtensions = true; /** * Initial mode name */ private String initialMode; /** * Initial template name */ private String initialTemplate; /** * Whether lineNumbering of the source document is switched on. Default is off. */ private boolean lineNumbering; /** * Trace stylesheet execution. Default is off. */ private boolean tracing; /** * Policy for handling XSLT recoverable errors: silent|recover|fatal */ private String recoveryPolicy; /** * Whether to use XML 1.0 or XML 1.1 rules for names, etc */ private String xmlVersion = "1.0"; /** * Create a new saxon-xslt Task. */ public AntTransform() { } /** * Set whether to style all files in the included directories as well; * optional, default is true. * * @param b true if files in included directories are processed. * @since Ant 1.5 */ public void setScanIncludedDirectories(boolean b) { performDirectoryScan = b; } /** * Controls whether the stylesheet is reloaded for every transform. * *

    Setting this to true may get around a bug in certain * Xalan-J versions, default is false.

    * @param b a boolean value * @since Ant 1.5.2 */ public void setReloadStylesheet(boolean b) { reuseLoadedStylesheet = !b; } /** * Defines the mapper to map source to destination files. * @param mapper the mapper to use * @exception BuildException if more than one mapper is defined * @since Ant 1.6.2 */ public void addMapper(Mapper mapper) { if (mapperElement != null) { throw new BuildException("Cannot define more than one mapper", getLocation()); } mapperElement = mapper; } /** * Adds a collection of resources to style in addition to the * given file or the implicit fileset. * * @param rc the collection of resources to style * @since Ant 1.7 */ public void add(ResourceCollection rc) { resources.add(rc); } /** * Add a nested <style> element. * @param rc the configured Resources object represented as <style>. * @since Ant 1.7 */ public void addConfiguredStyle(Resources rc) { if (rc.size() != 1) { throw new BuildException("The style element must be specified" + " with exactly one nested resource."); } setXslResource((Resource) rc.iterator().next()); } /** * API method to set the XSL Resource. * @param xslResource Resource to set as the stylesheet. * @since Ant 1.7 */ public void setXslResource(Resource xslResource) { this.xslResource = xslResource; } /** * Adds a nested filenamemapper. * @param fileNameMapper the mapper to add * @exception BuildException if more than one mapper is defined * @since Ant 1.7.0 */ public void add(FileNameMapper fileNameMapper) throws BuildException { Mapper mapper = new Mapper(getProject()); mapper.add(fileNameMapper); addMapper(mapper); } /** * Executes the task. * * @exception BuildException if there is an execution problem. */ public void execute() throws BuildException { log("AntTransform.execute() schema-aware=" + schemaAware + " version " + Version.getProductVersion()); if (schemaAware) { // remove this line to compile the code for use under Saxon-B only config = Configuration.makeSchemaAwareConfiguration(null, null); config.displayLicenseMessage(); } else { config = new Configuration(); } config.setAllowExternalFunctions(allowExtensions); config.setExpandAttributeDefaults(expandAttributeDefaults); config.setLineNumbering(lineNumbering); config.setValidation(dtdValidation); config.setCompileWithTracing(tracing); config.setXMLVersion("1.1".equals(xmlVersion) ? Configuration.XML11 : Configuration.XML10); if ("skip".equals(schemaValidation)) { config.setSchemaValidationMode(Validation.SKIP); } else if ("strict".equals(schemaValidation)) { config.setSchemaValidationMode(Validation.STRICT); } else if ("lax".equals(schemaValidation)) { config.setSchemaValidationMode(Validation.LAX); } else { throw new BuildException("Validation must be strict or lax or skip"); } File savedBaseDir = baseDir; DirectoryScanner scanner; String[] list; String[] dirs; if (xslResource == null && xslFile == null) { throw new BuildException("specify the " + "stylesheet either as a filename in style " + "attribute or as a nested resource", getLocation()); } if (xslResource != null && xslFile != null) { throw new BuildException("specify the " + "stylesheet either as a filename in style " + "attribute or as a nested resource but not " + "as both", getLocation()); } if (inFile != null && !inFile.exists()) { throw new BuildException( "input file " + inFile.toString() + " does not exist", getLocation()); } try { if (baseDir == null) { baseDir = getProject().resolveFile("."); } if (xslFile != null) { // If we enter here, it means that the stylesheet is supplied // via style attribute File stylesheet = getProject().resolveFile(xslFile); if (!stylesheet.exists()) { stylesheet = FILE_UTILS.resolveFile(baseDir, xslFile); /* * shouldn't throw out deprecation warnings before we know, * the wrong version has been used. */ if (stylesheet.exists()) { log("DEPRECATED - the 'style' attribute should be relative " + "to the project's"); log(" basedir, not the tasks's basedir."); } } FileResource fr = new FileResource(); fr.setProject(getProject()); fr.setFile(stylesheet); xslResource = fr; } // if we have an in file and out then process them if (inFile != null && outFile != null) { process(inFile, outFile, xslResource); return; } /* * if we get here, in and out have not been specified, we are * in batch processing mode. */ //-- make sure destination directory exists... checkDest(); if (useImplicitFileset) { scanner = getDirectoryScanner(baseDir); log("Transforming into " + destDir, Project.MSG_INFO); // Process all the files marked for styling list = scanner.getIncludedFiles(); for (int i = 0; i < list.length; ++i) { process(baseDir, list[i], destDir, xslResource); } if (performDirectoryScan) { // Process all the directories marked for styling dirs = scanner.getIncludedDirectories(); for (int j = 0; j < dirs.length; ++j) { list = new File(baseDir, dirs[j]).list(); for (int i = 0; i < list.length; ++i) { process(baseDir, dirs[j] + File.separator + list[i], destDir, xslResource); } } } } else { // only resource collections, there better be some if (resources.size() == 0) { throw new BuildException("no resources specified"); } } processResources(xslResource); } finally { if (loader != null) { loader.resetThreadContextLoader(); loader.cleanup(); loader = null; } stylesheetLoaded = false; baseDir = savedBaseDir; } } /** * Set whether to check dependencies, or always generate; * optional, default is false. * * @param force true if always generate. */ public void setForce(boolean force) { this.force = force; } /** * Set the base directory; * optional, default is the project's basedir. * * @param dir the base directory **/ public void setBasedir(File dir) { baseDir = dir; } /** * Set the destination directory into which the XSL result * files should be copied to; * required, unless in and out are * specified. * @param dir the name of the destination directory **/ public void setDestdir(File dir) { destDir = dir; } /** * Set the desired file extension to be used for the target; * optional, default is html. * @param name the extension to use **/ public void setExtension(String name) { targetExtension = name; } /** * Name of the stylesheet to use - given either relative * to the project's basedir or as an absolute path; required. * * @param xslFile the stylesheet to use */ public void setStyle(String xslFile) { this.xslFile = xslFile; } /** * Set the optional classpath to the XSL processor * * @param classpath the classpath to use when loading the XSL processor */ public void setClasspath(Path classpath) { createClasspath().append(classpath); } /** * Set the optional classpath to the XSL processor * * @return a path instance to be configured by the Ant core. */ public Path createClasspath() { if (classpath == null) { classpath = new Path(getProject()); } return classpath.createPath(); } /** * Set the reference to an optional classpath to the XSL processor * * @param r the id of the Ant path instance to act as the classpath * for loading the XSL processor */ public void setClasspathRef(Reference r) { createClasspath().setRefid(r); } /** * Indicate whether schema-aware processing is required * * @param schemaAware true if schema-aware processing is required */ public void setSchemaAware(boolean schemaAware) { //log("setSchemaAware = " + schemaAware); this.schemaAware = schemaAware; } /** * Indicate whether schema validation for all input files to the transformation is strict, lax, or skip * @param validation "strict", "lax" or "skip" */ public void setSchemaValidation(String validation) { //log("setValidation = " + validation); this.schemaValidation = validation; if (!validation.equals("skip")) { setSchemaAware(true); } } /** * Indicate whether DTD validation is on or off * @param validation set to true to request DTD validation of all input files to the transformation */ public void setDTDValidation(boolean validation) { dtdValidation = validation; } /** * Set whether DTD or schema-defined element and attribute default values should be expanded * Default is true * @param expand true to expand default values, false if they are to be suppressed */ public void setExpandDefaults(boolean expand) { expandAttributeDefaults = expand; } /** * Set the initial mode * @param mode the initial mode for the transformation, in Clark notation */ public void setInitialMode(String mode) { initialMode = mode; } /** * Set the initial template * @param name the name of the initial template for the transformation, in Clark notation */ public void setInitialTemplate(String name) { initialTemplate = name; } /** * Set the policy for handling recoverable errors * @param policy one of "silent", "recover", or "fatal". Default is "recover". */ public void setRecoveryPolicy(String policy) { recoveryPolicy = policy; } /** * Set whether to trace stylesheet execution * @param tracing true to trace execution. Default is false */ public void setTracing(boolean tracing) { this.tracing = tracing; } /** * Set whether to maintain line numbers for input documents * @param numbering true to maintain line numbers. Default is false */ public void setLineNumbering(boolean numbering) { lineNumbering = numbering; } /** * Set the XML version to be used for validating names * @param version One of "1.0" or "1.1". Default is "1.0". */ public void setXmlVersion(String version) { xmlVersion = version; } /** * Set whether to use the implicit fileset. * *

    Set this to false if you want explicit control with nested * resource collections.

    * @param useimplicitfileset set to true if you want to use implicit fileset * @since Ant 1.7 */ public void setUseImplicitFileset(boolean useimplicitfileset) { useImplicitFileset = useimplicitfileset; } /** * Add the catalog to our internal catalog * * @param xmlCatalog the XMLCatalog instance to use to look up DTDs */ public void addConfiguredXMLCatalog(XMLCatalog xmlCatalog) { this.xmlCatalog.addConfiguredXMLCatalog(xmlCatalog); } /** * Pass the filename of the current processed file as a xsl parameter * to the transformation. This value sets the name of that xsl parameter. * * @param fileNameParameter name of the xsl parameter retrieving the * current file name */ public void setFileNameParameter(String fileNameParameter) { this.fileNameParameter = fileNameParameter; } /** * Pass the directory name of the current processed file as a xsl parameter * to the transformation. This value sets the name of that xsl parameter. * * @param fileDirParameter name of the xsl parameter retrieving the * current file directory */ public void setFileDirParameter(String fileDirParameter) { this.fileDirParameter = fileDirParameter; } /** * Specifies the output name for the styled result from the * in attribute; required if in is set * * @param outFile the output File instance. */ public void setOut(File outFile) { this.outFile = outFile; } /** * specifies a single XML document to be styled. Should be used * with the out attribute; ; required if out is set * * @param inFile the input file */ public void setIn(File inFile) { this.inFile = inFile; } /** * Throws a BuildException if the destination directory hasn't * been specified. * @since Ant 1.7 */ private void checkDest() { if (destDir == null) { String msg = "destdir attributes must be set!"; throw new BuildException(msg); } } /** * Styles all existing resources. * * @since Ant 1.7 */ private void processResources(Resource stylesheet) { Iterator iter = resources.iterator(); while (iter.hasNext()) { Resource r = (Resource) iter.next(); if (!r.isExists()) { continue; } File base = baseDir; String name = r.getName(); if (r instanceof FileResource) { FileResource f = (FileResource) r; base = f.getBaseDir(); if (base == null) { name = f.getFile().getAbsolutePath(); } } process(base, name, destDir, stylesheet); } } /** * Processes the given input XML file and stores the result * in the given resultFile. * * @param baseDir the base directory for resolving files. * @param xmlFile the input file * @param destDir the destination directory * @param stylesheet the stylesheet to use. * @exception BuildException if the processing fails. */ private void process(File baseDir, String xmlFile, File destDir, Resource stylesheet) throws BuildException { File outF = null; File inF; if (fileNameParameter != null) { transformer.setParameter(fileNameParameter, xmlFile); } if (fileDirParameter != null) { transformer.setParameter(fileDirParameter, baseDir.getAbsolutePath()); } try { long styleSheetLastModified = stylesheet.getLastModified(); inF = new File(baseDir, xmlFile); if (inF.isDirectory()) { log("Skipping " + inF + " it is a directory.", Project.MSG_VERBOSE); return; } FileNameMapper mapper; if (mapperElement != null) { mapper = mapperElement.getImplementation(); } else { mapper = new StyleMapper(); } String[] outFileName = mapper.mapFileName(xmlFile); if (outFileName == null || outFileName.length == 0) { log("Skipping " + inFile + " it cannot get mapped to output.", Project.MSG_VERBOSE); return; } else if (outFileName == null || outFileName.length > 1) { log("Skipping " + inFile + " its mapping is ambiguous.", Project.MSG_VERBOSE); return; } outF = new File(destDir, outFileName[0]); if (force || inF.lastModified() > outF.lastModified() || styleSheetLastModified > outF.lastModified()) { ensureDirectoryFor(outF); log("Processing " + inF + " to " + outF); configureLiaison(stylesheet); transform(inF, outF); } } catch (Exception ex) { // If failed to process document, must delete target document, // or it will not attempt to process it the second time log("Failed to process " + inFile, Project.MSG_INFO); if (outF != null) { outF.delete(); } throw new BuildException(ex); } } //-- processXML /** * Process the input file to the output file with the given stylesheet. * * @param inFile the input file to process. * @param outFile the destination file. * @param stylesheet the stylesheet to use. * @exception BuildException if the processing fails. */ private void process(File inFile, File outFile, Resource stylesheet) throws BuildException { try { long styleSheetLastModified = stylesheet.getLastModified(); log("In file " + inFile + " time: " + inFile.lastModified(), Project.MSG_DEBUG); log("Out file " + outFile + " time: " + outFile.lastModified(), Project.MSG_DEBUG); log("Style file " + xslFile + " time: " + styleSheetLastModified, Project.MSG_DEBUG); if (force || inFile.lastModified() >= outFile.lastModified() || styleSheetLastModified >= outFile.lastModified()) { ensureDirectoryFor(outFile); log("Processing " + inFile + " to " + outFile, Project.MSG_INFO); configureLiaison(stylesheet); transform(inFile, outFile); } else { log("Skipping input file " + inFile + " because it is older than output file " + outFile + " and so is the stylesheet " + stylesheet, Project.MSG_DEBUG); } } catch (Exception ex) { log("Failed to process " + inFile, Project.MSG_INFO); if (outFile != null) { outFile.delete(); } throw new BuildException(ex); } } private void transform(File in, File out) { if (transformer == null) { throw new BuildException("No transformer has been created"); } Source ss = new StreamSource(in); Result sr = new StreamResult(out); try { transformer.transform(ss, sr); } catch (TransformerException ex) { log("Failed to transform " + in, Project.MSG_INFO); if (out != null) { out.delete(); } throw new BuildException(ex); } } /** * Ensure the directory exists for a given file * * @param targetFile the file for which the directories are required. * @exception BuildException if the directories cannot be created. */ private void ensureDirectoryFor(File targetFile) throws BuildException { File directory = targetFile.getParentFile(); if (!directory.exists()) { if (!directory.mkdirs()) { throw new BuildException("Unable to create directory: " + directory.getAbsolutePath()); } } } /** * Get the Saxon Configuration being used (useful for subclasses) * @return the Saxon Configuration */ public Configuration getConfiguration() { return config; } /** * Get the XML catalog containing entity definitions * * @return the XML catalog for the task. */ public XMLCatalog getXMLCatalog() { xmlCatalog.setProject(getProject()); return xmlCatalog; } /** * Get an enumeration on the outputproperties. * @return the outputproperties */ public Enumeration getOutputProperties() { return outputProperties.elements(); } /** * Create an instance of an XSL parameter for configuration by Ant. * * @return an instance of the Param class to be configured. */ public Param createParam() { Param p = new Param(); params.addElement(p); return p; } /** * The Param inner class used to store XSL parameters */ public static class Param { /** The parameter name */ private String name = null; /** The parameter's value */ private String expression = null; private String ifProperty; private String unlessProperty; private Project project; /** * Set the current project * * @param project the current project */ public void setProject(Project project) { this.project = project; } /** * Set the parameter name. * * @param name the name of the parameter. */ public void setName(String name) { this.name = name; } /** * The parameter value * NOTE : was intended to be an XSL expression. * @param expression the parameter's value. */ public void setExpression(String expression) { this.expression = expression; } /** * Get the parameter name * * @return the parameter name * @exception BuildException if the name is not set. */ public String getName() throws BuildException { if (name == null) { throw new BuildException("Name attribute is missing."); } return name; } /** * Get the parameter's value * * @return the parameter value * @exception BuildException if the value is not set. */ public String getExpression() throws BuildException { if (expression == null) { throw new BuildException("Expression attribute is missing."); } return expression; } /** * Set whether this param should be used. It will be * used if the property has been set, otherwise it won't. * @param ifProperty name of property */ public void setIf(String ifProperty) { this.ifProperty = ifProperty; } /** * Set whether this param should NOT be used. It * will not be used if the property has been set, otherwise it * will be used. * @param unlessProperty name of property */ public void setUnless(String unlessProperty) { this.unlessProperty = unlessProperty; } /** * Ensures that the param passes the conditions placed * on it with if and unless properties. * @return true if the task passes the "if" and "unless" parameters */ public boolean shouldUse() { if (ifProperty != null && project.getProperty(ifProperty) == null) { return false; } else if (unlessProperty != null && project.getProperty(unlessProperty) != null) { return false; } return true; } } // Param /** * Create an instance of an output property to be configured. * @return the newly created output property. * @since Ant 1.5 */ public OutputProperty createOutputProperty() { OutputProperty p = new OutputProperty(); outputProperties.addElement(p); return p; } /** * Specify how the result tree should be output as specified * in the Serialization specification. * @since Ant 1.5 */ public static class OutputProperty { /** output property name */ private String name; /** output property value */ private String value; /** * @return the output property name. */ public String getName() { return name; } /** * set the name for this property * @param name A non-null String that specifies an * output property name, which may be namespace qualified. */ public void setName(String name) { this.name = name; } /** * @return the output property value. */ public String getValue() { return value; } /** * set the value for this property * @param value The non-null string value of the output property. */ public void setValue(String value) { this.value = value; } } /** * Initialize internal instance of XMLCatalog * @throws BuildException on error */ public void init() throws BuildException { super.init(); xmlCatalog.setProject(getProject()); } /** * Loads the stylesheet and set xsl:param parameters. * * @param stylesheet the file from which to load the stylesheet. * @exception BuildException if the stylesheet cannot be loaded. * @deprecated since Ant 1.7 */ protected void configureLiaison(File stylesheet) throws BuildException { FileResource fr = new FileResource(); fr.setProject(getProject()); fr.setFile(stylesheet); configureLiaison(fr); } /** * Loads the stylesheet and set xsl:param parameters. * * @param stylesheet the resource from which to load the stylesheet. * @exception BuildException if the stylesheet cannot be loaded. * @since Ant 1.7 */ protected void configureLiaison(Resource stylesheet) throws BuildException { if (stylesheetLoaded && reuseLoadedStylesheet) { return; } stylesheetLoaded = true; try { log("Loading stylesheet " + stylesheet, Project.MSG_INFO); // We call liason.configure() and then liaison.setStylesheet() // so that the internal variables of liaison can be set up if (stylesheet instanceof FileResource) { File styleFile = ((FileResource) stylesheet).getFile(); CompilerInfo info = new CompilerInfo(); info.setURIResolver(config.getURIResolver()); info.setErrorListener(config.getErrorListener()); info.setCompileWithTracing(config.isCompileWithTracing()); PreparedStylesheet pss = PreparedStylesheet.compile(new StreamSource(styleFile), config, info); transformer = (Controller)pss.newTransformer(); transformer.setInitialMode(initialMode); transformer.setInitialTemplate(initialTemplate); if (tracing) { transformer.addTraceListener(new XSLTTraceListener()); } if (recoveryPolicy != null) { if (recoveryPolicy.equals("silent")) { transformer.setRecoveryPolicy(Configuration.RECOVER_SILENTLY); } else if (recoveryPolicy.equals("recover")) { transformer.setRecoveryPolicy(Configuration.RECOVER_WITH_WARNINGS); } else { transformer.setRecoveryPolicy(Configuration.DO_NOT_RECOVER); } } } else { throw new BuildException("Saxon accepts the stylesheet only as a file", getLocation()); } for (Enumeration e = params.elements(); e.hasMoreElements();) { Param p = (Param) e.nextElement(); if (p.shouldUse()) { transformer.setParameter(p.getName(), p.getExpression()); } } } catch (Exception ex) { log("Failed to transform using stylesheet " + stylesheet, Project.MSG_INFO); throw new BuildException(ex); } } /** * Mapper implementation of the "traditional" way <xslt> * mapped filenames. * *

    If the file has an extension, chop it off. Append whatever * the user has specified as extension or ".html".

    * * @since Ant 1.6.2 */ private class StyleMapper implements FileNameMapper { public void setFrom(String from) { } public void setTo(String to) { } public String[] mapFileName(String xmlFile) { int dotPos = xmlFile.lastIndexOf('.'); if (dotPos > 0) { xmlFile = xmlFile.substring(0, dotPos); } return new String[] {xmlFile + targetExtension}; } } } // The NOTICE file referred to in the Apache license is reproduced below: //========================================================================= //== NOTICE file corresponding to the section 4 d of == //== the Apache License, Version 2.0, == //== in this case for the Apache Ant distribution. == //========================================================================= // //Apache Ant //Copyright 1999-2006 The Apache Software Foundation // //This product includes software developed by //The Apache Software Foundation (http://www.apache.org/). // //This product includes also software developed by : // - the W3C consortium (http://www.w3c.org) , // - the SAX project (http://www.saxproject.org) // //The task is based on code Copyright (c) 2002, Landmark //Graphics Corp that has been kindly donated to the Apache Software //Foundation. // saxonb-9.1.0.8/bj/net/sf/saxon/ant/package.html0000644000175000017500000000072311033112257020444 0ustar eugeneeugene Package overview: net.sf.saxon.ant

    This package contains the code to implement Ant tasks that invoke Saxon.

    At present there is one such task, to invoke a Saxon transformation. This is based very closely on the xslt task provided as a core task in the Ant product, but extended to allow access to XSLT 2.0 and Saxon-specific features.

    saxonb-9.1.0.8/bj/net/sf/saxon/IdentityTransformerHandler.java0000644000175000017500000001454011033112257023560 0ustar eugeneeugenepackage net.sf.saxon; import net.sf.saxon.event.*; import net.sf.saxon.om.AllElementStripper; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.Whitespace; import org.xml.sax.SAXException; import javax.xml.transform.Result; import javax.xml.transform.Transformer; import javax.xml.transform.sax.TransformerHandler; import javax.xml.transform.stream.StreamResult; import java.util.Properties; /** * IdentityTransformerHandler implements the javax.xml.transform.sax.TransformerHandler * interface. It acts as a ContentHandler and LexicalHandler which receives a stream of * SAX events representing an input document, and performs an identity transformation passing * these events to a Result * @author Michael H. Kay */ public class IdentityTransformerHandler extends ReceivingContentHandler implements TransformerHandler { private Result result; private String systemId; private Controller controller; /** * Create a IdentityTransformerHandler and initialise variables. The constructor is protected, because * the Filter should be created using newTransformerHandler() in the SAXTransformerFactory * class * @param controller the Controller for this transformation */ protected IdentityTransformerHandler(Controller controller) { this.controller = controller; setPipelineConfiguration(controller.makePipelineConfiguration()); } /** * Get the Transformer used for this transformation */ public Transformer getTransformer() { return controller; } /** * Set the SystemId of the document */ public void setSystemId(String url) { systemId = url; } /** * Get the systemId of the document */ public String getSystemId() { return systemId; } /** * Set the output destination of the transformation */ public void setResult(Result result) { if (result==null) { throw new IllegalArgumentException("Result must not be null"); } this.result = result; } /** * Get the output destination of the transformation * @return the output destination */ public Result getResult() { return result; } /** * Override the behaviour of startDocument() in ReceivingContentHandler */ public void startDocument() throws SAXException { if (result==null) { result = new StreamResult(System.out); } try { Properties props = controller.getOutputProperties(); PipelineConfiguration pipe = controller.makePipelineConfiguration(); Configuration config = getConfiguration(); SerializerFactory sf = config.getSerializerFactory(); Receiver out = sf.getReceiver(result, pipe, props); setPipelineConfiguration(pipe); int stripSpace = config.getStripsWhiteSpace(); if (stripSpace == Whitespace.ALL) { Stripper s = new AllElementStripper(); s.setStripAll(); s.setPipelineConfiguration(pipe); s.setUnderlyingReceiver(out); out = s; } setReceiver(out); } catch (XPathException err) { throw new SAXException(err); } super.startDocument(); } // public static void main(String[] args) throws Exception { // String in = "" + " " + // "\t1\n2000inq1 \t\r\t\n inquiry1 " + // ""; // String expected = "" + // "" + // "12000inq1inquiry1" + // "" ; // //System.setProperty(TRANSFORMERFACTORY_PROPERTY,TRANSFORMERFACTORY_IMPL); // TransformerFactory transFactory = new TransformerFactoryImpl(); // transFactory.setAttribute( // net.sf.saxon.FeatureKeys.STRIP_WHITESPACE, "all"); // if (transFactory.getFeature(SAXTransformerFactory.FEATURE)) { // // We can use an intermediate SAXResult and feed it to a // // TransformerHandler // SAXTransformerFactory saxTransFactory = (SAXTransformerFactory) transFactory; // TransformerHandler identityTransformerHandler = saxTransFactory // .newTransformerHandler(); // // SAXParserFactory factory = SAXParserFactory.newInstance(); // factory.setNamespaceAware(true) ; // SAXParser saxParser = factory.newSAXParser(); // XMLReader reader = saxParser.getXMLReader(); // DOMResult result = new DOMResult() ; // identityTransformerHandler.setResult(result); // reader.setContentHandler(identityTransformerHandler); // reader.parse(new InputSource(new StringReader(in))); // // //When we further transform the result in a String using a transformer, the // //whitespace nodes are not there // Transformer transf = transFactory.newTransformer(); // DOMSource inDOM = new DOMSource(result.getNode()); // StringWriter resWriter = new StringWriter() ; // StreamResult resStream = new StreamResult(resWriter) ; // transf.transform(inDOM, resStream); // String res = resWriter.toString(); // System.err.println(expected); // System.err.println(res); // // But the whitespace nodes are available in the DOM represenatation // Node docNode = result.getNode(); // The document node // Node rowsNode = docNode.getFirstChild(); // String name = rowsNode.getNodeName() ; // System.err.println(name); // Node rNode = rowsNode.getFirstChild(); // System.err.println(Node.ELEMENT_NODE == rNode.getNodeType()); // } // else { // throw new UnsupportedOperationException() ; // } // // // } } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay. // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): None // saxonb-9.1.0.8/bj/net/sf/saxon/SourceResolver.java0000644000175000017500000000471211033112257021230 0ustar eugeneeugenepackage net.sf.saxon; import net.sf.saxon.trans.XPathException; import javax.xml.transform.Source; /** * This interface defines a SourceResolver. A SourceResolver can be registered as * part of the Configuration, and enables new kinds of Source to be recognized * beyond those that are natively recognized by Saxon. *

    * The task of the SourceResolver is to take any Source as input, and to return * a Source that has native support in Saxon: that is, one of the classes * StreamSource, SAXSource, DOMSource, {@link net.sf.saxon.om.NodeInfo}, * or {@link net.sf.saxon.pull.PullSource} * @author Michael H. Kay */ public interface SourceResolver { /** * Resolve a Source. * @param source A source object, typically the source supplied as the first * argument to {@link javax.xml.transform.Transformer#transform(javax.xml.transform.Source, javax.xml.transform.Result)} * or similar methods. * @param config The Configuration. This provides the SourceResolver with access to * configuration information; it also allows the SourceResolver to invoke the * resolveSource() method on the Configuration object as a fallback implementation. * @return a source object that Saxon knows how to process. This must be an instance of one * of the classes StreamSource, SAXSource, DOMSource, {@link net.sf.saxon.AugmentedSource}, * {@link net.sf.saxon.om.NodeInfo}, * or {@link net.sf.saxon.pull.PullSource}. Return null if the Source object is not * recognized * @throws XPathException if the Source object is recognized but cannot be processed */ public Source resolveSource(Source source, Configuration config) throws XPathException; } // // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License"); // you may not use this file except in compliance with the License. You may obtain a copy of the // License at http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is Michael H. Kay // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonb-9.1.0.8/bj/net/sf/saxon/package.html0000644000175000017500000000231311033112257017657 0ustar eugeneeugene Package overview for net.sf.saxon

    This package provides the core classes of the SAXON XSLT library.

    Some of the more important classes are listed below:

    Transform:
    This is the XSLT processor. It has a command-line interface allowing you to apply a given style sheet to a given source document.

    PreparedStylesheet:
    This represents a compiled XSLT stylesheet in memory. It is Saxon's implementation of the javax.xml.transform.Templates interface defined in JAXP 1.1

    Controller:
    This class represents the context information for a single execution of an XSLT stylesheet, and allows the application to process the tree navigationally. It is Saxon's implementation of the javax.xml.transform.Transformer interface defined in JAXP 1.1. It calls user-supplied handlers registered with the RuleManager. If you want to write your own Java application to process a document navigationally, you can write it as a subclass of Controller, or you can instantiate Controller directly.


    Michael H. Kay
    25 April 2002